gcsx_wpreview.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /* GCSx
  2. ** WPREVIEW.CPP
  3. **
  4. ** Widget that previews an image (tile, map, etc.)
  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. WPreview::WPreview(int pId, SDL_Surface* const* src, int myWidth, int myHeight, int pShowMultiple, int pAllowDistort) : Widget(pId, blankString, NULL) { start_func
  25. assert(src);
  26. showMultiple = pShowMultiple;
  27. allowDistort = pAllowDistort;
  28. source = src;
  29. scaled = NULL;
  30. scaledIsSource = 1;
  31. changeSize(myWidth, myHeight);
  32. }
  33. WPreview::~WPreview() { start_func
  34. if (scaled) SDL_FreeSurface(scaled);
  35. }
  36. void WPreview::changeSize(int newWidth, int newHeight) { start_func
  37. displayW = newWidth;
  38. displayH = newHeight;
  39. if ((newWidth <= 0) || (newHeight <= 0)) {
  40. resize(0, 0);
  41. }
  42. else {
  43. resize(newWidth + PREVIEW_BORDER_SIZE * 2, newHeight + PREVIEW_BORDER_SIZE * 2);
  44. }
  45. }
  46. int WPreview::event(int hasFocus, const SDL_Event* event) { start_func
  47. // Currently doesn't do any events
  48. return 0;
  49. }
  50. int WPreview::refuseAll() const { start_func
  51. // Currently doesn't do any events
  52. return 1;
  53. }
  54. void WPreview::load() { start_func
  55. if ((*source == NULL) || (displayW <= 0) || (displayH <= 0)) {
  56. if (scaled) SDL_FreeSurface(scaled);
  57. scaled = NULL;
  58. scaledIsSource = 1;
  59. }
  60. else {
  61. SDL_Surface* src= *source;
  62. int actualW = src->w;
  63. int actualH = src->h;
  64. // Scaling required?
  65. if (actualW <= displayW) {
  66. imageFullX = 1;
  67. imageScaleX = 1.0;
  68. }
  69. else {
  70. imageFullX = 0;
  71. imageScaleX = (float)(displayW) / (float)(actualW);
  72. }
  73. if (actualH <= displayH) {
  74. imageFullY = 1;
  75. imageScaleY = 1.0;
  76. }
  77. else {
  78. imageFullY = 0;
  79. imageScaleY = (float)(displayH) / (float)(actualH);
  80. }
  81. // Prevent distortion?
  82. if ((!allowDistort) && ((!imageFullX) || (!imageFullY))) {
  83. imageFullX = imageFullY = 0;
  84. if (imageScaleX > imageScaleY) imageScaleX = imageScaleY;
  85. else imageScaleY = imageScaleX;
  86. }
  87. // Calculate actual w/h (round up; limit to display size max)
  88. actualW = min(displayW, (int)ceil(actualW * imageScaleX));
  89. actualH = min(displayH, (int)ceil(actualH * imageScaleY));
  90. // Multiple copies? (only if not scaled)
  91. int copies = 1;
  92. int gutters = 0;
  93. if ((showMultiple) && (imageFullX) && (imageFullY)) {
  94. // Non-tiled copies must have at least one pixel between them
  95. // Room for at least two copies?
  96. if (displayW >= actualW * 2 + 1) {
  97. copies = 2;
  98. gutters = 1;
  99. }
  100. // Room for two copies and 2x? tiled?
  101. if (displayW >= actualW * 4 + 2) {
  102. // Room for two copies and 3x? tiled?
  103. if (displayW >= actualW * 5 + 2) copies = 5;
  104. else copies = 4;
  105. gutters = 2;
  106. }
  107. }
  108. // Size of gutters and l/r margins; gutters get twice as much space
  109. int gutterSize = (displayW - actualW * copies) / (gutters + 1);
  110. int marginSize = (displayW - actualW * copies) / (gutters * 2 + 2);
  111. // Margins can be 0, gutters must be at least 1
  112. if (gutterSize < 1) gutterSize = 1;
  113. // Position of primary image
  114. // Offset x/y by border amount
  115. imageX = marginSize + PREVIEW_BORDER_SIZE;
  116. imageY = (displayH - actualH) / 2 + PREVIEW_BORDER_SIZE;
  117. // Secondary image
  118. if (copies > 1) {
  119. imageWhiteX = marginSize + actualW + gutterSize + PREVIEW_BORDER_SIZE;
  120. imageWhiteY = (displayH - actualH) / 2 + PREVIEW_BORDER_SIZE;
  121. }
  122. else {
  123. imageWhiteX = imageWhiteY = 0;
  124. }
  125. // Tiled image
  126. if (copies > 2) {
  127. imageTiledQty = copies - 2;
  128. imageTiledX = marginSize + actualW * 2 + gutterSize * 2 + PREVIEW_BORDER_SIZE;
  129. // (can be negative, but if so, ensure rounds in right direction)
  130. if (actualH * imageTiledQty > displayH) imageTiledY = (displayH - actualH * imageTiledQty - 1) / 2 + PREVIEW_BORDER_SIZE;
  131. else imageTiledY = (displayH - actualH * imageTiledQty) / 2 + PREVIEW_BORDER_SIZE;
  132. }
  133. else {
  134. imageTiledX = imageTiledY = imageTiledQty = 0;
  135. }
  136. // Need to redraw actual image? Always redraw if scaled at all
  137. if ((!imageFullX) || (!imageFullY)) {
  138. // Deallocate
  139. if (scaled) SDL_FreeSurface(scaled);
  140. scaled = NULL;
  141. scaledIsSource = 1;
  142. // If scaling fails to allocate surface, we won't throw an error-
  143. // we'll just stick to the original source version
  144. scaled = sge_transform_surface(src, SDL_MapRGBA(src->format, 0, 0, 0, 0), 0, imageScaleX, imageScaleY, SGE_TAA|SGE_TSAFE);
  145. if (scaled) {
  146. scaledIsSource = 0;
  147. }
  148. else {
  149. // (ptr already NULL)
  150. scaledIsSource = 1;
  151. }
  152. }
  153. // Stick with copy of source if not really scaled
  154. else {
  155. // Deallocate?
  156. if (scaled) SDL_FreeSurface(scaled);
  157. scaled = NULL;
  158. scaledIsSource = 1;
  159. }
  160. }
  161. setDirty();
  162. }
  163. void WPreview::apply() { start_func
  164. // Doesn't apply anything
  165. }
  166. void WPreview::display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) { start_func
  167. assert(destSurface);
  168. if (visible) {
  169. // If dirty, redraw all
  170. if (dirty) {
  171. getRect(toDisplay);
  172. toDisplay.x += xOffset;
  173. toDisplay.y += yOffset;
  174. dirty = 0;
  175. intersectRects(toDisplay, clipArea);
  176. }
  177. // Anything to draw?
  178. if (toDisplay.w) {
  179. SDL_SetClipRect(destSurface, &toDisplay);
  180. xOffset += x;
  181. yOffset += y;
  182. // We specifically use black, except for "white" copy
  183. SDL_FillRect(destSurface, &toDisplay, SDL_MapRGB(destSurface->format, 0, 0, 0));
  184. // @TODO: Corners of inverted box aren't grey
  185. if (PREVIEW_BORDER_SIZE) drawGuiBoxInvert(xOffset, yOffset, width, height, PREVIEW_BORDER_SIZE, destSurface);
  186. // Just one copy?
  187. if (!imageWhiteX) {
  188. // (scaled images have a 1-pixel border we want to discard)
  189. if (scaled) blit(1, 1, scaled, xOffset + imageX, yOffset + imageY, destSurface, scaled->w - 2, scaled->h - 2);
  190. else if ((scaledIsSource) && (*source)) blit(0, 0, *source, xOffset + imageX, yOffset + imageY, destSurface);
  191. }
  192. else {
  193. int tileW = (*source)->w;
  194. int tileH = (*source)->h;
  195. SDL_SetAlpha(*source, SDL_SRCALPHA, 255);
  196. // Multiple copies- never scaled
  197. // Black copy
  198. blit(0, 0, *source, xOffset + imageX, yOffset + imageY, destSurface);
  199. // White copy, with alpha
  200. drawRect(xOffset + imageWhiteX, yOffset + imageWhiteY, tileW, tileH, SDL_MapRGB(destSurface->format, 255, 255, 255), destSurface);
  201. blit(0, 0, *source, xOffset + imageWhiteX, yOffset + imageWhiteY, destSurface);
  202. // Tiles
  203. if (imageTiledX) {
  204. // Reduce clip rectangle to within border vertically, tiled copy may go out
  205. Rect newClip = toDisplay;
  206. if (newClip.y == yOffset) {
  207. ++newClip.y;
  208. --newClip.h;
  209. }
  210. if (newClip.y + newClip.h == yOffset + height) --newClip.h;
  211. SDL_SetClipRect(destSurface, &newClip);
  212. for (int tX = 0; tX < imageTiledQty; ++tX)
  213. for (int tY = 0; tY < imageTiledQty; ++tY)
  214. blit(0, 0, *source, xOffset + imageTiledX + tileW * tX, yOffset + imageTiledY + tileH * tY, destSurface);
  215. }
  216. SDL_SetAlpha(*source, 0, 255);
  217. }
  218. }
  219. }
  220. }