gcsx_importimg.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. /* GCSx
  2. ** IMPORTIMG.CPP
  3. **
  4. ** Import image (creating tileset/fontset) dialog
  5. */
  6. /*****************************************************************************
  7. ** Copyright (C) 2003-2006 Janson
  8. **
  9. ** This program is free software; you can redistribute it and/or modify
  10. ** it under the terms of the GNU General Public License as published by
  11. ** the Free Software Foundation; either version 2 of the License, or
  12. ** (at your option) any later version.
  13. **
  14. ** This program is distributed in the hope that it will be useful,
  15. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ** GNU General Public License for more details.
  18. **
  19. ** You should have received a copy of the GNU General Public License
  20. ** along with this program; if not, write to the Free Software
  21. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  22. *****************************************************************************/
  23. #include "all.h"
  24. // Import image dialog
  25. ImportImgDialog* ImportImgDialog::dialogFontSet = NULL;
  26. ImportImgDialog* ImportImgDialog::dialogTileSet = NULL;
  27. ImportImgDialog* ImportImgDialog::createFontSet() { start_func
  28. if (!dialogFontSet) {
  29. dialogFontSet = new ImportImgDialog(1);
  30. }
  31. return dialogFontSet;
  32. }
  33. ImportImgDialog* ImportImgDialog::createTileSet() { start_func
  34. if (!dialogTileSet) {
  35. dialogTileSet = new ImportImgDialog(0);
  36. }
  37. return dialogTileSet;
  38. }
  39. void ImportImgDialog::destroy() { start_func
  40. if (dialogFontSet) {
  41. delete dialogFontSet;
  42. dialogFontSet = NULL;
  43. }
  44. if (dialogTileSet) {
  45. delete dialogTileSet;
  46. dialogTileSet = NULL;
  47. }
  48. }
  49. ImportImgDialog::ImportImgDialog(int font) : Dialog(font ? "Import Image as Font" : "Import Image as Image/Tile Set") { start_func
  50. initialized = 0;
  51. isFont = font;
  52. image = NULL;
  53. height = width = TileSet::TILE_DEFAULT_SIZE;
  54. left = top = horiz = vert = 0;
  55. skipBlank = skipDupe = importScene = 0;
  56. }
  57. ImportImgDialog::~ImportImgDialog() { start_func
  58. if (image) SDL_FreeSurface(image);
  59. }
  60. void ImportImgDialog::run(WorldEdit* world, Window* srcWin) { start_func
  61. if (!initialized) {
  62. Widget* w = NULL;
  63. Widget* tr = new WStatic(ID_LABEL, "Transparency:");
  64. w = new WStatic(ID_LABEL, "\tImage File:");
  65. w->addTo(this);
  66. w = new WTextBox(ID_FILE, &filename, 0);
  67. w->disable();
  68. w->addTo(this);
  69. w = new WButton(ID_FILECHOOSE, "\tChoose...", BUTTON_NOTHING);
  70. w->addTo(this);
  71. arrangeRow(1, tr->getWidth(), 1);
  72. w = new WStatic(ID_LABEL, "Preview:");
  73. w->addTo(this);
  74. w = new WSplitPreview(ID_PREVIEW, &bkColor, &image, 200, 100);
  75. w->addTo(this);
  76. arrangeRow(1, tr->getWidth(), 1);
  77. tr->addTo(this);
  78. w = new WShowColor(ID_TRANSPARENCY, 30, 30, &bkColor);
  79. w->setToolTip("Click on preview to select transparency color");
  80. w->addTo(this);
  81. w = new WCheckBox(ID_SKIPBLANK, "Skip \tblank tiles", &skipBlank, 1);
  82. w->setToolTip("Don't import tiles that are entirely transparent or black");
  83. w->addTo(this);
  84. arrangeRow(1, tr->getWidth(), 1);
  85. w = new WStatic(ID_LABEL, "\tTile size:");
  86. w->addTo(this);
  87. w = new WNumberBox(ID_WIDTH, &width, MIN_TILESIZE, MAX_TILESIZE);
  88. w->addTo(this);
  89. w = new WStatic(ID_LABEL, "wide;");
  90. w->addTo(this);
  91. w = new WNumberBox(ID_HEIGHT, &height, MIN_TILESIZE, MAX_TILESIZE);
  92. w->addTo(this);
  93. w = new WStatic(ID_LABEL, "high");
  94. w->addTo(this);
  95. arrangeRow(1, tr->getWidth(), 1);
  96. w = new WStatic(ID_LABEL, "\tPadding:");
  97. w->addTo(this);
  98. w = new WNumberBox(ID_LEFT, &left, 0, 999);
  99. w->setToolTip("Skip this many pixels on the left of the image");
  100. w->addTo(this);
  101. w = new WStatic(ID_LABEL, "left;");
  102. w->addTo(this);
  103. w = new WNumberBox(ID_TOP, &top, 0, 999);
  104. w->setToolTip("Skip this many pixels on the top of the image");
  105. w->addTo(this);
  106. w = new WStatic(ID_LABEL, "top");
  107. w->addTo(this);
  108. arrangeRow(1, tr->getWidth(), 1);
  109. w = new WStatic(ID_LABEL, "\tSpacing:");
  110. w->addTo(this);
  111. w = new WNumberBox(ID_HORIZ, &horiz, 0, 99);
  112. w->setToolTip("Skip this many pixels between tiles");
  113. w->addTo(this);
  114. w = new WStatic(ID_LABEL, "horizontal;");
  115. w->addTo(this);
  116. w = new WNumberBox(ID_VERT, &vert, 0, 99);
  117. w->setToolTip("Skip this many pixels between tiles");
  118. w->addTo(this);
  119. w = new WStatic(ID_LABEL, "vertical");
  120. w->addTo(this);
  121. arrangeRow(1, tr->getWidth(), 1);
  122. w = new WStatic(ID_LABEL, blankString);
  123. w->addTo(this);
  124. w = new WCheckBox(ID_SKIPDUPE, "Skip \tduplicate tiles", &skipDupe, 1);
  125. w->setToolTip("Don't import tiles that are exact duplicates");
  126. w->addTo(this);
  127. arrangeRow(1, tr->getWidth());
  128. if (!isFont) {
  129. w = new WStatic(ID_LABEL, blankString);
  130. w->addTo(this);
  131. w = new WCheckBox(ID_IMPORTSCENE, "C\treate tiled scene from image", &importScene, 1);
  132. w->setToolTip("Creates a new one-layer scene using the new tileset, based on the image");
  133. w->addTo(this);
  134. arrangeRow(1, tr->getWidth());
  135. }
  136. w = new WButton(ID_OK, messageBoxOK, BUTTON_OK);
  137. w->addTo(this);
  138. w = new WButton(ID_CANCEL, messageBoxCancel, BUTTON_CANCEL);
  139. w->addTo(this);
  140. makePretty();
  141. initialized = 1;
  142. }
  143. // Only reset filename, image, and bk color from last import
  144. bkColor.max = bkColor.maxAlpha = (1 << 8) - 1;
  145. bkColor.R = bkColor.G = bkColor.B = bkColor.A = 0;
  146. bkColor.RGBtoHSL();
  147. filename = blankString;
  148. if (image) SDL_FreeSurface(image);
  149. image = NULL;
  150. // Hit OK?
  151. if (runModal() == ID_OK) {
  152. if (image) {
  153. // Import now!
  154. TileSetEdit* myTileSet = new TileSetEdit(NULL, isFont, 0);
  155. SceneEdit* myScene = NULL;
  156. LayerEdit* myLayer = NULL;
  157. if (importScene) {
  158. myScene = new SceneEdit(NULL, 0);
  159. myLayer = new LayerEdit(NULL, myScene, 0);
  160. // Note that layer isn't actually added to scene yet
  161. }
  162. if (doImport(myTileSet, myScene, myLayer, world)) {
  163. myTileSet->setInfo(world, world->unusedTileSetId());
  164. world->importTileSet(myTileSet, 1, srcWin);
  165. if (importScene) {
  166. myScene->setInfo(world, world->unusedSceneId());
  167. myLayer->setInfo(world, world->unusedLayerId());
  168. // @TODO: can't be before setinfo, as needs world to work
  169. // but here, it triggers undo which is wrong
  170. myLayer->setTileset(myTileSet->getId());
  171. world->importScene(myScene, 1, srcWin);
  172. }
  173. }
  174. else {
  175. delete myLayer;
  176. delete myScene;
  177. delete myTileSet;
  178. }
  179. }
  180. else {
  181. guiErrorBox("No file was selected to import", errorTitleImport);
  182. }
  183. }
  184. // Free up some memory
  185. if (image) SDL_FreeSurface(image);
  186. image = NULL;
  187. }
  188. int ImportImgDialog::doImport(TileSetEdit* ts, SceneEdit* sc, LayerEdit* sl, WorldEdit* world) { start_func
  189. assert(image);
  190. // Work areas
  191. SDL_Surface* workArea = createSurface32(width, height);
  192. int pitch = workArea->pitch / 4;
  193. pitch -= width;
  194. Uint32* layerWork = NULL;
  195. // Size of source
  196. int sW = image->w;
  197. int sH = image->h;
  198. // Determine number of images we'd like (don't import partial tiles)
  199. int countW = (sW - left + horiz) / (width + horiz);
  200. int countH = (sH - top + vert) / (height + vert);
  201. if (countW < 1) {
  202. guiErrorBox("Image is not wide enough to import requested tile width", errorTitleImport);
  203. return 0;
  204. }
  205. if (countH < 1) {
  206. guiErrorBox("Image is not tall enough to import requested tile height", errorTitleImport);
  207. return 0;
  208. }
  209. int surfaceW, surfaceH, perLine; // We don't need these, but the next function needs references
  210. int numTiles = countW * countH;
  211. if (numTiles > MAX_TILES) numTiles = MAX_TILES;
  212. numTiles = TileSetEdit::calculateTileSurfaceSizing(width, height, numTiles, surfaceW, surfaceH, perLine);
  213. // If we're doing dupe checking, count total number of dupe checks
  214. long long dupeChecks = 0;
  215. long long totalProgress = 0;
  216. if (skipDupe) dupeChecks = ((long long)numTiles - 1) * (long long)numTiles / 2;
  217. // Initialize progress meter
  218. ProgressMeter* progress = new ProgressMeter(numTiles + dupeChecks);
  219. // Prep tileset/layer
  220. ts->markLock(); // @TODO: throw_File
  221. ts->setSize(width, height, numTiles, 0);
  222. if (sl) {
  223. assert(sc);
  224. sl->setType(Layer::LAYER_TILE);
  225. sl->setSize(countW, countH);
  226. sl->setExtended(0);
  227. sl->setEffects(0);
  228. layerWork = new Uint32[countW * countH];
  229. sc->markLock(); // @TODO: throw_File
  230. }
  231. // Start at...
  232. int sX = left;
  233. int sY = top;
  234. // Target tile
  235. int tTile = 1;
  236. // What tile we should be on if no dupes; also used for layer
  237. long ghostTile = 1;
  238. // Transparency
  239. Uint32 trans = mapColor32(bkColor.R, bkColor.G, bkColor.B, bkColor.A);
  240. Uint32 blank = mapColor32(0, 0, 0, 0);
  241. int anyBlank = 0; // Any transparent areas?
  242. // For dupe checking
  243. int cPitch = ts->viewTilePitch() / 4;
  244. cPitch -= width;
  245. while (tTile <= numTiles) {
  246. // Pull one tile
  247. blit(sX, sY, image, 0, 0, workArea, width, height);
  248. // Update transparency and check for all black/blank
  249. Uint32* point = (Uint32*)workArea->pixels;
  250. int allBlack = skipBlank ? 1 : 0;
  251. int allBlank = skipBlank ? 1 : 0;
  252. for (int y = 0; y < height; ++y) {
  253. for (int x = 0; x < width; ++x) {
  254. // Transparency
  255. if (*point == trans) *point = blank;
  256. // All alpha 0 or black?
  257. int R, G, B, A;
  258. splitColor32(*point, R, G, B, A);
  259. if ((R != 0) || (G != 0) || (B != 0)) allBlack = 0;
  260. if (A != 0) allBlank = 0;
  261. if (A == 0) anyBlank = 1;
  262. ++point;
  263. }
  264. point += pitch;
  265. }
  266. // Save tile?
  267. if ((!allBlank) && (!allBlack)) {
  268. int duplicated = 0;
  269. // Compare to all previously imported tiles to find duplicates?
  270. if ((skipDupe) && (tTile > 1)) {
  271. // Scan each existing tile
  272. int dupe;
  273. for (dupe = 1; dupe < tTile; ++dupe) {
  274. // Two points to compare
  275. Uint32* point = (Uint32*)workArea->pixels;
  276. const Uint32* check = (Uint32*)ts->viewTileData(dupe);
  277. int same = 1;
  278. // Scan entire tile
  279. for (int y = 0; y < height; ++y) {
  280. for (int x = 0; x < width; ++x) {
  281. // Stop as soon as something is different
  282. if (*point != *check) {
  283. same = 0;
  284. break;
  285. }
  286. ++point;
  287. ++check;
  288. }
  289. if (!same) break;
  290. point += pitch;
  291. check += cPitch;
  292. }
  293. progress->updateProgress(++totalProgress);
  294. if (same) {
  295. duplicated = dupe;
  296. // (so value of dupe is consistently the same
  297. // whether we exit normally or shortcut here)
  298. ++dupe;
  299. break;
  300. }
  301. }
  302. // Update meter for skipped checks
  303. if (dupe < ghostTile)
  304. totalProgress += ghostTile - dupe;
  305. }
  306. else if (skipDupe) {
  307. // Update meter for skipped dupe checks
  308. totalProgress += ghostTile - 1;
  309. }
  310. if (!duplicated) {
  311. if (sl) layerWork[ghostTile - 1] = tTile | Layer::LAYER_TILE_DEFAULT;
  312. ts->saveTile(tTile++, workArea, NULL);
  313. }
  314. else if (sl) layerWork[ghostTile - 1] = duplicated | Layer::LAYER_TILE_DEFAULT;
  315. }
  316. else {
  317. if (sl) layerWork[ghostTile - 1] = Layer::LAYER_TILE_DEFAULT;
  318. // Update meter for skipped dupe checks
  319. if (skipDupe) totalProgress += ghostTile - 1;
  320. }
  321. progress->updateProgress(++totalProgress);
  322. ++ghostTile;
  323. // Next tile
  324. sX += width + horiz;
  325. if (sX + width > sW) {
  326. sX = left;
  327. sY += height + vert;
  328. if (sY + height > sH) break;
  329. }
  330. }
  331. // Adjust size if less tiles (error if 0)
  332. --tTile;
  333. --ghostTile;
  334. // (don't waste time resizing if we're just gonna delete it)
  335. if ((tTile < numTiles) && (tTile >= 1)) ts->setSize(width, height, tTile, 0);
  336. progress->doneProgress();
  337. if (tTile < 1) {
  338. guiErrorBox("No non-blank tiles were found to import", errorTitleImport);
  339. ts->markUnlock();
  340. if (sl) sc->markUnlock();
  341. delete[] layerWork;
  342. return 0;
  343. }
  344. if (ghostTile < countW * countH) {
  345. guiErrorBox("Too many tiles- not all possible tiles were imported", errorTitleImport);
  346. if (sl)
  347. memSet32(layerWork + ghostTile, Layer::LAYER_TILE_DEFAULT, countW * countH - ghostTile);
  348. }
  349. // Name
  350. vector<string> splitName;
  351. splitFilename(filename.c_str(), splitName);
  352. string findName(splitName[splitName.size() - 1]);
  353. string lFindName = findName;
  354. toLower(lFindName);
  355. int pos = 1;
  356. while (world->findTileSet(lFindName)) {
  357. findName = splitName[splitName.size() - 1];
  358. findName += " ";
  359. findName += intToStr(++pos);
  360. lFindName = findName;
  361. toLower(lFindName);
  362. }
  363. ts->setName(findName);
  364. // Other settings
  365. ts->setTilesPerLine(tTile == ghostTile ? countW : 0);
  366. ts->setDefaultTransparent(anyBlank);
  367. ts->markUnlock();
  368. // Layer/scene
  369. if (sl) {
  370. // Layer load, name
  371. Rect rect;
  372. rect.x = rect.y = 0;
  373. rect.w = countW;
  374. rect.h = countH;
  375. sl->saveLayer(layerWork, NULL, NULL, countW, rect, NULL);
  376. sl->setName(splitName[splitName.size() - 1]);
  377. // Scene name
  378. findName = splitName[splitName.size() - 1];
  379. lFindName = findName;
  380. toLower(lFindName);
  381. pos = 1;
  382. while (world->findScene(lFindName)) {
  383. findName = splitName[splitName.size() - 1];
  384. findName += " ";
  385. findName += intToStr(++pos);
  386. lFindName = findName;
  387. toLower(lFindName);
  388. }
  389. sc->setName(findName);
  390. sc->markUnlock();
  391. sc->insertLayer(sl, 0);
  392. }
  393. delete[] layerWork;
  394. return 1;
  395. }
  396. void ImportImgDialog::childModified(Window* modified) { start_func
  397. Dialog::childModified(modified);
  398. WShowColor* wColor = NULL;
  399. WSplitPreview* wImg = NULL;
  400. Widget* widget = dynamic_cast<Widget*>(modified);
  401. if (widget) {
  402. switch (widget->getId()) {
  403. case ID_WIDTH:
  404. case ID_HEIGHT:
  405. case ID_LEFT:
  406. case ID_TOP:
  407. case ID_HORIZ:
  408. case ID_VERT:
  409. widget->apply();
  410. wImg = dynamic_cast<WSplitPreview*>(findWidget(ID_PREVIEW));
  411. wImg->changeStats(width, height, top, left, horiz, vert);
  412. break;
  413. case ID_PREVIEW:
  414. widget->apply();
  415. wColor = dynamic_cast<WShowColor*>(findWidget(ID_TRANSPARENCY));
  416. wColor->load();
  417. break;
  418. case ID_TRANSPARENCY:
  419. widget->apply();
  420. wImg = dynamic_cast<WSplitPreview*>(findWidget(ID_PREVIEW));
  421. wImg->load();
  422. break;
  423. }
  424. }
  425. }
  426. Dialog::ButtonAction ImportImgDialog::verifyEntry(int buttonId, Dialog::ButtonAction buttonType) { start_func
  427. if (buttonId == ID_FILECHOOSE) {
  428. try {
  429. if (fileOpen(FILETYPE_IMAGE, 0, filename)) {
  430. WTextBox* fn = dynamic_cast<WTextBox*>(findWidget(ID_FILE));
  431. fn->load();
  432. if (image) SDL_FreeSurface(image);
  433. image = NULL;
  434. image = IMG_Load(filename.c_str());
  435. if (image == NULL) {
  436. throw VideoException("Error loading image: %s", SDL_GetError());
  437. }
  438. else {
  439. SDL_SetAlpha(image, 0, 255);
  440. WSplitPreview* wImg = dynamic_cast<WSplitPreview*>(findWidget(ID_PREVIEW));
  441. wImg->load();
  442. }
  443. }
  444. }
  445. catch (FileException& e) {
  446. guiErrorBox(string(e.details), errorTitleFile);
  447. }
  448. }
  449. return Dialog::verifyEntry(buttonId, buttonType);
  450. }
  451. WSplitPreview::WSplitPreview(int pId, color* pSetting, SDL_Surface* const* src, int myWidth, int myHeight) : Widget(pId, blankString, pSetting) { start_func
  452. assert(src);
  453. source = src;
  454. split = NULL;
  455. dragMode = WSPLITPREVIEW_DRAG_NONE;
  456. topPad = leftPad = 0;
  457. horizSplit = vertSplit = 0;
  458. tileWidth = tileHeight = TileSet::TILE_DEFAULT_SIZE;
  459. changeSize(myWidth, myHeight);
  460. }
  461. WSplitPreview::~WSplitPreview() { start_func
  462. if (split) SDL_FreeSurface(split);
  463. }
  464. void WSplitPreview::changeSize(int newWidth, int newHeight) { start_func
  465. displayW = newWidth;
  466. displayH = newHeight;
  467. if ((newWidth <= 0) || (newHeight <= 0)) {
  468. resize(0, 0);
  469. }
  470. else {
  471. resize(newWidth + PREVIEW_BORDER_SIZE * 2, newHeight + PREVIEW_BORDER_SIZE * 2);
  472. }
  473. }
  474. void WSplitPreview::changeStats(int width, int height, int top, int left, int horiz, int vert) { start_func
  475. topPad = top;
  476. leftPad = left;
  477. horizSplit = horiz;
  478. vertSplit = vert;
  479. tileWidth = width;
  480. tileHeight = height;
  481. load();
  482. }
  483. void WSplitPreview::setBk(int x, int y) { start_func
  484. if (split) {
  485. splitColor32(getPixel(x, y, split), bkColor.R, bkColor.G, bkColor.B, bkColor.A);
  486. bkColor.RGBtoHSL();
  487. parent->childModified(this);
  488. }
  489. }
  490. int WSplitPreview::event(int hasFocus, const SDL_Event* event) { start_func
  491. assert(event);
  492. assert(parent);
  493. switch (event->type) {
  494. case SDL_MOUSEBUTTONDOWN:
  495. case SDL_MOUSEBUTTONDBL:
  496. if (event->button.button == SDL_BUTTON_LEFT) {
  497. dragMode = WSPLITPREVIEW_DRAG_NONE;
  498. if ((event->button.y >= PREVIEW_BORDER_SIZE) && (event->button.y < height - PREVIEW_BORDER_SIZE)) {
  499. setBk(event->button.x - PREVIEW_BORDER_SIZE, event->button.y - PREVIEW_BORDER_SIZE);
  500. dragMode = WSPLITPREVIEW_DRAG_BK;
  501. }
  502. return 1;
  503. }
  504. break;
  505. case SDL_MOUSEBUTTONUP:
  506. if (event->button.button == SDL_BUTTON_LEFT) {
  507. dragMode = WSPLITPREVIEW_DRAG_NONE;
  508. return 1;
  509. }
  510. break;
  511. case SDL_MOUSEMOTION:
  512. if (event->motion.state & SDL_BUTTON_LMASK) {
  513. if (dragMode == WSPLITPREVIEW_DRAG_BK) {
  514. setBk((Sint16)event->motion.x - PREVIEW_BORDER_SIZE, (Sint16)event->motion.y - PREVIEW_BORDER_SIZE);
  515. }
  516. return 1;
  517. }
  518. else if ((event->motion.y >= PREVIEW_BORDER_SIZE) &&
  519. (event->motion.y < height - PREVIEW_BORDER_SIZE) &&
  520. (event->motion.x >= PREVIEW_BORDER_SIZE) &&
  521. (event->motion.x < width - PREVIEW_BORDER_SIZE)) {
  522. selectMouse(MOUSE_PIXEL);
  523. }
  524. else {
  525. selectMouse(MOUSE_NORMAL);
  526. }
  527. break;
  528. }
  529. return 0;
  530. }
  531. void WSplitPreview::load() { start_func
  532. bkColor = *((color*)setting);
  533. if ((*source == NULL) || (displayW <= 0) || (displayH <= 0)) {
  534. if (split) SDL_FreeSurface(split);
  535. split = NULL;
  536. }
  537. else {
  538. SDL_Surface* src = *source;
  539. if (split) SDL_FreeSurface(split);
  540. split = NULL;
  541. split = createSurface32(displayW, displayH);
  542. // Start at...
  543. int sX = leftPad;
  544. int sY = topPad;
  545. // Target placement
  546. int tX = 0;
  547. int tY = 0;
  548. do {
  549. // Pull one tile
  550. blit(sX, sY, src, tX, tY, split, tileWidth, tileHeight);
  551. // Next tile
  552. tX += tileWidth + TILE_SPACING;
  553. if (tX >= displayW) {
  554. tX = 0;
  555. tY += tileHeight + TILE_SPACING;
  556. if (tY >= displayH) break;
  557. sX = leftPad;
  558. sY += tileHeight + vertSplit;
  559. }
  560. else {
  561. sX += tileWidth + horizSplit;
  562. }
  563. } while (1);
  564. }
  565. setDirty();
  566. }
  567. void WSplitPreview::apply() { start_func
  568. *((color*)setting) = bkColor;
  569. }
  570. void WSplitPreview::display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) { start_func
  571. assert(destSurface);
  572. if (visible) {
  573. // If dirty, redraw all
  574. if (dirty) {
  575. getRect(toDisplay);
  576. toDisplay.x += xOffset;
  577. toDisplay.y += yOffset;
  578. dirty = 0;
  579. intersectRects(toDisplay, clipArea);
  580. }
  581. // Anything to draw?
  582. if (toDisplay.w) {
  583. SDL_SetClipRect(destSurface, &toDisplay);
  584. xOffset += x;
  585. yOffset += y;
  586. // We specifically use black, except for "white" copy
  587. SDL_FillRect(destSurface, &toDisplay, SDL_MapRGB(destSurface->format, 0, 0, 0));
  588. // @TODO: Corners of inverted box aren't grey
  589. if (PREVIEW_BORDER_SIZE) drawGuiBoxInvert(xOffset, yOffset, width, height, PREVIEW_BORDER_SIZE, destSurface);
  590. if (split) blit(0, 0, split, xOffset + PREVIEW_BORDER_SIZE, yOffset + PREVIEW_BORDER_SIZE, destSurface);
  591. }
  592. }
  593. }