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 }