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)]);
84 
85 		//writeln(r.layerMap);
86 		//c = new CollisionDetector();
87 		dlangMan = loadBitmapFromImage!Bitmap8Bit(spriteSource);
88 		dlangManCS = dlangMan.generateStandardCollisionModel();
89 		ocd = new ObjectCollisionDetector(&onCollision, 0);
90 		s.addSprite(dlangMan, 65_536, 0, 0, 1);
91 		ocd.objects[65_536] = CollisionShape(Box(0, 0, 31, 31), dlangManCS);
92 		s.addSprite(dlangMan, 0, 0, 0, 1, -1024, -1024);
93 
94 		for(int i = 1 ; i < 10 ; i++){
95 			const int x = uniform(0,320), y = uniform(0,240);
96 			s.addSprite(dlangMan, i, x, y, 1);
97 			ocd.objects[i] = CollisionShape(Box(x, y, x + 31, y + 31), dlangManCS);
98 		}
99 		
100 		tiles = loadBitmapSheetFromImage!Bitmap8Bit(tileSource, 16, 16);//loadBitmapSheetFromFile!Bitmap8Bit("../assets/sci-fi-tileset.png",16,16);
101 		
102 		for (int i; i < tiles.length; i++) {
103 			tt.addTile(tiles[i], cast(wchar)i);
104 		}
105 		
106 		for (int i; i < tiles.length; i++) {
107 			t.addTile(tiles[i], cast(wchar)i);
108 		}
109 		
110 		{
111 			Bitmap8Bit[] fontSet = loadBitmapSheetFromImage!Bitmap8Bit(fontSource, 8, 8);
112 			for (ushort i; i < fontSet.length; i++) {
113 				textLayer.addTile(fontSet[i], i, 1);
114 			}
115 		}
116 		//wchar[] mapping;
117 		MappingElement[] mapping;
118 		mapping.length = mapWidth * mapHeight;//64*64;
119 		//attrMapping.length = 256*256;
120 		for(int i; i < mapping.length; i++){
121 			//mapping[i] = to!wchar(uniform(0x0000,0x00AA));
122 			const int rnd = uniform(0,1024);
123 			//attrMapping[i] = BitmapAttrib(rnd & 1 ? true : false, rnd & 2 ? true : false);
124 			mapping[i] = MappingElement(cast(wchar)(rnd & 63), BitmapAttrib(rnd & 1024 ? true : false, rnd & 512 ? true : false));
125 			//mapping[i] = MappingElement(0x0, BitmapAttrib(false,false));
126 		}
127 		ih = new InputHandler();
128 		ih.systemEventListener = this;
129 		ih.inputListener = this;
130 		
131 		{
132 			import pixelperfectengine.system.input.scancode;
133 			ih.addBinding(BindingCode(ScanCode.UP, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("up"));
134 			ih.addBinding(BindingCode(ScanCode.DOWN, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("down"));
135 			ih.addBinding(BindingCode(ScanCode.LEFT, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("left"));
136 			ih.addBinding(BindingCode(ScanCode.RIGHT, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("right"));
137 			ih.addBinding(BindingCode(ScanCode.np8, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrup"));
138 			ih.addBinding(BindingCode(ScanCode.np2, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrdown"));
139 			ih.addBinding(BindingCode(ScanCode.np4, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrleft"));
140 			ih.addBinding(BindingCode(ScanCode.np6, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrright"));
141 			ih.addBinding(BindingCode(ScanCode.Q, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("A+"));
142 			ih.addBinding(BindingCode(ScanCode.A, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("A-"));
143 			ih.addBinding(BindingCode(ScanCode.W, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("B+"));
144 			ih.addBinding(BindingCode(ScanCode.S, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("B-"));
145 			ih.addBinding(BindingCode(ScanCode.E, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("C+"));
146 			ih.addBinding(BindingCode(ScanCode.D, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("C-"));
147 			ih.addBinding(BindingCode(ScanCode.R, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("D+"));
148 			ih.addBinding(BindingCode(ScanCode.F, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("D-"));
149 			ih.addBinding(BindingCode(ScanCode.T, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("x0+"));
150 			ih.addBinding(BindingCode(ScanCode.G, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("x0-"));
151 			ih.addBinding(BindingCode(ScanCode.Y, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("y0+"));
152 			ih.addBinding(BindingCode(ScanCode.H, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("y0-"));
153 			ih.addBinding(BindingCode(ScanCode.PAGEUP, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("alpha+"));
154 			ih.addBinding(BindingCode(ScanCode.PAGEDOWN, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("alpha-"));
155 			ih.addBinding(BindingCode(ScanCode.HOME, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("hidettl"));
156 			ih.addBinding(BindingCode(ScanCode.END, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("unhidettl"));
157 			ih.addBinding(BindingCode(ScanCode.n1, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("sprtH-"));
158 			ih.addBinding(BindingCode(ScanCode.n2, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("sprtH+"));
159 			ih.addBinding(BindingCode(ScanCode.n3, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("sprtV-"));
160 			ih.addBinding(BindingCode(ScanCode.n4, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("sprtV+"));
161 			ih.addBinding(BindingCode(ScanCode.n5, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("2up"));
162 			ih.addBinding(BindingCode(ScanCode.n6, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("2down"));
163 			ih.addBinding(BindingCode(ScanCode.n7, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("2left"));
164 			ih.addBinding(BindingCode(ScanCode.n8, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("2right"));
165 		}
166 		
167 		tt.loadMapping(mapWidth, mapHeight, mapping);
168 		tt.warpMode = WarpMode.Off;
169 		
170 		t.loadMapping(mapWidth, mapHeight, mapping);
171 		t.warpMode = WarpMode.TileRepeat;
172 		
173 		//t.setWrapMode(true);
174 		//tt.D = -256;
175 		//loadPaletteFromXMP(tileSource, "default", r);
176 
177 		/*for(int y ; y < 240 ; y++){
178 			for(int x ; x < 240 ; x++){
179 				writeln('[',x,',',y,"] : ", t.transformFunc([x,y]));
180 			}
181 		}*/
182 		
183 		//writeln(r.palette);
184 		//r.palette[0].alpha = 255;
185 		//r.palette[256].base = 0;
186 		//textLayer.writeTextToMap(2,2,0,"Hello world!",BitmapAttrib(true, false));
187 		textLayer.writeTextToMap(0, 0, 0, "Framerate:", BitmapAttrib(true, false));
188 		textLayer.writeTextToMap(0, 1, 0, "Collision:", BitmapAttrib(true, false));
189 		textLayer.writeTextToMap(0, 2, 0, "Col. type:", BitmapAttrib(true, false));
190 		//writeln(tt);
191 		//r.palette[0] = 255;
192 		//r.addRefreshListener(output, 0);
193 
194 	}
195 	private @nogc void ttlHBlankInterrupt(ref short[4] localABCD, ref short[2] localsXsY, ref short[2] localx0y0, short y){
196 		localABCD[0]++;
197 	}
198 	public void whereTheMagicHappens(){
199 		while(isRunning){
200 			r.refresh();
201 			ih.test();
202 			if(up) {
203 				s.relMoveSprite(65_536,0,-1);
204 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
205 			}
206 			if(down) {
207 				s.relMoveSprite(65_536,0,1);
208 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
209 			}
210 			if(left) {
211 				s.relMoveSprite(65_536,-1,0);
212 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
213 			}
214 			if(right) {
215 				s.relMoveSprite(65_536,1,0);
216 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
217 			}
218 			ocd.objects.ptrOf(65_536).position = s.getSpriteCoordinate(65_536);
219 			ocd.testSingle(65_536);
220 			if(scrup) {
221 				t.relScroll(0,-1);
222 				tt.relScroll(0,-1);
223 				s.relScroll(0,-1);
224 			}
225 			if(scrdown) {
226 				t.relScroll(0,1);
227 				tt.relScroll(0,1);
228 				s.relScroll(0,1);
229 			}
230 			if(scrleft) {
231 				t.relScroll(-1,0);
232 				tt.relScroll(-1,0);
233 				s.relScroll(-1,0);
234 			}
235 			if(scrright) {
236 				t.relScroll(1,0);
237 				tt.relScroll(1,0);
238 				s.relScroll(1,0);
239 			}
240 			
241 			framecounter++;
242 			if(framecounter == 10){
243 				float avgFPS = r.avgfps;
244 				wstring fpsCounter = format(" %3.3f"w, avgFPS);
245 				textLayer.writeTextToMap(10,0,0,fpsCounter,BitmapAttrib(true, false));
246 				framecounter = 0;
247 			}
248 			//t.relScroll(1,0);
249 		}
250 	}
251 	public void onCollision(ObjectCollisionEvent event) {
252 		textLayer.writeTextToMap(10,1,0,format("%8X"w,event.idB),BitmapAttrib(true, false));
253 		final switch (event.type) with (ObjectCollisionEvent.Type) {
254 			case None:
255 				textLayer.writeTextToMap(10,2,0,"        None",BitmapAttrib(true, false));
256 				break;
257 			case BoxEdge:
258 				textLayer.writeTextToMap(10,2,0,"     BoxEdge",BitmapAttrib(true, false));
259 				break;
260 			case BoxOverlap:
261 				textLayer.writeTextToMap(10,2,0,"  BoxOverlap",BitmapAttrib(true, false));
262 				break;
263 			case ShapeOverlap:
264 				textLayer.writeTextToMap(10,2,0,"ShapeOverlap",BitmapAttrib(true, false));
265 				break;
266 		}
267 	}
268 	override public void onQuit() {
269 		isRunning = false;
270 	}
271 	public void controllerAdded(uint id) {
272 
273 	}
274 	public void controllerRemoved(uint id) {
275 
276 	}
277 	/**
278 	 * Called when a keybinding event is generated.
279 	 * The `id` should be generated from a string, usually the name of the binding.
280 	 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc).
281 	 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses.
282 	 * NOTE: Hat events on joysticks don't generate keyReleased events, instead they generate keyPressed events on release.
283 	 */
284 	public void keyEvent(uint id, BindingCode code, uint timestamp, bool isPressed) {
285 		//writeln(id, ";", code, ";",timestamp, ";",isPressed, ";");
286 		switch (id) {
287 			case hashCalc("up"):	//up
288 				up = isPressed;
289 				break;
290 			case hashCalc("down"):	//down
291 				down = isPressed;
292 				break;
293 			case hashCalc("left"):	//left
294 				left = isPressed;
295 				break;
296 			case hashCalc("right"):	//right
297 				right = isPressed;
298 				break;
299 			case hashCalc("scrup"):	//scrup
300 				scrup = isPressed;
301 				break;
302 			case hashCalc("scrdown"):		//scrdown
303 				scrdown = isPressed;
304 				break;
305 			case hashCalc("scrleft"):	//scrleft
306 				scrleft = isPressed;
307 				break;
308 			case hashCalc("scrright"):	//scrright
309 				scrright = isPressed;
310 				break;
311 			case hashCalc("A+"): 	//A+
312 				tt.A = cast(short)(tt.A + 16);
313 				break;
314 			case hashCalc("A-"):	//A-
315 				tt.A = cast(short)(tt.A - 16);
316 				break;
317 			case hashCalc("B+"):	//B+
318 				tt.B = cast(short)(tt.B + 16);
319 				break;
320 			case hashCalc("B-"):	//B-
321 				tt.B = cast(short)(tt.B - 16);
322 				break;
323 			case hashCalc("C+"):	//C+
324 				tt.C = cast(short)(tt.C + 16);
325 				break;
326 			case hashCalc("C-"):	//C-
327 				tt.C = cast(short)(tt.C - 16);
328 				break;
329 			case hashCalc("D+"):	//D+
330 				tt.D = cast(short)(tt.D + 16);
331 				break;
332 			case hashCalc("D-"):	//D-
333 				tt.D = cast(short)(tt.D - 16);
334 				break;
335 			case hashCalc("x0+"):	//x0+
336 				tt.x_0 = cast(short)(tt.x_0 + 1);
337 				break;
338 			case hashCalc("x0-"):	//x0-
339 				tt.x_0 = cast(short)(tt.x_0 - 1);
340 				break;
341 			case hashCalc("y0+"):	//y0+
342 				tt.y_0 = cast(short)(tt.y_0 + 1);
343 				break;
344 			case hashCalc("y0-"):	//y0-
345 				tt.y_0 = cast(short)(tt.y_0 - 1);
346 				break;
347 			case hashCalc("hidettl"):
348 				r.removeLayer(0);
349 				break;
350 			case hashCalc("unhidettl"):
351 				r.addLayer(tt, 0);
352 				break;
353 			case hashCalc("sprtH-"):
354 				if(s.getScaleSpriteHoriz(0) == 16)
355 					s.scaleSpriteHoriz(0,-16);
356 				else
357 					s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) - 16);
358 				break;
359 			case hashCalc("sprtH+"):
360 				if(s.getScaleSpriteHoriz(0) == -16)
361 					s.scaleSpriteHoriz(0,16);
362 				else
363 					s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) + 16);
364 				break;
365 			case hashCalc("sprtV-"):
366 				if(s.getScaleSpriteVert(0) == 16)
367 					s.scaleSpriteVert(0,-16);
368 				else
369 					s.scaleSpriteVert(0,s.getScaleSpriteVert(0) - 16);
370 				break;
371 			case hashCalc("sprtV+"):
372 				if(s.getScaleSpriteVert(0) == -16)
373 					s.scaleSpriteVert(0,16);
374 				else
375 					s.scaleSpriteVert(0,s.getScaleSpriteVert(0) + 16);
376 				break;
377 			case hashCalc("2up"):
378 				s.relMoveSprite(0,0,-1);
379 				break;
380 			case hashCalc("2down"):
381 				s.relMoveSprite(0,0,1);
382 				break;
383 			case hashCalc("2left"):
384 				s.relMoveSprite(0,-1,0);
385 				break;
386 			case hashCalc("2right"):
387 				s.relMoveSprite(0,1,0);
388 				break;
389 			default:
390 				break;
391 		}
392 	}
393 	/**
394 	 * Called when an axis is being operated.
395 	 * The `id` should be generated from a string, usually the name of the binding.
396 	 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc).
397 	 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses.
398 	 * `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
399 	 * triggers.
400 	 */
401 	public void axisEvent(uint id, BindingCode code, uint timestamp, float value) {
402 
403 	}
404 }