123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094 |
- /* GCSx
- ** GRAPHICS.CPP
- **
- ** Basic graphics primitives/support via SDL
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #include "all.h"
- SDL_Color phaseRGB[NUM_PHASES] = {
- { 0, 0, 0 },
- { 64, 64, 64 },
- { 128, 128, 128 },
- { 192, 192, 192 },
- { 255, 255, 255 },
- { 192, 192, 192 },
- { 128, 128, 128 },
- { 64, 64, 64 },
- };
- Uint32 phaseColors[NUM_PHASES];
- SDL_Color guiRGB[COLOR_COUNT] = {
- { 224, 224, 224 }, // COLOR_FILL - GUI fill
- { 255, 255, 255 }, // COLOR_LIGHT1 - Light bevel on GUI
- { 224, 224, 224 }, // COLOR_LIGHT2
- { 112, 112, 112 }, // COLOR_DARK1 - Dark bevel on GUI
- { 168, 168, 168 }, // COLOR_DARK2
- { 204, 204, 204 }, // COLOR_BUTTONFILL1 - Normal button gradient
- { 244, 244, 244 }, // COLOR_BUTTONFILL2
- { 176, 176, 176 }, // COLOR_BUTTONDOWN1 - Depressed button gradient
- { 216, 216, 216 }, // COLOR_BUTTONDOWN2
- { 0, 0, 0 }, // COLOR_TEXT - GUI text
- { 176, 176, 255 }, // COLOR_TITLEACTIVE1 - Active titlebar gradient
- { 255, 176, 255 }, // COLOR_TITLEACTIVE2
- { 112, 112, 152 }, // COLOR_TITLEINACTIVE1 - Inactive titlebar gradient
- { 152, 112, 152 }, // COLOR_TITLEINACTIVE2
- { 255, 255, 255 }, // COLOR_TEXTBOX - Textboxes fill
- { 0, 0, 0 }, // COLOR_CURSOR - Cursor in textboxes
- { 0, 0, 255 }, // COLOR_SELECTION1 - Selected text fill gradient
- { 128, 0, 128 }, // COLOR_SELECTION2
- { 255, 255, 128 }, // COLOR_TILECURSOR - Cursor when selecting tiles/sprites
- { 128, 128, 255 }, // COLOR_TILESELECTION - Overlaid over selected tiles/sprites
- { 255, 255, 255 }, // COLOR_TILECURSORBORDER1 - Fade range for glowing portion of tile cursor
- { 0, 0, 0 }, // COLOR_TILECURSORBORDER2
- { 160, 160, 160 }, // COLOR_SCROLLTRACK - Fill for scrollbar gutter
- { 0, 0, 0 }, // COLOR_LINEBORDER - Thin border on GUI widgets that don't use a bevel
- { 0, 0, 0 }, // COLOR_BKFILL - Fill/background for editing windows/areas
- { 64, 64, 192 }, // COLOR_GRID - Grid lines
- { 11, 11, 11 }, // COLOR_FRONTDESKTOP - Desktop fill for frontend
- { 0, 0, 26 }, // COLOR_EDITORDESKTOP - Desktop fill for editor
- { 0, 0, 0 }, // COLOR_TRANSPARENT1 - Used to show areas that are 100% transparent
- { 128, 128, 128 }, // COLOR_TRANSPARENT2
- { 255, 255, 192 }, // COLOR_TOOLTIP - Tooltip fill
- { 255, 0, 0 }, // COLOR_GLYPHWIDTH - Glyph width marker
- { 0, 0, 255 }, // COLOR_POPUPFILL1 - Selected menu item gradient
- { 128, 0, 128 }, // COLOR_POPUPFILL2
- { 255, 255, 255 }, // COLOR_POPUPTEXT - Selected menu item text
- { 128, 128, 128 }, // COLOR_CONSOLEPROMPT - Console prompt
- { 192, 0, 0 }, // COLOR_CONSOLEINPUT - User input in console
- };
-
- Uint32 guiPacked[COLOR_COUNT];
- SDL_Surface* actualScreen = NULL;
- // In normal mode, points to actual
- // In OpenGL mode, points to allocated 32bit surface
- SDL_Surface* proxyScreen = NULL;
- TextureMap* textureScreen = NULL;
- TextureMap* textureMice = NULL;
- int proxyScreenAllocated = 0;
- int glScreenState = 0;
- GLfloat glAlpha = 1.0f;
- int requestedX = 0;
- int requestedY = 0;
- int requestedBits = 0;
- int requestedFullscreen = 0;
- int requestedResizable = 0;
- int requestedGL = 0;
- int screenWidth = 0;
- int screenHeight = 0;
- int actualX = 0;
- int actualY = 0;
- int actualBits = 0; // bits of screen surface we have
- int hardwareBits = 0; // bits of the hardware itself currently
- int defaultBits = 0; // bits we will always use when windowed
- // (previous actual)
- int previousX = 0;
- int previousY = 0;
- int previousBits = 0;
- int previousFullscreen = 0;
- int previousResizable = 0;
- int previousGL = 0;
- MousePointer* micePointers[MOUSE_COUNT] = { NULL, NULL, NULL, NULL, NULL, NULL };
- const char* micePointerFiles[MOUSE_COUNT] = {
- "mousenorm.bmp",
- "mousevert.bmp",
- "mousehoriz.bmp",
- "mousebeam.bmp",
- "mousediagdown.bmp",
- "mousediagup.bmp",
- "mousepixel.bmp",
- "mouseadd.bmp",
- "mousesub.bmp",
- "mousefour.bmp"
- };
- int micePointerSpots[MOUSE_COUNT][2] = { { 0, 0 }, { 5, 8 }, { 8, 5 },
- { 3, 7 }, { 6, 6 }, { 6, 6 },
- { 5, 5 }, { 5, 5 }, { 5, 5 },
- { 10, 10 } };
- int currentMouse = 0;
- // Largest mouse size, and storage to unblit it from
- int mouseXSize = 0;
- int mouseYSize = 0;
- SDL_Surface* mouseUnblit = NULL;
- int lastMouseX = 0;
- int lastMouseY = 0;
- int mouseBlitted = -1;
- // Used for screenFlip- first rectangle is main screen
- // area to update; second and third are the last mouse
- // unblit and blit areas
- SDL_Rect updateRects[3];
- int numUpdate = 1;
- Uint32 convertRGB(SDL_Color color, int alpha) { start_func
- assert(proxyScreen);
- if (alpha >= 0) return SDL_MapRGBA(proxyScreen->format, color.r, color.g, color.b, alpha);
- return SDL_MapRGB(proxyScreen->format, color.r, color.g, color.b);
- }
- // Call whenever palette/mode changes
- void convertGuiItems() { start_func
- assert(proxyScreen);
- int pos;
-
- for (pos = 0; pos < COLOR_COUNT; ++pos) {
- guiPacked[pos] = convertRGB(guiRGB[pos]);
- }
- for (pos = 0; pos < MOUSE_COUNT; ++pos) {
- micePointers[pos]->convertFor(proxyScreen);
- if (requestedGL)
- micePointers[pos]->convertGL(textureMice, pos + 1, mouseXSize, mouseYSize);
- }
-
- for (pos = 0; pos < NUM_PHASES; ++pos) {
- phaseColors[pos] = convertRGB(phaseRGB[pos]);
- }
-
- // Storage for unblitting mouse
- if (mouseUnblit) SDL_FreeSurface(mouseUnblit);
- mouseUnblit = NULL;
- mouseUnblit = createSurface(mouseXSize, mouseYSize);
- mouseBlitted = -1;
- }
- void initVideo() { start_func
- const SDL_VideoInfo* videoInfo;
-
- if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) {
- fatalCrash(0, "Unable to init SDL: %s", SDL_GetError());
- }
- videoInfo = SDL_GetVideoInfo();
- defaultBits = videoInfo->vfmt->BitsPerPixel;
- if (defaultBits < 15) {
- fatalCrash(0, "Full-color video not supported");
- }
- string mouseFile;
- for (int pos = 0; pos < MOUSE_COUNT; ++pos) {
- if (micePointers[pos] == NULL) {
- createFilename(resourceDir->c_str(), micePointerFiles[pos], mouseFile);
- micePointers[pos] = new MousePointer(mouseFile.c_str(), micePointerSpots[pos][0], micePointerSpots[pos][1]);
- if (micePointers[pos]->xSize() > mouseXSize) mouseXSize = micePointers[pos]->xSize();
- if (micePointers[pos]->ySize() > mouseYSize) mouseYSize = micePointers[pos]->ySize();
- }
- }
-
- assert(mouseXSize > 0);
- assert(mouseYSize > 0);
- // We don't really care about inability to load our icon
- string iconFile;
- createFilename(resourceDir->c_str(), FILENAME_ICON, iconFile);
- SDL_Surface* icon = SDL_LoadBMP(iconFile.c_str());
- if (icon) SDL_WM_SetIcon(icon, NULL);
- SDL_FreeSurface(icon);
- }
- void selectVideoMode(int x, int y, int bpp, int fullscreen, int resizable, int gl) throw_Video { start_func
- const SDL_VideoInfo* videoInfo;
-
- if (bpp == -1) bpp = actualBits ? actualBits : defaultBits;
- if (x == -1) x = actualX;
- if (y == -1) y = actualY;
- if (fullscreen == -1) fullscreen = requestedFullscreen;
- if (resizable == -1) resizable = requestedResizable;
- if (gl == -1) gl = requestedGL;
- assert(x >= 0);
- assert(y >= 0);
- assert((bpp == 15) || (bpp == 16) || (bpp == 24) || (bpp == 32));
-
- // Certain minimum size
- if (x < 320) x = 320;
- if (y < 240) y = 240;
-
- // If fullscreen, not resizable
- if (fullscreen) {
- resizable = 0;
- }
-
- // If windowed, always go with default hardware bpp
- else {
- bpp = defaultBits;
- }
- previousX = actualX;
- previousY = actualY;
- previousBits = actualBits;
- previousFullscreen = requestedFullscreen;
- previousResizable = requestedResizable;
- previousGL = requestedGL;
- if (gl) {
- // @TODO: optimal settings here? should be based on bpp?
- SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0);
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
- }
- if (proxyScreenAllocated) {
- SDL_FreeSurface(proxyScreen);
- proxyScreenAllocated = 0;
- delete textureScreen;
- textureScreen = NULL;
- delete textureMice;
- textureMice = NULL;
- }
- // IMPORTANT: If you change this from SDL_SWSURFACE, you may need to add in surface locking!
- actualScreen = SDL_SetVideoMode(x, y, bpp,
- (gl ? SDL_OPENGL : SDL_SWSURFACE) |
- (fullscreen ? SDL_FULLSCREEN : 0) |
- (resizable ? SDL_RESIZABLE : 0)
- );
- if (actualScreen == NULL) {
- if (previousX) {
- // IMPORTANT: If you change this from SDL_SWSURFACE, you may need to add in surface locking!
- actualScreen = SDL_SetVideoMode(previousX, previousY, previousBits,
- (previousGL ? SDL_OPENGL : SDL_SWSURFACE) |
- (previousFullscreen ? SDL_FULLSCREEN : 0) |
- (previousResizable ? SDL_RESIZABLE : 0)
- );
- if ((previousGL) && (actualScreen)) {
- proxyScreen = createSurface32(actualScreen->w, actualScreen->h);
- proxyScreenAllocated = 1;
- textureScreen = new TextureMap(1, actualScreen->w, actualScreen->h, NULL);
- textureMice = new TextureMap(MOUSE_COUNT, mouseXSize, mouseYSize, NULL);
- glScreenState = 0;
- glAlpha = 1.0f;
- }
- else proxyScreen = actualScreen;
-
- if (actualScreen == NULL) {
- fatalCrash(0, "Unable to set %dx%dx%d video: %s", x, y, bpp, SDL_GetError());
- }
- else {
- throw VideoException("Unable to set %dx%dx%d video: %s", x, y, bpp, SDL_GetError());
- }
- }
- else {
- // Only fatal if no mode to fall back on
- fatalCrash(0, "Unable to set %dx%dx%d video: %s", x, y, bpp, SDL_GetError());
- }
- }
- else {
- if (fullscreen) {
- debugWrite(DEBUG_VIDEO, "Video mode %dx%dx%d", x, y, bpp);
- }
- else {
- debugWrite(DEBUG_VIDEO, "Video mode %dx%dx%d (w)", x, y, bpp);
- }
- }
-
- if (gl) {
- proxyScreen = createSurface32(actualScreen->w, actualScreen->h);
- proxyScreenAllocated = 1;
- textureScreen = new TextureMap(1, actualScreen->w, actualScreen->h, NULL);
- textureMice = new TextureMap(MOUSE_COUNT, mouseXSize, mouseYSize, NULL);
- glScreenState = 0;
- glAlpha = 1.0f;
- }
- else proxyScreen = actualScreen;
-
- requestedX = x;
- requestedY = y;
- requestedBits = bpp;
- requestedFullscreen = fullscreen;
- requestedResizable = resizable;
- requestedGL = gl;
- videoInfo = SDL_GetVideoInfo();
- hardwareBits = videoInfo->vfmt->BitsPerPixel;
- actualBits = actualScreen->format->BitsPerPixel;
- screenWidth = actualX = proxyScreen->w;
- screenHeight = actualY = proxyScreen->h;
-
- if ((x != actualX) || (y != actualY) || (bpp != actualBits)) {
- debugWrite(DEBUG_VIDEO, "Actual mode used: %dx%dx%d", actualX, actualY, actualBits);
- }
- if (hardwareBits != actualBits) {
- debugWrite(DEBUG_VIDEO, "Hardware BPP: %d", hardwareBits);
- }
-
- SDL_SetAlpha(proxyScreen, 0, 255);
- SDL_ShowCursor(SDL_DISABLE);
-
- convertGuiItems();
- // Resize desktop and all windows on it
- if (desktop != NULL) {
- desktop->resolutionChange(previousX, previousY, previousBits, actualX, actualY, actualBits);
- }
- // Save config (gl mode is game mode and doesn't count for configuration)
- if (!gl) {
- config->write(VIDEO_X, actualX);
- config->write(VIDEO_Y, actualY);
- config->write(VIDEO_BPP, actualBits);
- config->write(VIDEO_FULLSCREEN, requestedFullscreen);
- config->write(VIDEO_RESIZABLE, requestedResizable);
- }
-
- // Initialize OpenGL?
- if (gl) {
- oglInit(actualX, actualY);
- }
- }
- void exitVideo() { start_func
- for (int pos = 0; pos < MOUSE_COUNT; ++pos) {
- delete micePointers[pos];
- micePointers[pos] = NULL;
- }
- if (proxyScreenAllocated) {
- SDL_FreeSurface(proxyScreen);
- proxyScreenAllocated = 0;
- delete textureScreen;
- textureScreen = NULL;
- delete textureMice;
- textureMice = NULL;
- }
- }
- int screenBits() { start_func
- return actualBits;
- }
- int screenFullscreen() { start_func
- return requestedFullscreen;
- }
- int screenResizable() { start_func
- return requestedResizable;
- }
- int screenGL() { start_func
- return requestedGL;
- }
- void drawPixel(int x, int y, SDL_Color color, SDL_Surface* surface) { start_func
- drawPixel(x, y, convertRGB(color), surface);
- }
- void drawPixel(int x, int y, Uint32 data, SDL_Surface* surface) { start_func
- assert(surface);
- Uint16* bufp16;
- Uint32* bufp32;
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
- if ((x < clip.x) || (y < clip.y) || (x >= clip.x + clip.w) || (y >= clip.y + clip.h)) return;
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- *bufp16 = data;
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- *bufp32 = data;
- break;
- }
- }
- Uint32 getPixel(int x, int y, SDL_Surface* surface) { start_func
- assert(surface);
- Uint16* bufp16;
- Uint32* bufp32;
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
- if ((x < clip.x) || (y < clip.y) || (x >= clip.x + clip.w) || (y >= clip.y + clip.h)) return 0;
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- return *bufp16;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- return *bufp32;
- }
-
- return 0;
- }
- void alphaBlit32(int sX, int sY, const SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int width, int height) { start_func
- assert(src);
- assert(dest);
-
- width = (width == -1 ? src->w : width);
- height = (height == -1 ? src->h : height);
- Uint32 Amask = src->format->Amask;
- Uint32 Ashift = src->format->Ashift;
-
- for (int x = 0; x < width; ++x) {
- for (int y = 0; y < height; ++y) {
- Uint32 color = *((Uint32*)src->pixels + (sY + y)*src->pitch/4 + sX + x);
- Uint8 alpha = (color & Amask) >> Ashift;
- // Color becomes at 255 alpha, use alpha for blending instead
- _PutPixelAlpha(dest, dX + x, dY + y, color | Amask, alpha);
- }
- }
- }
- 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) {
- assert(src);
- assert(dest);
- if (alpha <= 0) return;
-
- // Default w/h
- width = (width == -1 ? src->w : width);
- height = (height == -1 ? src->h : height);
-
- // Determine target rect, accounting for clip
- Rect target = { dX, dY, width, height };
- SDL_Rect Sclip;
- SDL_GetClipRect(dest, &Sclip);
- Rect clip = { Sclip.x, Sclip.y, Sclip.w, Sclip.h };
- if (!intersectRects(target, clip)) return;
- // Adjust source position
- sX += target.x - dX;
- sY += target.y - dY;
-
- // Determine increment, accounting for flip/mirror
- int srcPitch = src->pitch / 4 - target.w;
- int srcAdd = 1;
- if (rotate90) {
- assert(width == height);
-
- srcAdd = src->pitch / -4;
- srcPitch = -srcAdd * target.h + 1;
- if (mirror) {
- srcAdd = -srcAdd;
- srcPitch = -srcAdd * target.h + 1;
- }
- else {
- sY = sY + target.h - 1;
- }
- if (flip) {
- sX = sX + target.w - 1;
- srcPitch -= 2;
- }
- }
- else {
- if (flip) {
- sY = sY + target.h - 1;
- srcPitch -= src->pitch / 2;
- }
- if (mirror) {
- sX = sX + target.w - 1;
- srcAdd = -1;
- srcPitch += target.w * 2;
- }
- }
- Uint32* srcP = (Uint32*)src->pixels + sX + sY * src->pitch / 4;
- // Destination range
- int odX = target.x;
- dY = target.y;
- int dX2 = odX + target.w;
- int dY2 = dY + target.h;
- // Bitmasks/shifts
- Uint32 rdmask = dest->format->Rmask;
- Uint32 gdmask = dest->format->Gmask;
- Uint32 bdmask = dest->format->Bmask;
- int runshift = dest->format->Rshift;
- int gunshift = dest->format->Gshift;
- int bunshift = dest->format->Bshift;
-
- // Optimize for no color/no alpha
- int applyColor = 0;
- int applyAlpha = 0;
- if (red < rgbScale) applyColor = 1;
- if (green < rgbScale) applyColor = 1;
- if (blue < rgbScale) applyColor = 1;
- if (alpha < alphaScale) applyAlpha = 1;
- switch (dest->format->BytesPerPixel) {
- case 2: {
- Uint16* destP = (Uint16*)dest->pixels + odX + dY * dest->pitch / 2;
- int destPitch = dest->pitch / 2 - target.w;
- int rloss = dest->format->Rloss;
- int gloss = dest->format->Gloss;
- int bloss = dest->format->Bloss;
- for (; dY < dY2; ++dY) {
- for (dX = odX; dX < dX2; ++dX) {
- // Pixel
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- int r = (*srcP & 0xff000000) >> 24;
- int g = (*srcP & 0x00ff0000) >> 16;
- int b = (*srcP & 0x0000ff00) >> 8;
- Uint32 a = *srcP & 0x000000ff;
- #else
- int r = *srcP & 0x000000ff;
- int g = (*srcP & 0x0000ff00) >> 8;
- int b = (*srcP & 0x00ff0000) >> 16;
- Uint32 a = *srcP & 0xff000000;
- #endif
- // Apply color
- if (applyColor) {
- r = r * red / rgbScale;
- g = g * green / rgbScale;
- b = b * blue / rgbScale;
- }
- // Apply alpha
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- if ((a != 0x000000ff) || (applyAlpha)) {
- #else
- if ((a != 0xff000000) || (applyAlpha)) {
- a = a >> 24;
- #endif
- a = a * alpha / alphaScale;
- a = a ^ 0xFF; // (flipped)
- r += (((int)((*destP & rdmask) >> runshift) - r) * a) >> 8;
- g += (((int)((*destP & gdmask) >> gunshift) - g) * a) >> 8;
- b += (((int)((*destP & bdmask) >> bunshift) - b) * a) >> 8;
- }
-
- // Scale down
- r >>= rloss;
- g >>= gloss;
- b >>= bloss;
- // Place
- *destP = (r << runshift) | (g << gunshift) | (b << bunshift);
- ++destP;
- srcP += srcAdd;
- }
- destP += destPitch;
- srcP += srcPitch;
- }
- break;
- }
- case 4: {
- Uint32* destP = (Uint32*)dest->pixels + odX + dY * dest->pitch / 4;
- int destPitch = dest->pitch / 4 - target.w;
- for (; dY < dY2; ++dY) {
- for (dX = odX; dX < dX2; ++dX) {
- // Pixel
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- int r = (*srcP & 0xff000000) >> 24;
- int g = (*srcP & 0x00ff0000) >> 16;
- int b = (*srcP & 0x0000ff00) >> 8;
- Uint32 a = *srcP & 0x000000ff;
- #else
- int r = *srcP & 0x000000ff;
- int g = (*srcP & 0x0000ff00) >> 8;
- int b = (*srcP & 0x00ff0000) >> 16;
- Uint32 a = *srcP & 0xff000000;
- #endif
- // Apply color
- if (applyColor) {
- r = r * red / rgbScale;
- g = g * green / rgbScale;
- b = b * blue / rgbScale;
- }
- // Apply alpha
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- if ((a != 0x000000ff) || (applyAlpha)) {
- #else
- if ((a != 0xff000000) || (applyAlpha)) {
- a = a >> 24;
- #endif
- a = a * alpha / alphaScale;
- a = a ^ 0xFF; // (flipped)
- r += (((int)((*destP & rdmask) >> runshift) - r) * a) >> 8;
- g += (((int)((*destP & gdmask) >> gunshift) - g) * a) >> 8;
- b += (((int)((*destP & bdmask) >> bunshift) - b) * a) >> 8;
- }
- // Place
- *destP = (r << runshift) | (g << gunshift) | (b << bunshift);
- ++destP;
- srcP += srcAdd;
- }
- destP += destPitch;
- srcP += srcPitch;
- }
- break;
- }
- }
- }
- 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
- assert(src);
- assert(dest);
- assert(mask);
- if (src == dest) {
- assert(sX == dX);
- assert(sY == dY);
- }
- if (src == mask) {
- assert(sX == mX);
- assert(sY == mY);
- }
- if (dest == mask) {
- assert(dX == mX);
- assert(dY == mY);
- }
- width = (width == -1 ? src->w : width);
- height = (height == -1 ? src->h : height);
- Uint32 Amask = mask->format->Amask;
-
- Uint32* srcData = (Uint32*)src->pixels + sY*src->pitch/4 + sX;
- Uint32* destData = (Uint32*)dest->pixels + dY*dest->pitch/4 + dX;
- Uint32* maskData = (Uint32*)mask->pixels + mY*mask->pitch/4 + mX;
- int srcPitch = src->pitch/4 - width;
- int destPitch = dest->pitch/4 - width;
- int maskPitch = mask->pitch/4 - width;
- for (int y = 0; y < height; ++y) {
- for (int x = 0; x < width; ++x) {
- if (*maskData & Amask) {
- *destData = *srcData;
- if (clear) *srcData = clearColor;
- }
-
- ++srcData;
- ++destData;
- ++maskData;
- }
- srcData += srcPitch;
- destData += destPitch;
- maskData += maskPitch;
- }
- }
- 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
- assert(src);
- assert(dest);
- assert(mask);
- if (src == dest) {
- assert(sX == dX);
- assert(sY == dY);
- }
- if (src == mask) {
- assert(sX == mX);
- assert(sY == mY);
- }
- if (dest == mask) {
- assert(dX == mX);
- assert(dY == mY);
- }
- width = (width == -1 ? src->w : width);
- height = (height == -1 ? src->h : height);
- Uint32 Amask = mask->format->Amask;
- Uint32 SrcAmask = src->format->Amask;
- Uint32 SrcAshift = src->format->Ashift;
-
- Uint32* srcData = (Uint32*)src->pixels + sY*src->pitch/4 + sX;
- Uint32* maskData = (Uint32*)mask->pixels + mY*mask->pitch/4 + mX;
- int srcPitch = src->pitch/4 - width;
- int maskPitch = mask->pitch/4 - width;
- for (int y = 0; y < height; ++y) {
- for (int x = 0; x < width; ++x) {
- if (*maskData & Amask) {
- // Prep color for putpixelalpha
- Uint32 color = *srcData;
- Uint8 alpha = (color & SrcAmask) >> SrcAshift;
- // Color becomes at 255 alpha, use alpha for blending instead
- _PutPixelAlpha(dest, dX + x, dY + y, color | SrcAmask, alpha * alphaPercent / 100);
- if (clear) *srcData = clearColor;
- }
-
- ++srcData;
- ++maskData;
- }
- srcData += srcPitch;
- maskData += maskPitch;
- }
- }
- void blit(int sX, int sY, SDL_Surface* src, int dX, int dY, SDL_Surface* dest, int width, int height) { start_func
- assert(src);
- assert(dest);
- SDL_Rect sourceRect;
- sourceRect.x = sX;
- sourceRect.y = sY;
- sourceRect.w = (width == -1 ? src->w : width);
- sourceRect.h = (height == -1 ? src->h : height);
-
- SDL_Rect destRect;
- destRect.x = dX;
- destRect.y = dY;
-
- if (SDL_BlitSurface(src, &sourceRect, dest, &destRect)) {
- fatalCrash(0, "SDL Blit error: %s", SDL_GetError());
- }
- }
- void preGLScreenFlip() { start_func
- if (requestedGL) {
- // @TODO: these should be moved to game loop or removed entirely
- // (including a bk color setting)
- glClear(GL_COLOR_BUFFER_BIT);
- glLoadIdentity();
- glScreenState = 1;
- }
- }
- void postGLScreenFlip() { start_func
- if ((glScreenState >= 1) && (requestedGL)) {
- SDL_GL_SwapBuffers();
- glScreenState = 0;
- }
- }
- void setScreenGLAlpha(int alpha) { start_func
- if (alpha < 0) alpha = 0;
- if (alpha > 256) alpha = 256;
- glAlpha = (GLfloat)alpha / 256.0f;
- }
- void screenFlip(const Rect* area) { start_func
- if (requestedGL) {
- int doFlip = !glScreenState;
- if (glScreenState != 1) preGLScreenFlip();
- // Just blit everything to openGL
- glLoadIdentity();
- if ((area) && (area->w)) {
- textureScreen->store(1, proxyScreen, area->x, area->y, area->x, area->y, area->w, area->h);
- textureScreen->updateTexture();
- }
- glColor4f(1.0f, 1.0f, 1.0f, glAlpha);
- textureScreen->draw(1, 0, 0);
- // Add mouse
- if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS) && (micePointers[currentMouse]))
- micePointers[currentMouse]->textureAt(lastMouseX, lastMouseY);
- if (doFlip) postGLScreenFlip();
- else glScreenState = 2;
- }
- else {
- if (area) {
- if (area->w) {
- updateRects[0].x = area->x;
- updateRects[0].y = area->y;
- updateRects[0].w = area->w;
- updateRects[0].h = area->h;
- SDL_UpdateRects(actualScreen, numUpdate, updateRects);
- }
- else if (numUpdate > 1) {
- SDL_UpdateRects(actualScreen, numUpdate - 1, updateRects + 1);
- }
- }
- else {
- SDL_UpdateRect(actualScreen, 0, 0, 0, 0);
- }
- }
- numUpdate = 1;
- }
- void prepareFont() { start_func
- if (TTF_Init()) {
- fatalCrash(0, "Unable to initialize TTF library");
- }
- string fontFile;
- for (int pos = 0; pos < FONT_COUNT; ++pos) {
- createFilename(resourceDir->c_str(), fonts[pos].file, fontFile);
- fonts[pos].font = TTF_OpenFont(fontFile.c_str(), fonts[pos].size);
- if (fonts[pos].font == NULL) {
- fatalCrash(0, "Unable to open font %s: %s", fontFile.c_str(), SDL_GetError());
- }
- int junk;
- if (TTF_SizeText(fonts[pos].font, "j", &junk, &fonts[pos].height)) {
- fatalCrash(0, "Unable to size font %s: %s", fontFile.c_str(), SDL_GetError());
- }
- fonts[pos].ascent = TTF_FontAscent(fonts[pos].font);
- }
- }
- void closeFont() { start_func
- for (int pos = 0; pos < FONT_COUNT; ++pos) {
- if (fonts[pos].font) {
- TTF_CloseFont(fonts[pos].font);
- fonts[pos].font = NULL;
- }
- }
- TTF_Quit();
- }
- SDL_Surface* createText(const string& text, SDL_Color fg, int alpha, int font) { start_func
- if (text.length() == 0) return NULL;
- assert(font >= 0);
- assert(font < FONT_COUNT);
- assert(fonts[font].font);
- SDL_Surface* textS;
- if (alpha) {
- textS = TTF_RenderText_Blended(fonts[font].font, text.c_str(), fg);
- }
- else {
- textS = TTF_RenderText_Solid(fonts[font].font, text.c_str(), fg);
- }
- if (textS == NULL) {
- fatalCrash(0, "SDL Text rendering error: %s", SDL_GetError());
- }
- return textS;
- }
- int drawText(const string& text, SDL_Color fg, int x, int y, SDL_Surface* surface, int font) { start_func
- if (text.length() == 0) return 0;
- // Change 1 to 0 to remove alpha
- SDL_Surface* textSurface = createText(text, fg, 1, font);
- assert(textSurface);
- blit(0, 0, textSurface, x, y, surface);
-
- int width = textSurface->w;
- SDL_FreeSurface(textSurface);
- return width;
- }
- void drawBox(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface) { start_func
- assert(w > 0);
- assert(h > 0);
- assert(surface);
-
- drawHLine(x, x + w - 1, y, color, surface);
- drawHLine(x, x + w - 1, y + h - 1, color, surface);
- drawVLine(y, y + h - 1, x, color, surface);
- drawVLine(y, y + h - 1, x + w - 1, color, surface);
- }
- int SDL_FillRect(SDL_Surface *dst, Rect *dstrect, Uint32 color) { start_func
- assert(dstrect);
- SDL_Rect newrect = { dstrect->x, dstrect->y, dstrect->w, dstrect->h };
- int ret = SDL_FillRect(dst, &newrect, color);
- dstrect->x = newrect.x;
- dstrect->y = newrect.y;
- dstrect->w = newrect.w;
- dstrect->h = newrect.h;
- return ret;
- }
- void SDL_SetClipRect(SDL_Surface *surface, Rect *rect) { start_func
- assert(rect);
- SDL_Rect newrect = { rect->x, rect->y, rect->w, rect->h };
- SDL_SetClipRect(surface, &newrect);
- rect->x = newrect.x;
- rect->y = newrect.y;
- rect->w = newrect.w;
- rect->h = newrect.h;
- }
- void SDL_SetClipRect(SDL_Surface *surface, const Rect *rect) { start_func
- assert(rect);
- SDL_Rect newrect = { rect->x, rect->y, rect->w, rect->h };
- SDL_SetClipRect(surface, &newrect);
- }
- void drawRect(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface) { start_func
- assert(w > 0);
- assert(h > 0);
- SDL_Rect rect = { x, y, w, h };
- assert(surface);
- // fillrect only fails from locking or <8 bpp surfaces, neither of which we care about
- SDL_FillRect(surface, &rect, color);
- }
- void drawGradient(int x, int y, int w, int h, SDL_Color color1, SDL_Color color2, SDL_Surface* surface) { start_func
- assert(w > 0);
- assert(h > 0);
- assert(surface);
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
-
- // y2, y clip
- int y2 = y + h - 1;
- if (y2 >= clip.y + clip.h) y2 = clip.y + clip.h - 1;
- if (y < clip.y) y = clip.y;
- if (y2 < y) return;
- // Position gradient is at and max position of gradient
- int pos = 0;
- int maxpos = w - 1;
- // (special case)
- if (maxpos == 0) maxpos = 1;
-
- // x2, x clip (x2 is actually 1 higher than last)
- int x2 = x + w;
- if (x2 > clip.x + clip.w) x2 = clip.x + clip.w;
- if (x < clip.x) {
- // Adjust gradient position too
- pos = clip.x - x;
- x = clip.x;
- }
- if (x2 < x) return;
-
- SDL_Color color;
- for (; x < x2; ++x, ++pos) {
- color.r = color1.r + (color2.r - color1.r) * pos / maxpos;
- color.g = color1.g + (color2.g - color1.g) * pos / maxpos;
- color.b = color1.b + (color2.b - color1.b) * pos / maxpos;
- drawVLine(y, y2, x, convertRGB(color), surface);
- }
- }
- void drawSelectRect(int x, int y, int w, int h, Uint32 color, SDL_Surface* surface, int alpha) { start_func
- assert(w > 0);
- assert(h > 0);
- assert(surface);
- SDL_Rect rect = { 0, 0, w, h };
- SDL_Surface* selection = createSurface(w, h);
- SDL_SetAlpha(selection, SDL_SRCALPHA, alpha);
-
- // fillrect only fails from locking or <8 bpp surfaces, neither of which we care about
- SDL_FillRect(selection, &rect, color);
- SDL_Rect destRect = { x, y, w, h };
- if (SDL_BlitSurface(selection, &rect, surface, &destRect)) {
- SDL_FreeSurface(selection);
- fatalCrash(0, "SDL Rect error: %s", SDL_GetError());
- }
- SDL_FreeSurface(selection);
- }
- // (unused)
- /*
- void drawSelectGradient(int x, int y, int w, int h, SDL_Color color1, SDL_Color color2, SDL_Surface* surface, int alpha) { start_func
- assert(w > 0);
- assert(h > 0);
- assert(surface);
- SDL_Surface* selection = createSurface(w, h);
- SDL_SetAlpha(selection, SDL_SRCALPHA, alpha);
- drawGradient(0, 0, w, h, color1, color2, selection);
- SDL_Rect rect = { 0, 0, w, h };
- SDL_Rect destRect = { x, y, w, h };
- if (SDL_BlitSurface(selection, &rect, surface, &destRect)) {
- SDL_FreeSurface(selection);
- fatalCrash(0, "SDL Rect error: %s", SDL_GetError());
- }
- SDL_FreeSurface(selection);
- }
- */
- void drawFocusBox(int x, int y, int w, int h, SDL_Surface* surface) { start_func
- assert(w > 0);
- assert(h > 0);
- assert(surface);
- drawDottedHLine(x, x + w - 1, y, guiPacked[COLOR_DARK1], surface);
- drawDottedVLine(y, y + h - 1, x + w - 1, guiPacked[COLOR_DARK1], surface);
- drawDottedHLine(x, x + w - 1, y + h - 1, guiPacked[COLOR_DARK1], surface);
- drawDottedVLine(y, y + h - 1, x, guiPacked[COLOR_DARK1], surface);
- }
- void drawGuiBox(int x, int y, int w, int h, int thickness, SDL_Surface* surface) { start_func
- assert((thickness == 1) || (thickness == 2));
- int colorl = (thickness == 1) ? COLOR_LIGHT1 : COLOR_LIGHT2;
- int colord = (thickness == 1) ? COLOR_DARK1 : COLOR_DARK2;
- drawRect(x, y, w, h, guiPacked[COLOR_FILL], surface);
- drawHLine(x, x + w - 2, y, guiPacked[colorl], surface);
- drawVLine(y, y + h - 2, x, guiPacked[colorl], surface);
- drawVLine(y + 1, y + h - 1, x + w - 1, guiPacked[colord], surface);
- drawHLine(x + 1, x + w - 1, y + h - 1, guiPacked[colord], surface);
- if (thickness > 1) {
- drawHLine(x + 1, x + w - 3, y + 1, guiPacked[COLOR_LIGHT1], surface);
- drawVLine(y + 1, y + h - 3, x + 1, guiPacked[COLOR_LIGHT1], surface);
- drawVLine(y + 2, y + h - 2, x + w - 2, guiPacked[COLOR_DARK1], surface);
- drawHLine(x + 2, x + w - 2, y + h - 2, guiPacked[COLOR_DARK1], surface);
- }
- }
- void drawGuiBoxInvert(int x, int y, int w, int h, int thickness, SDL_Surface* surface) { start_func
- assert((thickness == 1) || (thickness == 2));
-
- drawHLine(x, x + w - 2, y, guiPacked[COLOR_DARK1], surface);
- drawVLine(y, y + h - 2, x, guiPacked[COLOR_DARK1], surface);
- drawVLine(y + 1, y + h - 1, x + w - 1, guiPacked[COLOR_LIGHT1], surface);
- drawHLine(x + 1, x + w - 1, y + h - 1, guiPacked[COLOR_LIGHT1], surface);
- if (thickness > 1) {
- drawHLine(x + 1, x + w - 3, y + 1, guiPacked[COLOR_DARK2], surface);
- drawVLine(y + 1, y + h - 3, x + 1, guiPacked[COLOR_DARK2], surface);
- drawVLine(y + 2, y + h - 2, x + w - 2, guiPacked[COLOR_LIGHT2], surface);
- drawHLine(x + 2, x + w - 2, y + h - 2, guiPacked[COLOR_LIGHT2], surface);
- }
- }
- void drawLine(int x1, int y1, int x2, int y2, Uint32 color, SDL_Surface* surface) { start_func
- Uint16* bufp16;
- Uint32* bufp32;
- assert(surface);
- Sint16 x = x1;
- Sint16 y = y1;
- Sint16 dy = y2 - y1;
- Sint16 dx = x2 - x1;
-
- Sint16 G, DeltaG1, DeltaG2, minG, maxG;
- Sint16 inc = 1;
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
-
- Sint16 cx2 = clip.x + clip.w;
- Sint16 cy2 = clip.y + clip.h;
-
- // Skip entirely?
- if (((x1 < clip.x) && (x2 < clip.x)) ||
- ((y1 < clip.y) && (y2 < clip.y)) ||
- ((x1 >= cx2) && (x2 >= cx2)) ||
- ((y1 >= cy2) && (y2 >= cy2))) return;
-
- if (abs(dy) < abs(dx)) {
- if (dx < 0) {
- dx = -dx;
- dy = -dy;
-
- y1 = y2;
- y2 = y;
- y = y1;
-
- x1 = x2;
- x2 = x;
- x = x1;
- }
- if (dy < 0) {
- dy = -dy;
- inc = -1;
- }
-
- G = 2 * dy - dx;
- DeltaG1 = 2 * (dy - dx);
- DeltaG2 = 2 * dy;
-
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp16 = color;
- while (++x <= x2) {
- ++bufp16;
- if (G > 0) { G += DeltaG1; y += inc; bufp16 += inc*surface->pitch/2; }
- else G += DeltaG2;
-
- if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp16 = color;
- }
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp32 = color;
- while (++x <= x2) {
- ++bufp32;
- if (G > 0) { G += DeltaG1; y += inc; bufp32 += inc*surface->pitch/4; }
- else G += DeltaG2;
-
- if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp32 = color;
- }
- break;
- }
- }
- else {
- if (dy < 0) {
- dx = -dx;
- dy = -dy;
-
- y1 = y2;
- y2 = y;
- y = y1;
-
- x1 = x2;
- x2 = x;
- x = x1;
- }
- if (dx < 0) {
- dx = -dx;
- inc = -1;
- }
-
- G = 2 * dx - dy;
- minG = maxG = G;
- DeltaG1 = 2 * (dx - dy);
- DeltaG2 = 2 * dx;
-
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp16 = color;
- while (++y <= y2) {
- bufp16 += surface->pitch/2;
- if (G > 0) { G += DeltaG1; x += inc; bufp16 += inc; }
- else G += DeltaG2;
-
- if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp16 = color;
- }
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp32 = color;
- while (++y <= y2) {
- bufp32 += surface->pitch/4;
- if (G > 0) { G += DeltaG1; x += inc; bufp32 += inc; }
- else G += DeltaG2;
-
- if ((x >= clip.x) && (y >= clip.y) && (x < cx2) && (y < cy2)) *bufp32 = color;
- }
- break;
- }
- }
- }
- void drawHLine(int x1, int x2, int y1, Uint32 color, SDL_Surface* surface) { start_func
- Uint16* bufp16;
- Uint32* bufp32;
- assert(surface);
- Sint16 x = x1;
- Sint16 y = y1;
-
- if (x1 > x2) {
- x1 = x2;
- x2 = x;
- x = x1;
- }
-
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
-
- Sint16 cx2 = clip.x + clip.w;
- Sint16 cy2 = clip.y + clip.h;
-
- // Skip entirely?
- if ((y < clip.y) || (y >= cy2) ||
- (x2 < clip.x) || (x >= cx2)) return;
-
- // Clip
- if (x < clip.x) x = clip.x;
- if (x2 >= cx2) x2 = cx2 - 1;
-
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- *bufp16 = color;
- while (++x <= x2) {
- *++bufp16 = color;
- }
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- *bufp32 = color;
- while (++x <= x2) {
- *++bufp32 = color;
- }
- break;
- }
- }
- void drawVLine(int y1, int y2, int x1, Uint32 color, SDL_Surface* surface) { start_func
- Uint16* bufp16;
- Uint32* bufp32;
- assert(surface);
- Sint16 x = x1;
- Sint16 y = y1;
-
- if (y1 > y2) {
- y1 = y2;
- y2 = y;
- y = y1;
- }
-
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
-
- Sint16 cx2 = clip.x + clip.w;
- Sint16 cy2 = clip.y + clip.h;
-
- // Skip entirely?
- if ((x < clip.x) || (x >= cx2) ||
- (y2 < clip.y) || (y >= cy2)) return;
-
- // Clip
- if (y < clip.y) y = clip.y;
- if (y2 >= cy2) y2 = cy2 - 1;
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- *bufp16 = color;
- while (++y <= y2) {
- *(bufp16+= surface->pitch/2) = color;
- }
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- *bufp32 = color;
- while (++y <= y2) {
- *(bufp32+= surface->pitch/4) = color;
- }
- break;
- }
- }
- void drawDottedHLine(int x1, int x2, int y1, Uint32 color, SDL_Surface* surface) { start_func
- Uint16* bufp16;
- Uint32* bufp32;
- assert(surface);
- Sint16 x = x1;
- Sint16 y = y1;
-
- if (x1 > x2) {
- x1 = x2;
- x2 = x;
- x = x1;
- }
-
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
-
- Sint16 cx2 = clip.x + clip.w;
- Sint16 cy2 = clip.y + clip.h;
-
- // Skip entirely?
- if ((y < clip.y) || (y >= cy2) ||
- (x2 < clip.x) || (x >= cx2)) return;
-
- // Clip
- if (x < clip.x) x = clip.x;
- if (x2 >= cx2) x2 = cx2 - 1;
- Sint16 dot = (x + y) & 1;
-
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- if (dot) *bufp16 = color;
- while (++x <= x2) {
- ++bufp16;
- dot = dot ^ 1;
- if (dot) *bufp16 = color;
- }
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- if (dot) *bufp32 = color;
- while (++x <= x2) {
- ++bufp32;
- dot = dot ^ 1;
- if (dot) *bufp32 = color;
- }
- break;
- }
- }
- void drawDottedVLine(int y1, int y2, int x1, Uint32 color, SDL_Surface* surface) { start_func
- Uint16* bufp16;
- Uint32* bufp32;
- assert(surface);
- Sint16 x = x1;
- Sint16 y = y1;
-
- if (y1 > y2) {
- y1 = y2;
- y2 = y;
- y = y1;
- }
-
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
-
- Sint16 cx2 = clip.x + clip.w;
- Sint16 cy2 = clip.y + clip.h;
-
- // Skip entirely?
- if ((x < clip.x) || (x >= cx2) ||
- (y2 < clip.y) || (y >= cy2)) return;
-
- // Clip
- if (y < clip.y) y = clip.y;
- if (y2 >= cy2) y2 = cy2 - 1;
-
- Sint16 dot = (x + y) & 1;
-
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- if (dot) *bufp16 = color;
- while (++y <= y2) {
- bufp16+= surface->pitch/2;
- dot = dot ^ 1;
- if (dot) *bufp16 = color;
- }
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- if (dot) *bufp32 = color;
- while (++y <= y2) {
- bufp32 += surface->pitch/4;
- dot = dot ^ 1;
- if (dot) *bufp32 = color;
- }
- break;
- }
- }
- void drawAntsBox(int x1, int y1, int w, int h, int phase, SDL_Surface* surface) { start_func
- assert(surface);
-
- drawAntsHLine(x1, x1 + w - 1, y1, phase, surface);
- drawAntsHLine(x1, x1 + w - 1, y1 + h - 1, phase, surface);
- drawAntsVLine(y1, y1 + h - 1, x1, phase, surface);
- drawAntsVLine(y1, y1 + h - 1, x1 + w - 1, phase, surface);
- }
- void drawAntsHLine(int x1, int x2, int y1, int phase, SDL_Surface* surface) { start_func
- Uint16* bufp16;
- Uint32* bufp32;
- assert(surface);
-
- Sint16 x = x1;
- Sint16 y = y1;
-
- if (x1 > x2) swap(x1, x2);
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
-
- Sint16 cx2 = clip.x + clip.w;
- Sint16 cy2 = clip.y + clip.h;
-
- // Skip entirely?
- if ((y < clip.y) || (y >= cy2) ||
- (x2 < clip.x) || (x >= cx2)) return;
-
- // Clip
- if (x < clip.x) x = clip.x;
- if (x2 >= cx2) x2 = cx2 - 1;
- phase = (phase + x + y) % NUM_PHASES;
-
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- *bufp16 = phaseColors[phase];
- phase = (phase + 1) % NUM_PHASES;
- while (++x <= x2) {
- *++bufp16 = phaseColors[phase];
- phase = (phase + 1) % NUM_PHASES;
- }
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- *bufp32 = phaseColors[phase];
- phase = (phase + 1) % NUM_PHASES;
- while (++x <= x2) {
- *++bufp32 = phaseColors[phase];
- phase = (phase + 1) % NUM_PHASES;
- }
- break;
- }
- }
- void drawAntsVLine(int y1, int y2, int x1, int phase, SDL_Surface* surface) { start_func
- Uint16* bufp16;
- Uint32* bufp32;
- assert(surface);
- Sint16 x = x1;
- Sint16 y = y1;
-
- if (y1 > y2) swap(y1, y2);
- SDL_Rect clip;
- SDL_GetClipRect(surface, &clip);
-
- Sint16 cx2 = clip.x + clip.w;
- Sint16 cy2 = clip.y + clip.h;
-
- // Skip entirely?
- if ((x < clip.x) || (x >= cx2) ||
- (y2 < clip.y) || (y >= cy2)) return;
-
- // Clip
- if (y < clip.y) y = clip.y;
- if (y2 >= cy2) y2 = cy2 - 1;
-
- phase = (phase + x + y) % NUM_PHASES;
- switch (surface->format->BytesPerPixel) {
- case 2:
- bufp16 = (Uint16*)surface->pixels + y*surface->pitch/2 + x;
- *bufp16 = phaseColors[phase];
- phase = (phase + 1) % NUM_PHASES;
- while (++y <= y2) {
- *(bufp16+= surface->pitch/2) = phaseColors[phase];
- phase = (phase + 1) % NUM_PHASES;
- }
- break;
- case 4:
- bufp32 = (Uint32*)surface->pixels + y*surface->pitch/4 + x;
- *bufp32 = phaseColors[phase];
- phase = (phase + 1) % NUM_PHASES;
- while (++y <= y2) {
- *(bufp32+= surface->pitch/4) = phaseColors[phase];
- phase = (phase + 1) % NUM_PHASES;
- }
- break;
- }
- }
- int fontWidth(const string& text, int font) { start_func
- int width;
- int junk;
- if (text.length() == 0) return 0;
- assert(font >= 0);
- assert(font < FONT_COUNT);
- assert(fonts[font].font);
- if (TTF_SizeText(fonts[font].font, text.c_str(), &width, &junk)) {
- fatalCrash(0, "SDL Error sizing text: %s", SDL_GetError());
- }
- return width;
- }
- int convertGuiText(string* text, char* shortcut, int font) { start_func
- assert(font >= 0);
- assert(font < FONT_COUNT);
- assert(fonts[font].font);
- assert(text);
- *shortcut = 0;
- if (text->length() == 0) return 0;
- // Contains a \t?
- int pos = text->find('\t', 0);
- if (pos < 0) return 0;
-
- // Remove from string
- text->erase(pos, 1);
-
- // Calculate start of underline
- int start = 0;
- int junk;
- if (pos > 0) {
- string sub(*text, 0, pos);
- if (TTF_SizeText(fonts[font].font, sub.c_str(), &start, &junk)) {
- fatalCrash(0, "SDL Error sizing text: %s", SDL_GetError());
- }
- }
-
- // Calculate size of underline
- int size = 0;
- string sub(*text, pos, 1);
- // (no character after \t? no underline)
- if (sub.length() == 0) return 0;
- if (TTF_SizeText(fonts[font].font, sub.c_str(), &size, &junk)) {
- fatalCrash(0, "SDL Error sizing text: %s", SDL_GetError());
- }
-
- // Grab shortcut key
- if (shortcut) {
- *shortcut = tolower(sub[0]);
- }
-
- // Generate code (max 255 on start and size)
- return (start & 0xFF) | ((size & 0xFF) << 8);
- }
- void drawTextUnderline(int underlineCode, Uint32 color, int x, int y, SDL_Surface* surface, int font) { start_func
- assert(underlineCode >= 0);
- assert(underlineCode <= 0xFFFF);
- assert(font >= 0);
- assert(font < FONT_COUNT);
- assert(fonts[font].font);
- assert(surface);
- int start = underlineCode & 0xFF;
- int size = underlineCode >> 8;
- if (size) drawHLine(x + start - 1, x + start + size - 1, y + fonts[font].ascent + 1, color, surface);
- }
- void drawCheckbox(int isRadio, int isChecked, int isDisabled, int x, int y, int size, SDL_Surface* surface) { start_func
- assert(surface);
- if (isRadio) {
- int rad = (size + 1) / 2;
- int tweak = (size & 1) ^ 1;
- --rad;
- sge_FilledCircleDual(surface, x + rad, y + rad, rad, tweak, guiPacked[COLOR_DARK1], guiPacked[COLOR_LIGHT1]);
- sge_FilledCircleDual(surface, x + rad, y + rad, rad - 1, tweak, guiPacked[COLOR_DARK2], guiPacked[COLOR_LIGHT2]);
- sge_FilledCircleDual(surface, x + rad, y + rad, rad - 2, tweak, guiPacked[isDisabled ? COLOR_FILL : COLOR_TEXTBOX], guiPacked[isDisabled ? COLOR_FILL : COLOR_TEXTBOX]);
- if (isChecked) {
- sge_FilledCircleDual(surface, x + rad, y + rad, rad - 3, tweak, guiPacked[COLOR_DARK1], guiPacked[COLOR_DARK1]);
- sge_FilledCircleDual(surface, x + rad, y + rad, rad - 4, tweak, guiPacked[isDisabled ? COLOR_DARK1 : COLOR_TEXT], guiPacked[isDisabled ? COLOR_DARK1 : COLOR_TEXT]);
- }
- }
- else {
- drawRect(x, y, size, size, guiPacked[COLOR_FILL], surface);
- drawGuiBoxInvert(x, y, size, size, 2, surface);
- if (!isDisabled) drawRect(x + 2, y + 2, size - 4, size - 4, guiPacked[COLOR_TEXTBOX], surface);
- if (isChecked) {
- sge_Line(surface, x + 4, y + 3, x + size - 4, y + size - 5, guiPacked[COLOR_DARK2]);
- sge_Line(surface, x + 3, y + 3, x + size - 4, y + size - 4, guiPacked[isDisabled ? COLOR_DARK1 : COLOR_TEXT]);
- sge_Line(surface, x + 3, y + 4, x + size - 5, y + size - 4, guiPacked[COLOR_DARK2]);
- sge_Line(surface, x + 4, y + size - 4, x + size - 4, y + 4, guiPacked[COLOR_DARK2]);
- sge_Line(surface, x + 3, y + size - 4, x + size - 4, y + 3, guiPacked[isDisabled ? COLOR_DARK1 : COLOR_TEXT]);
- sge_Line(surface, x + 3, y + size - 5, x + size - 5, y + 3, guiPacked[COLOR_DARK2]);
- }
- }
- }
- int fontHeight(int font) { start_func
- assert(font >= 0);
- assert(font < FONT_COUNT);
- assert(fonts[font].font);
- return fonts[font].height;
- }
- int fontAscent(int font) { start_func
- assert(font >= 0);
- assert(font < FONT_COUNT);
- assert(fonts[font].font);
- return fonts[font].ascent;
- }
- SDL_Surface* createSurface(int width, int height) { start_func
- SDL_Surface* ptr = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, proxyScreen->format->BitsPerPixel,
- proxyScreen->format->Rmask, proxyScreen->format->Gmask, proxyScreen->format->Bmask, proxyScreen->format->Amask);
-
- if (ptr == NULL) fatalCrash(0, "SDL Error allocating surface %d by %d", width, height);
- SDL_SetAlpha(ptr, 0, 255);
- return ptr;
- }
- SDL_Surface* createSurface32(int width, int height) { start_func
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- Uint32 rMask = 0xff000000;
- Uint32 gMask = 0x00ff0000;
- Uint32 bMask = 0x0000ff00;
- Uint32 aMask = 0x000000ff;
- #else
- Uint32 rMask = 0x000000ff;
- Uint32 gMask = 0x0000ff00;
- Uint32 bMask = 0x00ff0000;
- Uint32 aMask = 0xff000000;
- #endif
- SDL_Surface* ptr = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, rMask, gMask, bMask, aMask);
- if (ptr == NULL) fatalCrash(0, "SDL Error allocating surface %d by %d by 8", width, height);
- SDL_SetAlpha(ptr, 0, 255);
- return ptr;
- }
- SDL_Surface* createSurface8(int width, int height) { start_func
- SDL_Surface* ptr = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 8, 0, 0, 0, 0);
- if (ptr == NULL) fatalCrash(0, "SDL Error allocating surface %d by %d by 32", width, height);
- return ptr;
- }
- SDL_Surface* getScreen() { start_func
- assert(proxyScreen);
- return proxyScreen;
- }
- int guiOk() { start_func
- return proxyScreen ? 1 : 0;
- }
- void selectMouse(int type) { start_func
- assert(type >= 0);
- assert(type < MOUSE_COUNT);
- currentMouse = type;
- }
- int mouseTooltipYOffset() { start_func
- return micePointers[currentMouse]->tooltipYOffset();
- }
- void blitMouse() { start_func
- if ((SDL_GetAppState() & SDL_APPMOUSEFOCUS) && (micePointers[currentMouse])) {
- SDL_GetMouseState(&lastMouseX, &lastMouseY);
- if (!requestedGL) {
- if (numUpdate == 1) {
- micePointers[currentMouse]->displayAt(lastMouseX, lastMouseY, mouseUnblit, updateRects + 1);
- numUpdate = 2;
- }
- else {
- micePointers[currentMouse]->displayAt(lastMouseX, lastMouseY, mouseUnblit, updateRects + 2);
- numUpdate = 3;
- }
- mouseBlitted = currentMouse;
- }
- }
- }
- void unblitMouse() { start_func
- if ((mouseBlitted >= 0) && (micePointers[mouseBlitted]) && (!requestedGL)) {
- micePointers[mouseBlitted]->unDisplay(lastMouseX, lastMouseY, mouseUnblit, updateRects + 1);
- if (numUpdate < 2) numUpdate = 2;
- mouseBlitted = -1;
- }
- }
- // Clipping routines
- int intersectRects(Rect& a, const Rect& b) { start_func
- if (a.x < b.x) {
- Sint32 aw = a.w + a.x - b.x;
- if (aw <= 0) {
- a.w = 0;
- return 0;
- }
- a.x = b.x;
- if (aw > b.w) aw = b.w;
- a.w = aw;
- }
- else {
- Sint32 bw = b.w + b.x - a.x;
- if (bw <= 0) {
- a.w = 0;
- return 0;
- }
- if (a.w > bw) a.w = bw;
- }
- if (a.y < b.y) {
- Sint32 ah = a.h + a.y - b.y;
- if (ah <= 0) {
- a.w = 0;
- return 0;
- }
- a.y = b.y;
- if (ah > b.h) ah = b.h;
- a.h = ah;
- }
- else {
- Sint32 bh = b.h + b.y - a.y;
- if (bh <= 0) {
- a.w = 0;
- return 0;
- }
- if (a.h > bh) a.h = bh;
- }
- return a.w;
- }
- int boundRects(Rect& a, const Rect& b) { start_func
- // (special case)
- if (b.w == 0) {
- return a.w;
- }
- if (a.w == 0) {
- a = b;
- return 1;
- }
- if (a.x > b.x) {
- a.w += a.x - b.x;
- a.x = b.x;
- if (a.w < b.w) a.w = b.w;
- }
- else {
- Sint32 bw = b.w + b.x - a.x;
- if (a.w < bw) a.w = bw;
- }
- if (a.y > b.y) {
- a.h += a.y - b.y;
- a.y = b.y;
- if (a.h < b.h) a.h = b.h;
- }
- else {
- Sint32 bh = b.h + b.y - a.y;
- if (a.h < bh) a.h = bh;
- }
- return 1;
- }
- Rect createRect(int x1, int y1, int x2, int y2) { start_func
- Rect data;
-
- if (x1 > x2) swap(x1, x2);
- if (y1 > y2) swap(y1, y2);
-
- data.x = x1;
- data.y = y1;
- data.w = x2 - x1 + 1;
- data.h = y2 - y1 + 1;
-
- return data;
- }
- // Helper function for flood fill
- inline int colorDifference(Uint32 a, Uint32 b) { start_func
- // Special optimized case
- if (a == b) return 0;
-
- // Zero alpha matches itself and itself only, regardless of tolerance
- #if SDL_BYTEORDER == SDL_BIG_ENDIAN
- if (((a & 0x000000ff) == 0) || ((b & 0x000000ff) == 0)) {
- if ((a & 0x000000ff) == (b & 0x000000ff)) return 0;
- // (arbitrarily large value)
- return 0x7FFF;
- }
- #else
- if (((a & 0xff000000) == 0) || ((b & 0xff000000) == 0)) {
- if ((a & 0xff000000) == (b & 0xff000000)) return 0;
- // (arbitrarily large value)
- return 0x7FFF;
- }
- #endif
-
- // Last 8 bits we must shift before subtracting, so negatives are properly discovered
- return
- abs((int)(a & 0x000000FF) - (int)(b & 0x000000FF)) +
- (abs((int)(a & 0x0000FF00) - (int)(b & 0x0000FF00)) >> 8) +
- (abs((int)(a & 0x00FF0000) - (int)(b & 0x00FF0000)) >> 16) +
- abs((int)((a & 0xFF000000) >> 24) - (int)((b & 0xFF000000) >> 24))
- ;
- }
- // Flood fill- see .h for usage notes
- Rect floodFill32(SDL_Surface* src, SDL_Surface* dest, int x, int y, Uint32 color, int tolerance) { start_func
- assert(src);
- assert(dest);
- assert(tolerance >= 0);
- // Min/Max area
- Rect result = { 0, 0, 0, 0 };
- // Clip area
- SDL_Rect Sclip;
- SDL_Rect SclipD;
- SDL_GetClipRect(src, &Sclip);
- SDL_GetClipRect(dest, &SclipD);
- Rect clip = { Sclip.x, Sclip.y, Sclip.w, Sclip.h };
- Rect clipD = { SclipD.x, SclipD.y, SclipD.w, SclipD.h };
- if (!intersectRects(clip, clipD)) return result;
-
- int minX = clip.x;
- int minY = clip.y;
- int maxX = clip.x + clip.w - 1;
- int maxY = clip.y + clip.h - 1;
-
- if ((x < minX) || (x > maxX) || (y < minY) || (y > maxY)) return result;
-
- // Extreme points
- int x1 = x;
- int x2 = x;
- int y1 = y;
- int y2 = y;
-
- // Stack
- #define FLOOD_STACK_SIZE 250
- struct {
- Uint32* s;
- Uint32* d;
- int x;
- int y;
- int yD;
- } floodStack[FLOOD_STACK_SIZE];
- int stackPos = 0;
-
- #define PUSH(sp, dp, xp, yp, ydiff) {\
- if (stackPos < FLOOD_STACK_SIZE) {\
- floodStack[stackPos].s = sp;\
- floodStack[stackPos].d = dp;\
- floodStack[stackPos].x = xp;\
- floodStack[stackPos].y = yp;\
- floodStack[stackPos++].yD = ydiff;\
- }\
- }\
- #define POP(sp, dp, xp, yp, ydiff) {\
- assert(stackPos);\
- sp = floodStack[--stackPos].s;\
- dp = floodStack[stackPos].d;\
- xp = floodStack[stackPos].x;\
- yp = floodStack[stackPos].y;\
- ydiff = floodStack[stackPos].yD;\
- }\
-
- // Starting point and pitch, etc.
- int srcPitch = src->pitch / 4;
- int destPitch = dest->pitch / 4;
- Uint32* srcPoint = (Uint32*)src->pixels + x + y * srcPitch;
- Uint32* destPoint = (Uint32*)dest->pixels + x + y * destPitch;
- Uint32 targetColor = *srcPoint;
-
- // Special case
- if ((src == dest) && (targetColor == color) && (tolerance == 0)) return result;
- // Work areas
- int top, bottom;
- int lX;
- int yDiff;
-
- // Push starting point
- PUSH(srcPoint, destPoint, x, y, 0);
-
- while (stackPos) {
- // Next point to fill, then scan left and right
- POP(srcPoint, destPoint, x, y, yDiff);
- srcPoint += yDiff * srcPitch;
- destPoint += yDiff * destPitch;
- y += yDiff;
-
- // Don't fill given point directly- instead, we'll scan it manually in the second loop
- // Update extreme points- y
- if (y < y1) y1 = y;
- if (y > y2) y2 = y;
-
- // Check both top and bottom for matches
- top = bottom = 1;
-
- // Fill as far left as possible
- lX = x;
- while ((lX > minX) && (colorDifference(srcPoint[-1], targetColor) <= tolerance) && (destPoint[-1] != color)) {
- --lX;
- --srcPoint;
- --destPoint;
- *destPoint = color;
-
- // Is point above fillable?
- if ((y > minY) && (colorDifference(srcPoint[-srcPitch], targetColor) <= tolerance) && (destPoint[-srcPitch] != color)) {
- // Are we pushing "above" points right now?
- if (top) {
- // Push onto stack
- PUSH(srcPoint, destPoint, lX, y, -1);
- top = 0;
- }
- }
- // Not fillable, we will now push the next "above" point we find
- else top = 1;
-
- // Is point below fillable?
- if ((y < maxY) && (colorDifference(srcPoint[srcPitch], targetColor) <= tolerance) && (destPoint[srcPitch] != color)) {
- // Are we pushing "below" points right now?
- if (bottom) {
- // Push onto stack
- PUSH(srcPoint, destPoint, lX, y, 1);
- bottom = 0;
- }
- }
- // Not fillable, we will now push the next "below" point we find
- else bottom = 1;
- }
-
- // Update extreme left point
- if (lX < x1) x1 = lX;
-
- // Recenter, minus one, so that we scan the center/given point as well
- --x;
- srcPoint += x - lX;
- destPoint += x - lX;
- top = bottom = 1;
-
- // Fill as far right as possible; this loop intentionally catches our first, central point
- while ((x < maxX) && (colorDifference(srcPoint[1], targetColor) <= tolerance) && (destPoint[1] != color)) {
- ++x;
- ++srcPoint;
- ++destPoint;
- *destPoint = color;
-
- // Is point above fillable?
- if ((y > minY) && (colorDifference(srcPoint[-srcPitch], targetColor) <= tolerance) && (destPoint[-srcPitch] != color)) {
- // Are we pushing "above" points right now?
- if (top) {
- // Push onto stack
- PUSH(srcPoint, destPoint, x, y, -1);
- top = 0;
- }
- }
- // Not fillable, we will now push the next "above" point we find
- else top = 1;
-
- // Is point below fillable?
- if ((y < maxY) && (colorDifference(srcPoint[srcPitch], targetColor) <= tolerance) && (destPoint[srcPitch] != color)) {
- // Are we pushing "below" points right now?
- if (bottom) {
- // Push onto stack
- PUSH(srcPoint, destPoint, x, y, 1);
- bottom = 0;
- }
- }
- // Not fillable, we will now push the next "below" point we find
- else bottom = 1;
- }
- // Update extreme right point
- if (x > x2) x2 = x;
- }
-
- result.x = x1;
- result.y = y1;
- result.w = x2 - x1 + 1;
- result.h = y2 - y1 + 1;
- return result;
- }
- Rect floodFillNonContiguous32(SDL_Surface* src, SDL_Surface* dest, int x, int y, Uint32 color, int tolerance) { start_func
- assert(src);
- assert(dest);
- assert(tolerance >= 0);
- // Min/Max area
- Rect result = { 0, 0, 0, 0 };
-
- // Clip area
- SDL_Rect Sclip;
- SDL_Rect SclipD;
- SDL_GetClipRect(src, &Sclip);
- SDL_GetClipRect(dest, &SclipD);
- Rect clip = { Sclip.x, Sclip.y, Sclip.w, Sclip.h };
- Rect clipD = { SclipD.x, SclipD.y, SclipD.w, SclipD.h };
- if (!intersectRects(clip, clipD)) return result;
-
- int minX = clip.x;
- int minY = clip.y;
- int maxX = clip.x + clip.w - 1;
- int maxY = clip.y + clip.h - 1;
-
- if ((x < minX) || (x > maxX) || (y < minY) || (y > maxY)) return result;
-
- // Extreme points
- int x1 = x;
- int x2 = x;
- int y1 = y;
- int y2 = y;
-
- // Starting point and pitch, etc.
- int srcPitch = src->pitch / 4;
- int destPitch = dest->pitch / 4;
- Uint32* srcPoint = (Uint32*)src->pixels + minX + minY * srcPitch;
- Uint32* destPoint = (Uint32*)dest->pixels + minX + minY * destPitch;
- Uint32 targetColor = *((Uint32*)src->pixels + x + y * (src->pitch / 4));
- // Special case
- if ((src == dest) && (targetColor == color) && (tolerance == 0)) return result;
-
- // Preadjust pitches
- srcPitch -= maxX - minX + 1;
- destPitch -= maxX - minX + 1;
- for (y = minY; y <= maxY; ++y) {
- for (x = minX; x <= maxX; ++x) {
- if (colorDifference(*srcPoint, targetColor) <= tolerance) {
- *destPoint = color;
-
- // Update extreme points
- if (y < y1) y1 = y;
- if (y > y2) y2 = y;
- if (x < x1) x1 = x;
- if (x > x2) x2 = x;
- }
-
- ++srcPoint;
- ++destPoint;
- }
-
- srcPoint += srcPitch;
- destPoint += destPitch;
- }
-
- result.x = x1;
- result.y = y1;
- result.w = x2 - x1 + 1;
- result.h = y2 - y1 + 1;
- return result;
- }
|