|
This lesson will go over how to begin with lighting, creating and applying textures, and materials, so let's dig in!
The original didn't include normals (which are needed for lighting), therefore, lessons 6 and 7 are fused together.
Tip: If you are on a windows platform, I recomend using Usenti for creating .pcx files for textures. It can also load .PNG. I suggest this, because there seemed to have been a problem when I saved a .PCX from photoshop, but it's still a nice tool.
Lesson 6 Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 |
#include <nds.h>
#include <malloc.h>
#include <nds/arm9/image.h>
#include "drunkenlogo_pcx.h"
int DrawGLScene();
float xrot; float yrot; float zrot;
int texture[1];
int LoadGLTextures() {
sImage pcx;
loadPCX((u8*)drunkenlogo_pcx, &pcx);
image8to16(&pcx);
glGenTextures(1, &texture[0]);
glBindTexture(0, texture[0]);
glTexImage2D(0, 0, GL_RGB, TEXTURE_SIZE_128 , TEXTURE_SIZE_128,
0, TEXGEN_TEXCOORD, pcx.data8);
imageDestroy(&pcx);
return TRUE;
}
int main()
{
powerON(POWER_ALL);
videoSetMode(MODE_0_3D);
vramSetBankA(VRAM_A_TEXTURE);
irqInit();
irqSet(IRQ_VBLANK, 0);
glViewPort(0,0,255,191);
glClearColor(0,0,0);
glClearDepth(0x7FFF);
LoadGLTextures();
while (1)
{
glReset();
gluPerspective(35, 256.0 / 192.0, 0.1, 100);
glColor3f(1,1,1);
glLight(0, RGB15(31,31,31) , 0, floattov10(-1.0), 0);
glLight(1, RGB15(31,31,31) , 0, 0, floattov10(-1.0));
glLight(2, RGB15(31,31,31) , 0, 0, floattov10(1.0));
glPushMatrix();
glMatrixMode(GL_TEXTURE);
glIdentity();
glMatrixMode(GL_MODELVIEW);
glMaterialf(GL_AMBIENT, RGB15(16,16,16));
glMaterialf(GL_DIFFUSE, RGB15(16,16,16));
glMaterialf(GL_SPECULAR, BIT(15) | RGB15(8,8,8));
glMaterialf(GL_EMISSION, RGB15(16,16,16));
glMaterialShinyness();
glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE | POLY_FORMAT_LIGHT0|
POLY_FORMAT_LIGHT1| POLY_FORMAT_LIGHT2);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
DrawGLScene();
glPopMatrix(1);
glFlush();
}
return 0;
}
int DrawGLScene() {
glLoadIdentity(); glTranslatef(0.0f,0.0f,-5.0f);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glBegin(GL_QUADS);
glNormal3f( 0.0f, 0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glNormal3f( 0.0f, 0.0f,-1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glNormal3f( 0.0f, 1.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glNormal3f( 0.0f,-1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glNormal3f( 1.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glNormal3f(-1.0f, 0.0f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glEnd();
xrot+=0.3f;
yrot+=0.2f;
zrot+=0.4f;
return TRUE;
} |
Analyze:
Line 7: #incude "drunkenlogo_pcx.h"
This include file is generated with the bin2o macro in devkitARM\base_rules. check the makefile for more information on using the macro.
Line 17: int texture[1];
When creating the texture, it will be placed in here for us to call at our disposal when rendering and applying it.
Line 24: loadPCX((u8*)drunkenlogo_pcx, &pcx);
Load drunkenlogo.pcx (which was converted to a (const unsigned char[]) variable and externed in drunkenlogo_pcx.h) from memory and store it in the variable, pcx.
Line 27: image8to16(&pcx);
Convert the image from 8-bit to 16-bit
Line 29: glGenTextures(1, &texture[0]);
Generate enough space for 1 texture map inside of int texture.
Line 30: glBindTexture(0, texture[0]); Set this texture into memory for further usage (only one texture at a time and if this were PC OpenGL, the 0 would most likely be GL_TEXTURE_2D).
To disable the currently bound texture, call glBindTexture(0,0). The first variable does absolutely nothing, it's only there for easier code porting.
Lines 31-32: glTexImage2D(0, 0, GL_RGB, TEXTURE_SIZE_128 , TEXTURE_SIZE_128,
0, TEXGEN_TEXCOORD, pcx.data8);
Create a 2D texture in VRAM (only if there's enough space. A 128x128 texture takes up quite a bit of room in the bank. If you have a lot of textures, set multiple banks for textures. It's probably best to use small, tileable textures, such as 32x32)
You can have an alpha channel with GL_RGBA instead, but you would also need to change to bit converter for transparency and input the index of the channel.
Line 34: imageDestroy(&pcx);
Free pcx
Line 47:vramSetBankA(VRAM_A_TEXTURE);
Set bank A for texture use, as mentioned in glTexImage2D, a bank can only hold so much data, if you have lots of textures, make them smaller dimensions and possibly even set more banks for textures.
Lines 71-73: glLight ...
The first parameter is for which light index you wish to set (0-3), and next is for the color.
The last 3 are for the x,y,z direction, respectively. These coordinates are special and converted to a different fixed point (v10) which ranges from -1 to 0.998 in float, since there is no vector normalization on hardware.
Lines 77-78: glMatrixMode(GL_TEXTURE);
Set the current matrix mode to texture and make it an identity matrix (no need to modify appearance in this lesson).
Lines 84-87: glMaterialf ...
Set some material properties which pertains to to the lighting, typically in an attempt to create a smoother appearance.
Smoothing Tip: Ambient and Diffuse should be the same. The magnitude of Diffuse + Specular (when they are added together) should be close to 1 (or RGB15(31,31,31)) to prevent a color value overflow.
Line 90: glMaterialShinyness();
Instead of having to create your own table, you may use this function.
Lines 94-95: glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE |
POLY_FORMAT_LIGHT0| POLY_FORMAT_LIGHT1| POLY_FORMAT_LIGHT2);
We are using 3 lights, so we add light indices {0,1,2} to the poly format.
Line 128: glBindTexture(GL_TEXTURE_2D, texture[0]);
Set the texture to be used for rendering. This may NOT be called inside of a begin/end block (you will not be able to change textures inside of it and will get no display). Always remember to set the texture before the block.
When you are finished with a texture, disable it with glBindTexture(0,0) so it doesn't interfere with further rendering.
Line 132: glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f takes the x and y coords (origin is top left, just as for the framebuffer) there is a maximum of 1.0f for both axis, unless you enable texture wrapping in glTexImage2D. You must set the texture coordinates before the vertex. And as stated in past lessons, make sure you call glColor3f(1,1,1) to leave the applied texture untouched/un-tinted.
The 0-1 limit is only for a 128x128 texture, a 256x256 texture would need to go from 0-2.0f to get the whole image. a 64x64 would only need 0-0.5f, and so on...
Line 133: glNormal3f ....
The normal of a face is what lights look for when calculating the shading appearance. In general, the normal is perpindicular to the face for an even distribution of lighting. You can calculate the normal yourself using the cross product:
Given a point p and a line through a and b in a plane, all with z coordinate zero, then the z component of (p-a) × (b-a) will be positive or negative, depending on which side of the line p is.
It's easier to have a 3D application such as Maya or 3DS Max to do this for you. There is a 30-day evaluation available for max, you can use maxscript to export the data you want.
After this lesson, play around some more with the materials to get a better understanding of how it affects objects, then go on to the next tutorial for some more fun.
|