/* * Copyright (C) 2002-2007 The Warp Rogue Team * Part of the Warp Rogue Project * * This software is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License. * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY. * * See the license.txt file for more details. */ /* * SDL platform code */ /* * The symbols used by the SDL platform are created by * SDL_ttf. If you want to update the symbol set (needed * after changing colours) you have to recompile the game * with "UPDATE_SYMBOLS" defined and run the game once. * When compiled with "UPDATE_SYMBOLS" defined the game * depends on SDL_ttf 2.0.7 or higher. */ /* #define UPDATE_SYMBOLS */ #if defined(__APPLE__) # include # if defined(UPDATE_SYMBOLS) # include # endif #else # include # if defined(UPDATE_SYMBOLS) # include # endif #endif #define Uses_Ui #define Uses_ProgramManager #define Uses_Game #define Uses_DataFile #define Uses_Options #define Uses_Util #include "mheader.h" /* * image files */ #define FILE_BACKGROUND_IMAGE "back.bmp" #define FILE_ICON_IMAGE "icon.bmp" #define FILE_SYMBOLS_IMAGE "symbols.bmp" #define FILE_CURSOR_IMAGE "cursor.bmp" #if defined(UPDATE_SYMBOLS) #define FILE_SPECIAL_SYMBOLS "./src/platform/sdl/ssym.bmp" #define FILE_FONT "./src/platform/sdl/font.ttf" #endif #define LINE_SKIP_PADDING 3 #define GLYPH_OFFSET 32 #define N_GLYPHS 95 #define DEFAULT_SCREEN_WIDTH 800 #define DEFAULT_SCREEN_HEIGHT 600 #define DEFAULT_COLOUR_DEPTH 16 #define DEFAULT_FONT_SIZE 12 #define DEFAULT_GAMMA 1.0 #define DEFAULT_FULLSCREEN true typedef int SCREEN_HEIGHT; typedef int SCREEN_WIDTH; typedef int COLOUR_DEPTH; typedef float GAMMA_VALUE; static void sdl_init(void); static void sdl_clean_up(void); static void colours_init(void); static void symbols_init(void); static void symbols_clean_up(void); static void cursor_init(void); static void cursor_clean_up(void); static void background_image_init(void); static void background_image_clean_up(void); #if defined(UPDATE_SYMBOLS) static void sdl_ttf_init(void); static void sdl_ttf_clean_up(void); static void font_init(void); static void font_clean_up(void); static void special_symbols_init(void); static void special_symbols_clean_up(void); static void update_symbols(void); #endif static SDL_Surface * Screen = NULL; static Uint32 ScreenBlack; static SCREEN_WIDTH ScreenWidth = DEFAULT_SCREEN_WIDTH; static SCREEN_HEIGHT ScreenHeight = DEFAULT_SCREEN_HEIGHT; static COLOUR_DEPTH ColourDepth = DEFAULT_COLOUR_DEPTH; #if defined(UPDATE_SYMBOLS) static TTF_Font * Font = NULL; static int FontHeight = 0; static int FontPointSize = DEFAULT_FONT_SIZE; static SDL_Surface * SpecialSymbols = NULL; #endif static int FontWidth = 0; static int FontLineSkip = 0; static SDL_Colour Colour[MAX_COLOURS]; static SDL_Colour ColourGlyphBackground; static SCREEN_COORD CursorX = 0; static SCREEN_COORD CursorY = 0; static SDL_Surface * CursorImage = NULL; static SDL_Surface * BackgroundImage = NULL; static SDL_Surface * Symbol = NULL; static SDL_Rect GlyphRect; /* * IO init */ void io_init(void) { sdl_init(); colours_init(); #if defined(UPDATE_SYMBOLS) sdl_ttf_init(); font_init(); special_symbols_init(); update_symbols(); #endif symbols_init(); cursor_init(); background_image_init(); } /* * IO clean up */ void io_clean_up(void) { #if defined(UPDATE_SYMBOLS) special_symbols_clean_up(); font_clean_up(); sdl_ttf_clean_up(); #endif background_image_clean_up(); cursor_clean_up(); symbols_clean_up(); sdl_clean_up(); } /* * updates the screen */ void update_screen(void) { SDL_Flip(Screen); } /* * clears the screen */ void clear_screen(void) { SDL_FillRect(Screen, NULL, ScreenBlack); } /* * places the cursor at the specified location */ void place_cursor_at(SCREEN_COORD y, SCREEN_COORD x) { CursorY = y; CursorX = x; } /* * returns the current Y coordinate of the cursor */ SCREEN_COORD cursor_y(void) { return CursorY; } /* * returns the current X coordinate of the cursor */ SCREEN_COORD cursor_x(void) { return CursorX; } /* * renders the cursor at its current position */ void render_cursor(COLOUR colour) { SDL_Rect rect; SDL_SetColors(CursorImage, &Colour[colour], 1, 1); rect.x = (CursorX * FontWidth); rect.y = (CursorY * FontLineSkip); SDL_BlitSurface(CursorImage, NULL, Screen, &rect); } /* * renders a character at the current cursor position */ void render_char(COLOUR colour, SYMBOL ch) { SDL_Rect dest; if (ch >= SPECIAL_SYMBOL_OFFSET) { ch = N_GLYPHS + (ch - SPECIAL_SYMBOL_OFFSET); } else { ch -= GLYPH_OFFSET; } GlyphRect.x = ch * FontWidth; GlyphRect.y = colour * FontLineSkip; dest.x = CursorX * FontWidth; dest.y = CursorY * FontLineSkip; SDL_BlitSurface(Symbol, &GlyphRect, Screen, &dest); ++CursorX; } /* * renders a character at the specified position */ void render_char_at(COLOUR colour, SCREEN_COORD y, SCREEN_COORD x, SYMBOL c) { CursorY = y; CursorX = x; render_char(colour, c); } /* * get key */ KEY_CODE lowlevel_get_key(void) { SDL_Event event; SDLKey key; do { do { SDL_WaitEvent(&event); if (event.type == SDL_QUIT) { die("abnormal program "\ "termination (SDL_QUIT)" ); } } while (event.type != SDL_KEYDOWN); key = event.key.keysym.sym; } while ( key == SDLK_CAPSLOCK || key == SDLK_RSHIFT || key == SDLK_LSHIFT || key == SDLK_RCTRL || key == SDLK_LCTRL || key == SDLK_RALT || key == SDLK_LALT || key == SDLK_RMETA || key == SDLK_LMETA || key == SDLK_MODE ); switch (event.key.keysym.sym) { case SDLK_ESCAPE: return KEY_ESC; case SDLK_RETURN: /* FALLTHROUGH */ case SDLK_KP_ENTER: return KEY_ENTER; case SDLK_BACKSPACE: return KEY_BKSP; case SDLK_TAB: return KEY_TAB; case SDLK_SPACE: return KEY_SPACE; case SDLK_DELETE: return KEY_DELETE; case SDLK_UP: return KEY_UP; case SDLK_DOWN: return KEY_DOWN; case SDLK_RIGHT: return KEY_RIGHT; case SDLK_LEFT: return KEY_LEFT; case SDLK_F1: return KEY_F1; case SDLK_F2: return KEY_F2; case SDLK_F3: return KEY_F3; case SDLK_F4: return KEY_F4; case SDLK_F5: return KEY_F5; case SDLK_F6: return KEY_F6; case SDLK_F7: return KEY_F7; case SDLK_F8: return KEY_F8; case SDLK_F9: return KEY_F9; case SDLK_F10: return KEY_F10; case SDLK_F11: return KEY_F11; case SDLK_F12: return KEY_F12; case SDLK_KP0: return '0'; case SDLK_KP1: return '1'; case SDLK_KP2: return '2'; case SDLK_KP3: return '3'; case SDLK_KP4: return '4'; case SDLK_KP5: return '5'; case SDLK_KP6: return '6'; case SDLK_KP7: return '7'; case SDLK_KP8: return '8'; case SDLK_KP9: return '9'; case SDLK_PAGEUP: return KEY_PAGE_UP; case SDLK_PAGEDOWN: return KEY_PAGE_DOWN; default: return event.key.keysym.unicode; } } /* * clears a section of the screen for text display */ void clear_text_window(SCREEN_COORD y1, SCREEN_COORD x1, SCREEN_COORD y2, SCREEN_COORD x2 ) { SDL_Rect rect; /* nasty font-dependent hack */ rect.x = x1 * FontWidth - 2; rect.y = y1 * FontLineSkip - 1; rect.w = FontWidth + 4 + FontWidth * (x2 - x1); rect.h = FontLineSkip + 2 + FontLineSkip * (y2 - y1); SDL_FillRect(Screen, &rect, ScreenBlack); } /* * renders the background */ void render_background(void) { int y, x, y_inc, x_inc; SDL_Rect rect; for (y = 0, y_inc = BackgroundImage->h; y <= ScreenHeight; y += y_inc) { for (x = 0, x_inc = BackgroundImage->w; x <= ScreenWidth; x += x_inc) { rect.x = x; rect.y = y; SDL_BlitSurface(BackgroundImage, NULL, Screen, &rect ); } } } /* * waits n seconds */ void sec_sleep(int n_seconds) { SDL_Delay(n_seconds * 1000); } /* * SDL init */ static void sdl_init(void) { SDL_Surface *window_icon; GAMMA_VALUE gamma; Uint32 flags = SDL_SWSURFACE; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0 ) { die("*** SDL ERROR *** unable to initialize SDL (%s)", SDL_GetError() ); } SDL_WM_SetCaption(ENGINE_NAME, ENGINE_NAME); set_data_path(DIR_GRAPHICS, FILE_ICON_IMAGE); window_icon = SDL_LoadBMP(data_path()); if (window_icon == NULL) { die("*** SDL ERROR *** unable to load bitmap (%s)", SDL_GetError() ); } SDL_WM_SetIcon(window_icon, NULL); SDL_FreeSurface(window_icon); if (option_enabled(OPT_FULLSCREEN)) { flags |= SDL_FULLSCREEN; } Screen = SDL_SetVideoMode(ScreenWidth, ScreenHeight, ColourDepth, flags ); if (Screen == NULL) { die("*** SDL ERROR *** unable to set video mode (%s)", SDL_GetError() ); } SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL ); SDL_EnableUNICODE(1); SDL_ShowCursor(SDL_DISABLE); ScreenBlack = SDL_MapRGB(Screen->format, 0x00, 0x00, 0x00); gamma = 1.0 + (option_get_value(OPT_BRIGHTNESS) * 0.1); SDL_SetGamma(gamma, gamma, gamma); } /* * SDL clean up */ static void sdl_clean_up(void) { SDL_Quit(); } /* * Colours init */ static void colours_init(void) { COLOUR i; for (i = 0; i < MAX_COLOURS; i++) { const RGB_DATA *rgb; rgb = colour_rgb(i); Colour[i].r = rgb->red; Colour[i].g = rgb->green; Colour[i].b = rgb->blue; } ColourGlyphBackground = Colour[C_BLACK]; } /* * symbols init */ static void symbols_init(void) { SDL_Surface *symbols_image; set_data_path(DIR_GRAPHICS, FILE_SYMBOLS_IMAGE); symbols_image = SDL_LoadBMP(data_path()); Symbol = SDL_DisplayFormat(symbols_image); SDL_FreeSurface(symbols_image); FontWidth = Symbol->w / N_GLYPHS; FontLineSkip = Symbol->h / MAX_COLOURS; GlyphRect.w = FontWidth; GlyphRect.h = FontLineSkip; } /* * symbols clean up */ static void symbols_clean_up(void) { if (Symbol != NULL) { SDL_FreeSurface(Symbol); } } /* * cursor init */ static void cursor_init(void) { set_data_path(DIR_GRAPHICS, FILE_CURSOR_IMAGE); CursorImage = SDL_LoadBMP(data_path()); if (CursorImage == NULL) { die("*** SDL ERROR *** unable to load bitmap (%s)", SDL_GetError() ); } SDL_SetColorKey(CursorImage, SDL_SRCCOLORKEY | SDL_RLEACCEL, SDL_MapRGB(CursorImage->format, 0, 0, 0) ); } /* * cursor clean up */ static void cursor_clean_up(void) { if (CursorImage != NULL) { SDL_FreeSurface(CursorImage); } } /* * background image init */ static void background_image_init(void) { SDL_Surface *image; set_data_path(DIR_GRAPHICS, FILE_BACKGROUND_IMAGE); image = SDL_LoadBMP(data_path()); if (image == NULL) { die("*** SDL ERROR *** unable to load bitmap (%s)", SDL_GetError() ); } BackgroundImage = SDL_DisplayFormat(image); SDL_FreeSurface(image); } /* * background image clean up */ static void background_image_clean_up(void) { if (BackgroundImage != NULL) { SDL_FreeSurface(BackgroundImage); } } #if defined(UPDATE_SYMBOLS) /* * SDL_ttf init */ static void sdl_ttf_init(void) { if(TTF_Init() == -1) { die("*** SDL_TTF ERROR *** %s", TTF_GetError()); } } /* * SDL_ttf clean up */ static void sdl_ttf_clean_up(void) { TTF_Quit(); } /* * Font init */ static void font_init(void) { int min_x, max_x; Font = TTF_OpenFont(FILE_FONT, FontPointSize); if (Font == NULL) { die("*** SDL_TTF ERROR *** %s", TTF_GetError()); } FontHeight = TTF_FontHeight(Font); FontLineSkip = FontHeight + LINE_SKIP_PADDING; if(TTF_GlyphMetrics(Font,'A', &min_x, &max_x, NULL, NULL, NULL) == -1) { die("*** SDL_TTF ERROR *** %s", TTF_GetError()); } FontWidth = max_x - min_x; GlyphRect.w = FontWidth; GlyphRect.h = FontLineSkip; } /* * Font clean up */ static void font_clean_up(void) { TTF_CloseFont(Font); } /* * special symbols init */ static void special_symbols_init(void) { SpecialSymbols = SDL_LoadBMP(FILE_SPECIAL_SYMBOLS); if (SpecialSymbols == NULL) { die("*** SDL ERROR *** unable to load bitmap (%s)", SDL_GetError() ); } } /* * special symbols clean up */ static void special_symbols_clean_up(void) { if (SpecialSymbols != NULL) { SDL_FreeSurface(SpecialSymbols); } } /* * updates the symbols bitmap */ static void update_symbols(void) { SDL_Rect dest; SDL_Surface *glyph; SDL_Surface *image; Uint32 black; int i; int colour; image = SDL_CreateRGBSurface( SDL_SWSURFACE, FontWidth * (N_GLYPHS + 2), FontLineSkip * MAX_COLOURS, 16, 0, 0, 0, 0 ); black = SDL_MapRGB(image->format, 0x00, 0x00, 0x00); for (colour = 0; colour < MAX_COLOURS; colour++) { for (i = 0; i < N_GLYPHS; i++) { int min_x, max_y; TTF_GlyphMetrics(Font, i + GLYPH_OFFSET, &min_x, NULL, NULL, &max_y, NULL ); glyph = TTF_RenderGlyph_Shaded(Font, i + GLYPH_OFFSET, Colour[colour], ColourGlyphBackground ); GlyphRect.x = i * FontWidth; GlyphRect.y = colour * FontLineSkip; dest.x = GlyphRect.x + min_x; dest.y = GlyphRect.y + FontHeight - max_y - 1; SDL_FillRect(image, &GlyphRect, black); SDL_BlitSurface(glyph, NULL, image, &dest); SDL_FreeSurface(glyph); } SDL_SetColors(SpecialSymbols, &Colour[colour], 1, 1); dest.x = (N_GLYPHS + 1) * FontWidth; dest.y = colour * FontLineSkip; GlyphRect.x = 1 * FontWidth; GlyphRect.y = 0 * FontHeight; SDL_BlitSurface(SpecialSymbols, &GlyphRect, image, &dest); dest.x = N_GLYPHS * FontWidth; dest.y = colour * FontLineSkip; GlyphRect.x = 0 * FontWidth; GlyphRect.y = 0 * FontHeight; SDL_BlitSurface(SpecialSymbols, &GlyphRect, image, &dest); } set_data_path(DIR_GRAPHICS, FILE_SYMBOLS_IMAGE); SDL_SaveBMP(image, data_path()); SDL_FreeSurface(image); } #endif