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 }