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