1 /* 2 Copyright (C) 2015, by Laszlo Szeremi under the Boost license. 3 4 VDP Engine 5 */ 6 7 8 module app; 9 10 import std.stdio; 11 import std..string; 12 import std.conv; 13 import std.format; 14 import std.random; 15 16 import bindbc.sdl; 17 //import derelict.freeimage.freeimage; 18 19 //import system.config; 20 21 import PixelPerfectEngine.graphics.outputScreen; 22 import PixelPerfectEngine.graphics.raster; 23 import PixelPerfectEngine.graphics.layers; 24 25 import PixelPerfectEngine.graphics.bitmap; 26 //import PixelPerfectEngine.collision; 27 import PixelPerfectEngine.system.input; 28 import PixelPerfectEngine.system.file; 29 import PixelPerfectEngine.system.etc; 30 import PixelPerfectEngine.system.config; 31 //import PixelPerfectEngine.system.binarySearchTree; 32 import PixelPerfectEngine.system.common; 33 34 public import editor; 35 //import PixelPerfectEngine.extbmp.extbmp; 36 37 public Editor prg; 38 39 int main(string[] args){ 40 initialzeSDL(); 41 42 if (args.length > 1) { 43 if (args[1] == "--test") { 44 bool testTransformableTileLayer; 45 if (args.length > 2) 46 if (args[2] == "transform") 47 testTransformableTileLayer = true; 48 TileLayerTest lprg = new TileLayerTest(testTransformableTileLayer, 8, 8); 49 lprg.whereTheMagicHappens; 50 return 0; 51 } 52 } 53 54 prg = new Editor(args); 55 prg.whereTheMagicHappens; 56 return 0; 57 } 58 59 class TileLayerTest : SystemEventListener, InputListener{ 60 bool isRunning, up, down, left, right, scrup, scrdown, scrleft, scrright; 61 OutputScreen output; 62 Raster r; 63 TileLayer t; 64 TileLayer textLayer; 65 TransformableTileLayer!(Bitmap8Bit,16,16) tt; 66 Bitmap8Bit[] tiles; 67 Bitmap8Bit dlangMan; 68 SpriteLayer s; 69 InputHandler ih; 70 float theta; 71 int framecounter; 72 this (bool testTransformableTileLayer, int mapWidth, int mapHeight) { 73 theta = 0; 74 isRunning = true; 75 Image tileSource = loadImage(File("../assets/sci-fi-tileset.png")); 76 //Image tileSource = loadImage(File("../assets/_system/concreteGUIE0.tga")); 77 Image spriteSource = loadImage(File("../assets/d-man.tga")); 78 Image fontSource = loadImage(File("../system/codepage_8_8.png")); 79 output = new OutputScreen("TileLayer test", 424 * 4, 240 * 4); 80 r = new Raster(424,240,output,0); 81 output.setMainRaster(r); 82 t = new TileLayer(16,16, RenderingMode.Copy); 83 textLayer = new TileLayer(8,8, RenderingMode.AlphaBlend); 84 textLayer.paletteOffset = 512; 85 textLayer.masterVal = 127; 86 textLayer.loadMapping(53, 30, new MappingElement[](53 * 30)); 87 tt = new TransformableTileLayer!(Bitmap8Bit,16,16)(RenderingMode.Copy); 88 s = new SpriteLayer(RenderingMode.AlphaBlend); 89 if (testTransformableTileLayer) r.addLayer(tt, 0); 90 else r.addLayer(t, 0); 91 r.addLayer(s, 1); 92 r.addLayer(textLayer, 65_536); 93 //writeln(r.layerMap); 94 //c = new CollisionDetector(); 95 dlangMan = loadBitmapFromImage!Bitmap8Bit(spriteSource); 96 //CollisionModel cm = new CollisionModel(dlangMan.width, dlangMan.height, dlangMan.generateStandardCollisionModel()); 97 //dlangMan.offsetIndexes(256,false); 98 s.addSprite(dlangMan, 65_536, 0, 0, 1); 99 writeln(s.getDisplayListItem(65_536).toString); 100 //s.scaleSpriteHoriz(0,-1024); 101 //s.scaleSpriteVert(0,-1024); 102 for(int i = 1 ; i < 10 ; i++){ 103 s.addSprite(dlangMan, i, uniform(0,320), uniform(0,240), 1); 104 //assert(check, "DisplayList Error!"); 105 } 106 //s.collisionDetector[1] = c; 107 //c.source = s; 108 //c.addCollisionModel(cm,0); 109 //c.addCollisionModel(cm,1); 110 //c.addCollisionListener(this); 111 //tiles.length = tileSource.bitmapID.length; 112 tiles = loadBitmapSheetFromImage!Bitmap8Bit(tileSource, 16, 16);//loadBitmapSheetFromFile!Bitmap8Bit("../assets/sci-fi-tileset.png",16,16); 113 //tiles = loadBitmapSheetFromFile!(Bitmap8Bit)("../assets/sci-fi-tileset.png", 16, 16); 114 if (testTransformableTileLayer) { 115 for (int i; i < tiles.length; i++) { 116 tt.addTile(tiles[i], cast(wchar)i); 117 } 118 } else { 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 /+ih.kb ~= KeyBinding(0, SDL_SCANCODE_UP,0, "up", Devicetype.KEYBOARD, KeyModifier.All); 144 ih.kb ~= KeyBinding(0, SDL_SCANCODE_DOWN,0, "down", Devicetype.KEYBOARD, KeyModifier.All); 145 ih.kb ~= KeyBinding(0, SDL_SCANCODE_LEFT,0, "left", Devicetype.KEYBOARD, KeyModifier.All); 146 ih.kb ~= KeyBinding(0, SDL_SCANCODE_RIGHT,0, "right", Devicetype.KEYBOARD, KeyModifier.All); 147 ih.kb ~= KeyBinding(0, ScanCode.np8,0, "scrup", Devicetype.KEYBOARD, KeyModifier.All); 148 ih.kb ~= KeyBinding(0, ScanCode.np2,0, "scrdown", Devicetype.KEYBOARD, KeyModifier.All); 149 ih.kb ~= KeyBinding(0, ScanCode.np4,0, "scrleft", Devicetype.KEYBOARD, KeyModifier.All); 150 ih.kb ~= KeyBinding(0, ScanCode.np6,0, "scrright", Devicetype.KEYBOARD, KeyModifier.All); 151 ih.kb ~= KeyBinding(0, ScanCode.F1,0, "A+", Devicetype.KEYBOARD, KeyModifier.All); 152 ih.kb ~= KeyBinding(0, ScanCode.F2,0, "A-", Devicetype.KEYBOARD, KeyModifier.All); 153 ih.kb ~= KeyBinding(0, ScanCode.F3,0, "B+", Devicetype.KEYBOARD, KeyModifier.All); 154 ih.kb ~= KeyBinding(0, ScanCode.F4,0, "B-", Devicetype.KEYBOARD, KeyModifier.All); 155 ih.kb ~= KeyBinding(0, ScanCode.F5,0, "C+", Devicetype.KEYBOARD, KeyModifier.All); 156 ih.kb ~= KeyBinding(0, ScanCode.F6,0, "C-", Devicetype.KEYBOARD, KeyModifier.All); 157 ih.kb ~= KeyBinding(0, ScanCode.F7,0, "D+", Devicetype.KEYBOARD, KeyModifier.All); 158 ih.kb ~= KeyBinding(0, ScanCode.F8,0, "D-", Devicetype.KEYBOARD, KeyModifier.All); 159 ih.kb ~= KeyBinding(0, ScanCode.F9,0, "x0+", Devicetype.KEYBOARD, KeyModifier.All); 160 ih.kb ~= KeyBinding(0, ScanCode.F10,0, "x0-", Devicetype.KEYBOARD, KeyModifier.All); 161 ih.kb ~= KeyBinding(0, ScanCode.PAGEUP,0, "y0+", Devicetype.KEYBOARD, KeyModifier.All); 162 ih.kb ~= KeyBinding(0, ScanCode.PAGEDOWN,0, "y0-", Devicetype.KEYBOARD, KeyModifier.All); 163 ih.kb ~= KeyBinding(0, ScanCode.NP_PLUS,0, "theta+", Devicetype.KEYBOARD, KeyModifier.All); 164 ih.kb ~= KeyBinding(0, ScanCode.NP_MINUS,0, "theta-", Devicetype.KEYBOARD, KeyModifier.All); 165 ih.kb ~= KeyBinding(0, ScanCode.n1,0, "sV+", Devicetype.KEYBOARD, KeyModifier.All); 166 ih.kb ~= KeyBinding(0, ScanCode.n2,0, "sV-", Devicetype.KEYBOARD, KeyModifier.All); 167 ih.kb ~= KeyBinding(0, ScanCode.n3,0, "sH+", Devicetype.KEYBOARD, KeyModifier.All); 168 ih.kb ~= KeyBinding(0, ScanCode.n4,0, "sH-", Devicetype.KEYBOARD, KeyModifier.All); 169 ih.kb ~= KeyBinding(0, ScanCode.Q,0, "HM", Devicetype.KEYBOARD, KeyModifier.All); 170 ih.kb ~= KeyBinding(0, ScanCode.W,0, "VM", Devicetype.KEYBOARD, KeyModifier.All);+/ 171 { 172 import PixelPerfectEngine.system.input.scancode; 173 ih.addBinding(BindingCode(ScanCode.UP, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("up")); 174 ih.addBinding(BindingCode(ScanCode.DOWN, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("down")); 175 ih.addBinding(BindingCode(ScanCode.LEFT, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("left")); 176 ih.addBinding(BindingCode(ScanCode.RIGHT, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("right")); 177 ih.addBinding(BindingCode(ScanCode.np8, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrup")); 178 ih.addBinding(BindingCode(ScanCode.np2, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrdown")); 179 ih.addBinding(BindingCode(ScanCode.np4, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrleft")); 180 ih.addBinding(BindingCode(ScanCode.np6, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("scrright")); 181 ih.addBinding(BindingCode(ScanCode.Q, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("A+")); 182 ih.addBinding(BindingCode(ScanCode.A, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("A-")); 183 ih.addBinding(BindingCode(ScanCode.W, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("B+")); 184 ih.addBinding(BindingCode(ScanCode.S, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("B-")); 185 ih.addBinding(BindingCode(ScanCode.E, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("C+")); 186 ih.addBinding(BindingCode(ScanCode.D, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("C-")); 187 ih.addBinding(BindingCode(ScanCode.R, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("D+")); 188 ih.addBinding(BindingCode(ScanCode.F, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("D-")); 189 ih.addBinding(BindingCode(ScanCode.T, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("x0+")); 190 ih.addBinding(BindingCode(ScanCode.G, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("x0-")); 191 ih.addBinding(BindingCode(ScanCode.Y, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("y0+")); 192 ih.addBinding(BindingCode(ScanCode.H, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("y0-")); 193 ih.addBinding(BindingCode(ScanCode.PAGEUP, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("alpha+")); 194 ih.addBinding(BindingCode(ScanCode.PAGEDOWN, 0, Devicetype.Keyboard, 0, KeyModifier.All), InputBinding("alpha-")); 195 } 196 if (testTransformableTileLayer) { 197 tt.loadMapping(mapWidth, mapHeight, mapping); 198 tt.warpMode = WarpMode.TileRepeat; 199 } else { 200 t.loadMapping(mapWidth, mapHeight, mapping); 201 t.warpMode = WarpMode.TileRepeat; 202 } 203 //t.setWrapMode(true); 204 //tt.D = -256; 205 //loadPaletteFromXMP(tileSource, "default", r); 206 207 /*for(int y ; y < 240 ; y++){ 208 for(int x ; x < 240 ; x++){ 209 writeln('[',x,',',y,"] : ", t.transformFunc([x,y])); 210 } 211 }*/ 212 Color[] localPal = loadPaletteFromImage(tileSource); 213 localPal.length = 256; 214 r.addPaletteChunk(localPal); 215 localPal = loadPaletteFromImage(spriteSource); 216 localPal.length = 256; 217 r.addPaletteChunk(localPal); 218 r.addPaletteChunk([Color(0x00,0x00,0x00,0xFF),Color(0xff,0xff,0xff,0xFF),Color(0x00,0x00,0x00,0xFF), 219 Color(0xff,0x00,0x00,0xFF),Color(0x00,0x00,0x00,0xFF),Color(0x00,0xff,0x00,0xFF),Color(0x00,0x00,0x00,0xFF), 220 Color(0x00,0x00,0xff,0xFF)]); 221 //writeln(r.palette); 222 //r.palette[0].alpha = 255; 223 r.palette[256].base = 0; 224 //textLayer.writeTextToMap(2,2,0,"Hello world!",BitmapAttrib(true, false)); 225 textLayer.writeTextToMap(0,0,0,"Framerate:",BitmapAttrib(true, false)); 226 //writeln(tt); 227 //r.palette[0] = 255; 228 //r.addRefreshListener(output, 0); 229 230 } 231 private @nogc void ttlHBlankInterrupt(ref short[4] localABCD, ref short[2] localsXsY, ref short[2] localx0y0, short y){ 232 localABCD[0]++; 233 } 234 public void whereTheMagicHappens(){ 235 while(isRunning){ 236 r.refresh(); 237 ih.test(); 238 if(up) s.relMoveSprite(65_536,0,-1); 239 if(down) s.relMoveSprite(65_536,0,1); 240 if(left) s.relMoveSprite(65_536,-1,0); 241 if(right) s.relMoveSprite(65_536,1,0); 242 243 if(scrup) { 244 t.relScroll(0,-1); 245 tt.relScroll(0,-1); 246 s.relScroll(0,-1); 247 } 248 if(scrdown) { 249 t.relScroll(0,1); 250 tt.relScroll(0,1); 251 s.relScroll(0,1); 252 } 253 if(scrleft) { 254 t.relScroll(-1,0); 255 tt.relScroll(-1,0); 256 s.relScroll(-1,0); 257 } 258 if(scrright) { 259 t.relScroll(1,0); 260 tt.relScroll(1,0); 261 s.relScroll(1,0); 262 } 263 264 framecounter++; 265 if(framecounter == 10){ 266 textLayer.writeTextToMap(10,0,0,format("%3.3f"w,r.avgfps),BitmapAttrib(true, false)); 267 framecounter = 0; 268 } 269 //t.relScroll(1,0); 270 } 271 } 272 override public void onQuit() { 273 isRunning = false; 274 } 275 public void controllerAdded(uint id) { 276 277 } 278 public void controllerRemoved(uint id) { 279 280 } 281 /+override public void keyPressed(string ID,uint timestamp,uint devicenumber,uint devicetype) { 282 //writeln(ID); 283 import PixelPerfectEngine.graphics.transformFunctions; 284 switch(ID){ 285 case "up": up = true; break; 286 case "down": down = true; break; 287 case "left": left = true; break; 288 case "right": right = true; break; 289 case "scrup": scrup = true; break; 290 case "scrdown": scrdown = true; break; 291 case "scrleft": scrleft = true; break; 292 case "scrright": scrright = true; break; 293 case "A+": tt.A = cast(short)(tt.A + 16); break; 294 case "A-": tt.A = cast(short)(tt.A - 16); break; 295 case "B+": tt.B = cast(short)(tt.B + 16); break; 296 case "B-": tt.B = cast(short)(tt.B - 16); break; 297 case "C+": tt.C = cast(short)(tt.C + 16); break; 298 case "C-": tt.C = cast(short)(tt.C - 16); break; 299 case "D+": tt.D = cast(short)(tt.D + 16); break; 300 case "D-": tt.D = cast(short)(tt.D - 16); break; 301 case "x0+": tt.x_0 = cast(short)(tt.x_0 + 1); break; 302 case "x0-": tt.x_0 = cast(short)(tt.x_0 - 1); break; 303 case "y0+": tt.y_0 = cast(short)(tt.y_0 + 1); break; 304 case "y0-": tt.y_0 = cast(short)(tt.y_0 - 1); break; 305 case "sH-": 306 if(s.getScaleSpriteHoriz(0) == 16){ 307 s.scaleSpriteHoriz(0,-16); 308 return; 309 } 310 s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) - 16); 311 //writeln(s.getScaleSpriteHoriz(0)); 312 break; 313 case "sH+": 314 if(s.getScaleSpriteHoriz(0) == -16){ 315 s.scaleSpriteHoriz(0,16); 316 return; 317 } 318 s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) + 16); 319 //writeln(s.getScaleSpriteHoriz(0)); 320 break; 321 case "sV-": 322 if(s.getScaleSpriteVert(0) == 16){ 323 s.scaleSpriteVert(0,-16); 324 return; 325 } 326 s.scaleSpriteVert(0,s.getScaleSpriteVert(0) - 16); 327 break; 328 case "sV+": 329 if(s.getScaleSpriteVert(0) == -16){ 330 s.scaleSpriteVert(0,16); 331 return; 332 } 333 s.scaleSpriteVert(0,s.getScaleSpriteVert(0) + 16); 334 break; 335 case "HM": 336 s.scaleSpriteHoriz(0,s.getScaleSpriteHoriz(0) * -1); 337 break; 338 case "VM": 339 s.scaleSpriteVert(0,s.getScaleSpriteVert(0) * -1); 340 break; 341 case "theta+": 342 theta += 1; 343 short[4] newTP = rotateFunction(theta); 344 tt.A = newTP[0]; 345 tt.B = newTP[1]; 346 tt.C = newTP[2]; 347 tt.D = newTP[3]; 348 break; 349 case "theta-": 350 theta -= 1; 351 short[4] newTP = rotateFunction(theta); 352 tt.A = newTP[0]; 353 tt.B = newTP[1]; 354 tt.C = newTP[2]; 355 tt.D = newTP[3]; 356 break; 357 default: break; 358 } 359 } 360 override public void keyReleased(string ID,uint timestamp,uint devicenumber,uint devicetype) { 361 switch(ID){ 362 case "up": up = false; break; 363 case "down": down = false; break; 364 case "left": left = false; break; 365 case "right": right = false; break; 366 case "scrup": scrup = false; break; 367 case "scrdown": scrdown = false; break; 368 case "scrleft": scrleft = false; break; 369 case "scrright": scrright = false; break; 370 default: break; 371 } 372 }+/ 373 /*public void spriteCollision(CollisionEvent ce){ 374 writeln("COLLISION!!!!11!1111!!!ONEONEONE!!!"); 375 } 376 377 public void backgroundCollision(CollisionEvent ce){}*/ 378 /** 379 * Called when a keybinding event is generated. 380 * The `id` should be generated from a string, usually the name of the binding. 381 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc). 382 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses. 383 * NOTE: Hat events on joysticks don't generate keyReleased events, instead they generate keyPressed events on release. 384 */ 385 public void keyEvent(uint id, BindingCode code, uint timestamp, bool isPressed) { 386 writeln(id, ";", code, ";",timestamp, ";",isPressed, ";"); 387 switch (id) { 388 case 1720810685: //up 389 up = isPressed; 390 break; 391 case 1672064345: //down 392 down = isPressed; 393 break; 394 case 2840212248: //left 395 left = isPressed; 396 break; 397 case 1786548735: //right 398 right = isPressed; 399 break; 400 case 3938104347: //scrup 401 scrup = isPressed; 402 break; 403 case 131561283: //scrdown 404 scrdown = isPressed; 405 break; 406 case 4011913815: //scrleft 407 scrleft = isPressed; 408 break; 409 case 2073272778: //scrright 410 scrright = isPressed; 411 break; 412 case 4284782897: //A+ 413 tt.A = cast(short)(tt.A + 16); 414 break; 415 case 142754382: //A- 416 tt.A = cast(short)(tt.A - 16); 417 break; 418 case 2060572171: //B+ 419 tt.B = cast(short)(tt.B + 16); 420 break; 421 case 919786464: //B- 422 tt.B = cast(short)(tt.B - 16); 423 break; 424 case 2857229774: //C+ 425 tt.C = cast(short)(tt.C + 16); 426 break; 427 case 1598464886: //C- 428 tt.C = cast(short)(tt.C - 16); 429 break; 430 case 2476135441: //D+ 431 tt.D = cast(short)(tt.D + 16); 432 break; 433 case 3708187064: //D- 434 tt.D = cast(short)(tt.D - 16); 435 break; 436 case 3238134781: //x0+ 437 tt.x_0 = cast(short)(tt.x_0 + 1); 438 break; 439 case 135027337: //x0- 440 tt.x_0 = cast(short)(tt.x_0 - 1); 441 break; 442 case 983492653: //y0+ 443 tt.y_0 = cast(short)(tt.y_0 + 1); 444 break; 445 case 2733639921: //y0- 446 tt.y_0 = cast(short)(tt.y_0 - 1); 447 break; 448 default: 449 break; 450 } 451 } 452 /** 453 * Called when an axis is being operated. 454 * The `id` should be generated from a string, usually the name of the binding. 455 * `code` is a duplicate of the code used for fast lookup of the binding, which also contains other info (deviceID, etc). 456 * `timestamp` is the time lapsed since the start of the program, can be used to measure time between keypresses. 457 * `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 458 * triggers. 459 */ 460 public void axisEvent(uint id, BindingCode code, uint timestamp, float value) { 461 462 } 463 }