2 Copyright (C) 2004 Parallel Realities
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 for (int i = 0 ; i < MAX_TILES ; i++)
38 takeRandomScreenShots = false;
47 debug(("graphics.free: Background\n"));
48 if (background != NULL)
50 SDL_FreeSurface(background);
52 debug(("graphics.free: Background - Done\n"));
56 debug(("graphics.free: Tiles\n"));
57 for (int i = 0 ; i < MAX_TILES ; i++)
61 SDL_FreeSurface(tile[i]);
65 debug(("graphics.free: Tiles - Done\n"));
67 debug(("graphics.free: Sprites\n"));
68 Sprite *sprite = (Sprite*)spriteList.getHead();
69 while (sprite->next != NULL)
71 sprite = (Sprite*)sprite->next;
72 //debug(("graphics.free: Sprites Sprite::Free - %s\n", sprite->name));
75 debug(("graphics.free: Sprites Clear()\n"));
77 debug(("graphics.free: Sprites - Done\n"));
80 void Graphics::destroy()
84 for (int i = 0 ; i < 5 ; i++)
88 TTF_CloseFont(font[i]);
95 SDL_FreeSurface(fadeBlack);
100 SDL_FreeSurface(infoBar);
104 void Graphics::registerEngine(Engine *engine)
106 this->engine = engine;
109 void Graphics::mapColors()
111 red = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00);
112 yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0x00);
113 green = SDL_MapRGB(screen->format, 0x00, 0xff, 0x00);
114 darkGreen = SDL_MapRGB(screen->format, 0x00, 0x77, 0x00);
115 skyBlue = SDL_MapRGB(screen->format, 0x66, 0x66, 0xff);
116 blue = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
117 cyan = SDL_MapRGB(screen->format, 0x00, 0x99, 0xff);
118 white = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
119 lightGrey = SDL_MapRGB(screen->format, 0xcc, 0xcc, 0xcc);
120 grey = SDL_MapRGB(screen->format, 0x88, 0x88, 0x88);
121 darkGrey = SDL_MapRGB(screen->format, 0x33, 0x33, 0x33);
122 black = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
124 fontForeground.r = fontForeground.g = fontForeground.b = 0xff;
125 fontBackground.r = fontBackground.g = fontBackground.b = 0x00;
127 fontForeground.unused = fontBackground.unused = 0;
129 fadeBlack = alphaRect(640, 480, 0x00, 0x00, 0x00);
131 infoBar = alphaRect(640, 25, 0x00, 0x00, 0x00);
134 Sprite *Graphics::getSpriteHead()
136 return (Sprite*)spriteList.getHead();
139 void Graphics::setTransparent(SDL_Surface *sprite)
141 SDL_SetColorKey(sprite, (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(sprite->format, 0, 0, 0));
144 void Graphics::updateScreen()
149 if (takeRandomScreenShots)
151 if ((Math::prand() % 500) == 0)
153 sprintf(screenshot, "screenshots/screenshot%.3d.bmp", screenShotNumber);
154 SDL_SaveBMP(screen, screenshot);
161 if (engine->keyState[SDLK_F12])
163 sprintf(screenshot, "screenshots/screenshot%.3d.bmp", screenShotNumber);
164 SDL_SaveBMP(screen, screenshot);
167 engine->keyState[SDLK_F12] = 0;
170 if ((engine->keyState[SDLK_F10]) || ((engine->keyState[SDLK_RETURN]) && (engine->keyState[SDLK_LALT])))
172 SDL_WM_ToggleFullScreen(screen);
173 engine->fullScreen = !engine->fullScreen;
175 engine->keyState[SDLK_F10] = engine->keyState[SDLK_LALT] = engine->keyState[SDLK_RETURN] = 0;
179 void Graphics::delay(int time)
181 unsigned long then = SDL_GetTicks();
183 engine->keyState[SDLK_ESCAPE] = 0;
189 if (SDL_GetTicks() >= then + time)
197 if (engine->keyState[SDLK_ESCAPE])
205 void Graphics::RGBtoHSV(float r, float g, float b, float *h, float *s, float *v)
208 mn = min(min(r, g), b);
209 mx = max(max(r, g), b);
226 *h = (g - b) / delta;
230 *h = 2 + (b - r) / delta;
234 *h = 4 + (r - g) / delta;
245 void Graphics::HSVtoRGB(float *r, float *g, float *b, float h, float s, float v)
260 t = v * (1 - s * (1 - f));
302 SDL_Surface *Graphics::loadImage(const char *filename)
304 SDL_Surface *image, *newImage;
307 if (!engine->unpack(filename, PAK_IMG))
308 showErrorAndExit(ERR_FILE, filename);
309 image = IMG_Load_RW(engine->sdlrw, 1);
311 image = IMG_Load(filename);
315 showErrorAndExit(ERR_FILE, filename);
317 newImage = SDL_DisplayFormat(image);
321 SDL_FreeSurface(image);
325 // This happens when we are loading the window icon image
329 setTransparent(newImage);
334 SDL_Surface *Graphics::loadImage(const char *filename, int hue, int sat, int value)
336 SDL_Surface *image, *newImage;
339 if (!engine->unpack(filename, PAK_IMG))
340 showErrorAndExit(ERR_FILE, filename);
341 image = IMG_Load_RW(engine->sdlrw, 1);
343 image = IMG_Load(filename);
347 showErrorAndExit(ERR_FILE, filename);
349 if ((hue != 0) || (sat != 0) || (value != 0))
351 if (image->format->BitsPerPixel != 8)
353 debug(("WARNING: Could not set Hue for '%s'! Not an 8 bit image!\n", filename));
358 float r, g, b, h, s, v;
360 if (image->format->palette->colors != NULL)
362 for (int i = 1 ; i < image->format->palette->ncolors ; i++)
364 color = &image->format->palette->colors[i];
370 RGBtoHSV(r, g, b, &h, &s, &v);
376 HSVtoRGB(&r, &g, &b, h, s, v);
387 newImage = SDL_DisplayFormat(image);
391 SDL_FreeSurface(image);
395 // This happens when we are loading the window icon image
399 setTransparent(newImage);
404 SDL_Surface *Graphics::quickSprite(const char *name, SDL_Surface *image)
406 Sprite *sprite = addSprite(name);
407 sprite->setFrame(0, image, 60);
409 return sprite->getCurrentFrame();
412 void Graphics::fade(int amount)
414 SDL_SetAlpha(fadeBlack, SDL_SRCALPHA|SDL_RLEACCEL, amount);
415 blit(fadeBlack, 0, 0, screen, false);
418 void Graphics::fadeToBlack()
424 SDL_SetAlpha(fadeBlack, SDL_SRCALPHA|SDL_RLEACCEL, start);
425 blit(fadeBlack, 0, 0, screen, false);
431 void Graphics::loadMapTiles(const char *baseDir)
433 bool found, autoAlpha;
435 strcpy(filename, "");
439 if (strcmp(baseDir, "gfx/common") == 0)
448 for (int i = 1 ; i < MAX_TILES ; i++)
452 sprintf(filename, "%s/%d.png", baseDir, i);
456 if (!engine->getPak()->fileExists(filename))
461 fp = fopen(filename, "rb");
470 tile[i] = loadImage(filename);
474 if ((i < MAP_EXITSIGN) || (i >= MAP_WATERANIM))
476 SDL_SetAlpha(tile[i], SDL_SRCALPHA|SDL_RLEACCEL, 130);
481 if (i < MAP_DECORATION)
483 SDL_SetColorKey(tile[i], 0, SDL_MapRGB(tile[i]->format, 0, 0, 0));
491 Note : We need to search for the right >>> PIXEL SIZE <<< and NOT point size!!
492 If a user has a resolution other than approximately 72dpi then
493 they will get a small or larger font and this won't work. This might look
494 weird since we'll load and delete multiple fonts, but it works...
496 void Graphics::loadFont(int i, const char *filename, int pixelSize)
498 int minx, maxx, miny, maxy, advance;
500 debug(("Attempting to load a font with pixel size of %d...\n", pixelSize));
504 debug(("Freeing Font %d first...\n", i));
505 TTF_CloseFont(font[i]);
508 char tempPath[PATH_MAX];
510 sprintf(tempPath, "%sfont.ttf", engine->userHomeDirectory);
519 TTF_CloseFont(font[i]);
523 font[i] = TTF_OpenFont(tempPath, ++size);
525 font[i] = TTF_OpenFont("data/vera.ttf", ++size);
530 engine->reportFontFailure();
533 TTF_GlyphMetrics(font[i], '8', &minx, &maxx, &miny, &maxy, &advance);
535 // great! we have an exact match
536 if (maxx == pixelSize)
541 // we've overshot, so we'll use the previous size!
542 if (maxx > pixelSize)
544 TTF_CloseFont(font[i]);
547 font[i] = TTF_OpenFont(tempPath, size - 1);
549 font[i] = TTF_OpenFont("data/vera.ttf", size - 1);
552 TTF_GlyphMetrics(font[i], '8', &minx, &maxx, &miny, &maxy, &advance);
559 debug(("Pixel size has exceeded 99 pixels! I'm giving up!\n"));
560 engine->reportFontFailure();
564 TTF_SetFontStyle(font[i], TTF_STYLE_NORMAL);
566 debug(("Got a match for font size %d - Nearest = %d\n", pixelSize, maxx));
569 Sprite *Graphics::addSprite(const char *name)
571 Sprite *sprite = new Sprite;
572 strcpy(sprite->name, name);
574 spriteList.add(sprite);
579 Sprite *Graphics::getSprite(const char *name, bool required)
581 Sprite *sprite = (Sprite*)spriteList.getHead();
583 while (sprite->next != NULL)
585 sprite = (Sprite*)sprite->next;
587 if (strcmp(sprite->name, name) == 0)
594 showErrorAndExit("The requested sprite '%s' does not exist", name);
599 void Graphics::animateSprites()
601 Sprite *sprite = (Sprite*)spriteList.getHead();
603 while (sprite->next != NULL)
605 sprite = (Sprite*)sprite->next;
610 if ((engine->getFrameLoop() % 8) == 0)
612 Math::wrapInt(&(++waterAnim), 201, 204);
613 Math::wrapInt(&(++slimeAnim), 207, 212);
614 Math::wrapInt(&(++lavaAnim), 214, 220);
618 int Graphics::getWaterAnim()
623 int Graphics::getSlimeAnim()
628 int Graphics::getLavaAnim()
633 int Graphics::getLavaAnim(int current)
635 if ((engine->getFrameLoop() % 8) == 0)
636 return Math::rrand(214, 220);
641 void Graphics::loadBackground(const char *filename)
643 if (background != NULL)
644 SDL_FreeSurface(background);
646 if (strcmp(filename, "@none@") == 0)
649 background = loadImage(filename);
651 SDL_SetColorKey(background, 0, SDL_MapRGB(background->format, 0, 0, 0));
654 void Graphics::putPixel(int x, int y, Uint32 pixel, SDL_Surface *dest)
656 if ((x < 0) || (x > 639) || (y < 0) || (y > 479))
659 int bpp = dest->format->BytesPerPixel;
660 /* Here p is the address to the pixel we want to set */
661 Uint8 *p = (Uint8 *)dest->pixels + y * dest->pitch + x * bpp;
670 *(Uint16 *)p = pixel;
674 if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
676 p[0] = (pixel >> 16) & 0xff;
677 p[1] = (pixel >> 8) & 0xff;
683 p[1] = (pixel >> 8) & 0xff;
684 p[2] = (pixel >> 16) & 0xff;
689 *(Uint32 *)p = pixel;
694 Uint32 Graphics::getPixel(SDL_Surface *surface, int x, int y)
696 if ((x < 0) || (x > (surface->w - 1)) || (y < 0) || (y > (surface->h - 1)))
699 int bpp = surface->format->BytesPerPixel;
700 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
710 if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
711 return p[0] << 16 | p[1] << 8 | p[2];
713 return p[0] | p[1] << 8 | p[2] << 16;
719 return 0; /* shouldn't happen, but avoids warnings */
723 void Graphics::drawLine(float startX, float startY, float endX, float endY, int color, SDL_Surface *dest)
729 Math::calculateSlope(startX, startY, endX, endY, &dx, &dy);
733 putPixel((int)startX, (int)startY, color, dest);
735 if ((int)startX == (int)endX)
745 void Graphics::blit(SDL_Surface *image, int x, int y, SDL_Surface *dest, bool centered)
749 showErrorAndExit("graphics::blit() - NULL pointer", SDL_GetError());
752 if ((x < -image->w) || (x > 640 + image->w))
755 if ((y < -image->h) || (y > 480 + image->h))
758 // Set up a rectangle to draw to
763 gRect.x -= (image->w / 2);
764 gRect.y -= (image->h / 2);
770 /* Blit onto the screen surface */
771 if (SDL_BlitSurface(image, NULL, dest, &gRect) < 0)
772 showErrorAndExit("graphics::blit() - %s", SDL_GetError());
775 void Graphics::drawBackground()
777 if (background != NULL)
778 blit(background, 0, 0, screen, false);
780 SDL_FillRect(screen, NULL, black);
783 void Graphics::drawBackground(SDL_Rect *r)
785 if (r->x < 0) r->x = 0;
786 if (r->y < 0) r->y = 0;
787 if (r->x + r->w > 639) r->w = 640 - r->x;
788 if (r->y + r->h > 639) r->h = 480 - r->y;
790 if (SDL_BlitSurface(background, r, screen, r) < 0)
791 showErrorAndExit("graphics::blit() - %s", SDL_GetError());
794 void Graphics::drawRect(int x, int y, int w, int h, int color, SDL_Surface *dest)
801 SDL_FillRect(dest, &gRect, color);
804 void Graphics::drawRect(int x, int y, int w, int h, int color, int borderColor, SDL_Surface *dest)
806 drawRect(x - 1, y - 1, w + 2, h + 2, borderColor, dest);
807 drawRect(x, y, w, h, color, dest);
810 void Graphics::setFontColor(int red, int green, int blue, int red2, int green2, int blue2)
812 fontForeground.r = red;
813 fontForeground.g = green;
814 fontForeground.b = blue;
816 fontBackground.r = red2;
817 fontBackground.g = green2;
818 fontBackground.b = blue2;
820 fontForeground.unused = fontBackground.unused = 0;
823 void Graphics::setFontSize(int size)
826 Math::limitInt(&fontSize, 0, 4);
829 SDL_Surface *Graphics::getString(const char *in, bool transparent)
831 SDL_Surface *text = TTF_RenderUTF8_Shaded(font[fontSize], in, fontForeground, fontBackground);
835 text = TTF_RenderUTF8_Shaded(font[fontSize], "FONT_ERROR", fontForeground, fontBackground);
839 setTransparent(text);
844 void Graphics::drawString(const char *in, int x, int y, int alignment, SDL_Surface *dest)
848 SDL_Surface *text = TTF_RenderUTF8_Shaded(font[fontSize], in, fontForeground, fontBackground);
852 text = TTF_RenderUTF8_Shaded(font[fontSize], "FONT_ERROR", fontForeground, fontBackground);
855 if (alignment == TXT_RIGHT) x -= text->w;
856 if (alignment == TXT_CENTERED) center = true;
858 setTransparent(text);
859 blit(text, x, y, dest, center);
860 SDL_FreeSurface(text);
863 void Graphics::clearChatString()
865 strcpy(chatString, "");
868 void Graphics::createChatString(const char *in)
870 sprintf(chatString, "%s %s", chatString, in);
873 void Graphics::drawChatString(SDL_Surface *surface, int y)
875 char *word = strtok(chatString, " ");
876 char wordWithSpace[100];
881 int surfaceWidth = surface->w - 10;
883 SDL_Surface *wordSurface;
887 if (strcmp(word, "<RGB>") == 0)
889 r = atoi(strtok(NULL, " "));
890 g = atoi(strtok(NULL, " "));
891 b = atoi(strtok(NULL, " "));
893 if ((!r) && (!g) && (!b))
895 debug(("Parse Error in Text Color (%d:%d:%d)!!\n", r, g, b));
899 setFontColor(r, g, b, 0, 0, 0);
901 word = strtok(NULL, " ");
906 sprintf(wordWithSpace, "%s ", word);
908 wordSurface = getString(wordWithSpace, false);
910 if (x + wordSurface->w > surfaceWidth)
912 y += (int)(wordSurface->h * 1.5) ;
916 blit(wordSurface, x, y, surface, false);
918 SDL_FreeSurface(wordSurface);
922 word = strtok(NULL, " ");
926 void Graphics::drawWidgetRect(int x, int y, int w, int h)
928 drawRect(x - 5, y - 4, w + 10, h + 8, white, screen);
929 drawRect(x - 4, y - 3, w + 8, h + 6, black, screen);
930 drawRect(x - 3, y - 2, w + 6, h + 4, green, screen);
933 SDL_Surface *Graphics::createSurface(int width, int height)
935 SDL_Surface *surface, *newImage;
937 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
940 showErrorAndExit("CreateRGBSurface failed: %s\n", SDL_GetError());
942 newImage = SDL_DisplayFormat(surface);
944 SDL_FreeSurface(surface);
949 SDL_Surface *Graphics::alphaRect(int width, int height, Uint8 red, Uint8 green, Uint8 blue)
951 SDL_Surface *surface = createSurface(width, height);
953 SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, red, green, blue));
955 SDL_SetAlpha(surface, SDL_SRCALPHA|SDL_RLEACCEL, 130);
960 void Graphics::colorize(SDL_Surface *image, int red, int green, int blue)
962 SDL_Surface *alpha = alphaRect(image->w, image->h, red, green, blue);
964 blit(alpha, 0, 0, image, false);
966 SDL_SetColorKey(image, (SDL_SRCCOLORKEY|SDL_RLEACCEL), SDL_MapRGB(image->format, red / 2, green / 2, blue / 2));
969 void Graphics::lock(SDL_Surface *surface)
971 /* Lock the screen for direct access to the pixels */
972 if (SDL_MUSTLOCK(surface))
974 if (SDL_LockSurface(surface) < 0 )
976 showErrorAndExit("Could not lock surface", "");
981 void Graphics::unlock(SDL_Surface *surface)
983 if (SDL_MUSTLOCK(surface))
985 SDL_UnlockSurface(surface);
989 void Graphics::resetLoading()
994 void Graphics::showLoading(int amount, int max)
1002 Math::limitInt(&(currentLoading += amount), 0, max);
1004 drawRect(120, 420, 400, 10, black, white, screen);
1005 drawRect(121, 421, currentLoading, 8, red, screen);
1007 SDL_UpdateRect(screen, 120, 420, 400, 10);
1011 void Graphics::showLicenseErrorAndExit()
1013 setFontSize(3); setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
1014 drawString("License Agreement Missing", 320, 50, true, screen);
1016 setFontSize(1); setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
1018 drawString("The GNU General Public License was not found.", 320, 180, true, screen);
1019 drawString("It could either not be properly loaded or has been removed.", 320, 220, true, screen);
1020 drawString("Blob Wars : Metal Blob Solid will not run with the license missing.", 320, 260, true, screen);
1022 drawString("Blob Wars : Metal Blob Solid will now exit", 320, 420, true, screen);
1023 drawString("Press Escape to continue", 320, 450, true, screen);
1025 engine->flushInput();
1031 if (engine->keyState[SDLK_ESCAPE])
1037 void Graphics::showErrorAndExit(const char *error, const char *param)
1039 SDL_FillRect(screen, NULL, black);
1041 if (strcmp(param, "LICENSE") == 0)
1043 showLicenseErrorAndExit();
1047 sprintf(message, error, param);
1049 setFontSize(3); setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
1050 drawString("An unforseen error has occurred", 320, 50, true, screen);
1051 setFontSize(1); setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
1052 drawString(message, 320, 90, true, screen);
1054 drawString("You may wish to try the following,", 50, 150, false, screen);
1057 drawString("1) Try reinstalling the game.", 75, 190, false, screen);
1058 drawString("2) Ensure you have SDL 1.2.5 or greater installed.", 75, 210, false, screen);
1059 drawString("3) Ensure you have the latest versions of additional required SDL libraries.", 75, 230, false, screen);
1060 drawString("4) Install using an RPM if you originally built the game from source", 75, 250, false, screen);
1061 drawString("or try building from source if you installed using an RPM.", 75, 270, false, screen);
1062 drawString("5) Visit http://www.parallelrealities.co.uk/blobWars.php and check for updates.", 75, 290, false, screen);
1066 drawString("If problems persist contact Parallel Realities. Please be aware however that we will not", 320, 360, true, screen);
1067 drawString("be able to assist in cases where the code or data has been modified.", 320, 380, true, screen);
1069 drawString("Blob Wars : Metal Blob Solid will now exit", 320, 420, true, screen);
1070 drawString("Press Escape to continue", 320, 450, true, screen);
1072 engine->flushInput();
1078 if (engine->keyState[SDLK_ESCAPE])
1086 void Graphics::showRootWarning()
1088 setFontSize(3); setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
1089 drawString("CAUTION - RUNNING AS ROOT USER!", 320, 50, true, screen);
1091 setFontSize(1); setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
1093 drawString("WARNING - You appear to be running the game as the root user!", 320, 180, true, screen);
1094 drawString("This is not recommended and is it strongly advised that you do not run", 320, 220, true, screen);
1095 drawString("the game as root. You may still continue but consider running as regular user in future!", 320, 260, true, screen);
1097 drawString("Press Space to Exit", 320, 420, true, screen);
1098 drawString("Press Escape to Continue", 320, 450, true, screen);
1100 engine->flushInput();
1107 if (engine->keyState[SDLK_ESCAPE])
1111 else if (engine->keyState[SDLK_SPACE])