1 module editorEvents; 2 3 import document; 4 5 public import PixelPerfectEngine.concrete.eventChainSystem; 6 public import PixelPerfectEngine.graphics.layers; 7 public import PixelPerfectEngine.map.mapformat; 8 9 import PixelPerfectEngine.system.file; 10 11 import std.stdio; 12 import std.conv : to; 13 import sdlang; 14 15 public class WriteToMapVoidFill : UndoableEvent { 16 ITileLayer target; 17 Coordinate area; 18 MappingElement me; 19 ubyte[] mask; 20 public this(ITileLayer target, Coordinate area, MappingElement me){ 21 this.target = target; 22 this.area = area; 23 this.me = me; 24 } 25 public void redo() { 26 for(int y = area.top ; y < area.bottom ; y++){ 27 for(int x = area.left ; x < area.right ; x++){ 28 if(target.readMapping(x,y).tileID != 0xFFFF){ 29 mask[area.width * y + x] = 0xFF; 30 target.writeMapping(x,y,me); 31 } 32 } 33 } 34 } 35 public void undo() { 36 for(int y = area.top ; y < area.bottom ; y++){ 37 for(int x = area.left ; x < area.right ; x++){ 38 if(mask[area.width * y + x] == 0xFF){ 39 target.writeMapping(x,y,MappingElement(0xFFFF)); 40 } 41 } 42 } 43 } 44 } 45 46 public class WriteToMapOverwrite : UndoableEvent { 47 ITileLayer target; 48 Coordinate area; 49 MappingElement me; 50 MappingElement[] original; 51 public this(ITileLayer target, Coordinate area, MappingElement me){ 52 this.target = target; 53 this.area = area; 54 this.me = me; 55 original.length = area.area; 56 } 57 public void redo() { 58 size_t pos; 59 for(int y = area.top ; y < area.bottom ; y++){ 60 for(int x = area.left ; x < area.right ; x++){ 61 original[pos] = target.readMapping(x,y); 62 target.writeMapping(x,y,me); 63 pos++; 64 } 65 } 66 } 67 public void undo() { 68 size_t pos; 69 for(int y = area.top ; y < area.bottom ; y++){ 70 for(int x = area.left ; x < area.right ; x++){ 71 target.writeMapping(x,y,original[pos]); 72 pos++; 73 } 74 } 75 } 76 } 77 78 public class WriteToMapSingle : UndoableEvent { 79 ITileLayer target; 80 int x; 81 int y; 82 MappingElement me; 83 MappingElement original; 84 public this(ITileLayer target, int x, int y, MappingElement me) { 85 this.target = target; 86 this.x = x; 87 this.y = y; 88 this.me = me; 89 } 90 public void redo() { 91 original = target.readMapping(x,y); 92 target.writeMapping(x,y,me); 93 debug { 94 import std.stdio : writeln; 95 writeln("Layer was written at position ", x, ";", y," with values ", me); 96 } 97 } 98 public void undo() { 99 target.writeMapping(x,y,original); 100 } 101 } 102 103 public class CreateTileLayerEvent : UndoableEvent { 104 TileLayer creation; 105 MapDocument target; 106 int tX; 107 int tY; 108 int mX; 109 int mY; 110 int pri; 111 string name; 112 string file; 113 string res; 114 bool embed; 115 Tag backup; 116 Image tileSource; 117 118 public this(MapDocument target, int tX, int tY, int mX, int mY, dstring name, string file, string res, 119 bool embed) { 120 import std.utf : toUTF8; 121 creation = new TileLayer(tX, tY); 122 this.target = target; 123 //this.md = md; 124 this.tX = tX; 125 this.tY = tY; 126 this.mX = mX; 127 this.mY = mY; 128 this.name = toUTF8(name); 129 this.file = file; 130 this.res = res; 131 this.embed = embed; 132 //this.imageReturnFunc = imageReturnFunc; 133 } 134 public void redo() { 135 import std.file : exists, isFile; 136 import std.path : baseName; 137 import std.utf : toUTF8; 138 import PixelPerfectEngine.system.etc : intToHex; 139 if (backup) { //If a backup exists, then re-add that to the document, then return. 140 target.mainDoc.addNewLayer(pri, backup, creation); 141 target.outputWindow.addLayer(pri); 142 return; 143 } 144 try { 145 const int nextLayer = target.nextLayerNumber; 146 147 //handle the following instances for mapping: 148 //file == null AND embed 149 //file == existing file AND embed 150 //file == existing file AND !embed 151 //file == nonexisting file 152 if ((!exists(file) || !isFile(file)) && embed) { //create new instance for the map by embedding data into the SDLang file 153 //selDoc.mainDoc.tld[nextLayer] = new 154 MappingElement[] me; 155 me.length = mX * mY; 156 creation.loadMapping(mX, mY, me); 157 target.mainDoc.addNewTileLayer(nextLayer, tX, tY, mX, mY, name, creation); 158 target.mainDoc.addEmbeddedMapData(nextLayer, me); 159 } else if (!exists(file)) { //Create empty file 160 File f = File(file, "wb"); 161 MappingElement[] me; 162 me.length = mX * mY; 163 creation.loadMapping(mX, mY, me); 164 target.mainDoc.addNewTileLayer(nextLayer, tX, tY, mX, mY, name, creation); 165 saveMapFile(MapDataHeader(mX, mY), me, f); 166 target.mainDoc.addMapDataFile(nextLayer, res); 167 } else { //load mapping, embed data into current file if needed 168 MapDataHeader mdh; 169 MappingElement[] me = loadMapFile(File(file), mdh); 170 creation.loadMapping(mdh.sizeX, mdh.sizeY, me); 171 if (embed) 172 target.mainDoc.addEmbeddedMapData(nextLayer, me); 173 else 174 target.mainDoc.addMapDataFile(nextLayer, res); 175 } 176 177 //handle the following instances for materials: 178 //res == image file 179 //TODO: check if material resource file has any embedded resource data 180 //TODO: enable importing from SDLang map files (*.ppm) 181 //TODO: generate dummy tiles for nonexistent material 182 if (exists(res)) { 183 //load the resource file and test if it's the correct size (through an exception) 184 tileSource = loadImage(File(res)); 185 ABitmap[] tilesheet; 186 switch (tileSource.getBitdepth()) { 187 case 4: 188 Bitmap4Bit[] output = loadBitmapSheetFromImage!Bitmap4Bit(tileSource, tX, tY); 189 foreach(p; output) 190 tilesheet ~= p; 191 break; 192 case 8: 193 Bitmap8Bit[] output = loadBitmapSheetFromImage!Bitmap8Bit(tileSource, tX, tY); 194 foreach(p; output) 195 tilesheet ~= p; 196 break; 197 case 16: 198 Bitmap16Bit[] output = loadBitmapSheetFromImage!Bitmap16Bit(tileSource, tX, tY); 199 foreach(p; output) 200 tilesheet ~= p; 201 break; 202 case 32: 203 Bitmap32Bit[] output = loadBitmapSheetFromImage!Bitmap32Bit(tileSource, tX, tY); 204 foreach(p; output) 205 tilesheet ~= p; 206 break; 207 default: 208 throw new Exception("Unsupported bitdepth!"); 209 210 } 211 if (tilesheet.length == 0) throw new Exception("No tiles were imported!"); 212 target.addTileSet(nextLayer, tilesheet); 213 target.mainDoc.addTileSourceFile(nextLayer, res); 214 /+debug { 215 TileLayer tl = cast(TileLayer)target; 216 writeln(tl.displayList); 217 }+/ 218 //writeln(tilesheet.length); 219 //generate default names for the tiles 220 { 221 TileInfo[] idList; 222 string nameBase = baseName(res); 223 for (int id ; id < tilesheet.length ; id++) { 224 idList ~= TileInfo(cast(wchar)id, id, nameBase ~ "0x" ~ intToHex(id, 4)); 225 //writeln(idList); 226 } 227 target.mainDoc.addTileInfo(nextLayer, idList, res); 228 } 229 if (tileSource.isIndexed) { 230 Color[] palette; 231 /*foreach (color ; tileSource.palette) { 232 palette ~= Color(color.a, color.r, color.g, color.b); 233 debug writeln(color); 234 }*/ 235 auto sourcePalette = tileSource.palette; 236 palette.reserve(sourcePalette.length); 237 for (ushort i ; i < sourcePalette.length ; i++){ 238 const auto origC = sourcePalette[i]; 239 const Color c = Color(origC.a, origC.r, origC.g, origC.b); 240 palette ~= c; 241 } 242 debug writeln(palette); 243 target.mainDoc.addPaletteFile(file, "", cast(int)target.outputWindow.palette.length); 244 target.outputWindow.palette = target.outputWindow.palette ~ palette; 245 } 246 247 } 248 target.outputWindow.addLayer(nextLayer); 249 target.selectedLayer = nextLayer; 250 pri = nextLayer; 251 target.updateLayerList(); 252 target.updateMaterialList(); 253 } catch (Exception e) { 254 debug writeln(e); 255 } 256 } 257 public void undo() { 258 //Just remove the added layer from the layerlists 259 target.outputWindow.removeLayer(pri); 260 backup = target.mainDoc.removeLayer(pri); 261 target.updateLayerList(); 262 target.updateMaterialList(); 263 } 264 }