program Lesson11;
{$L build/drunkenlogo.pcx.o}

{$mode objfpc} 

uses
  ctypes, nds9; 

{$include inc/drunkenlogo.pcx.inc}

var
  points: array [0..63, 0..31, 0..2] of v16;    // The Array For The Points On The Grid Of Our "Wave"
  wiggle_count: integer = 0;		// Counter Used To Control How Fast Flag Waves

  xrot: cfloat;				// X Rotation ( NEW )
  yrot: cfloat;				// Y Rotation ( NEW )
  zrot: cfloat;				// Z Rotation ( NEW )
  hold: v16;				  // Temporarily Holds A Floating Point Value

  texture: array [0..0] of integer;			// Storage For 3 Textures (only going to use 1 on the DS for this demo)

function sin(angle: cfloat): cfloat;
var
  s: cint32;
begin
  s := sinLerp(cint((angle * DEGREES_IN_CIRCLE) / 360.0));
  result := f32tofloat(s);
end;

function cos(angle: cfloat): cfloat;
var
  c: int32;
begin
  c := cosLerp(cint((angle * DEGREES_IN_CIRCLE) / 360.0));
  result := f32tofloat(c);
end;

function DrawGLScene(): boolean;											// Here's Where We Do All The Drawing
var
  x, y: integer;
  float_x, float_y, float_xb, float_yb: t16;
begin

	glColor3b(255,255,255);    // set the vertex color
	
	glLoadIdentity();									// Reset The View

	glTranslatef(0.0,0.0,-12.0);
	  
	glRotatef(xrot,1.0,0.0,0.0);
	glRotatef(yrot,0.0,1.0,0.0);  
	glRotatef(zrot,0.0,0.0,1.0);

	glBindTexture(GL_TEXTURE_2D, texture[0]);

	glBegin(GL_QUADS);
	for x := 0 to 30 do
	begin
		for  y := 0 to 30 do
		begin
			float_x := inttot16(x) shl 2;
			float_y := inttot16(y) shl 2;
			float_xb := inttot16(x+1) shl 2;
			float_yb := inttot16(y+1) shl 2;

			glTexCoord2t16( float_x, float_y);
			glVertex3v16( points[x][y][0], points[x][y][1], points[x][y][2] );

			glTexCoord2t16( float_x, float_yb );
			glVertex3v16( points[x][y+1][0], points[x][y+1][1], points[x][y+1][2] );

			glTexCoord2t16( float_xb, float_yb );
			glVertex3v16( points[x+1][y+1][0], points[x+1][y+1][1], points[x+1][y+1][2] );

			glTexCoord2t16( float_xb, float_y );
			glVertex3v16( points[x+1][y][0], points[x+1][y][1], points[x+1][y][2] );
		end;
	end;
	glEnd();

	if ( wiggle_count = 2 ) then
	begin
		for y := 0 to 31 do
		begin
			hold := points[0][y][2];
			for x := 0 to 31 do
			begin
				points[x][y][2] := points[x+1][y][2];
			end;
			points[31][y][2]:=hold;
		end;
		wiggle_count := 0;
	end;

	inc(wiggle_count);

	xrot:=xrot+0.3;
	yrot:=yrot+0.2;
	zrot:=zrot+0.4;

	result := true;											// Everything Went OK

end;


 
function LoadGLTextures(): boolean;									// Load PCX files And Convert To Textures
var
	pcx: sImage;                //////////////(NEW) and different from nehe.
begin
	//load our texture
	loadPCX(pcuint8(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.image.data8);

	result := true;
end;

procedure InitGL();
var
  x, y:integer;
begin
	// Setup the Main screen for 3D 
	videoSetMode(MODE_0_3D);
	vramSetBankA(VRAM_A_TEXTURE);                        //NEW  must set up some memory for textures
	
	// initialize the geometry engine
	glInit();
	
	// enable textures
	glEnable(GL_TEXTURE_2D);
	
	// Set our viewport to be the same size as the screen
	glViewPort(0,0,255,191);
	
	// enable antialiasing
	glEnable(GL_ANTIALIAS);
	
	// 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);
	
	LoadGLTextures();
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(70, 256.0 / 192.0, 0.1, 100);
	
	//need to set up some material properties since DS does not have them set by default
	glMaterialf(GL_AMBIENT, RGB15(31,31,31));
	glMaterialf(GL_DIFFUSE, RGB15(31,31,31));
	glMaterialf(GL_SPECULAR, BIT(15) or RGB15(16,16,16));
	glMaterialf(GL_EMISSION, RGB15(31,31,31));
	
	//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 );
	

	for x:=0 to 31 do
	begin
		for y:=0 to 31 do
		begin
			points[x][y][0] := (inttov16(x) div 4);
			points[x][y][1] := (inttov16(y) div 4);
			points[x][y][2] := sinLerp(x * (DEGREES_IN_CIRCLE div 32));
		end;
	end;
end;


begin	
	InitGL();
	
	glMatrixMode(GL_MODELVIEW);

	while true do
	begin	
		DrawGLScene();
		
		// flush to screen	
		glFlush(0);
		
		// wait for the screen to refresh
		swiWaitForVBlank();
	end;
end.
