gcsx_graphics.cpp 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094
  1. /* GCSx
  2. ** GRAPHICS.CPP
  3. **
  4. ** Basic graphics primitives/support via SDL
  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. SDL_Color phaseRGB[NUM_PHASES] = {
  25. { 0, 0, 0 },
  26. { 64, 64, 64 },
  27. { 128, 128, 128 },
  28. { 192, 192, 192 },
  29. { 255, 255, 255 },
  30. { 192, 192, 192 },
  31. { 128, 128, 128 },
  32. { 64, 64, 64 },
  33. };
  34. Uint32 phaseColors[NUM_PHASES];
  35. SDL_Color guiRGB[COLOR_COUNT] = {
  36. { 224, 224, 224 }, // COLOR_FILL - GUI fill
  37. { 255, 255, 255 }, // COLOR_LIGHT1 - Light bevel on GUI
  38. { 224, 224, 224 }, // COLOR_LIGHT2
  39. { 112, 112, 112 }, // COLOR_DARK1 - Dark bevel on GUI
  40. { 168, 168, 168 }, // COLOR_DARK2
  41. { 204, 204, 204 }, // COLOR_BUTTONFILL1 - Normal button gradient
  42. { 244, 244, 244 }, // COLOR_BUTTONFILL2
  43. { 176, 176, 176 }, // COLOR_BUTTONDOWN1 - Depressed button gradient
  44. { 216, 216, 216 }, // COLOR_BUTTONDOWN2
  45. { 0, 0, 0 }, // COLOR_TEXT - GUI text
  46. { 176, 176, 255 }, // COLOR_TITLEACTIVE1 - Active titlebar gradient
  47. { 255, 176, 255 }, // COLOR_TITLEACTIVE2
  48. { 112, 112, 152 }, // COLOR_TITLEINACTIVE1 - Inactive titlebar gradient
  49. { 152, 112, 152 }, // COLOR_TITLEINACTIVE2
  50. { 255, 255, 255 }, // COLOR_TEXTBOX - Textboxes fill
  51. { 0, 0, 0 }, // COLOR_CURSOR - Cursor in textboxes
  52. { 0, 0, 255 }, // COLOR_SELECTION1 - Selected text fill gradient
  53. { 128, 0, 128 }, // COLOR_SELECTION2
  54. { 255, 255, 128 }, // COLOR_TILECURSOR - Cursor when selecting tiles/sprites
  55. { 128, 128, 255 }, // COLOR_TILESELECTION - Overlaid over selected tiles/sprites
  56. { 255, 255, 255 }, // COLOR_TILECURSORBORDER1 - Fade range for glowing portion of tile cursor
  57. { 0, 0, 0 }, // COLOR_TILECURSORBORDER2
  58. { 160, 160, 160 }, // COLOR_SCROLLTRACK - Fill for scrollbar gutter
  59. { 0, 0, 0 }, // COLOR_LINEBORDER - Thin border on GUI widgets that don't use a bevel
  60. { 0, 0, 0 }, // COLOR_BKFILL - Fill/background for editing windows/areas
  61. { 64, 64, 192 }, // COLOR_GRID - Grid lines
  62. { 11, 11, 11 }, // COLOR_FRONTDESKTOP - Desktop fill for frontend
  63. { 0, 0, 26 }, // COLOR_EDITORDESKTOP - Desktop fill for editor
  64. { 0, 0, 0 }, // COLOR_TRANSPARENT1 - Used to show areas that are 100% transparent
  65. { 128, 128, 128 }, // COLOR_TRANSPARENT2
  66. { 255, 255, 192 }, // COLOR_TOOLTIP - Tooltip fill
  67. { 255, 0, 0 }, // COLOR_GLYPHWIDTH - Glyph width marker
  68. { 0, 0, 255 }, // COLOR_POPUPFILL1 - Selected menu item gradient
  69. { 128, 0, 128 }, // COLOR_POPUPFILL2
  70. { 255, 255, 255 }, // COLOR_POPUPTEXT - Selected menu item text
  71. { 128, 128, 128 }, // COLOR_CONSOLEPROMPT - Console prompt
  72. { 192, 0, 0 }, // COLOR_CONSOLEINPUT - User input in console
  73. };
  74. Uint32 guiPacked[COLOR_COUNT];
  75. SDL_Surface* actualScreen = NULL;
  76. // In normal mode, points to actual
  77. // In OpenGL mode, points to allocated 32bit surface
  78. SDL_Surface* proxyScreen = NULL;
  79. TextureMap* textureScreen = NULL;
  80. TextureMap* textureMice = NULL;
  81. int proxyScreenAllocated = 0;
  82. int glScreenState = 0;
  83. GLfloat glAlpha = 1.0f;
  84. int requestedX = 0;
  85. int requestedY = 0;
  86. int requestedBits = 0;
  87. int requestedFullscreen = 0;
  88. int requestedResizable = 0;
  89. int requestedGL = 0;
  90. int screenWidth = 0;
  91. int screenHeight = 0;
  92. int actualX = 0;
  93. int actualY = 0;
  94. int actualBits = 0; // bits of screen surface we have
  95. int hardwareBits = 0; // bits of the hardware itself currently
  96. int defaultBits = 0; // bits we will always use when windowed
  97. // (previous actual)
  98. int previousX = 0;
  99. int previousY = 0;
  100. int previousBits = 0;
  101. int previousFullscreen = 0;
  102. int previousResizable = 0;
  103. int previousGL = 0;
  104. MousePointer* micePointers[MOUSE_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL };
  105. const char* micePointerFiles[MOUSE_COUNT] = {
  106. "mousenorm.bmp",
  107. "mousevert.bmp",
  108. "mousehoriz.bmp",
  109. "mousebeam.bmp",
  110. "mousediagdown.bmp",
  111. "mousediagup.bmp",
  112. "mousepixel.bmp",
  113. "mouseadd.bmp",
  114. "mousesub.bmp",
  115. "mousefour.bmp"
  116. };
  117. int micePointerSpots[MOUSE_COUNT][2] = { { 0, 0 }, { 5, 8 }, { 8, 5 },
  118. { 3, 7 }, { 6, 6 }, { 6, 6 },
  119. { 5, 5 }, { 5, 5 }, { 5, 5 },
  120. { 10, 10 } };
  121. int currentMouse = 0;
  122. // Largest mouse size, and storage to unblit it from
  123. int mouseXSize = 0;
  124. int mouseYSize = 0;
  125. SDL_Surface* mouseUnblit = NULL;
  126. int lastMouseX = 0;
  127. int lastMouseY = 0;
  128. int mouseBlitted = -1;
  129. // Used for screenFlip- first rectangle is main screen
  130. // area to update; second and third are the last mouse
  131. // unblit and blit areas
  132. SDL_Rect updateRects[3];
  133. int numUpdate = 1;
  134. Uint32 convertRGB(SDL_Color color, int alpha) { start_func
  135. assert(proxyScreen);
  136. if (alpha >= 0) return SDL_MapRGBA(proxyScreen->format, color.r, color.g, color.b, alpha);
  137. return SDL_MapRGB(proxyScreen->format, color.r, color.g, color.b);
  138. }
  139. // Call whenever palette/mode changes
  140. void convertGuiItems() { start_func
  141. assert(proxyScreen);
  142. int pos;
  143. for (pos = 0; pos < COLOR_COUNT; ++pos) {
  144. guiPacked[pos] = convertRGB(guiRGB[pos]);
  145. }
  146. for (pos = 0; pos < MOUSE_COUNT; ++pos) {
  147. micePointers[pos]->convertFor(proxyScreen);
  148. if (requestedGL)
  149. micePointers[pos]->convertGL(textureMice, pos + 1, mouseXSize, mouseYSize);
  150. }
  151. for (pos = 0; pos < NUM_PHASES; ++pos) {
  152. phaseColors[pos] = convertRGB(phaseRGB[pos]);
  153. }
  154. // Storage for unblitting mouse
  155. if (mouseUnblit) SDL_FreeSurface(mouseUnblit);
  156. mouseUnblit = NULL;
  157. mouseUnblit = createSurface(mouseXSize, mouseYSize);
  158. mouseBlitted = -1;
  159. }
  160. void initVideo() { start_func
  161. const SDL_VideoInfo* videoInfo;
  162. if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) {
  163. fatalCrash(0, "Unable to init SDL: %s", SDL_GetError());
  164. }
  165. videoInfo = SDL_GetVideoInfo();
  166. defaultBits = videoInfo->vfmt->BitsPerPixel;
  167. if (defaultBits < 15) {
  168. fatalCrash(0, "Full-color video not supported");
  169. }
  170. string mouseFile;
  171. for (int pos = 0; pos < MOUSE_COUNT; ++pos) {
  172. if (micePointers[pos] == NULL) {
  173. createFilename(resourceDir->c_str(), micePointerFiles[pos], mouseFile);
  174. micePointers[pos] = new MousePointer(mouseFile.c_str(), micePointerSpots[pos][0], micePointerSpots[pos][1]);
  175. if (micePointers[pos]->xSize() > mouseXSize) mouseXSize = micePointers[pos]->xSize();
  176. if (micePointers[pos]->ySize() > mouseYSize) mouseYSize = micePointers[pos]->ySize();
  177. }
  178. }
  179. assert(mouseXSize > 0);
  180. assert(mouseYSize > 0);
  181. // We don't really care about inability to load our icon
  182. string iconFile;
  183. createFilename(resourceDir->c_str(), FILENAME_ICON, iconFile);
  184. SDL_Surface* icon = SDL_LoadBMP(iconFile.c_str());
  185. if (icon) SDL_WM_SetIcon(icon, NULL);
  186. SDL_FreeSurface(icon);
  187. }
  188. void selectVideoMode(int x, int y, int bpp, int fullscreen, int resizable, int gl) throw_Video { start_func
  189. const SDL_VideoInfo* videoInfo;
  190. if (bpp == -1) bpp = actualBits ? actualBits : defaultBits;
  191. if (x == -1) x = actualX;
  192. if (y == -1) y = actualY;
  193. if (fullscreen == -1) fullscreen = requestedFullscreen;
  194. if (resizable == -1) resizable = requestedResizable;
  195. if (gl == -1) gl = requestedGL;
  196. assert(x >= 0);
  197. assert(y >= 0);
  198. assert((bpp == 15) || (bpp == 16) || (bpp == 24) || (bpp == 32));
  199. // Certain minimum size
  200. if (x < 320) x = 320;
  201. if (y < 240) y = 240;
  202. // If fullscreen, not resizable
  203. if (fullscreen) {
  204. resizable = 0;
  205. }
  206. // If windowed, always go with default hardware bpp
  207. else {
  208. bpp = defaultBits;
  209. }
  210. previousX = actualX;
  211. previousY = actualY;
  212. previousBits = actualBits;
  213. previousFullscreen = requestedFullscreen;
  214. previousResizable = requestedResizable;
  215. previousGL = requestedGL;
  216. if (gl) {
  217. // @TODO: optimal settings here? should be based on bpp?
  218. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
  219. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
  220. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
  221. SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
  222. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
  223. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  224. }
  225. if (proxyScreenAllocated) {
  226. SDL_FreeSurface(proxyScreen);
  227. proxyScreenAllocated = 0;
  228. delete textureScreen;
  229. textureScreen = NULL;
  230. delete textureMice;
  231. textureMice = NULL;
  232. }
  233. // IMPORTANT: If you change this from SDL_SWSURFACE, you may need to add in surface locking!
  234. actualScreen = SDL_SetVideoMode(x, y, bpp,
  235. (gl ? SDL_OPENGL : SDL_SWSURFACE) |
  236. (fullscreen ? SDL_FULLSCREEN : 0) |
  237. (resizable ? SDL_RESIZABLE : 0)
  238. );
  239. if (actualScreen == NULL) {
  240. if (previousX) {
  241. // IMPORTANT: If you change this from SDL_SWSURFACE, you may need to add in surface locking!
  242. actualScreen = SDL_SetVideoMode(previousX, previousY, previousBits,
  243. (previousGL ? SDL_OPENGL : SDL_SWSURFACE) |
  244. (previousFullscreen ? SDL_FULLSCREEN : 0) |
  245. (previousResizable ? SDL_RESIZABLE : 0)
  246. );
  247. if ((previousGL) && (actualScreen)) {
  248. proxyScreen = createSurface32(actualScreen->w, actualScreen->h);
  249. proxyScreenAllocated = 1;
  250. textureScreen = new TextureMap(1, actualScreen->w, actualScreen->h, NULL);
  251. textureMice = new TextureMap(MOUSE_COUNT, mouseXSize, mouseYSize, NULL);
  252. glScreenState = 0;
  253. glAlpha = 1.0f;
  254. }
  255. else proxyScreen = actualScreen;
  256. if (actualScreen == NULL) {
  257. fatalCrash(0, "Unable to set %dx%dx%d video: %s", x, y, bpp, SDL_GetError());
  258. }
  259. else {
  260. throw VideoException("Unable to set %dx%dx%d video: %s", x, y, bpp, SDL_GetError());
  261. }
  262. }
  263. else {
  264. // Only fatal if no mode to fall back on
  265. fatalCrash(0, "Unable to set %dx%dx%d video: %s", x, y, bpp, SDL_GetError());
  266. }
  267. }
  268. else {
  269. if (fullscreen) {
  270. debugWrite(DEBUG_VIDEO, "Video mode %dx%dx%d", x, y, bpp);
  271. }
  272. else {
  273. debugWrite(DEBUG_VIDEO, "Video mode %dx%dx%d (w)", x, y, bpp);
  274. }
  275. }
  276. if (gl) {
  277. proxyScreen = createSurface32(actualScreen->w, actualScreen->h);
  278. proxyScreenAllocated = 1;
  279. textureScreen = new TextureMap(1, actualScreen->w, actualScreen->h, NULL);
  280. textureMice = new TextureMap(MOUSE_COUNT, mouseXSize, mouseYSize, NULL);
  281. glScreenState = 0;
  282. glAlpha = 1.0f;
  283. }
  284. else proxyScreen = actualScreen;
  285. requestedX = x;
  286. requestedY = y;
  287. requestedBits = bpp;
  288. requestedFullscreen = fullscreen;
  289. requestedResizable = resizable;
  290. requestedGL = gl;
  291. videoInfo = SDL_GetVideoInfo();
  292. hardwareBits = videoInfo->vfmt->BitsPerPixel;
  293. actualBits = actualScreen->format->BitsPerPixel;
  294. screenWidth = actualX = proxyScreen->w;
  295. screenHeight = actualY = proxyScreen->h;
  296. if ((x != actualX) || (y != actualY) || (bpp != actualBits)) {
  297. debugWrite(DEBUG_VIDEO, "Actual mode used: %dx%dx%d", actualX, actualY, actualBits);
  298. }
  299. if (hardwareBits != actualBits) {
  300. debugWrite(DEBUG_VIDEO, "Hardware BPP: %d", hardwareBits);
  301. }
  302. SDL_SetAlpha(proxyScreen, 0, 255);
  303. SDL_ShowCursor(SDL_DISABLE);
  304. convertGuiItems();
  305. // Resize desktop and all windows on it
  306. if (desktop != NULL) {
  307. desktop->resolutionChange(previousX, previousY, previousBits, actualX, actualY, actualBits);
  308. }
  309. // Save config (gl mode is game mode and doesn't count for configuration)
  310. if (!gl) {
  311. config->write(VIDEO_X, actualX);
  312. config->write(VIDEO_Y, actualY);
  313. config->write(VIDEO_BPP, actualBits);
  314. config->write(VIDEO_FULLSCREEN, requestedFullscreen);
  315. config->write(VIDEO_RESIZABLE, requestedResizable);
  316. }
  317. // Initialize OpenGL?
  318. if (gl) {
  319. oglInit(actualX, actualY);
  320. }
  321. }
  322. void exitVideo() { start_func
  323. for (int pos = 0; pos < MOUSE_COUNT; ++pos) {
  324. delete micePointers[pos];
  325. micePointers[pos] = NULL;
  326. }
  327. if (proxyScreenAllocated) {
  328. SDL_FreeSurface(proxyScreen);
  329. proxyScreenAllocated = 0;
  330. delete textureScreen;
  331. textureScreen = NULL;
  332. delete textureMice;
  333. textureMice = NULL;
  334. }
  335. }
  336. int screenBits() { start_func
  337. return actualBits;
  338. }
  339. int screenFullscreen() { start_func
  340. return requestedFullscreen;
  341. }
  342. int screenResizable() { start_func
  343. return requestedResizable;
  344. }
  345. int screenGL() { start_func
  346. return requestedGL;
  347. }
  348. void drawPixel(int x, int y, SDL_Color color, SDL_Surface* surface) { start_func
  349. drawPixel(x, y, convertRGB(color), surface);
  350. }
  351. void drawPixel(int x, int y, Uint32 data, SDL_Surface* surface) { start_func
  352. assert(surface);
  353. Uint16* bufp16;
  354. Uint32* bufp32;
  355. SDL_Rect clip;
  356. SDL_GetClipRect(surface, &clip);
  357. if ((x < clip.x) || (y < clip.y) || (x >= clip.x + clip.w) || (y >= clip.y + clip.h)) return;
  358. switch (surface->format->BytesPerPixel) {
  359. case 2:
  360. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  361. *bufp16 = data;
  362. break;
  363. case 4:
  364. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  365. *bufp32 = data;
  366. break;
  367. }
  368. }
  369. Uint32 getPixel(int x, int y, SDL_Surface* surface) { start_func
  370. assert(surface);
  371. Uint16* bufp16;
  372. Uint32* bufp32;
  373. SDL_Rect clip;
  374. SDL_GetClipRect(surface, &clip);
  375. if ((x < clip.x) || (y < clip.y) || (x >= clip.x + clip.w) || (y >= clip.y + clip.h)) return 0;
  376. switch (surface->format->BytesPerPixel) {
  377. case 2:
  378. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  379. return *bufp16;
  380. case 4:
  381. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  382. return *bufp32;
  383. }
  384. return 0;
  385. }
  386. void alphaBlit32(int sX, int sY, const SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int width, int height) { start_func
  387. assert(src);
  388. assert(dest);
  389. width = (width == -1 ? src->w : width);
  390. height = (height == -1 ? src->h : height);
  391. Uint32 Amask = src->format->Amask;
  392. Uint32 Ashift = src->format->Ashift;
  393. for (int x = 0; x < width; ++x) {
  394. for (int y = 0; y < height; ++y) {
  395. Uint32 color = *((Uint32*)src->pixels + (sY + y)*src->pitch/4 + sX + x);
  396. Uint8 alpha = (color & Amask) >> Ashift;
  397. // Color becomes at 255 alpha, use alpha for blending instead
  398. _PutPixelAlpha(dest, dX + x, dY + y, color | Amask, alpha);
  399. }
  400. }
  401. }
  402. void alphaBlitFx(int sX, int sY, const SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int width, int height, int mirror, int flip, int rotate90, int red, int green, int blue, int rgbScale, int alpha, int alphaScale) {
  403. assert(src);
  404. assert(dest);
  405. if (alpha <= 0) return;
  406. // Default w/h
  407. width = (width == -1 ? src->w : width);
  408. height = (height == -1 ? src->h : height);
  409. // Determine target rect, accounting for clip
  410. Rect target = { dX, dY, width, height };
  411. SDL_Rect Sclip;
  412. SDL_GetClipRect(dest, &Sclip);
  413. Rect clip = { Sclip.x, Sclip.y, Sclip.w, Sclip.h };
  414. if (!intersectRects(target, clip)) return;
  415. // Adjust source position
  416. sX += target.x - dX;
  417. sY += target.y - dY;
  418. // Determine increment, accounting for flip/mirror
  419. int srcPitch = src->pitch / 4 - target.w;
  420. int srcAdd = 1;
  421. if (rotate90) {
  422. assert(width == height);
  423. srcAdd = src->pitch / -4;
  424. srcPitch = -srcAdd * target.h + 1;
  425. if (mirror) {
  426. srcAdd = -srcAdd;
  427. srcPitch = -srcAdd * target.h + 1;
  428. }
  429. else {
  430. sY = sY + target.h - 1;
  431. }
  432. if (flip) {
  433. sX = sX + target.w - 1;
  434. srcPitch -= 2;
  435. }
  436. }
  437. else {
  438. if (flip) {
  439. sY = sY + target.h - 1;
  440. srcPitch -= src->pitch / 2;
  441. }
  442. if (mirror) {
  443. sX = sX + target.w - 1;
  444. srcAdd = -1;
  445. srcPitch += target.w * 2;
  446. }
  447. }
  448. Uint32* srcP = (Uint32*)src->pixels + sX + sY * src->pitch / 4;
  449. // Destination range
  450. int odX = target.x;
  451. dY = target.y;
  452. int dX2 = odX + target.w;
  453. int dY2 = dY + target.h;
  454. // Bitmasks/shifts
  455. Uint32 rdmask = dest->format->Rmask;
  456. Uint32 gdmask = dest->format->Gmask;
  457. Uint32 bdmask = dest->format->Bmask;
  458. int runshift = dest->format->Rshift;
  459. int gunshift = dest->format->Gshift;
  460. int bunshift = dest->format->Bshift;
  461. // Optimize for no color/no alpha
  462. int applyColor = 0;
  463. int applyAlpha = 0;
  464. if (red < rgbScale) applyColor = 1;
  465. if (green < rgbScale) applyColor = 1;
  466. if (blue < rgbScale) applyColor = 1;
  467. if (alpha < alphaScale) applyAlpha = 1;
  468. switch (dest->format->BytesPerPixel) {
  469. case 2: {
  470. Uint16* destP = (Uint16*)dest->pixels + odX + dY * dest->pitch / 2;
  471. int destPitch = dest->pitch / 2 - target.w;
  472. int rloss = dest->format->Rloss;
  473. int gloss = dest->format->Gloss;
  474. int bloss = dest->format->Bloss;
  475. for (; dY < dY2; ++dY) {
  476. for (dX = odX; dX < dX2; ++dX) {
  477. // Pixel
  478. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  479. int r = (*srcP & 0xff000000) >> 24;
  480. int g = (*srcP & 0x00ff0000) >> 16;
  481. int b = (*srcP & 0x0000ff00) >> 8;
  482. Uint32 a = *srcP & 0x000000ff;
  483. #else
  484. int r = *srcP & 0x000000ff;
  485. int g = (*srcP & 0x0000ff00) >> 8;
  486. int b = (*srcP & 0x00ff0000) >> 16;
  487. Uint32 a = *srcP & 0xff000000;
  488. #endif
  489. // Apply color
  490. if (applyColor) {
  491. r = r * red / rgbScale;
  492. g = g * green / rgbScale;
  493. b = b * blue / rgbScale;
  494. }
  495. // Apply alpha
  496. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  497. if ((a != 0x000000ff) || (applyAlpha)) {
  498. #else
  499. if ((a != 0xff000000) || (applyAlpha)) {
  500. a = a >> 24;
  501. #endif
  502. a = a * alpha / alphaScale;
  503. a = a ^ 0xFF; // (flipped)
  504. r += (((int)((*destP & rdmask) >> runshift) - r) * a) >> 8;
  505. g += (((int)((*destP & gdmask) >> gunshift) - g) * a) >> 8;
  506. b += (((int)((*destP & bdmask) >> bunshift) - b) * a) >> 8;
  507. }
  508. // Scale down
  509. r >>= rloss;
  510. g >>= gloss;
  511. b >>= bloss;
  512. // Place
  513. *destP = (r << runshift) | (g << gunshift) | (b << bunshift);
  514. ++destP;
  515. srcP += srcAdd;
  516. }
  517. destP += destPitch;
  518. srcP += srcPitch;
  519. }
  520. break;
  521. }
  522. case 4: {
  523. Uint32* destP = (Uint32*)dest->pixels + odX + dY * dest->pitch / 4;
  524. int destPitch = dest->pitch / 4 - target.w;
  525. for (; dY < dY2; ++dY) {
  526. for (dX = odX; dX < dX2; ++dX) {
  527. // Pixel
  528. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  529. int r = (*srcP & 0xff000000) >> 24;
  530. int g = (*srcP & 0x00ff0000) >> 16;
  531. int b = (*srcP & 0x0000ff00) >> 8;
  532. Uint32 a = *srcP & 0x000000ff;
  533. #else
  534. int r = *srcP & 0x000000ff;
  535. int g = (*srcP & 0x0000ff00) >> 8;
  536. int b = (*srcP & 0x00ff0000) >> 16;
  537. Uint32 a = *srcP & 0xff000000;
  538. #endif
  539. // Apply color
  540. if (applyColor) {
  541. r = r * red / rgbScale;
  542. g = g * green / rgbScale;
  543. b = b * blue / rgbScale;
  544. }
  545. // Apply alpha
  546. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  547. if ((a != 0x000000ff) || (applyAlpha)) {
  548. #else
  549. if ((a != 0xff000000) || (applyAlpha)) {
  550. a = a >> 24;
  551. #endif
  552. a = a * alpha / alphaScale;
  553. a = a ^ 0xFF; // (flipped)
  554. r += (((int)((*destP & rdmask) >> runshift) - r) * a) >> 8;
  555. g += (((int)((*destP & gdmask) >> gunshift) - g) * a) >> 8;
  556. b += (((int)((*destP & bdmask) >> bunshift) - b) * a) >> 8;
  557. }
  558. // Place
  559. *destP = (r << runshift) | (g << gunshift) | (b << bunshift);
  560. ++destP;
  561. srcP += srcAdd;
  562. }
  563. destP += destPitch;
  564. srcP += srcPitch;
  565. }
  566. break;
  567. }
  568. }
  569. }
  570. void maskBlit32(int sX, int sY, SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int mX, int mY, const SDL_Surface* mask, int width, int height, int clear, Uint32 clearColor) { start_func
  571. assert(src);
  572. assert(dest);
  573. assert(mask);
  574. if (src == dest) {
  575. assert(sX == dX);
  576. assert(sY == dY);
  577. }
  578. if (src == mask) {
  579. assert(sX == mX);
  580. assert(sY == mY);
  581. }
  582. if (dest == mask) {
  583. assert(dX == mX);
  584. assert(dY == mY);
  585. }
  586. width = (width == -1 ? src->w : width);
  587. height = (height == -1 ? src->h : height);
  588. Uint32 Amask = mask->format->Amask;
  589. Uint32* srcData = (Uint32*)src->pixels + sY*src->pitch/4 + sX;
  590. Uint32* destData = (Uint32*)dest->pixels + dY*dest->pitch/4 + dX;
  591. Uint32* maskData = (Uint32*)mask->pixels + mY*mask->pitch/4 + mX;
  592. int srcPitch = src->pitch/4 - width;
  593. int destPitch = dest->pitch/4 - width;
  594. int maskPitch = mask->pitch/4 - width;
  595. for (int y = 0; y < height; ++y) {
  596. for (int x = 0; x < width; ++x) {
  597. if (*maskData & Amask) {
  598. *destData = *srcData;
  599. if (clear) *srcData = clearColor;
  600. }
  601. ++srcData;
  602. ++destData;
  603. ++maskData;
  604. }
  605. srcData += srcPitch;
  606. destData += destPitch;
  607. maskData += maskPitch;
  608. }
  609. }
  610. void maskAlphaBlit32(int sX, int sY, SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int mX, int mY, const SDL_Surface* mask, int alphaPercent, int width, int height, int clear, Uint32 clearColor) { start_func
  611. assert(src);
  612. assert(dest);
  613. assert(mask);
  614. if (src == dest) {
  615. assert(sX == dX);
  616. assert(sY == dY);
  617. }
  618. if (src == mask) {
  619. assert(sX == mX);
  620. assert(sY == mY);
  621. }
  622. if (dest == mask) {
  623. assert(dX == mX);
  624. assert(dY == mY);
  625. }
  626. width = (width == -1 ? src->w : width);
  627. height = (height == -1 ? src->h : height);
  628. Uint32 Amask = mask->format->Amask;
  629. Uint32 SrcAmask = src->format->Amask;
  630. Uint32 SrcAshift = src->format->Ashift;
  631. Uint32* srcData = (Uint32*)src->pixels + sY*src->pitch/4 + sX;
  632. Uint32* maskData = (Uint32*)mask->pixels + mY*mask->pitch/4 + mX;
  633. int srcPitch = src->pitch/4 - width;
  634. int maskPitch = mask->pitch/4 - width;
  635. for (int y = 0; y < height; ++y) {
  636. for (int x = 0; x < width; ++x) {
  637. if (*maskData & Amask) {
  638. // Prep color for putpixelalpha
  639. Uint32 color = *srcData;
  640. Uint8 alpha = (color & SrcAmask) >> SrcAshift;
  641. // Color becomes at 255 alpha, use alpha for blending instead
  642. _PutPixelAlpha(dest, dX + x, dY + y, color | SrcAmask, alpha * alphaPercent / 100);
  643. if (clear) *srcData = clearColor;
  644. }
  645. ++srcData;
  646. ++maskData;
  647. }
  648. srcData += srcPitch;
  649. maskData += maskPitch;
  650. }
  651. }
  652. void blit(int sX, int sY, SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int width, int height) { start_func
  653. assert(src);
  654. assert(dest);
  655. SDL_Rect sourceRect;
  656. sourceRect.x = sX;
  657. sourceRect.y = sY;
  658. sourceRect.w = (width == -1 ? src->w : width);
  659. sourceRect.h = (height == -1 ? src->h : height);
  660. SDL_Rect destRect;
  661. destRect.x = dX;
  662. destRect.y = dY;
  663. if (SDL_BlitSurface(src, &sourceRect, dest, &destRect)) {
  664. fatalCrash(0, "SDL Blit error: %s", SDL_GetError());
  665. }
  666. }
  667. void preGLScreenFlip() { start_func
  668. if (requestedGL) {
  669. // @TODO: these should be moved to game loop or removed entirely
  670. // (including a bk color setting)
  671. glClear(GL_COLOR_BUFFER_BIT);
  672. glLoadIdentity();
  673. glScreenState = 1;
  674. }
  675. }
  676. void postGLScreenFlip() { start_func
  677. if ((glScreenState >= 1) && (requestedGL)) {
  678. SDL_GL_SwapBuffers();
  679. glScreenState = 0;
  680. }
  681. }
  682. void setScreenGLAlpha(int alpha) { start_func
  683. if (alpha < 0) alpha = 0;
  684. if (alpha > 256) alpha = 256;
  685. glAlpha = (GLfloat)alpha / 256.0f;
  686. }
  687. void screenFlip(const Rect* area) { start_func
  688. if (requestedGL) {
  689. int doFlip = !glScreenState;
  690. if (glScreenState != 1) preGLScreenFlip();
  691. // Just blit everything to openGL
  692. glLoadIdentity();
  693. if ((area) && (area->w)) {
  694. textureScreen->store(1, proxyScreen, area->x, area->y, area->x, area->y, area->w, area->h);
  695. textureScreen->updateTexture();
  696. }
  697. glColor4f(1.0f, 1.0f, 1.0f, glAlpha);
  698. textureScreen->draw(1, 0, 0);
  699. // Add mouse
  700. if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS) && (micePointers[currentMouse]))
  701. micePointers[currentMouse]->textureAt(lastMouseX, lastMouseY);
  702. if (doFlip) postGLScreenFlip();
  703. else glScreenState = 2;
  704. }
  705. else {
  706. if (area) {
  707. if (area->w) {
  708. updateRects[0].x = area->x;
  709. updateRects[0].y = area->y;
  710. updateRects[0].w = area->w;
  711. updateRects[0].h = area->h;
  712. SDL_UpdateRects(actualScreen, numUpdate, updateRects);
  713. }
  714. else if (numUpdate > 1) {
  715. SDL_UpdateRects(actualScreen, numUpdate - 1, updateRects + 1);
  716. }
  717. }
  718. else {
  719. SDL_UpdateRect(actualScreen, 0, 0, 0, 0);
  720. }
  721. }
  722. numUpdate = 1;
  723. }
  724. void prepareFont() { start_func
  725. if (TTF_Init()) {
  726. fatalCrash(0, "Unable to initialize TTF library");
  727. }
  728. string fontFile;
  729. for (int pos = 0; pos < FONT_COUNT; ++pos) {
  730. createFilename(resourceDir->c_str(), fonts[pos].file, fontFile);
  731. fonts[pos].font = TTF_OpenFont(fontFile.c_str(), fonts[pos].size);
  732. if (fonts[pos].font == NULL) {
  733. fatalCrash(0, "Unable to open font %s: %s", fontFile.c_str(), SDL_GetError());
  734. }
  735. int junk;
  736. if (TTF_SizeText(fonts[pos].font, "j", &junk, &fonts[pos].height)) {
  737. fatalCrash(0, "Unable to size font %s: %s", fontFile.c_str(), SDL_GetError());
  738. }
  739. fonts[pos].ascent = TTF_FontAscent(fonts[pos].font);
  740. }
  741. }
  742. void closeFont() { start_func
  743. for (int pos = 0; pos < FONT_COUNT; ++pos) {
  744. if (fonts[pos].font) {
  745. TTF_CloseFont(fonts[pos].font);
  746. fonts[pos].font = NULL;
  747. }
  748. }
  749. TTF_Quit();
  750. }
  751. SDL_Surface* createText(const string& text, SDL_Color fg, int alpha, int font) { start_func
  752. if (text.length() == 0) return NULL;
  753. assert(font >= 0);
  754. assert(font < FONT_COUNT);
  755. assert(fonts[font].font);
  756. SDL_Surface* textS;
  757. if (alpha) {
  758. textS = TTF_RenderText_Blended(fonts[font].font, text.c_str(), fg);
  759. }
  760. else {
  761. textS = TTF_RenderText_Solid(fonts[font].font, text.c_str(), fg);
  762. }
  763. if (textS == NULL) {
  764. fatalCrash(0, "SDL Text rendering error: %s", SDL_GetError());
  765. }
  766. return textS;
  767. }
  768. int drawText(const string& text, SDL_Color fg, int x, int y, SDL_Surface* surface, int font) { start_func
  769. if (text.length() == 0) return 0;
  770. // Change 1 to 0 to remove alpha
  771. SDL_Surface* textSurface = createText(text, fg, 1, font);
  772. assert(textSurface);
  773. blit(0, 0, textSurface, x, y, surface);
  774. int width = textSurface->w;
  775. SDL_FreeSurface(textSurface);
  776. return width;
  777. }
  778. void drawBox(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface) { start_func
  779. assert(w > 0);
  780. assert(h > 0);
  781. assert(surface);
  782. drawHLine(x, x + w - 1, y, color, surface);
  783. drawHLine(x, x + w - 1, y + h - 1, color, surface);
  784. drawVLine(y, y + h - 1, x, color, surface);
  785. drawVLine(y, y + h - 1, x + w - 1, color, surface);
  786. }
  787. int SDL_FillRect(SDL_Surface *dst, Rect *dstrect, Uint32 color) { start_func
  788. assert(dstrect);
  789. SDL_Rect newrect = { (Sint16)dstrect->x, (Sint16)dstrect->y, (Uint16)dstrect->w, (Uint16)dstrect->h };
  790. int ret = SDL_FillRect(dst, &newrect, color);
  791. dstrect->x = newrect.x;
  792. dstrect->y = newrect.y;
  793. dstrect->w = newrect.w;
  794. dstrect->h = newrect.h;
  795. return ret;
  796. }
  797. void SDL_SetClipRect(SDL_Surface *surface, Rect *rect) { start_func
  798. assert(rect);
  799. SDL_Rect newrect = { (Sint16)rect->x, (Sint16)rect->y, (Uint16)rect->w, (Uint16)rect->h };
  800. SDL_SetClipRect(surface, &newrect);
  801. rect->x = newrect.x;
  802. rect->y = newrect.y;
  803. rect->w = newrect.w;
  804. rect->h = newrect.h;
  805. }
  806. void SDL_SetClipRect(SDL_Surface *surface, const Rect *rect) { start_func
  807. assert(rect);
  808. SDL_Rect newrect = { (Sint16)rect->x, (Sint16)rect->y, (Uint16)rect->w, (Uint16)rect->h };
  809. SDL_SetClipRect(surface, &newrect);
  810. }
  811. void drawRect(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface) { start_func
  812. assert(w > 0);
  813. assert(h > 0);
  814. SDL_Rect rect = { (Sint16)x, (Sint16)y, (Uint16)w, (Uint16)h };
  815. assert(surface);
  816. // fillrect only fails from locking or <8 bpp surfaces, neither of which we care about
  817. SDL_FillRect(surface, &rect, color);
  818. }
  819. void drawGradient(int x, int y, int w, int h, SDL_Color color1, SDL_Color color2, SDL_Surface* surface) { start_func
  820. assert(w > 0);
  821. assert(h > 0);
  822. assert(surface);
  823. SDL_Rect clip;
  824. SDL_GetClipRect(surface, &clip);
  825. // y2, y clip
  826. int y2 = y + h - 1;
  827. if (y2 >= clip.y + clip.h) y2 = clip.y + clip.h - 1;
  828. if (y < clip.y) y = clip.y;
  829. if (y2 < y) return;
  830. // Position gradient is at and max position of gradient
  831. int pos = 0;
  832. int maxpos = w - 1;
  833. // (special case)
  834. if (maxpos == 0) maxpos = 1;
  835. // x2, x clip (x2 is actually 1 higher than last)
  836. int x2 = x + w;
  837. if (x2 > clip.x + clip.w) x2 = clip.x + clip.w;
  838. if (x < clip.x) {
  839. // Adjust gradient position too
  840. pos = clip.x - x;
  841. x = clip.x;
  842. }
  843. if (x2 < x) return;
  844. SDL_Color color;
  845. for (; x < x2; ++x, ++pos) {
  846. color.r = color1.r + (color2.r - color1.r) * pos / maxpos;
  847. color.g = color1.g + (color2.g - color1.g) * pos / maxpos;
  848. color.b = color1.b + (color2.b - color1.b) * pos / maxpos;
  849. drawVLine(y, y2, x, convertRGB(color), surface);
  850. }
  851. }
  852. void drawSelectRect(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface, int alpha) { start_func
  853. assert(w > 0);
  854. assert(h > 0);
  855. assert(surface);
  856. SDL_Rect rect = { 0, 0, (Uint16)w, (Uint16)h };
  857. SDL_Surface* selection = createSurface(w, h);
  858. SDL_SetAlpha(selection, SDL_SRCALPHA, alpha);
  859. // fillrect only fails from locking or <8 bpp surfaces, neither of which we care about
  860. SDL_FillRect(selection, &rect, color);
  861. SDL_Rect destRect = { (Sint16)x, (Sint16)y, (Uint16)w, (Uint16)h };
  862. if (SDL_BlitSurface(selection, &rect, surface, &destRect)) {
  863. SDL_FreeSurface(selection);
  864. fatalCrash(0, "SDL Rect error: %s", SDL_GetError());
  865. }
  866. SDL_FreeSurface(selection);
  867. }
  868. // (unused)
  869. /*
  870. void drawSelectGradient(int x, int y, int w, int h, SDL_Color color1, SDL_Color color2, SDL_Surface* surface, int alpha) { start_func
  871. assert(w > 0);
  872. assert(h > 0);
  873. assert(surface);
  874. SDL_Surface* selection = createSurface(w, h);
  875. SDL_SetAlpha(selection, SDL_SRCALPHA, alpha);
  876. drawGradient(0, 0, w, h, color1, color2, selection);
  877. SDL_Rect rect = { 0, 0, w, h };
  878. SDL_Rect destRect = { x, y, w, h };
  879. if (SDL_BlitSurface(selection, &rect, surface, &destRect)) {
  880. SDL_FreeSurface(selection);
  881. fatalCrash(0, "SDL Rect error: %s", SDL_GetError());
  882. }
  883. SDL_FreeSurface(selection);
  884. }
  885. */
  886. void drawFocusBox(int x, int y, int w, int h, SDL_Surface* surface) { start_func
  887. assert(w > 0);
  888. assert(h > 0);
  889. assert(surface);
  890. drawDottedHLine(x, x + w - 1, y, guiPacked[COLOR_DARK1], surface);
  891. drawDottedVLine(y, y + h - 1, x + w - 1, guiPacked[COLOR_DARK1], surface);
  892. drawDottedHLine(x, x + w - 1, y + h - 1, guiPacked[COLOR_DARK1], surface);
  893. drawDottedVLine(y, y + h - 1, x, guiPacked[COLOR_DARK1], surface);
  894. }
  895. void drawGuiBox(int x, int y, int w, int h, int thickness, SDL_Surface* surface) { start_func
  896. assert((thickness == 1) || (thickness == 2));
  897. int colorl = (thickness == 1) ? COLOR_LIGHT1 : COLOR_LIGHT2;
  898. int colord = (thickness == 1) ? COLOR_DARK1 : COLOR_DARK2;
  899. drawRect(x, y, w, h, guiPacked[COLOR_FILL], surface);
  900. drawHLine(x, x + w - 2, y, guiPacked[colorl], surface);
  901. drawVLine(y, y + h - 2, x, guiPacked[colorl], surface);
  902. drawVLine(y + 1, y + h - 1, x + w - 1, guiPacked[colord], surface);
  903. drawHLine(x + 1, x + w - 1, y + h - 1, guiPacked[colord], surface);
  904. if (thickness > 1) {
  905. drawHLine(x + 1, x + w - 3, y + 1, guiPacked[COLOR_LIGHT1], surface);
  906. drawVLine(y + 1, y + h - 3, x + 1, guiPacked[COLOR_LIGHT1], surface);
  907. drawVLine(y + 2, y + h - 2, x + w - 2, guiPacked[COLOR_DARK1], surface);
  908. drawHLine(x + 2, x + w - 2, y + h - 2, guiPacked[COLOR_DARK1], surface);
  909. }
  910. }
  911. void drawGuiBoxInvert(int x, int y, int w, int h, int thickness, SDL_Surface* surface) { start_func
  912. assert((thickness == 1) || (thickness == 2));
  913. drawHLine(x, x + w - 2, y, guiPacked[COLOR_DARK1], surface);
  914. drawVLine(y, y + h - 2, x, guiPacked[COLOR_DARK1], surface);
  915. drawVLine(y + 1, y + h - 1, x + w - 1, guiPacked[COLOR_LIGHT1], surface);
  916. drawHLine(x + 1, x + w - 1, y + h - 1, guiPacked[COLOR_LIGHT1], surface);
  917. if (thickness > 1) {
  918. drawHLine(x + 1, x + w - 3, y + 1, guiPacked[COLOR_DARK2], surface);
  919. drawVLine(y + 1, y + h - 3, x + 1, guiPacked[COLOR_DARK2], surface);
  920. drawVLine(y + 2, y + h - 2, x + w - 2, guiPacked[COLOR_LIGHT2], surface);
  921. drawHLine(x + 2, x + w - 2, y + h - 2, guiPacked[COLOR_LIGHT2], surface);
  922. }
  923. }
  924. void drawLine(int x1, int y1, int x2, int y2, Uint32 color, SDL_Surface* surface) { start_func
  925. Uint16* bufp16;
  926. Uint32* bufp32;
  927. assert(surface);
  928. Sint16 x = x1;
  929. Sint16 y = y1;
  930. Sint16 dy = y2 - y1;
  931. Sint16 dx = x2 - x1;
  932. Sint16 G, DeltaG1, DeltaG2;//, minG, maxG;
  933. Sint16 inc = 1;
  934. SDL_Rect clip;
  935. SDL_GetClipRect(surface, &clip);
  936. Sint16 cx2 = clip.x + clip.w;
  937. Sint16 cy2 = clip.y + clip.h;
  938. // Skip entirely?
  939. if (((x1 < clip.x) && (x2 < clip.x)) ||
  940. ((y1 < clip.y) && (y2 < clip.y)) ||
  941. ((x1 >= cx2) && (x2 >= cx2)) ||
  942. ((y1 >= cy2) && (y2 >= cy2))) return;
  943. if (abs(dy) < abs(dx)) {
  944. if (dx < 0) {
  945. dx = -dx;
  946. dy = -dy;
  947. y1 = y2;
  948. y2 = y;
  949. y = y1;
  950. x1 = x2;
  951. x2 = x;
  952. x = x1;
  953. }
  954. if (dy < 0) {
  955. dy = -dy;
  956. inc = -1;
  957. }
  958. G = 2 * dy - dx;
  959. DeltaG1 = 2 * (dy - dx);
  960. DeltaG2 = 2 * dy;
  961. switch (surface->format->BytesPerPixel) {
  962. case 2:
  963. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  964. if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp16 = color;
  965. while (++x <= x2) {
  966. ++bufp16;
  967. if (G > 0) { G += DeltaG1; y += inc; bufp16 += inc*surface->pitch/2; }
  968. else G += DeltaG2;
  969. if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp16 = color;
  970. }
  971. break;
  972. case 4:
  973. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  974. if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp32 = color;
  975. while (++x <= x2) {
  976. ++bufp32;
  977. if (G > 0) { G += DeltaG1; y += inc; bufp32 += inc*surface->pitch/4; }
  978. else G += DeltaG2;
  979. if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp32 = color;
  980. }
  981. break;
  982. }
  983. }
  984. else {
  985. if (dy < 0) {
  986. dx = -dx;
  987. dy = -dy;
  988. y1 = y2;
  989. y2 = y;
  990. y = y1;
  991. x1 = x2;
  992. x2 = x;
  993. x = x1;
  994. }
  995. if (dx < 0) {
  996. dx = -dx;
  997. inc = -1;
  998. }
  999. G = 2 * dx - dy;
  1000. //minG = maxG = G;
  1001. DeltaG1 = 2 * (dx - dy);
  1002. DeltaG2 = 2 * dx;
  1003. switch (surface->format->BytesPerPixel) {
  1004. case 2:
  1005. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  1006. if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp16 = color;
  1007. while (++y <= y2) {
  1008. bufp16 += surface->pitch/2;
  1009. if (G > 0) { G += DeltaG1; x += inc; bufp16 += inc; }
  1010. else G += DeltaG2;
  1011. if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp16 = color;
  1012. }
  1013. break;
  1014. case 4:
  1015. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  1016. if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp32 = color;
  1017. while (++y <= y2) {
  1018. bufp32 += surface->pitch/4;
  1019. if (G > 0) { G += DeltaG1; x += inc; bufp32 += inc; }
  1020. else G += DeltaG2;
  1021. if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp32 = color;
  1022. }
  1023. break;
  1024. }
  1025. }
  1026. }
  1027. void drawHLine(int x1, int x2, int y1, Uint32 color, SDL_Surface* surface) { start_func
  1028. Uint16* bufp16;
  1029. Uint32* bufp32;
  1030. assert(surface);
  1031. Sint16 x = x1;
  1032. Sint16 y = y1;
  1033. if (x1 > x2) {
  1034. x1 = x2;
  1035. x2 = x;
  1036. x = x1;
  1037. }
  1038. SDL_Rect clip;
  1039. SDL_GetClipRect(surface, &clip);
  1040. Sint16 cx2 = clip.x + clip.w;
  1041. Sint16 cy2 = clip.y + clip.h;
  1042. // Skip entirely?
  1043. if ((y < clip.y) || (y >= cy2) ||
  1044. (x2 < clip.x) || (x >= cx2)) return;
  1045. // Clip
  1046. if (x < clip.x) x = clip.x;
  1047. if (x2 >= cx2) x2 = cx2 - 1;
  1048. switch (surface->format->BytesPerPixel) {
  1049. case 2:
  1050. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  1051. *bufp16 = color;
  1052. while (++x <= x2) {
  1053. *++bufp16 = color;
  1054. }
  1055. break;
  1056. case 4:
  1057. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  1058. *bufp32 = color;
  1059. while (++x <= x2) {
  1060. *++bufp32 = color;
  1061. }
  1062. break;
  1063. }
  1064. }
  1065. void drawVLine(int y1, int y2, int x1, Uint32 color, SDL_Surface* surface) { start_func
  1066. Uint16* bufp16;
  1067. Uint32* bufp32;
  1068. assert(surface);
  1069. Sint16 x = x1;
  1070. Sint16 y = y1;
  1071. if (y1 > y2) {
  1072. y1 = y2;
  1073. y2 = y;
  1074. y = y1;
  1075. }
  1076. SDL_Rect clip;
  1077. SDL_GetClipRect(surface, &clip);
  1078. Sint16 cx2 = clip.x + clip.w;
  1079. Sint16 cy2 = clip.y + clip.h;
  1080. // Skip entirely?
  1081. if ((x < clip.x) || (x >= cx2) ||
  1082. (y2 < clip.y) || (y >= cy2)) return;
  1083. // Clip
  1084. if (y < clip.y) y = clip.y;
  1085. if (y2 >= cy2) y2 = cy2 - 1;
  1086. switch (surface->format->BytesPerPixel) {
  1087. case 2:
  1088. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  1089. *bufp16 = color;
  1090. while (++y <= y2) {
  1091. *(bufp16+= surface->pitch/2) = color;
  1092. }
  1093. break;
  1094. case 4:
  1095. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  1096. *bufp32 = color;
  1097. while (++y <= y2) {
  1098. *(bufp32+= surface->pitch/4) = color;
  1099. }
  1100. break;
  1101. }
  1102. }
  1103. void drawDottedHLine(int x1, int x2, int y1, Uint32 color, SDL_Surface* surface) { start_func
  1104. Uint16* bufp16;
  1105. Uint32* bufp32;
  1106. assert(surface);
  1107. Sint16 x = x1;
  1108. Sint16 y = y1;
  1109. if (x1 > x2) {
  1110. x1 = x2;
  1111. x2 = x;
  1112. x = x1;
  1113. }
  1114. SDL_Rect clip;
  1115. SDL_GetClipRect(surface, &clip);
  1116. Sint16 cx2 = clip.x + clip.w;
  1117. Sint16 cy2 = clip.y + clip.h;
  1118. // Skip entirely?
  1119. if ((y < clip.y) || (y >= cy2) ||
  1120. (x2 < clip.x) || (x >= cx2)) return;
  1121. // Clip
  1122. if (x < clip.x) x = clip.x;
  1123. if (x2 >= cx2) x2 = cx2 - 1;
  1124. Sint16 dot = (x + y) & 1;
  1125. switch (surface->format->BytesPerPixel) {
  1126. case 2:
  1127. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  1128. if (dot) *bufp16 = color;
  1129. while (++x <= x2) {
  1130. ++bufp16;
  1131. dot = dot ^ 1;
  1132. if (dot) *bufp16 = color;
  1133. }
  1134. break;
  1135. case 4:
  1136. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  1137. if (dot) *bufp32 = color;
  1138. while (++x <= x2) {
  1139. ++bufp32;
  1140. dot = dot ^ 1;
  1141. if (dot) *bufp32 = color;
  1142. }
  1143. break;
  1144. }
  1145. }
  1146. void drawDottedVLine(int y1, int y2, int x1, Uint32 color, SDL_Surface* surface) { start_func
  1147. Uint16* bufp16;
  1148. Uint32* bufp32;
  1149. assert(surface);
  1150. Sint16 x = x1;
  1151. Sint16 y = y1;
  1152. if (y1 > y2) {
  1153. y1 = y2;
  1154. y2 = y;
  1155. y = y1;
  1156. }
  1157. SDL_Rect clip;
  1158. SDL_GetClipRect(surface, &clip);
  1159. Sint16 cx2 = clip.x + clip.w;
  1160. Sint16 cy2 = clip.y + clip.h;
  1161. // Skip entirely?
  1162. if ((x < clip.x) || (x >= cx2) ||
  1163. (y2 < clip.y) || (y >= cy2)) return;
  1164. // Clip
  1165. if (y < clip.y) y = clip.y;
  1166. if (y2 >= cy2) y2 = cy2 - 1;
  1167. Sint16 dot = (x + y) & 1;
  1168. switch (surface->format->BytesPerPixel) {
  1169. case 2:
  1170. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  1171. if (dot) *bufp16 = color;
  1172. while (++y <= y2) {
  1173. bufp16+= surface->pitch/2;
  1174. dot = dot ^ 1;
  1175. if (dot) *bufp16 = color;
  1176. }
  1177. break;
  1178. case 4:
  1179. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  1180. if (dot) *bufp32 = color;
  1181. while (++y <= y2) {
  1182. bufp32 += surface->pitch/4;
  1183. dot = dot ^ 1;
  1184. if (dot) *bufp32 = color;
  1185. }
  1186. break;
  1187. }
  1188. }
  1189. void drawAntsBox(int x1, int y1, int w, int h, int phase, SDL_Surface* surface) { start_func
  1190. assert(surface);
  1191. drawAntsHLine(x1, x1 + w - 1, y1, phase, surface);
  1192. drawAntsHLine(x1, x1 + w - 1, y1 + h - 1, phase, surface);
  1193. drawAntsVLine(y1, y1 + h - 1, x1, phase, surface);
  1194. drawAntsVLine(y1, y1 + h - 1, x1 + w - 1, phase, surface);
  1195. }
  1196. void drawAntsHLine(int x1, int x2, int y1, int phase, SDL_Surface* surface) { start_func
  1197. Uint16* bufp16;
  1198. Uint32* bufp32;
  1199. assert(surface);
  1200. Sint16 x = x1;
  1201. Sint16 y = y1;
  1202. if (x1 > x2) swap(x1, x2);
  1203. SDL_Rect clip;
  1204. SDL_GetClipRect(surface, &clip);
  1205. Sint16 cx2 = clip.x + clip.w;
  1206. Sint16 cy2 = clip.y + clip.h;
  1207. // Skip entirely?
  1208. if ((y < clip.y) || (y >= cy2) ||
  1209. (x2 < clip.x) || (x >= cx2)) return;
  1210. // Clip
  1211. if (x < clip.x) x = clip.x;
  1212. if (x2 >= cx2) x2 = cx2 - 1;
  1213. phase = (phase + x + y) % NUM_PHASES;
  1214. switch (surface->format->BytesPerPixel) {
  1215. case 2:
  1216. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  1217. *bufp16 = phaseColors[phase];
  1218. phase = (phase + 1) % NUM_PHASES;
  1219. while (++x <= x2) {
  1220. *++bufp16 = phaseColors[phase];
  1221. phase = (phase + 1) % NUM_PHASES;
  1222. }
  1223. break;
  1224. case 4:
  1225. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  1226. *bufp32 = phaseColors[phase];
  1227. phase = (phase + 1) % NUM_PHASES;
  1228. while (++x <= x2) {
  1229. *++bufp32 = phaseColors[phase];
  1230. phase = (phase + 1) % NUM_PHASES;
  1231. }
  1232. break;
  1233. }
  1234. }
  1235. void drawAntsVLine(int y1, int y2, int x1, int phase, SDL_Surface* surface) { start_func
  1236. Uint16* bufp16;
  1237. Uint32* bufp32;
  1238. assert(surface);
  1239. Sint16 x = x1;
  1240. Sint16 y = y1;
  1241. if (y1 > y2) swap(y1, y2);
  1242. SDL_Rect clip;
  1243. SDL_GetClipRect(surface, &clip);
  1244. Sint16 cx2 = clip.x + clip.w;
  1245. Sint16 cy2 = clip.y + clip.h;
  1246. // Skip entirely?
  1247. if ((x < clip.x) || (x >= cx2) ||
  1248. (y2 < clip.y) || (y >= cy2)) return;
  1249. // Clip
  1250. if (y < clip.y) y = clip.y;
  1251. if (y2 >= cy2) y2 = cy2 - 1;
  1252. phase = (phase + x + y) % NUM_PHASES;
  1253. switch (surface->format->BytesPerPixel) {
  1254. case 2:
  1255. bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
  1256. *bufp16 = phaseColors[phase];
  1257. phase = (phase + 1) % NUM_PHASES;
  1258. while (++y <= y2) {
  1259. *(bufp16+= surface->pitch/2) = phaseColors[phase];
  1260. phase = (phase + 1) % NUM_PHASES;
  1261. }
  1262. break;
  1263. case 4:
  1264. bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
  1265. *bufp32 = phaseColors[phase];
  1266. phase = (phase + 1) % NUM_PHASES;
  1267. while (++y <= y2) {
  1268. *(bufp32+= surface->pitch/4) = phaseColors[phase];
  1269. phase = (phase + 1) % NUM_PHASES;
  1270. }
  1271. break;
  1272. }
  1273. }
  1274. int fontWidth(const string& text, int font) { start_func
  1275. int width;
  1276. int junk;
  1277. if (text.length() == 0) return 0;
  1278. assert(font >= 0);
  1279. assert(font < FONT_COUNT);
  1280. assert(fonts[font].font);
  1281. if (TTF_SizeText(fonts[font].font, text.c_str(), &width, &junk)) {
  1282. fatalCrash(0, "SDL Error sizing text: %s", SDL_GetError());
  1283. }
  1284. return width;
  1285. }
  1286. int convertGuiText(string* text, char* shortcut, int font) { start_func
  1287. assert(font >= 0);
  1288. assert(font < FONT_COUNT);
  1289. assert(fonts[font].font);
  1290. assert(text);
  1291. *shortcut = 0;
  1292. if (text->length() == 0) return 0;
  1293. // Contains a \t?
  1294. int pos = text->find('\t', 0);
  1295. if (pos < 0) return 0;
  1296. // Remove from string
  1297. text->erase(pos, 1);
  1298. // Calculate start of underline
  1299. int start = 0;
  1300. int junk;
  1301. if (pos > 0) {
  1302. string sub(*text, 0, pos);
  1303. if (TTF_SizeText(fonts[font].font, sub.c_str(), &start, &junk)) {
  1304. fatalCrash(0, "SDL Error sizing text: %s", SDL_GetError());
  1305. }
  1306. }
  1307. // Calculate size of underline
  1308. int size = 0;
  1309. string sub(*text, pos, 1);
  1310. // (no character after \t? no underline)
  1311. if (sub.length() == 0) return 0;
  1312. if (TTF_SizeText(fonts[font].font, sub.c_str(), &size, &junk)) {
  1313. fatalCrash(0, "SDL Error sizing text: %s", SDL_GetError());
  1314. }
  1315. // Grab shortcut key
  1316. if (shortcut) {
  1317. *shortcut = tolower(sub[0]);
  1318. }
  1319. // Generate code (max 255 on start and size)
  1320. return (start & 0xFF) | ((size & 0xFF) << 8);
  1321. }
  1322. void drawTextUnderline(int underlineCode, Uint32 color, int x, int y, SDL_Surface* surface, int font) { start_func
  1323. assert(underlineCode >= 0);
  1324. assert(underlineCode <= 0xFFFF);
  1325. assert(font >= 0);
  1326. assert(font < FONT_COUNT);
  1327. assert(fonts[font].font);
  1328. assert(surface);
  1329. int start = underlineCode & 0xFF;
  1330. int size = underlineCode >> 8;
  1331. if (size) drawHLine(x + start - 1, x + start + size - 1, y + fonts[font].ascent + 1, color, surface);
  1332. }
  1333. void drawCheckbox(int isRadio, int isChecked, int isDisabled, int x, int y, int size, SDL_Surface* surface) { start_func
  1334. assert(surface);
  1335. if (isRadio) {
  1336. int rad = (size + 1) / 2;
  1337. int tweak = (size & 1) ^ 1;
  1338. --rad;
  1339. sge_FilledCircleDual(surface, x + rad, y + rad, rad, tweak, guiPacked[COLOR_DARK1], guiPacked[COLOR_LIGHT1]);
  1340. sge_FilledCircleDual(surface, x + rad, y + rad, rad - 1, tweak, guiPacked[COLOR_DARK2], guiPacked[COLOR_LIGHT2]);
  1341. sge_FilledCircleDual(surface, x + rad, y + rad, rad - 2, tweak, guiPacked[isDisabled ? COLOR_FILL : COLOR_TEXTBOX], guiPacked[isDisabled ? COLOR_FILL : COLOR_TEXTBOX]);
  1342. if (isChecked) {
  1343. sge_FilledCircleDual(surface, x + rad, y + rad, rad - 3, tweak, guiPacked[COLOR_DARK1], guiPacked[COLOR_DARK1]);
  1344. sge_FilledCircleDual(surface, x + rad, y + rad, rad - 4, tweak, guiPacked[isDisabled ? COLOR_DARK1 : COLOR_TEXT], guiPacked[isDisabled ? COLOR_DARK1 : COLOR_TEXT]);
  1345. }
  1346. }
  1347. else {
  1348. drawRect(x, y, size, size, guiPacked[COLOR_FILL], surface);
  1349. drawGuiBoxInvert(x, y, size, size, 2, surface);
  1350. if (!isDisabled) drawRect(x + 2, y + 2, size - 4, size - 4, guiPacked[COLOR_TEXTBOX], surface);
  1351. if (isChecked) {
  1352. sge_Line(surface, x + 4, y + 3, x + size - 4, y + size - 5, guiPacked[COLOR_DARK2]);
  1353. sge_Line(surface, x + 3, y + 3, x + size - 4, y + size - 4, guiPacked[isDisabled ? COLOR_DARK1 : COLOR_TEXT]);
  1354. sge_Line(surface, x + 3, y + 4, x + size - 5, y + size - 4, guiPacked[COLOR_DARK2]);
  1355. sge_Line(surface, x + 4, y + size - 4, x + size - 4, y + 4, guiPacked[COLOR_DARK2]);
  1356. sge_Line(surface, x + 3, y + size - 4, x + size - 4, y + 3, guiPacked[isDisabled ? COLOR_DARK1 : COLOR_TEXT]);
  1357. sge_Line(surface, x + 3, y + size - 5, x + size - 5, y + 3, guiPacked[COLOR_DARK2]);
  1358. }
  1359. }
  1360. }
  1361. int fontHeight(int font) { start_func
  1362. assert(font >= 0);
  1363. assert(font < FONT_COUNT);
  1364. assert(fonts[font].font);
  1365. return fonts[font].height;
  1366. }
  1367. int fontAscent(int font) { start_func
  1368. assert(font >= 0);
  1369. assert(font < FONT_COUNT);
  1370. assert(fonts[font].font);
  1371. return fonts[font].ascent;
  1372. }
  1373. SDL_Surface* createSurface(int width, int height) { start_func
  1374. SDL_Surface* ptr = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, proxyScreen->format->BitsPerPixel,
  1375. proxyScreen->format->Rmask, proxyScreen->format->Gmask, proxyScreen->format->Bmask, proxyScreen->format->Amask);
  1376. if (ptr == NULL) fatalCrash(0, "SDL Error allocating surface %d by %d", width, height);
  1377. SDL_SetAlpha(ptr, 0, 255);
  1378. return ptr;
  1379. }
  1380. SDL_Surface* createSurface32(int width, int height) { start_func
  1381. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  1382. Uint32 rMask = 0xff000000;
  1383. Uint32 gMask = 0x00ff0000;
  1384. Uint32 bMask = 0x0000ff00;
  1385. Uint32 aMask = 0x000000ff;
  1386. #else
  1387. Uint32 rMask = 0x000000ff;
  1388. Uint32 gMask = 0x0000ff00;
  1389. Uint32 bMask = 0x00ff0000;
  1390. Uint32 aMask = 0xff000000;
  1391. #endif
  1392. SDL_Surface* ptr = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, rMask, gMask, bMask, aMask);
  1393. if (ptr == NULL) fatalCrash(0, "SDL Error allocating surface %d by %d by 8", width, height);
  1394. SDL_SetAlpha(ptr, 0, 255);
  1395. return ptr;
  1396. }
  1397. SDL_Surface* createSurface8(int width, int height) { start_func
  1398. SDL_Surface* ptr = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
  1399. if (ptr == NULL) fatalCrash(0, "SDL Error allocating surface %d by %d by 32", width, height);
  1400. return ptr;
  1401. }
  1402. SDL_Surface* getScreen() { start_func
  1403. assert(proxyScreen);
  1404. return proxyScreen;
  1405. }
  1406. int guiOk() { start_func
  1407. return proxyScreen ? 1 : 0;
  1408. }
  1409. void selectMouse(int type) { start_func
  1410. assert(type >= 0);
  1411. assert(type < MOUSE_COUNT);
  1412. currentMouse = type;
  1413. }
  1414. int mouseTooltipYOffset() { start_func
  1415. return micePointers[currentMouse]->tooltipYOffset();
  1416. }
  1417. void blitMouse() { start_func
  1418. if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS) && (micePointers[currentMouse])) {
  1419. SDL_GetMouseState(&lastMouseX, &lastMouseY);
  1420. if (!requestedGL) {
  1421. if (numUpdate == 1) {
  1422. micePointers[currentMouse]->displayAt(lastMouseX, lastMouseY, mouseUnblit, updateRects + 1);
  1423. numUpdate = 2;
  1424. }
  1425. else {
  1426. micePointers[currentMouse]->displayAt(lastMouseX, lastMouseY, mouseUnblit, updateRects + 2);
  1427. numUpdate = 3;
  1428. }
  1429. mouseBlitted = currentMouse;
  1430. }
  1431. }
  1432. }
  1433. void unblitMouse() { start_func
  1434. if ((mouseBlitted >= 0) && (micePointers[mouseBlitted]) && (!requestedGL)) {
  1435. micePointers[mouseBlitted]->unDisplay(lastMouseX, lastMouseY, mouseUnblit, updateRects + 1);
  1436. if (numUpdate < 2) numUpdate = 2;
  1437. mouseBlitted = -1;
  1438. }
  1439. }
  1440. // Clipping routines
  1441. int intersectRects(Rect& a, const Rect& b) { start_func
  1442. if (a.x < b.x) {
  1443. Sint32 aw = a.w + a.x - b.x;
  1444. if (aw <= 0) {
  1445. a.w = 0;
  1446. return 0;
  1447. }
  1448. a.x = b.x;
  1449. if (aw > b.w) aw = b.w;
  1450. a.w = aw;
  1451. }
  1452. else {
  1453. Sint32 bw = b.w + b.x - a.x;
  1454. if (bw <= 0) {
  1455. a.w = 0;
  1456. return 0;
  1457. }
  1458. if (a.w > bw) a.w = bw;
  1459. }
  1460. if (a.y < b.y) {
  1461. Sint32 ah = a.h + a.y - b.y;
  1462. if (ah <= 0) {
  1463. a.w = 0;
  1464. return 0;
  1465. }
  1466. a.y = b.y;
  1467. if (ah > b.h) ah = b.h;
  1468. a.h = ah;
  1469. }
  1470. else {
  1471. Sint32 bh = b.h + b.y - a.y;
  1472. if (bh <= 0) {
  1473. a.w = 0;
  1474. return 0;
  1475. }
  1476. if (a.h > bh) a.h = bh;
  1477. }
  1478. return a.w;
  1479. }
  1480. int boundRects(Rect& a, const Rect& b) { start_func
  1481. // (special case)
  1482. if (b.w == 0) {
  1483. return a.w;
  1484. }
  1485. if (a.w == 0) {
  1486. a = b;
  1487. return 1;
  1488. }
  1489. if (a.x > b.x) {
  1490. a.w += a.x - b.x;
  1491. a.x = b.x;
  1492. if (a.w < b.w) a.w = b.w;
  1493. }
  1494. else {
  1495. Sint32 bw = b.w + b.x - a.x;
  1496. if (a.w < bw) a.w = bw;
  1497. }
  1498. if (a.y > b.y) {
  1499. a.h += a.y - b.y;
  1500. a.y = b.y;
  1501. if (a.h < b.h) a.h = b.h;
  1502. }
  1503. else {
  1504. Sint32 bh = b.h + b.y - a.y;
  1505. if (a.h < bh) a.h = bh;
  1506. }
  1507. return 1;
  1508. }
  1509. Rect createRect(int x1, int y1, int x2, int y2) { start_func
  1510. Rect data;
  1511. if (x1 > x2) swap(x1, x2);
  1512. if (y1 > y2) swap(y1, y2);
  1513. data.x = x1;
  1514. data.y = y1;
  1515. data.w = x2 - x1 + 1;
  1516. data.h = y2 - y1 + 1;
  1517. return data;
  1518. }
  1519. // Helper function for flood fill
  1520. inline int colorDifference(Uint32 a, Uint32 b) { start_func
  1521. // Special optimized case
  1522. if (a == b) return 0;
  1523. // Zero alpha matches itself and itself only, regardless of tolerance
  1524. #if SDL_BYTEORDER == SDL_BIG_ENDIAN
  1525. if (((a & 0x000000ff) == 0) || ((b & 0x000000ff) == 0)) {
  1526. if ((a & 0x000000ff) == (b & 0x000000ff)) return 0;
  1527. // (arbitrarily large value)
  1528. return 0x7FFF;
  1529. }
  1530. #else
  1531. if (((a & 0xff000000) == 0) || ((b & 0xff000000) == 0)) {
  1532. if ((a & 0xff000000) == (b & 0xff000000)) return 0;
  1533. // (arbitrarily large value)
  1534. return 0x7FFF;
  1535. }
  1536. #endif
  1537. // Last 8 bits we must shift before subtracting, so negatives are properly discovered
  1538. return
  1539. abs((int)(a & 0x000000FF) - (int)(b & 0x000000FF)) +
  1540. (abs((int)(a & 0x0000FF00) - (int)(b & 0x0000FF00)) >> 8) +
  1541. (abs((int)(a & 0x00FF0000) - (int)(b & 0x00FF0000)) >> 16) +
  1542. abs((int)((a & 0xFF000000) >> 24) - (int)((b & 0xFF000000) >> 24))
  1543. ;
  1544. }
  1545. // Flood fill- see .h for usage notes
  1546. Rect floodFill32(SDL_Surface* src, SDL_Surface* dest, int x, int y, Uint32 color, int tolerance) { start_func
  1547. assert(src);
  1548. assert(dest);
  1549. assert(tolerance >= 0);
  1550. // Min/Max area
  1551. Rect result = { 0, 0, 0, 0 };
  1552. // Clip area
  1553. SDL_Rect Sclip;
  1554. SDL_Rect SclipD;
  1555. SDL_GetClipRect(src, &Sclip);
  1556. SDL_GetClipRect(dest, &SclipD);
  1557. Rect clip = { Sclip.x, Sclip.y, Sclip.w, Sclip.h };
  1558. Rect clipD = { SclipD.x, SclipD.y, SclipD.w, SclipD.h };
  1559. if (!intersectRects(clip, clipD)) return result;
  1560. int minX = clip.x;
  1561. int minY = clip.y;
  1562. int maxX = clip.x + clip.w - 1;
  1563. int maxY = clip.y + clip.h - 1;
  1564. if ((x < minX) || (x > maxX) || (y < minY) || (y > maxY)) return result;
  1565. // Extreme points
  1566. int x1 = x;
  1567. int x2 = x;
  1568. int y1 = y;
  1569. int y2 = y;
  1570. // Stack
  1571. #define FLOOD_STACK_SIZE 250
  1572. struct {
  1573. Uint32* s;
  1574. Uint32* d;
  1575. int x;
  1576. int y;
  1577. int yD;
  1578. } floodStack[FLOOD_STACK_SIZE];
  1579. int stackPos = 0;
  1580. #define PUSH(sp, dp, xp, yp, ydiff) {\
  1581. if (stackPos < FLOOD_STACK_SIZE) {\
  1582. floodStack[stackPos].s = sp;\
  1583. floodStack[stackPos].d = dp;\
  1584. floodStack[stackPos].x = xp;\
  1585. floodStack[stackPos].y = yp;\
  1586. floodStack[stackPos++].yD = ydiff;\
  1587. }\
  1588. }\
  1589. #define POP(sp, dp, xp, yp, ydiff) {\
  1590. assert(stackPos);\
  1591. sp = floodStack[--stackPos].s;\
  1592. dp = floodStack[stackPos].d;\
  1593. xp = floodStack[stackPos].x;\
  1594. yp = floodStack[stackPos].y;\
  1595. ydiff = floodStack[stackPos].yD;\
  1596. }\
  1597. // Starting point and pitch, etc.
  1598. int srcPitch = src->pitch / 4;
  1599. int destPitch = dest->pitch / 4;
  1600. Uint32* srcPoint = (Uint32*)src->pixels + x + y * srcPitch;
  1601. Uint32* destPoint = (Uint32*)dest->pixels + x + y * destPitch;
  1602. Uint32 targetColor = *srcPoint;
  1603. // Special case
  1604. if ((src == dest) && (targetColor == color) && (tolerance == 0)) return result;
  1605. // Work areas
  1606. int top, bottom;
  1607. int lX;
  1608. int yDiff;
  1609. // Push starting point
  1610. PUSH(srcPoint, destPoint, x, y, 0);
  1611. while (stackPos) {
  1612. // Next point to fill, then scan left and right
  1613. POP(srcPoint, destPoint, x, y, yDiff);
  1614. srcPoint += yDiff * srcPitch;
  1615. destPoint += yDiff * destPitch;
  1616. y += yDiff;
  1617. // Don't fill given point directly- instead, we'll scan it manually in the second loop
  1618. // Update extreme points- y
  1619. if (y < y1) y1 = y;
  1620. if (y > y2) y2 = y;
  1621. // Check both top and bottom for matches
  1622. top = bottom = 1;
  1623. // Fill as far left as possible
  1624. lX = x;
  1625. while ((lX > minX) && (colorDifference(srcPoint[-1], targetColor) <= tolerance) && (destPoint[-1] != color)) {
  1626. --lX;
  1627. --srcPoint;
  1628. --destPoint;
  1629. *destPoint = color;
  1630. // Is point above fillable?
  1631. if ((y > minY) && (colorDifference(srcPoint[-srcPitch], targetColor) <= tolerance) && (destPoint[-srcPitch] != color)) {
  1632. // Are we pushing "above" points right now?
  1633. if (top) {
  1634. // Push onto stack
  1635. PUSH(srcPoint, destPoint, lX, y, -1);
  1636. top = 0;
  1637. }
  1638. }
  1639. // Not fillable, we will now push the next "above" point we find
  1640. else top = 1;
  1641. // Is point below fillable?
  1642. if ((y < maxY) && (colorDifference(srcPoint[srcPitch], targetColor) <= tolerance) && (destPoint[srcPitch] != color)) {
  1643. // Are we pushing "below" points right now?
  1644. if (bottom) {
  1645. // Push onto stack
  1646. PUSH(srcPoint, destPoint, lX, y, 1);
  1647. bottom = 0;
  1648. }
  1649. }
  1650. // Not fillable, we will now push the next "below" point we find
  1651. else bottom = 1;
  1652. }
  1653. // Update extreme left point
  1654. if (lX < x1) x1 = lX;
  1655. // Recenter, minus one, so that we scan the center/given point as well
  1656. --x;
  1657. srcPoint += x - lX;
  1658. destPoint += x - lX;
  1659. top = bottom = 1;
  1660. // Fill as far right as possible; this loop intentionally catches our first, central point
  1661. while ((x < maxX) && (colorDifference(srcPoint[1], targetColor) <= tolerance) && (destPoint[1] != color)) {
  1662. ++x;
  1663. ++srcPoint;
  1664. ++destPoint;
  1665. *destPoint = color;
  1666. // Is point above fillable?
  1667. if ((y > minY) && (colorDifference(srcPoint[-srcPitch], targetColor) <= tolerance) && (destPoint[-srcPitch] != color)) {
  1668. // Are we pushing "above" points right now?
  1669. if (top) {
  1670. // Push onto stack
  1671. PUSH(srcPoint, destPoint, x, y, -1);
  1672. top = 0;
  1673. }
  1674. }
  1675. // Not fillable, we will now push the next "above" point we find
  1676. else top = 1;
  1677. // Is point below fillable?
  1678. if ((y < maxY) && (colorDifference(srcPoint[srcPitch], targetColor) <= tolerance) && (destPoint[srcPitch] != color)) {
  1679. // Are we pushing "below" points right now?
  1680. if (bottom) {
  1681. // Push onto stack
  1682. PUSH(srcPoint, destPoint, x, y, 1);
  1683. bottom = 0;
  1684. }
  1685. }
  1686. // Not fillable, we will now push the next "below" point we find
  1687. else bottom = 1;
  1688. }
  1689. // Update extreme right point
  1690. if (x > x2) x2 = x;
  1691. }
  1692. result.x = x1;
  1693. result.y = y1;
  1694. result.w = x2 - x1 + 1;
  1695. result.h = y2 - y1 + 1;
  1696. return result;
  1697. }
  1698. Rect floodFillNonContiguous32(SDL_Surface* src, SDL_Surface* dest, int x, int y, Uint32 color, int tolerance) { start_func
  1699. assert(src);
  1700. assert(dest);
  1701. assert(tolerance >= 0);
  1702. // Min/Max area
  1703. Rect result = { 0, 0, 0, 0 };
  1704. // Clip area
  1705. SDL_Rect Sclip;
  1706. SDL_Rect SclipD;
  1707. SDL_GetClipRect(src, &Sclip);
  1708. SDL_GetClipRect(dest, &SclipD);
  1709. Rect clip = { Sclip.x, Sclip.y, Sclip.w, Sclip.h };
  1710. Rect clipD = { SclipD.x, SclipD.y, SclipD.w, SclipD.h };
  1711. if (!intersectRects(clip, clipD)) return result;
  1712. int minX = clip.x;
  1713. int minY = clip.y;
  1714. int maxX = clip.x + clip.w - 1;
  1715. int maxY = clip.y + clip.h - 1;
  1716. if ((x < minX) || (x > maxX) || (y < minY) || (y > maxY)) return result;
  1717. // Extreme points
  1718. int x1 = x;
  1719. int x2 = x;
  1720. int y1 = y;
  1721. int y2 = y;
  1722. // Starting point and pitch, etc.
  1723. int srcPitch = src->pitch / 4;
  1724. int destPitch = dest->pitch / 4;
  1725. Uint32* srcPoint = (Uint32*)src->pixels + minX + minY * srcPitch;
  1726. Uint32* destPoint = (Uint32*)dest->pixels + minX + minY * destPitch;
  1727. Uint32 targetColor = *((Uint32*)src->pixels + x + y * (src->pitch / 4));
  1728. // Special case
  1729. if ((src == dest) && (targetColor == color) && (tolerance == 0)) return result;
  1730. // Preadjust pitches
  1731. srcPitch -= maxX - minX + 1;
  1732. destPitch -= maxX - minX + 1;
  1733. for (y = minY; y <= maxY; ++y) {
  1734. for (x = minX; x <= maxX; ++x) {
  1735. if (colorDifference(*srcPoint, targetColor) <= tolerance) {
  1736. *destPoint = color;
  1737. // Update extreme points
  1738. if (y < y1) y1 = y;
  1739. if (y > y2) y2 = y;
  1740. if (x < x1) x1 = x;
  1741. if (x > x2) x2 = x;
  1742. }
  1743. ++srcPoint;
  1744. ++destPoint;
  1745. }
  1746. srcPoint += srcPitch;
  1747. destPoint += destPitch;
  1748. }
  1749. result.x = x1;
  1750. result.y = y1;
  1751. result.w = x2 - x1 + 1;
  1752. result.h = y2 - y1 + 1;
  1753. return result;
  1754. }