(**************************************** * NDS NeHe Lesson 10 * * Author: Dovoto * ****************************************) program Lesson10; {$mode objfpc} {$L build/Mud.pcx.o} {$L build/World.txt.o} {$L build/drunkenlogo.pcx.o} uses ctypes, nds9; {$include inc/Mud.pcx.inc} {$include inc/World.txt.inc} {$include inc/drunkenlogo.pcx.inc} const piover180: cfloat = 0.0174532925; var heading: cfloat = 0.0; xpos: cfloat = 0.0; zpos: cfloat = 0.0; yrot: cfloat = 0.0; // Y Rotation walkbias: cfloat = 0.0; walkbiasangle: cfloat = 0.0; lookupdown: cfloat = 0.0; texture: array [0..2] of integer; // Storage For 3 Textures (only going to use 1 on the DS for this demo) type tagVERTEX = record x, y, z: cfloat; u, v: cfloat; end; VERTEX = tagVERTEX; tagTRIANGLE = record vertex: array [0..2] of VERTEX; end; TRIANGLE = tagTRIANGLE; TTriangle = TRIANGLE; PTriangle = ^TRIANGLE; tagSECTOR = record numtriangles: integer; triangle: PTRIANGLE; end; SECTOR = tagSECTOR; TCubeRot = record x, y, z: cfloat; end; var sector1: SECTOR; // Our Model Goes Here: Myfile: PAnsiChar; cuberot: TCubeRot; procedure ShadowDemo(); forward; function DrawGLScene(): boolean; var x_m, y_m, z_m: cfloat; u_m, v_m: cfloat; xtrans, ztrans, ytrans: cfloat; sceneroty: cfloat; numtriangles: integer; loop_m: integer; begin // Reset The View xtrans := -xpos; ztrans := -zpos; ytrans := -walkbias - 0.25; sceneroty := 360.0 - yrot; glLoadIdentity(); glRotatef(lookupdown,1.0,0,0); glRotatef(sceneroty,0,1.0,0); glTranslatef(xtrans, ytrans, ztrans); glBindTexture(GL_TEXTURE_2D, texture[0]); numtriangles := sector1.numtriangles; // Process Each Triangle for loop_m := 0 to numtriangles - 1 do begin glBegin(GL_TRIANGLES); glNormal3f( 0.0, 0.0, 1.0); x_m := sector1.triangle[loop_m].vertex[0].x; y_m := sector1.triangle[loop_m].vertex[0].y; z_m := sector1.triangle[loop_m].vertex[0].z; u_m := sector1.triangle[loop_m].vertex[0].u; v_m := sector1.triangle[loop_m].vertex[0].v; glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m); x_m := sector1.triangle[loop_m].vertex[1].x; y_m := sector1.triangle[loop_m].vertex[1].y; z_m := sector1.triangle[loop_m].vertex[1].z; u_m := sector1.triangle[loop_m].vertex[1].u; v_m := sector1.triangle[loop_m].vertex[1].v; glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m); x_m := sector1.triangle[loop_m].vertex[2].x; y_m := sector1.triangle[loop_m].vertex[2].y; z_m := sector1.triangle[loop_m].vertex[2].z; u_m := sector1.triangle[loop_m].vertex[2].u; v_m := sector1.triangle[loop_m].vertex[2].v; glTexCoord2f(u_m,v_m); glVertex3f(x_m,y_m,z_m); glEnd(); end; ShadowDemo(); DrawGLScene := true; // Everything Went OK end; function tsin(angle: cfloat): cfloat; var s: cint32; begin s := sinLerp(trunc((angle * DEGREES_IN_CIRCLE) / 360.0)); tsin := f32tofloat(s); end; function tcos(angle: cfloat): cfloat; var c: cint32; begin c := cosLerp(trunc((angle * DEGREES_IN_CIRCLE) / 360.0)); tcos := f32tofloat(c); end; procedure myGetStr(buff: PAnsiChar; size: integer); begin buff^ := Myfile^; inc(MyFile); while (buff^ <> #10) and (buff^ <> #13) do begin inc(buff); buff^ := Myfile^; inc(MyFile); end; buff[0] := #10; buff[1] := #0; end; procedure readstr(str: PAnsiChar); begin repeat myGetStr(str, 255); until ((str[0] <> '/') and (str[0] <> #10)); end; procedure SetupWorld(); var x, y, z: cfloat; u, v: cfloat; numtriangles: integer; oneline: array [0..254] of AnsiChar; loop, vert: integer; begin readstr(oneline); sscanf(oneline, 'NUMPOLLIES %d'#10, @numtriangles); GetMem(sector1.triangle, numtriangles * sizeof(TTRIANGLE)); sector1.numtriangles := numtriangles; for loop := 0 to numtriangles - 1 do begin for vert := 0 to 2 do begin readstr(oneline); sscanf(oneline, '%f %f %f %f %f', @x, @y, @z, @u, @v); sector1.triangle[loop].vertex[vert].x := x; sector1.triangle[loop].vertex[vert].y := y; sector1.triangle[loop].vertex[vert].z := z; sector1.triangle[loop].vertex[vert].u := u; sector1.triangle[loop].vertex[vert].v := v; end; end; end; // Load PCX files And Convert To Textures function LoadGLTextures(): boolean; var pcx: sImage; begin glGenTextures(2, @texture[0]); //load our texture loadPCX(pcuint8(Mud_pcx), @pcx); image8to16(@pcx); glBindTexture(0, texture[0]); glTexImage2D(0, 0, GL_RGB, TEXTURE_SIZE_128 , TEXTURE_SIZE_128, 0, TEXGEN_TEXCOORD or GL_TEXTURE_WRAP_S or GL_TEXTURE_WRAP_T, pcx.image.data8); imageDestroy(@pcx); loadPCX(pcuint8(drunkenlogo_pcx), @pcx); image8to16(@pcx); glBindTexture(0, texture[1]); glTexImage2D(0, 0, GL_RGB, TEXTURE_SIZE_128, TEXTURE_SIZE_128, 0, TEXGEN_TEXCOORD, pcx.image.data8); imageDestroy(@pcx); result := true; end; procedure TransformCube(); begin glRotatef(cubeRot.x, 1.0, 0.0, 0.0); glRotatef(cubeRot.y, 0.0, 1.0, 0.0); glRotatef(cubeRot.z, 0.0, 0.0, 1.0); end; procedure EmitCube(); begin glPushMatrix(); glScalef(0.03, 0.03, 0.03); glRotatef(cubeRot.x, 1.0, 0.0, 0.0); glRotatef(cubeRot.y, 0.0, 1.0, 0.0); glRotatef(cubeRot.z, 0.0, 0.0, 1.0); glBegin(GL_QUADS); // Front Face glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); // Back Face glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); // Top Face glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 1.0); glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, 1.0, 1.0); glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); // Bottom Face glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, -1.0, -1.0); glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, -1.0, -1.0); glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); // Right face glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); // Left Face glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); glEnd(); glPopMatrix(1); end; procedure ShadowDemo(); begin cubeRot.y := cubeRot.y + 0.8; //draw the actual cube glPushMatrix(); glTranslatef(0.0, 0.4, -0.4); //draw the cube up in the air TransformCube(); glBindTexture(GL_TEXTURE_2D, texture[1]); EmitCube(); glPopMatrix(1); //draw the shadow: begin //draw the cube shadow on the ground glPushMatrix(); glTranslatef(0.0, 0.0, -0.4); TransformCube(); //use no texture. set shadow color: we'll use green just to show that it is possible glBindTexture(0, 0); glColor(RGB15(0, 8, 0)); //1st shadow pass //be sure to use opaque here glPolyFmt(POLY_SHADOW or POLY_CULL_FRONT or POLY_ALPHA(31)); EmitCube(); //2nd shadow pass //be sure to use a different polyID here (shadow with polyID 0 can't be cast on surface with polyID 0) //we set the fog bit here because we want the shadow to be fogged later. i think it may be buggy but it looks better. glPolyFmt(POLY_SHADOW or POLY_CULL_BACK or POLY_ALPHA(15) or POLY_ID(1) or POLY_FOG); EmitCube(); //reset poly attribute glPolyFmt(POLY_ALPHA(31) or POLY_CULL_NONE or POLY_FORMAT_LIGHT0 or POLY_FOG); glPopMatrix(1); end; end; var thisXY: touchPosition; lastXY: touchPosition; dx, dy: cint16; i: integer; held: integer; begin MyFile := PAnsiChar(@World_txt); // Setup the Main screen for 3D videoSetMode(MODE_0_3D); vramSetBankA(VRAM_A_TEXTURE); //NEW must set up some memory for textures consoleDemoInit(); // initialize the geometry engine glInit(); // enable textures glEnable(GL_TEXTURE_2D); // enable antialiasing glEnable(GL_ANTIALIAS); // enable alpha blending for shadow demo glEnable(GL_BLEND); // setup the rear plane glClearColor(0,0,0,31); // BG must be opaque for AA to work glClearPolyID(63); // BG must have a unique polygon ID for AA to work glClearDepth($7FFF); // Set our viewport to be the same size as the screen glViewport(0,0,255,191); LoadGLTextures(); SetupWorld(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(70, 256.0 / 192.0, 0.1, 100); glLight(0, RGB15(31,31,31) , 0, floattov10(-1.0), 0); //need to set up some material properties since DS does not have them set by default glMaterialf(GL_AMBIENT, RGB15(16,16,16)); glMaterialf(GL_DIFFUSE, RGB15(16,16,16)); glMaterialf(GL_SPECULAR, BIT(15) or RGB15(8,8,8)); glMaterialf(GL_EMISSION, RGB15(16,16,16)); //ds uses a table for shinyness..this generates a half-ass one glMaterialShinyness(); //ds specific, several attributes can be set here glPolyFmt(POLY_ALPHA(31) or POLY_CULL_NONE or POLY_FORMAT_LIGHT0 or POLY_FOG); // Set the current matrix to be the model matrix glMatrixMode(GL_MODELVIEW); //setup demo fog parameters //these parameters are somewhat arbitrary, and designed to illustrate fog in just this one case. //you will certainly need to tweak them for your own use. //be sure to have set the POLY_FOG bit on any material you want to be fogged. glEnable(GL_FOG); glFogShift(2); glFogColor(0, 0, 0, 0); for i := 0 to 31 do glFogDensity(i, i * 4); glFogDensity(31, 127); glFogOffset($6000); while true do begin //these little button functions are pretty handy scanKeys(); held := keysHeld(); if (held and KEY_A) <> 0 then lookupdown := lookupdown - 1.0; if (held and KEY_B) <> 0 then lookupdown := lookupdown + 1.0; if (held and KEY_LEFT) <> 0 then begin heading := heading + 1.0; yrot := heading; end; if (held and KEY_RIGHT) <> 0 then begin heading := heading - 1.0; yrot := heading; end; if (held and KEY_DOWN) <> 0 then begin xpos := xpos + (tsin(heading)) * 0.05; zpos := zpos + (tcos(heading)) * 0.05; if (walkbiasangle >= 359.0) then walkbiasangle := 0.0 else walkbiasangle:= walkbiasangle+10; walkbias := tsin(walkbiasangle) / 20.0; end; if (held and KEY_UP) <> 0 then begin xpos := xpos - (tsin(heading)) * 0.05; zpos := zpos - (tcos(heading)) * 0.05; if (walkbiasangle <= 1.0) then walkbiasangle := 359.0 else walkbiasangle := walkbiasangle- 10; walkbias := tsin(walkbiasangle) / 20.0; end; glColor3f(1,1,1); DrawGLScene(); // flush to screen glFlush(0); // wait for the screen to refresh swiWaitForVBlank(); if (held and KEY_START) <> 0 then break; end; end.