1 module test0.app;
2 
3 import std.stdio;
4 import std.string;
5 import std.conv;
6 import std.format;
7 import std.random;
8 
9 import bindbc.sdl;
10 
11 
12 import pixelperfectengine.graphics.outputscreen;
13 import pixelperfectengine.graphics.raster;
14 import pixelperfectengine.graphics.layers;
15 
16 import pixelperfectengine.graphics.bitmap;
17 
18 import pixelperfectengine.collision.common;
19 import pixelperfectengine.collision.objectcollision;
20 
21 import pixelperfectengine.system.input;
22 import pixelperfectengine.system.file;
23 import pixelperfectengine.system.etc;
24 import pixelperfectengine.system.config;
25 
26 import pixelperfectengine.system.common;
27 
28 int main() {
29 	initialzeSDL();
30     TileLayerTest tlt = new TileLayerTest(8, 8);
31     tlt.whereTheMagicHappens();
32     return 0;
33 }
34 
35 /**
36  * Tests graphics output, input events, collision, etc.
37  */
38 class TileLayerTest : SystemEventListener, InputListener {
39 	bool isRunning, up, down, left, right, scrup, scrdown, scrleft, scrright;
40 	OutputScreen output;
41 	Raster r;
42 	TileLayer t;
43 	TileLayer textLayer;
44 	TransformableTileLayer!(Bitmap8Bit,16,16) tt;
45 	Bitmap8Bit[] tiles;
46 	Bitmap8Bit dlangMan;
47 	Bitmap1Bit dlangManCS;
48 	SpriteLayer s;
49 	InputHandler ih;
50 	ObjectCollisionDetector ocd;
51 	float theta;
52 	int framecounter;
53 	this (int mapWidth, int mapHeight) {
54 		theta = 0;
55 		isRunning = true;
56 		Image tileSource = loadImage(File("../assets/sci-fi-tileset.png"));
57 		//Image tileSource = loadImage(File("../assets/_system/concreteGUIE0.tga"));
58 		Image spriteSource = loadImage(File("../assets/d-man.tga"));
59 		Image fontSource = loadImage(File("../system/codepage_8_8.png"));
60 		output = new OutputScreen("TileLayer test", 424 * 4, 240 * 4);
61 		r = new Raster(424,240,output,0);
62 		output.setMainRaster(r);
63 		t = new TileLayer(16,16, RenderingMode.Copy);
64 		textLayer = new TileLayer(8,8, RenderingMode.AlphaBlend);
65 		textLayer.paletteOffset = 512;
66 		textLayer.masterVal = 127;
67 		textLayer.loadMapping(53, 30, new MappingElement[](53 * 30));
68 		tt = new TransformableTileLayer!(Bitmap8Bit,16,16)(RenderingMode.AlphaBlend);
69 		s = new SpriteLayer(RenderingMode.AlphaBlend);
70 		r.addLayer(tt, 1);
71 		r.addLayer(t, 0);
72 		r.addLayer(s, 2);
73 		r.addLayer(textLayer, 65_536);
74 
75 		Color[] localPal = loadPaletteFromImage(tileSource);
76 		localPal.length = 256;
77 		r.addPaletteChunk(localPal);
78 		localPal = loadPaletteFromImage(spriteSource);
79 		localPal.length = 256;
80 		r.addPaletteChunk(localPal);
81 		r.addPaletteChunk([Color(0x00,0x00,0x00,0xFF),Color(0xff,0xff,0xff,0xFF),Color(0x00,0x00,0x00,0xFF),
82 				Color(0xff,0x00,0x00,0xFF),Color(0x00,0x00,0x00,0xFF),Color(0x00,0xff,0x00,0xFF),Color(0x00,0x00,0x00,0xFF),
83 				Color(0x00,0x00,0xff,0xFF),Color(0x00,0x00,0xff,0xFF),Color(0x00,0x00,0xff,0xFF),Color(0x00,0x00,0xff,0xFF),
84 				Color(0x00,0x00,0xff,0xFF),Color(0x00,0x00,0xff,0xFF),Color(0x00,0x00,0xff,0xFF),Color(0x00,0x00,0xff,0xFF),
85 				Color(0x00,0x00,0xff,0xFF)]);
86 
87 		//writeln(r.layerMap);
88 		//c = new CollisionDetector();
89 		dlangMan = loadBitmapFromImage!Bitmap8Bit(spriteSource);
90 		dlangManCS = dlangMan.generateStandardCollisionModel();
91 		ocd = new ObjectCollisionDetector(&onCollision, 0);
92 		{
93 			Image i = loadImage(File("../assets/basn3p04.png"));
94 			r.addPaletteChunk(loadPaletteFromImage(i));
95 			s.addSprite(loadBitmapFromImage!Bitmap4Bit(i), 65_537, 320, 200, 0x21);//34
96 		}
97 		{
98 			Image i = loadImage(File("../assets/basn3p02.png"));
99 			r.addPaletteChunk(loadPaletteFromImage(i));
100 			s.addSprite(loadBitmapFromImage!Bitmap2Bit(i), 65_538, 352, 200, 0x88);//0x88
101 		}
102 		//s.addSprite(loadBitmapFromFile!Bitmap2Bit("..assets/basn3p04.png"));
103 		s.addSprite(dlangMan, 65_536, 0, 0, 1);
104 		ocd.objects[65_536] = CollisionShape(Box(0, 0, 31, 31), dlangManCS);
105 		s.addSprite(dlangMan, 0, 0, 0, 1, 0x0, 0x0, -1024, -1024);
106 
107 		for(int i = 1 ; i < 1500 ; i++){
108 			const int x = uniform(0,320), y = uniform(0,240);
109 			s.addSprite(dlangMan, i, x, y, 1);
110 			ocd.objects[i] = CollisionShape(Box(x, y, x + 31, y + 31), dlangManCS);
111 		}
112 		
113 		tiles = loadBitmapSheetFromImage!Bitmap8Bit(tileSource, 16, 16);//loadBitmapSheetFromFile!Bitmap8Bit("../assets/sci-fi-tileset.png",16,16);
114 		
115 		for (int i; i < tiles.length; i++) {
116 			tt.addTile(tiles[i], cast(wchar)i);
117 		}
118 		
119 		for (int i; i < tiles.length; i++) {
120 			t.addTile(tiles[i], cast(wchar)i);
121 		}
122 		
123 		{
124 			Bitmap8Bit[] fontSet = loadBitmapSheetFromImage!Bitmap8Bit(fontSource, 8, 8);
125 			for (ushort i; i < fontSet.length; i++) {
126 				textLayer.addTile(fontSet[i], i, 1);
127 			}
128 		}
129 		//wchar[] mapping;
130 		MappingElement[] mapping;
131 		mapping.length = mapWidth * mapHeight;//64*64;
132 		//attrMapping.length = 256*256;
133 		for(int i; i < mapping.length; i++){
134 			//mapping[i] = to!wchar(uniform(0x0000,0x00AA));
135 			const int rnd = uniform(0,1024);
136 			//attrMapping[i] = BitmapAttrib(rnd & 1 ? true : false, rnd & 2 ? true : false);
137 			mapping[i] = MappingElement(cast(wchar)(rnd & 63), BitmapAttrib(rnd & 1024 ? true : false, rnd & 512 ? true : false));
138 			//mapping[i] = MappingElement(0x0, BitmapAttrib(false,false));
139 		}
140 		ih = new InputHandler();
141 		ih.systemEventListener = this;
142 		ih.inputListener = this;
143 		
144 		{
145 			import pixelperfectengine.system.input.scancode;
146 			ih.addBinding(BindingCode(ScanCode.UP, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("up"));
147 			ih.addBinding(BindingCode(ScanCode.DOWN, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("down"));
148 			ih.addBinding(BindingCode(ScanCode.LEFT, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("left"));
149 			ih.addBinding(BindingCode(ScanCode.RIGHT, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("right"));
150 			ih.addBinding(BindingCode(ScanCode.np8, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrup"));
151 			ih.addBinding(BindingCode(ScanCode.np2, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrdown"));
152 			ih.addBinding(BindingCode(ScanCode.np4, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrleft"));
153 			ih.addBinding(BindingCode(ScanCode.np6, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrright"));
154 			ih.addBinding(BindingCode(ScanCode.Q, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("A+"));
155 			ih.addBinding(BindingCode(ScanCode.A, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("A-"));
156 			ih.addBinding(BindingCode(ScanCode.W, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("B+"));
157 			ih.addBinding(BindingCode(ScanCode.S, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("B-"));
158 			ih.addBinding(BindingCode(ScanCode.E, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("C+"));
159 			ih.addBinding(BindingCode(ScanCode.D, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("C-"));
160 			ih.addBinding(BindingCode(ScanCode.R, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("D+"));
161 			ih.addBinding(BindingCode(ScanCode.F, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("D-"));
162 			ih.addBinding(BindingCode(ScanCode.T, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("x0+"));
163 			ih.addBinding(BindingCode(ScanCode.G, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("x0-"));
164 			ih.addBinding(BindingCode(ScanCode.Y, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("y0+"));
165 			ih.addBinding(BindingCode(ScanCode.H, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("y0-"));
166 			ih.addBinding(BindingCode(ScanCode.PAGEUP, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("alpha+"));
167 			ih.addBinding(BindingCode(ScanCode.PAGEDOWN, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("alpha-"));
168 			ih.addBinding(BindingCode(ScanCode.HOME, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("hidettl"));
169 			ih.addBinding(BindingCode(ScanCode.END, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("unhidettl"));
170 			ih.addBinding(BindingCode(ScanCode.n1, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("sprtH-"));
171 			ih.addBinding(BindingCode(ScanCode.n2, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("sprtH+"));
172 			ih.addBinding(BindingCode(ScanCode.n3, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("sprtV-"));
173 			ih.addBinding(BindingCode(ScanCode.n4, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("sprtV+"));
174 			ih.addBinding(BindingCode(ScanCode.n5, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("2up"));
175 			ih.addBinding(BindingCode(ScanCode.n6, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("2down"));
176 			ih.addBinding(BindingCode(ScanCode.n7, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("2left"));
177 			ih.addBinding(BindingCode(ScanCode.n8, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("2right"));
178 		}
179 		
180 		tt.loadMapping(mapWidth, mapHeight, mapping);
181 		tt.warpMode = WarpMode.Off;
182 		
183 		t.loadMapping(mapWidth, mapHeight, mapping);
184 		t.warpMode = WarpMode.TileRepeat;
185 		
186 		//t.setWrapMode(true);
187 		//tt.D = -256;
188 		//loadPaletteFromXMP(tileSource, "default", r);
189 
190 		/*for(int y ; y < 240 ; y++){
191 			for(int x ; x < 240 ; x++){
192 				writeln('[',x,',',y,"] : ", t.transformFunc([x,y]));
193 			}
194 		}*/
195 		
196 		//writeln(r.palette);
197 		//r.palette[0].alpha = 255;
198 		//r.palette[256].base = 0;
199 		//textLayer.writeTextToMap(2,2,0,"Hello world!",BitmapAttrib(true, false));
200 		textLayer.writeTextToMap(0, 0, 0, "Framerate:", BitmapAttrib(true, false));
201 		textLayer.writeTextToMap(0, 1, 0, "Collision:", BitmapAttrib(true, false));
202 		textLayer.writeTextToMap(0, 2, 0, "Col. type:", BitmapAttrib(true, false));
203 		//writeln(tt);
204 		//r.palette[0] = 255;
205 		//r.addRefreshListener(output, 0);
206 
207 	}
208 	private @nogc void ttlHBlankInterrupt(ref short[4] localABCD, ref short[2] localsXsY, ref short[2] localx0y0, short y){
209 		localABCD[0]++;
210 	}
211 	public void whereTheMagicHappens(){
212 		while(isRunning){
213 			r.refresh();
214 			ih.test();
215 			if(up) {
216 				s.relMoveSprite(65_536,0,-1);
217 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
218 			}
219 			if(down) {
220 				s.relMoveSprite(65_536,0,1);
221 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
222 			}
223 			if(left) {
224 				s.relMoveSprite(65_536,-1,0);
225 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
226 			}
227 			if(right) {
228 				s.relMoveSprite(65_536,1,0);
229 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
230 			}
231 			ocd.objects.ptrOf(65_536).position = s.getSpriteCoordinate(65_536);
232 			ocd.testSingle(65_536);
233 			if(scrup) {
234 				t.relScroll(0,-1);
235 				tt.relScroll(0,-1);
236 				s.relScroll(0,-1);
237 			}
238 			if(scrdown) {
239 				t.relScroll(0,1);
240 				tt.relScroll(0,1);
241 				s.relScroll(0,1);
242 			}
243 			if(scrleft) {
244 				t.relScroll(-1,0);
245 				tt.relScroll(-1,0);
246 				s.relScroll(-1,0);
247 			}
248 			if(scrright) {
249 				t.relScroll(1,0);
250 				tt.relScroll(1,0);
251 				s.relScroll(1,0);
252 			}
253 			
254 			framecounter++;
255 			if(framecounter == 10){
256 				float avgFPS = r.avgfps;
257 				wstring fpsCounter = format(" %3.3f"w, avgFPS);
258 				textLayer.writeTextToMap(10,0,0,fpsCounter,BitmapAttrib(true, false));
259 				framecounter = 0;
260 			}
261 			//t.relScroll(1,0);
262 		}
263 	}
264 	public void onCollision(ObjectCollisionEvent event) {
265 		textLayer.writeTextToMap(10,1,0,format("%8X"w,event.idB),BitmapAttrib(true, false));
266 		final switch (event.type) with (ObjectCollisionEvent.Type) {
267 			case None:
268 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
269 				break;
270 			case BoxEdge:
271 				textLayer.writeTextToMap(10,2,0,"     BoxEdge",BitmapAttrib(true, false));
272 				break;
273 			case BoxOverlap:
274 				textLayer.writeTextToMap(10,2,0,"  BoxOverlap",BitmapAttrib(true, false));
275 				break;
276 			case ShapeOverlap:
277 				textLayer.writeTextToMap(10,2,0,"ShapeOverlap",BitmapAttrib(true, false));
278 				break;
279 		}
280 	}
281 	override public void onQuit() {
282 		isRunning = false;
283 	}
284 	public void controllerAdded(uint id) {
285 
286 	}
287 	public void controllerRemoved(uint id) {
288 
289 	}
290 	/**
291 	 * Called when a keybinding event is generated.
292 	 * The `id` should be generated from a string, usually the name of the binding.
293 	 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc).
294 	 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses.
295 	 * NOTE: Hat events on joysticks don't generate keyReleased events, instead they generate keyPressed events on release.
296 	 */
297 	public void keyEvent(uint id, BindingCode code, uint timestamp, bool isPressed) {
298 		//writeln(id, ";", code, ";",timestamp, ";",isPressed, ";");
299 		switch (id) {
300 			case hashCalc("up"):	//up
301 				up = isPressed;
302 				break;
303 			case hashCalc("down"):	//down
304 				down = isPressed;
305 				break;
306 			case hashCalc("left"):	//left
307 				left = isPressed;
308 				break;
309 			case hashCalc("right"):	//right
310 				right = isPressed;
311 				break;
312 			case hashCalc("scrup"):	//scrup
313 				scrup = isPressed;
314 				break;
315 			case hashCalc("scrdown"):		//scrdown
316 				scrdown = isPressed;
317 				break;
318 			case hashCalc("scrleft"):	//scrleft
319 				scrleft = isPressed;
320 				break;
321 			case hashCalc("scrright"):	//scrright
322 				scrright = isPressed;
323 				break;
324 			case hashCalc("A+"): 	//A+
325 				tt.A = cast(short)(tt.A + 16);
326 				break;
327 			case hashCalc("A-"):	//A-
328 				tt.A = cast(short)(tt.A - 16);
329 				break;
330 			case hashCalc("B+"):	//B+
331 				tt.B = cast(short)(tt.B + 16);
332 				break;
333 			case hashCalc("B-"):	//B-
334 				tt.B = cast(short)(tt.B - 16);
335 				break;
336 			case hashCalc("C+"):	//C+
337 				tt.C = cast(short)(tt.C + 16);
338 				break;
339 			case hashCalc("C-"):	//C-
340 				tt.C = cast(short)(tt.C - 16);
341 				break;
342 			case hashCalc("D+"):	//D+
343 				tt.D = cast(short)(tt.D + 16);
344 				break;
345 			case hashCalc("D-"):	//D-
346 				tt.D = cast(short)(tt.D - 16);
347 				break;
348 			case hashCalc("x0+"):	//x0+
349 				tt.x_0 = cast(short)(tt.x_0 + 1);
350 				break;
351 			case hashCalc("x0-"):	//x0-
352 				tt.x_0 = cast(short)(tt.x_0 - 1);
353 				break;
354 			case hashCalc("y0+"):	//y0+
355 				tt.y_0 = cast(short)(tt.y_0 + 1);
356 				break;
357 			case hashCalc("y0-"):	//y0-
358 				tt.y_0 = cast(short)(tt.y_0 - 1);
359 				break;
360 			case hashCalc("hidettl"):
361 				r.removeLayer(0);
362 				break;
363 			case hashCalc("unhidettl"):
364 				r.addLayer(tt, 0);
365 				break;
366 			case hashCalc("sprtH-"):
367 				if(s.getScaleSpriteHoriz(0) == 16)
368 					s.scaleSpriteHoriz(0,-16);
369 				else
370 					s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) - 16);
371 				break;
372 			case hashCalc("sprtH+"):
373 				if(s.getScaleSpriteHoriz(0) == -16)
374 					s.scaleSpriteHoriz(0,16);
375 				else
376 					s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) + 16);
377 				break;
378 			case hashCalc("sprtV-"):
379 				if(s.getScaleSpriteVert(0) == 16)
380 					s.scaleSpriteVert(0,-16);
381 				else
382 					s.scaleSpriteVert(0,s.getScaleSpriteVert(0) - 16);
383 				break;
384 			case hashCalc("sprtV+"):
385 				if(s.getScaleSpriteVert(0) == -16)
386 					s.scaleSpriteVert(0,16);
387 				else
388 					s.scaleSpriteVert(0,s.getScaleSpriteVert(0) + 16);
389 				break;
390 			case hashCalc("2up"):
391 				s.relMoveSprite(0,0,-1);
392 				break;
393 			case hashCalc("2down"):
394 				s.relMoveSprite(0,0,1);
395 				break;
396 			case hashCalc("2left"):
397 				s.relMoveSprite(0,-1,0);
398 				break;
399 			case hashCalc("2right"):
400 				s.relMoveSprite(0,1,0);
401 				break;
402 			default:
403 				break;
404 		}
405 	}
406 	/**
407 	 * Called when an axis is being operated.
408 	 * The `id` should be generated from a string, usually the name of the binding.
409 	 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc).
410 	 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses.
411 	 * `value` is the current position of the axis normalized between -1.0 and +1.0 for joysticks, and 0.0 and +1.0 for analog
412 	 * triggers.
413 	 */
414 	public void axisEvent(uint id, BindingCode code, uint timestamp, float value) {
415 
416 	}
417 }