1 module document; 2 3 import PixelPerfectEngine.map.mapdata; 4 import PixelPerfectEngine.map.mapformat; 5 import editorEvents; 6 import rasterWindow; 7 import PixelPerfectEngine.concrete.eventChainSystem; 8 import PixelPerfectEngine.graphics.common : Color, Coordinate; 9 import PixelPerfectEngine.graphics.bitmap; 10 import PixelPerfectEngine.graphics.layers; 11 import PixelPerfectEngine.system.inputHandler : MouseButton, ButtonState; 12 import std.stdio; 13 14 import app; 15 ///Individual document for parallel editing 16 public class MapDocument { 17 /** 18 * Specifies the current edit mode 19 */ 20 public enum EditMode { 21 selectDragScroll, 22 tilePlacement, 23 boxPlacement, 24 spritePlacement, 25 } 26 UndoableStack events; ///Per document event stack 27 MapFormat mainDoc; ///Used to reduce duplicate data as much as possible 28 //ABitmap[] delegate() imageReturnFunc; 29 Color[] delegate(MapDocument sender) paletteReturnFunc; ///Used for adding the palette for the document 30 int selectedLayer; ///Indicates the currently selected layer 31 RasterWindow outputWindow; ///Window used to output the screen data 32 EditMode mode; ///Mose event mode selector 33 protected int prevMouseX; ///Previous mouse X position 34 protected int prevMouseY; ///Previous mouse Y position 35 protected MappingElement selectedMappingElement; ///Currently selected mapping element to write, including mirroring properties, palette selection, and priority attributes 36 protected bool voidfill; ///If true, tilePlacement overrides only transparent (0xFFFF) tiles. 37 /** 38 * Loads the document from disk. 39 */ 40 public this(string filename) @trusted { 41 events = new UndoableStack(20); 42 } 43 ///New from scratch 44 public this(string docName, int resX, int resY) @trusted { 45 events = new UndoableStack(20); 46 mainDoc = new MapFormat(docName, resX, resY); 47 mode = EditMode.tilePlacement; 48 } 49 ///Returns the next available layer number. 50 public int nextLayerNumber() @safe { 51 int result = selectedLayer; 52 bool found; 53 do { 54 if (mainDoc[result] is null) 55 found = true; 56 else 57 result++; 58 } while (!found); 59 return result; 60 } 61 ///Puts the loaded tiles onto a TileLayer 62 public void addTileSet(int layer, ABitmap[ushort] tiles) @trusted { 63 ITileLayer itl = cast(ITileLayer)mainDoc[layer]; 64 foreach (i ; tiles.byKey) { 65 itl.addTile(tiles[i], i); 66 } 67 } 68 ///Ditto 69 public void addTileSet(int layer, ABitmap[] tiles) @trusted { 70 ITileLayer itl = cast(ITileLayer)mainDoc[layer]; 71 for (ushort i ; i < tiles.length ; i++) { 72 itl.addTile(tiles[i], i); 73 } 74 } 75 /** 76 * Pass mouse events here. 77 */ 78 public void passMouseEvent(int x, int y, int state, ubyte button) { 79 //Normal mode: 80 //left : drag layer/select ; right : menu ; middle : quick nav ; other buttons : user defined 81 //TileLayer placement mode: 82 //left : placement ; right : menu ; middle : delete ; other buttons : user defined 83 final switch (mode) { 84 case EditMode.selectDragScroll: 85 switch (button) { 86 case MouseButton.LEFT: 87 //Test if an object is being hit by the cursor. If yes, then select the object. If not, then initialize drag layer mode. 88 break; 89 case MouseButton.MID: 90 //Enable quicknav mode. Scroll the layer by delta/10 for each frame. Stop if button is released. 91 break; 92 default: 93 break; 94 } 95 break; 96 case EditMode.tilePlacement: 97 98 switch (button) { 99 case MouseButton.LEFT: 100 //Record the first cursor position upon mouse button press, then initialize either a single or zone write for the selected tile layer. 101 if (state == ButtonState.PRESSED) { 102 prevMouseX = x; 103 prevMouseY = y; 104 } else { 105 106 ITileLayer target = cast(ITileLayer)(mainDoc[selectedLayer]); 107 x = (x - mainDoc[selectedLayer].getSX) / target.getTileWidth; 108 y = (y - mainDoc[selectedLayer].getSY) / target.getTileHeight; 109 prevMouseX = (prevMouseX - mainDoc[selectedLayer].getSX) / target.getTileWidth; 110 prevMouseY = (prevMouseY - mainDoc[selectedLayer].getSY) / target.getTileHeight; 111 Coordinate c; 112 if (x > prevMouseX){ 113 c.left = prevMouseX; 114 c.right = x; 115 } else { 116 c.left = x; 117 c.right = prevMouseX; 118 } 119 if (y > prevMouseY){ 120 c.top = prevMouseY; 121 c.bottom = y; 122 } else { 123 c.top = y; 124 c.bottom = prevMouseY; 125 } 126 127 if (voidfill) { 128 if (c.width == 0 && c.height == 0) { 129 if (target.readMapping(c.left, c.top).tileID == 0xFFFF) 130 events.addToTop(new WriteToMapSingle(target, c.left, c.top, selectedMappingElement)); 131 /+ target.writeMapping(c.left, c.top, selectedMappingElement);+/ 132 133 } else { 134 /+for (int y0 = c.top ; y0 <= c.bottom ; y0++){ 135 for (int x0 = c.left ; x0 <= c.right ; x0++) { 136 if (target.readMapping(x0, y0).tileID == 0xFFFF) 137 target.writeMapping(x0, y0, selectedMappingElement); 138 } 139 }+/ 140 events.addToTop(new WriteToMapVoidFill(target, c, selectedMappingElement)); 141 } 142 } else { 143 if (c.width == 0 && c.height == 0) { 144 events.addToTop(new WriteToMapSingle(target, c.left, c.top, selectedMappingElement)); 145 146 } else { 147 events.addToTop(new WriteToMapOverwrite(target, c, selectedMappingElement)); 148 } 149 } 150 debug { 151 import std.stdio : writeln; 152 writeln(events.events); 153 } 154 } 155 break; 156 case MouseButton.MID: 157 //Record the first cursor position upon mouse button press, then initialize either a single or zone delete for the selected tile layer. 158 if (state == ButtonState.PRESSED) { 159 prevMouseX = x; 160 prevMouseY = y; 161 } else { 162 163 } 164 break; 165 case MouseButton.RIGHT: 166 //Open quick menu with basic edit options and ability of toggling both vertically and horizontally. 167 break; 168 default: 169 break; 170 } 171 outputWindow.draw(); 172 //outputWindow.updateRaster(); 173 break; 174 case EditMode.spritePlacement: 175 break; 176 case EditMode.boxPlacement: 177 break; 178 } 179 } 180 public void updateMaterialList () { 181 if (mainDoc[selectedLayer] !is null) { 182 if (prg.wh.materialList !is null) { 183 TileInfo[] list = mainDoc.getTileInfo(selectedLayer); 184 //writeln(list.length); 185 prg.wh.materialList.updateMaterialList(list); 186 } 187 } 188 } 189 public void updateLayerList () { 190 if (prg.wh.layerList !is null) { 191 LayerInfo[] list = mainDoc.getLayerInfo; 192 prg.wh.layerList.updateLayerList(list); 193 //prg.wh.layerlist 194 } 195 } 196 public void onSelection () { 197 updateLayerList; 198 updateMaterialList; 199 } 200 public void tileMaterial_FlipHorizontal() { 201 selectedMappingElement.attributes.horizMirror = !selectedMappingElement.attributes.horizMirror; 202 } 203 public void tileMaterial_FlipVertical() { 204 selectedMappingElement.attributes.vertMirror = !selectedMappingElement.attributes.vertMirror; 205 } 206 public void tileMaterial_Select(wchar id) { 207 selectedMappingElement.tileID = id; 208 mode = EditMode.tilePlacement; 209 210 } 211 public void tileMaterial_PaletteUp() { 212 selectedMappingElement.paletteSel++; 213 } 214 public void tileMaterial_PaletteDown() { 215 selectedMappingElement.paletteSel--; 216 } 217 }