program Image;
@addemulatorparam "-nothrottle"
@use "system/z80cpm"
@use "system/system"
@use "system/screen"
@use "system/graphics"
@use "benchmark"
@use "misc"//-----------------------------------------

//-----------------------------------------
// uncomment JUST ONE of these three !
//@define clear_method_line 0
//@define clear_method_box 0
@define clear_method_backbuffer 0
//-----------------------------------------

@ifdef clear_method_line
// color 0 to clear
@define lib3d_clearlines 0
@define linemethod "Graphics::Line"
@endif

@ifdef clear_method_box
@define linemethod "Graphics::Line"
@endif

@ifdef clear_method_backbuffer
// Use pascal version
@define linemethod "Graphics::BLine"
@endif


@define max3dobjects 1
@define lib3d_projection_x_scale 2

@use "gfx/lib3d"


var  
	time, time2, i,j, curFrame : byte;
	size : integer;
	obj1 : incbin("data/torus1.bin");
	// objPos is the location where the object is stored: rotation matrix, 
	// rotated vertices and projected 2d coordinates
	const objPos : address = $2000;
	// Three matrices
	matX, matY, matZ, matT : Matrix::mat4;

	font: incbin("zxchars.bin", $3000);	// load an 8x8 font
	src, dst : pointer;
@ifdef clear_method_line
	clear_method_string: string = ("Line(...)");
@endif

@ifdef clear_method_box
	clear_method_string: string = ("ClearBox(...)");
@endif

@ifdef clear_method_backbuffer
	clear_method_string: string = ("Backbuffer");
@endif
	


procedure Render();
begin
	// Flips the projection pointers so that we always keep a copy of the previous line list for 
	// black line clearing
	Lib3d::FlipPointPointers(0);
	// Rotate x,y and z with some random time value
	Matrix::RotateX(#matX, time*4);
	Matrix::RotateY(#matY, time*3);
	Matrix::RotateZ(#matZ, time*2);

	// Mul X and Y to a temp mat T	
	Matrix::MatMul3(#matX, #matY, #matT);
	// Mul together and store in the objects rotation matrix
	Matrix::MatMul3(#matT, #matZ, Lib3d::objects[0].rotmat);
	// Perform the rotation (rotation_matrix * each vertex_in_the_object)
	Lib3d::RotateVertices(0);	
//	Lib3d::RotateVerticesOptimisedZ80(0);	
	// Projects the rotated vertices in a simple manner to 2d coordinates
	Lib3d::ProjectSimple(0,128,64,90,  80);
	
@ifdef clear_method_box
	//Screen::ClearBox(35,18,30,30,$55);
	Screen::ClearBox(5,4,55,25,0);
@endif
	Lib3d::RenderWireframeColor(0,3);
	
@ifdef clear_method_backbuffer
	Graphics::CopyBuffer128ToScreen($4000, $8A40);
@endif

end;	

begin
	Z80CPM::Startup();
	System::CursorOff();
	Screen::ClearBox(0, 0, 128, 64,0);
	Screen::SetFont(#font);

	Screen::GotoXY(10,2);
	Screen::PrintStr("Realtime calculation, clearing with ");
	Screen::PrintStr(#clear_method_string);

	Lib3d::InitializeData(#objPos);	
	Lib3d::LoadObject(0, #obj1);

	Matrix::Identity(#matX);
	Matrix::Identity(#matY);
	Matrix::Identity(#matZ);
	Matrix::Identity(Lib3d::objects[0].rotmat);
	
	time:=16;
	Benchmark::Setup();
	Misc::InitKeyboardCheck(5);
	while (not Misc::keyPressed) do
	begin
		Render();
		time+=1;
		Misc::KeyboardCheck();
		Benchmark::drawCount += 1;
		if Benchmark::benchFps <> 0 then Benchmark::Display();
	end;

	Z80CPM::GetChar();
	Benchmark::Cleanup();
	System::CursorOn();
	Z80CPM::Exit();
end.
