/*************************************************************************** sdl.c - description ------------------- begin : Thu Apr 20 2000 copyright : (C) 2000 by Michael Speck email : kulkanie@gmx.net ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #include #include #include #include "sdl.h" #ifdef USE_PNG #include #endif Sdl sdl; SDL_Cursor *empty_cursor = 0; SDL_Cursor *std_cursor = 0; /* ==================================================================== Default video modes. The first value is the id and indicates if a mode is a standard video mode. If the mode was created by directly by video_mode() this id is set to -1. The very last value indicates if this is a valid mode and is checked by init_sdl(). Init_sdl sets the available desktop bit depth. ==================================================================== */ int const mode_count = 2; Video_Mode modes[] = { { 0, "640x480x16 Window", 640, 480, 8, SDL_SWSURFACE, 0 }, { 1, "640x480x16 Fullscreen", 640, 480, 8, SDL_SWSURFACE | SDL_FULLSCREEN, 0 }, }; Video_Mode *def_mode = &modes[0]; /* default resolution */ Video_Mode cur_mode; /* current video mode set in set_video_mode */ /* timer */ int cur_time, last_time; /* sdl surface */ #ifdef USE_PNG /* loads an image from png file and returns surface * or NULL in case of error; * you can get additional information with SDL_GetError * * stolen from SDL_image: * * Copyright (C) 1999 Sam Lantinga * * Sam Lantinga * 5635-34 Springhouse Dr. * Pleasanton, CA 94588 (USA) * slouken@devolution.com */ SDL_Surface *load_png( const char *file ) { FILE *volatile fp = NULL; SDL_Surface *volatile surface = NULL; png_structp png_ptr = NULL; png_infop info_ptr = NULL; png_bytep *volatile row_pointers = NULL; png_uint_32 width, height; int bit_depth, color_type, interlace_type; Uint32 Rmask; Uint32 Gmask; Uint32 Bmask; Uint32 Amask; SDL_Palette *palette; int row, i; volatile int ckey = -1; png_color_16 *transv; /* create the PNG loading context structure */ png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL ); if( png_ptr == NULL ) { SDL_SetError( "Couldn't allocate memory for PNG file" ); goto done; } /* allocate/initialize the memory for image information. REQUIRED. */ info_ptr = png_create_info_struct( png_ptr ); if( info_ptr == NULL ) { SDL_SetError( "Couldn't create image information for PNG file" ); goto done; } /* set error handling if you are using setjmp/longjmp method (this is * the normal method of doing things with libpng). REQUIRED unless you * set up your own error handlers in png_create_read_struct() earlier. */ if( setjmp( png_ptr->jmpbuf ) ) { SDL_SetError( "Error reading the PNG file." ); goto done; } /* open file */ fp = fopen( file, "r" ); if( fp == NULL ) { SDL_SetError( "Could not open png file." ); goto done; } png_init_io( png_ptr, fp ); /* read PNG header info */ png_read_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ png_set_strip_16( png_ptr ); /* extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ png_set_packing( png_ptr ); /* scale greyscale values to the range 0..255 */ if( color_type == PNG_COLOR_TYPE_GRAY ) png_set_expand( png_ptr ); /* for images with a single "transparent colour", set colour key; if more than one index has transparency, use full alpha channel */ if( png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS ) ) { int num_trans; Uint8 *trans; png_get_tRNS( png_ptr, info_ptr, &trans, &num_trans, &transv ); if( color_type == PNG_COLOR_TYPE_PALETTE ) { if( num_trans == 1 ) { /* exactly one transparent value: set colour key */ ckey = trans[0]; } else png_set_expand( png_ptr ); } else ckey = 0; /* actual value will be set later */ } if( color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) png_set_gray_to_rgb( png_ptr ); png_read_update_info( png_ptr, info_ptr ); png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL ); /* allocate the SDL surface to hold the image */ Rmask = Gmask = Bmask = Amask = 0 ; if( color_type != PNG_COLOR_TYPE_PALETTE ) { if( SDL_BYTEORDER == SDL_LIL_ENDIAN ) { Rmask = 0x000000FF; Gmask = 0x0000FF00; Bmask = 0x00FF0000; Amask = (info_ptr->channels == 4) ? 0xFF000000 : 0; } else { int s = (info_ptr->channels == 4) ? 0 : 8; Rmask = 0xFF000000 >> s; Gmask = 0x00FF0000 >> s; Bmask = 0x0000FF00 >> s; Amask = 0x000000FF >> s; } } surface = SDL_AllocSurface( SDL_SWSURFACE, width, height, bit_depth * info_ptr->channels, Rmask, Gmask, Bmask, Amask ); if( surface == NULL ) { SDL_SetError( "Out of memory" ); goto done; } if( ckey != -1 ) { if( color_type != PNG_COLOR_TYPE_PALETTE ) /* FIXME: should these be truncated or shifted down? */ ckey = SDL_MapRGB( surface->format, (Uint8)transv->red, (Uint8)transv->green, (Uint8)transv->blue ); SDL_SetColorKey( surface, SDL_SRCCOLORKEY, ckey ); } /* create the array of pointers to image data */ row_pointers = (png_bytep*)malloc( sizeof( png_bytep ) * height ); if( ( row_pointers == NULL ) ) { SDL_SetError( "Out of memory" ); SDL_FreeSurface( surface ); surface = NULL; goto done; } for( row = 0; row < (int)height; row++ ) { row_pointers[row] = (png_bytep) (Uint8*)surface->pixels + row * surface->pitch; } /* read the entire image in one go */ png_read_image( png_ptr, row_pointers ); /* read rest of file, get additional chunks in info_ptr - REQUIRED */ png_read_end( png_ptr, info_ptr ); /* load the palette, if any */ palette = surface->format->palette; if( palette ) { if( color_type == PNG_COLOR_TYPE_GRAY ) { palette->ncolors = 256; for( i = 0; i < 256; i++ ) { palette->colors[i].r = i; palette->colors[i].g = i; palette->colors[i].b = i; } } else if( info_ptr->num_palette > 0 ) { palette->ncolors = info_ptr->num_palette; for( i = 0; i < info_ptr->num_palette; ++i ) { palette->colors[i].b = info_ptr->palette[i].blue; palette->colors[i].g = info_ptr->palette[i].green; palette->colors[i].r = info_ptr->palette[i].red; } } } done: /* clean up and return */ png_destroy_read_struct( &png_ptr, info_ptr ? &info_ptr : (png_infopp)0, (png_infopp)0 ); if( row_pointers ) free( row_pointers ); if( fp ) fclose( fp ); return surface; } #endif #define SRC_DIR "" /* return full path of bitmap */ static inline void get_full_bmp_path( char *full_path, char *file_name ) { sprintf(full_path, "%s", file_name ); } /* load a surface from file putting it in soft or hardware mem */ SDL_Surface* load_surf(char *fname, int f) { SDL_Surface *buf; SDL_Surface *new_sur; char path[ 512 ]; SDL_PixelFormat *spf; #ifdef USE_PNG char png_name[32]; #endif #ifdef USE_PNG /* override file name as all graphics were changed from bitmap to png so the extension must be corrected */ memset( png_name, 0, sizeof( png_name ) ); strncpy( png_name, fname, strlen( fname ) - 4 ); strcat( png_name, ".png" ); get_full_bmp_path( path, png_name ); buf = load_png( path ); #else get_full_bmp_path( path, fname ); buf = SDL_LoadBMP( path ); #endif if ( buf == 0 ) { fprintf( stderr, "load_surf: file '%s' not found or not enough memory\n", path ); return NULL; } /* if ( !(f & SDL_HWSURFACE) ) { SDL_SetColorKey( buf, SDL_SRCCOLORKEY, 0x0 ); return buf; } new_sur = create_surf(buf->w, buf->h, f); SDL_BlitSurface(buf, 0, new_sur, 0); SDL_FreeSurface(buf);*/ spf = SDL_GetVideoSurface()->format; new_sur = SDL_ConvertSurface( buf, spf, f ); SDL_FreeSurface( buf ); SDL_SetColorKey( new_sur, SDL_SRCCOLORKEY, 0x0 ); SDL_SetAlpha( new_sur, 0, 0 ); /* no alpha */ return new_sur; } /* create an surface MUST NOT BE USED IF NO SDLSCREEN IS SET */ SDL_Surface* create_surf(int w, int h, int f) { SDL_Surface *sur; SDL_PixelFormat *spf = SDL_GetVideoSurface()->format; if ((sur = SDL_CreateRGBSurface(f, w, h, spf->BitsPerPixel, spf->Rmask, spf->Gmask, spf->Bmask, spf->Amask)) == 0) { fprintf(stderr, "create_surf: not enough memory to create surface...\n"); exit(1); } /* if (f & SDL_HWSURFACE && !(sur->flags & SDL_HWSURFACE)) fprintf(stderr, "unable to create surface (%ix%ix%i) in hardware memory...\n", w, h, spf->BitsPerPixel);*/ SDL_SetColorKey(sur, SDL_SRCCOLORKEY, 0x0); SDL_SetAlpha(sur, 0, 0); /* no alpha */ return sur; } /* * Free a surface if != NULL and set pointer to NULL */ void free_surf( SDL_Surface **surf ) { if ( *surf ) SDL_FreeSurface( *surf ); *surf = 0; } /* lock surface */ inline void lock_surf(SDL_Surface *sur) { if (SDL_MUSTLOCK(sur)) SDL_LockSurface(sur); } /* unlock surface */ inline void unlock_surf(SDL_Surface *sur) { if (SDL_MUSTLOCK(sur)) SDL_UnlockSurface(sur); } /* blit surface with destination DEST and source SOURCE using it's actual alpha and color key settings */ void blit_surf(void) { #ifdef SDL_1_1_5 if (sdl.s.s->flags & SDL_SRCALPHA) SDL_SetAlpha(sdl.s.s, SDL_SRCALPHA, 255 - sdl.s.s->format->alpha); #endif SDL_BlitSurface(sdl.s.s, &sdl.s.r, sdl.d.s, &sdl.d.r); #ifdef SDL_1_1_5 if (sdl.s.s->flags & SDL_SRCALPHA) SDL_SetAlpha(sdl.s.s, SDL_SRCALPHA, 255 - sdl.s.s->format->alpha); #endif } /* do an alpha blit */ void alpha_blit_surf(int alpha) { #ifdef SDL_1_1_5 SDL_SetAlpha(sdl.s.s, SDL_SRCALPHA, 255 - alpha); #else SDL_SetAlpha(sdl.s.s, SDL_SRCALPHA, alpha); #endif SDL_BlitSurface(sdl.s.s, &sdl.s.r, sdl.d.s, &sdl.d.r); SDL_SetAlpha(sdl.s.s, 0, 0); } /* fill surface with color c */ void fill_surf(int c) { SDL_FillRect(sdl.d.s, &sdl.d.r, SDL_MapRGB(sdl.d.s->format, c >> 16, (c >> 8) & 0xFF, c & 0xFF)); } /* set clipping rect */ void set_surf_clip( SDL_Surface *surf, int x, int y, int w, int h ) { SDL_Rect rect = { x, y, w, h }; if ( w == h || h == 0 ) SDL_SetClipRect( surf, 0 ); else SDL_SetClipRect( surf, &rect ); } /* set pixel */ Uint32 set_pixel( SDL_Surface *surf, int x, int y, int pixel ) { int pos = 0; pos = y * surf->pitch + x * surf->format->BytesPerPixel; memcpy( surf->pixels + pos, &pixel, surf->format->BytesPerPixel ); return pixel; } /* get pixel */ Uint32 get_pixel( SDL_Surface *surf, int x, int y ) { int pos = 0; Uint32 pixel = 0; pos = y * surf->pitch + x * surf->format->BytesPerPixel; memcpy( &pixel, surf->pixels + pos, surf->format->BytesPerPixel ); return pixel; } /* draw a shadowed frame and darken contents which starts at cx,cy */ void draw_3dframe( SDL_Surface *surf, int cx, int cy, int w, int h, int border ) { int i, j; SDL_Surface *frame = 0; SDL_Surface *contents = 0; frame = create_surf( w + border * 2, h + border * 2, SDL_SWSURFACE ); SDL_SetColorKey( frame, SDL_SRCCOLORKEY, SDL_MapRGB( surf->format, 0xff, 0, 0 ) ); FULL_DEST( frame ); fill_surf ( 0xff0000 ); /* move contents by border size -1 */ DEST( surf, cx, cy, w, h ); SOURCE( surf, cx - border + 1, cy - border + 1 ); blit_surf(); /* shadow part */ FULL_DEST( frame ); fill_surf ( 0xff0000 ); DEST( frame, 0, 0, w + border, border ); fill_surf( 0x0 ); DEST( frame, 0, 0, border, h + border ); fill_surf( 0x0 ); for ( i = 0; i < border; i++ ) { for ( j = 0; j < border; j++ ) { if ( i < j ) set_pixel( frame, border + w + i, border - j - 1, SDL_MapRGB( frame->format, 0,0,0 ) ); } } for ( i = 0; i < border; i++ ) { for ( j = 0; j < border; j++ ) { if ( i > j ) set_pixel( frame, border - i - 1, border + h + j, SDL_MapRGB( frame->format, 0,0,0 ) ); } } DEST( surf, cx - border, cy - border, w + border * 2, h + border * 2 ); SOURCE( frame, 0, 0 ); alpha_blit_surf( 48 ); /* bright part */ FULL_DEST( frame ); fill_surf ( 0xff0000 ); DEST( frame, w + border, border, border, h + border ); fill_surf( 0xffffff ); DEST( frame, border, h + border, w + border, border ); fill_surf( 0xffffff ); for ( i = 0; i < border; i++ ) { for ( j = 0; j < border; j++ ) { if ( i >= j ) set_pixel( frame, border + w + i, border - j - 1, SDL_MapRGB( frame->format, 0xff,0xff,0xff ) ); } } for ( i = 0; i < border; i++ ) { for ( j = 0; j < border; j++ ) { if ( i <= j ) set_pixel( frame, border - i - 1, border + h + j, SDL_MapRGB( frame->format, 0xff,0xff,0xff ) ); } } DEST( surf, cx - border, cy - border, w + border * 2, h + border * 2 ); SOURCE( frame, 0, 0 ); alpha_blit_surf( 128 ); /* darken contents */ contents = create_surf( w, h, SDL_SWSURFACE ); SDL_SetColorKey( contents, 0, 0 ); FULL_DEST( contents ); fill_surf( 0x0 ); DEST( surf, cx, cy, w, h ); SOURCE( contents, 0, 0 ); alpha_blit_surf( 96 ); SDL_FreeSurface( contents ); SDL_FreeSurface( frame ); } /* sdl font */ /* return full font path */ static void get_full_font_path( char *path, char *file_name ) { strcpy( path, file_name ); /* sprintf(path, "./gfx/fonts/%s", file_name ); */ } /* load a font using the width values in the file */ SDLFont* load_font(char *fname) { SDLFont *fnt = 0; FILE *file = 0; char path[512]; int i; get_full_font_path( path, fname ); fnt = malloc(sizeof(SDLFont)); if (fnt == 0) { fprintf(stderr, "load_font: not enough memory\n"); exit(1); } if ((fnt->pic = load_surf(path, SDL_HWSURFACE)) == 0) return NULL; /* use very first pixel as transparency key */ SDL_SetColorKey( fnt->pic, SDL_SRCCOLORKEY, get_pixel( fnt->pic, 0, 0 ) ); fnt->align = ALIGN_X_LEFT | ALIGN_Y_TOP; fnt->color = 0x00FFFFFF; fnt->height = fnt->pic->h; /* table */ file = fopen(path, "r"); fseek(file, -1, SEEK_END); fread(&fnt->offset, 1, 1, file); #ifdef SDL_DEBUG printf("offset: %i\n", fnt->offset); #endif fseek(file, -2, SEEK_END); fread(&fnt->length, 1, 1, file); #ifdef SDL_DEBUG printf("number: %i\n", fnt->length); #endif fseek(file, -2 - fnt->length, SEEK_END); fread(fnt->char_width, 1, fnt->length, file); #ifdef SDL_DEBUG printf("letter width: %i\n", fnt->length); for (i = 0; i < fnt->length; i++) printf("%i ", fnt->char_width[i]); printf("\n"); #endif fclose(file); /* letter offsets */ fnt->char_offset[0] = 0; for (i = 1; i < fnt->length; i++) fnt->char_offset[i] = fnt->char_offset[i - 1] + fnt->char_width[i - 1]; /* allowed keys */ memset(fnt->keys, 0, 256); for (i = 0; i < fnt->length; i++) { fnt->keys[i + fnt->offset] = 1; } fnt->last_x = fnt->last_y = fnt->last_width = fnt->last_height = 0; return fnt; } /* load a font with fixed size */ SDLFont *load_fixed_font(char *f, int off, int len, int w) { int i; SDLFont *fnt; char path[512]; get_full_font_path( path, f ); fnt = malloc(sizeof(SDLFont)); if (fnt == 0) { fprintf(stderr, "load_fixed_font: not enough memory\n"); exit(1); } if ((fnt->pic = load_surf(path, SDL_HWSURFACE)) == 0) return NULL; /* use very first pixel as transparency key */ SDL_SetColorKey( fnt->pic, SDL_SRCCOLORKEY, get_pixel( fnt->pic, 0, 0 ) ); fnt->align = ALIGN_X_LEFT | ALIGN_Y_TOP; fnt->color = 0x00FFFFFF; fnt->height = fnt->pic->h; fnt->offset = off; fnt->length = len; for (i = 0; i < len; i++) fnt->char_width[i] = w; /* letter offsets */ fnt->char_offset[0] = 0; for (i = 1; i < fnt->length; i++) fnt->char_offset[i] = fnt->char_offset[i - 1] + w; /* allowed keys*/ memset(fnt->keys, 0, 256); for (i = 0; i < fnt->length; i++) { fnt->keys[i + fnt->offset] = 1; } fnt->last_x = fnt->last_y = fnt->last_width = fnt->last_height = 0; return fnt; } /* free memory */ void free_font(SDLFont **fnt) { if ( (*fnt)->pic) SDL_FreeSurface( (*fnt)->pic); free( *fnt ); *fnt = 0; } /* write something with transparency */ int write_text(SDLFont *fnt, SDL_Surface *dest, int x, int y, char *str, int alpha) { int c_abs; int len = strlen(str); int pix_len = 0; int px = x, py = y; int i; SDL_Surface *spf = SDL_GetVideoSurface(); pix_len = text_width(fnt, str); for (i = 0; i < len; i++) if (!fnt->keys[(int)str[i]]) str[i] = ' '; /* alignment */ if (fnt->align & ALIGN_X_CENTER) px -= pix_len >> 1; else if (fnt->align & ALIGN_X_RIGHT) px -= pix_len; if (fnt->align & ALIGN_Y_CENTER) py -= (fnt->height >> 1 ) + 1; else if (fnt->align & ALIGN_Y_BOTTOM) py -= fnt->height; /* do only set last rect if font->save_last is true */ if ( fnt->save_last ) { fnt->last_x = px; if (fnt->last_x < 0) fnt->last_x = 0; fnt->last_y = py; if (fnt->last_y < 0) fnt->last_y = 0; fnt->last_width = pix_len; if (fnt->last_x + fnt->last_width >= spf->w) fnt->last_width = spf->w - fnt->last_x; fnt->last_height = fnt->height; if (fnt->last_y + fnt->last_height >= spf->h) fnt->last_height = spf->h - fnt->last_y; } if (alpha != 0) SDL_SetAlpha(fnt->pic, SDL_SRCALPHA, alpha); else SDL_SetAlpha(fnt->pic, 0, 0); for (i = 0; i < len; i++) { c_abs = str[i] - fnt->offset; DEST(dest, px, py, fnt->char_width[c_abs], fnt->height); SOURCE(fnt->pic, fnt->char_offset[c_abs], 0); blit_surf(); px += fnt->char_width[c_abs]; } return 0; } /* lock font surface */ inline void lock_font(SDLFont *fnt) { if (SDL_MUSTLOCK(fnt->pic)) SDL_LockSurface(fnt->pic); } /* unlock font surface */ inline void unlock_font(SDLFont *fnt) { if (SDL_MUSTLOCK(fnt->pic)) SDL_UnlockSurface(fnt->pic); } /* return last update region */ SDL_Rect last_write_rect(SDLFont *fnt) { SDL_Rect rect={fnt->last_x, fnt->last_y, fnt->last_width, fnt->last_height}; return rect; } /* return the text width in pixels */ int text_width(SDLFont *fnt, char *str) { unsigned int i; int pix_len = 0; for (i = 0; i < strlen(str); i++) pix_len += fnt->char_width[str[i] - fnt->offset]; return pix_len; } /* sdl */ /* initialize sdl */ void init_sdl( int f ) { int i; int valid_depth = 0; /* check flags: if SOUND is not enabled flag SDL_INIT_AUDIO musn't be set */ #ifndef WITH_SOUND if ( f & SDL_INIT_AUDIO ) f = f & ~SDL_INIT_AUDIO; #endif sdl.screen = 0; if (SDL_Init(f) < 0) { fprintf(stderr, "ERR: sdl_init: %s", SDL_GetError()); exit(1); } SDL_EnableUNICODE(1); atexit(SDL_Quit); /* check resolutions */ for ( i = 0; i < mode_count; i++ ) { if ( ( valid_depth = SDL_VideoModeOK( modes[i].width, modes[i].height, modes[i].depth, modes[i].flags ) ) != 0 ) { modes[i].depth = valid_depth; modes[i].ok = 1; printf( "Mode %s valid\n", modes[i].name ); } } /* reset default video mode if none found exit */ if ( !def_mode->ok ) { for ( i = 0; i < mode_count; i++ ) if ( modes[i].ok ) { def_mode = &modes[i]; break; } /* no valid default mode found? exit */ if ( i == mode_count ) { fprintf( stderr, "No valid video mode found!\n" ); exit( 1 ); } } /* create empty cursor */ empty_cursor = create_cursor( 16, 16, 8, 8, " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ); std_cursor = SDL_GetCursor(); } /* free screen */ void quit_sdl(void) { if (sdl.screen) SDL_FreeSurface(sdl.screen); if ( empty_cursor ) SDL_FreeCursor( empty_cursor ); } /* ==================================================================== Get a verified video mode. ==================================================================== */ Video_Mode def_video_mode(void) { return *def_mode; } Video_Mode std_video_mode( int id ) { return modes[id]; } Video_Mode video_mode( int width, int height, int depth, int flags ) { Video_Mode mode; /* set name */ sprintf( mode.name, "%ix%ix%i", width, height, depth ); if ( flags & SDL_FULLSCREEN ) strcat( mode.name, " Fullscreen" ); else strcat( mode.name, " Window" ); /* check mode */ if ( SDL_VideoModeOK( width, height, depth, flags ) != depth ) { fprintf( stderr, "video_mode: %s invalid: using default mode\n", mode.name ); return def_video_mode(); } /* set and return this mode */ mode.id = -1; mode.width = width; mode.height = height; mode.depth = depth; mode.flags = flags; return mode; } /* ==================================================================== Current video mode. ==================================================================== */ Video_Mode* cur_video_mode() { return &cur_mode; } /* ==================================================================== Get a list with all valid standard mode names. ==================================================================== */ char** get_mode_names( int *count ) { char **lines; int i, j; *count = 0; for ( i = 0; i < mode_count; i++ ) if ( modes[i].ok ) (*count)++; lines = calloc( *count, sizeof( char* ) ); for ( i = 0, j = 0; i < mode_count; i++ ) if ( modes[i].ok ) lines[j++] = strdup( modes[i].name ); return lines; } /* ==================================================================== Switch to passed video mode. ==================================================================== */ int set_video_mode( Video_Mode mode ) { #ifdef SDL_DEBUG SDL_PixelFormat *fmt; #endif /* free old screen */ if (sdl.screen) SDL_FreeSurface( sdl.screen ); /* check again */ mode = video_mode( mode.width, mode.height, mode.depth, mode.flags ); /* set as current mode */ cur_mode = mode; /* set video mode */ if ( ( sdl.screen = SDL_SetVideoMode( mode.width, mode.height, mode.depth, mode.flags ) ) == 0 ) { fprintf(stderr, "set_video_mode: cannot allocate screen: %s", SDL_GetError()); return 1; } #ifdef SDL_DEBUG if (f & SDL_HWSURFACE && !(sdl.screen->flags & SDL_HWSURFACE)) fprintf(stderr, "unable to create screen in hardware memory...\n"); if (f & SDL_DOUBLEBUF && !(sdl.screen->flags & SDL_DOUBLEBUF)) fprintf(stderr, "unable to create double buffered screen...\n"); if (f & SDL_FULLSCREEN && !(sdl.screen->flags & SDL_FULLSCREEN)) fprintf(stderr, "unable to switch to fullscreen...\n"); fmt = sdl.screen->format; printf("video mode format:\n"); printf("Masks: R=%i, G=%i, B=%i\n", fmt->Rmask, fmt->Gmask, fmt->Bmask); printf("LShft: R=%i, G=%i, B=%i\n", fmt->Rshift, fmt->Gshift, fmt->Bshift); printf("RShft: R=%i, G=%i, B=%i\n", fmt->Rloss, fmt->Gloss, fmt->Bloss); printf("BBP: %i\n", fmt->BitsPerPixel); printf("-----\n"); #endif return 0; } /* show hardware capabilities */ void hardware_cap() { const SDL_VideoInfo *vi = SDL_GetVideoInfo(); char *ny[2] = {"No", "Yes"}; printf("video hardware capabilities:\n"); printf("Hardware Surfaces: %s\n", ny[vi->hw_available]); printf("HW_Blit (CC, A): %s (%s, %s)\n", ny[vi->blit_hw], ny[vi->blit_hw_CC], ny[vi->blit_hw_A]); printf("SW_Blit (CC, A): %s (%s, %s)\n", ny[vi->blit_sw], ny[vi->blit_sw_CC], ny[vi->blit_sw_A]); printf("HW_Fill: %s\n", ny[vi->blit_fill]); printf("Video Memory: %i\n", vi->video_mem); printf("------\n"); } /* update rectangle (0,0,0,0)->fullscreen */ inline void refresh_screen(int x, int y, int w, int h) { SDL_UpdateRect(sdl.screen, x, y, w, h); } /* draw all update regions */ void refresh_rects() { if (sdl.rect_count == RECT_LIMIT) SDL_UpdateRect(sdl.screen, 0, 0, sdl.screen->w, sdl.screen->h); else SDL_UpdateRects(sdl.screen, sdl.rect_count, sdl.rect); sdl.rect_count = 0; } /* add update region */ void add_refresh_rect(int x, int y, int w, int h) { if (sdl.rect_count == RECT_LIMIT) return; if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } if (x + w > sdl.screen->w) w = sdl.screen->w - x; if (y + h > sdl.screen->h) h = sdl.screen->h - y; if (w <= 0 || h <= 0) return; sdl.rect[sdl.rect_count].x = x; sdl.rect[sdl.rect_count].y = y; sdl.rect[sdl.rect_count].w = w; sdl.rect[sdl.rect_count].h = h; sdl.rect_count++; } #if 0 /* fade screen to black */ static void dim_screen(int steps, int delay, int trp) { #ifndef NODIM SDL_Surface *buffer; int per_step = trp / steps; int i; buffer = create_surf(sdl.screen->w, sdl.screen->h, SDL_SWSURFACE); SDL_SetColorKey(buffer, 0, 0); FULL_DEST(buffer); FULL_SOURCE(sdl.screen); blit_surf(); for (i = 0; i <= trp; i += per_step) { FULL_DEST(sdl.screen); fill_surf(0x0); FULL_SOURCE(buffer); alpha_blit_surf(i); refresh_screen( 0, 0, 0, 0); SDL_Delay(delay); } if (trp == 255) { FULL_DEST(sdl.screen); fill_surf(0x0); refresh_screen( 0, 0, 0, 0); } SDL_FreeSurface(buffer); #else refresh_screen( 0, 0, 0, 0); #endif } /* undim screen */ static void undim_screen(int steps, int delay, int trp) { #ifndef NODIM SDL_Surface *buffer; int per_step = trp / steps; int i; buffer = create_surf(sdl.screen->w, sdl.screen->h, SDL_SWSURFACE); SDL_SetColorKey(buffer, 0, 0); FULL_DEST(buffer); FULL_SOURCE(sdl.screen); blit_surf(); for (i = trp; i >= 0; i -= per_step) { FULL_DEST(sdl.screen); fill_surf(0x0); FULL_SOURCE(buffer); alpha_blit_surf(i); refresh_screen( 0, 0, 0, 0); SDL_Delay(delay); } FULL_DEST(sdl.screen); FULL_SOURCE(buffer); blit_surf(); refresh_screen( 0, 0, 0, 0); SDL_FreeSurface(buffer); #else refresh_screen( 0, 0, 0, 0); #endif } #endif /* 0 */ /* wait for a key */ int wait_for_key() { /* wait for key */ SDL_Event event; while (1) { SDL_WaitEvent(&event); if (event.type == SDL_QUIT) { return 0; } if (event.type == SDL_KEYUP) return event.key.keysym.sym; } } /* wait for a key or mouse click */ void wait_for_click() { /* wait for key or button */ SDL_Event event; while (1) { SDL_WaitEvent(&event); if (event.type == SDL_QUIT) { return; } if (event.type == SDL_KEYUP || event.type == SDL_MOUSEBUTTONUP) return; } } /* lock surface */ inline void lock_screen() { if (SDL_MUSTLOCK(sdl.screen)) SDL_LockSurface(sdl.screen); } /* unlock surface */ inline void unlock_screen() { if (SDL_MUSTLOCK(sdl.screen)) SDL_UnlockSurface(sdl.screen); } /* flip hardware screens (double buffer) */ inline void flip_screen() { SDL_Flip(sdl.screen); } /* cursor */ /* creates cursor */ SDL_Cursor* create_cursor( int width, int height, int hot_x, int hot_y, char *source ) { char *mask = 0, *data = 0; SDL_Cursor *cursor = 0; int i, j, k; char data_byte, mask_byte; int pot; /* meaning of char from source: b : black, w: white, ' ':transparent */ /* create mask&data */ mask = malloc( width * height * sizeof ( char ) / 8 ); data = malloc( width * height * sizeof ( char ) / 8 ); k = 0; for (j = 0; j < width * height; j += 8, k++) { pot = 1; data_byte = mask_byte = 0; /* create byte */ for (i = 7; i >= 0; i--) { switch ( source[j + i] ) { case 'b': data_byte += pot; case 'w': mask_byte += pot; break; } pot *= 2; } /* add to mask */ data[k] = data_byte; mask[k] = mask_byte; } /* create and return cursor */ cursor = SDL_CreateCursor( data, mask, width, height, hot_x, hot_y ); free( mask ); free( data ); return cursor; } /* get milliseconds since last call */ inline int get_time() { int ms; cur_time = SDL_GetTicks(); ms = cur_time - last_time; last_time = cur_time; if (ms == 0) { ms = 1; SDL_Delay(1); } return ms; } /* reset timer */ inline void reset_timer() { last_time = SDL_GetTicks(); } void fade_screen( int type, int length ) { SDL_Surface *buffer = 0; float alpha; float alpha_change; /* per ms */ int leave = 0; int ms; if ( !sdl.fade ) { if ( type == FADE_IN ) refresh_screen( 0, 0, 0, 0 ); else { FULL_DEST( sdl.screen ); fill_surf( 0x0 ); refresh_screen( 0, 0, 0, 0 ); } } /* get screen contents */ buffer = create_surf( sdl.screen->w, sdl.screen->h, SDL_SWSURFACE ); SDL_SetColorKey( buffer, 0, 0 ); FULL_DEST( buffer ); FULL_SOURCE( sdl.screen ); blit_surf(); /* compute alpha and alpha change */ if ( type == FADE_OUT ) { alpha = 0; alpha_change = 255.0 / length; } else { alpha = 255; alpha_change = -255.0 / length; } /* fade */ reset_timer(); while ( !leave ) { ms = get_time(); alpha += alpha_change * ms; if ( type == FADE_OUT && alpha >= 255 ) break; if ( type == FADE_IN && alpha <= 0 ) break; /* update */ FULL_DEST( sdl.screen ); fill_surf(0x0); FULL_SOURCE( buffer ); alpha_blit_surf( (int)alpha ); refresh_screen( 0, 0, 0, 0); } /* update screen */ FULL_DEST( sdl.screen ); FULL_SOURCE( buffer ); if ( type == FADE_IN ) blit_surf(); else fill_surf( 0x0 ); refresh_screen( 0, 0, 0, 0 ); SDL_FreeSurface(buffer); } void take_screenshot( int i ) { char str[32]; sprintf( str, "screenshot%i.bmp", i ); SDL_SaveBMP( sdl.screen, str ); } // Performs Callback at each line point. This came straight from the // asphyxia vga trainers static int PolyHelp (Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, int *buffer) { Sint32 dx, dy, sdx, sdy, x, y, px, py; dx = X2 - X1; dy = Y2 - Y1; sdx = (dx < 0) ? -1 : 1; sdy = (dy < 0) ? -1 : 1; dx = sdx * dx + 1; dy = sdy * dy + 1; x = y = 0; px = X1; py = Y1; if (dx >= dy) { for (x = 0; x < dx; x++) { if (py >= 0) buffer[py] = px; y += dy; if (y >= dx) { y -= dx; py += sdy; } px += sdx; } } else { for (y = 0; y < dy; y++) { if (py >= 0) buffer[py] = px; x += dx; if (x >= dy) { x -= dy; px += sdx; } py += sdy; } } return 0; } int DoFilledPolygon (SDL_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, Sint32 X3, Sint32 Y3, Sint32 X4, Sint32 Y4, Uint32 Color, int alpha) { int cords1[1000]; int cords2[1000]; int i; int miny = 99999; /* xxx */ int maxy = -1; if (Y1 < miny) miny = Y1; if (Y1 > maxy) maxy = Y1; if (Y2 < miny) miny = Y2; if (Y2 > maxy) maxy = Y2; if (Y3 < miny) miny = Y3; if (Y3 > maxy) maxy = Y3; if (Y4 < miny) miny = Y4; if (Y4 > maxy) maxy = Y4; if (miny < 0) miny = 0; memset(cords1, miny*sizeof(int), (maxy-miny+1) * sizeof(int)); memset(cords2, miny*sizeof(int), (maxy-miny+1) * sizeof(int)); PolyHelp (X1, Y1, X2, Y2, cords1); PolyHelp (X4, Y4, X1, Y1, cords1); PolyHelp (X2, Y2, X3, Y3, cords2); PolyHelp (X3, Y3, X4, Y4, cords2); for (i = miny; i <= maxy; i++) { if (cords2[i] > 0) { DoLine (Surface, cords1[i], i, cords2[i], i, Color, alpha); } } return 0; } extern int DoPattern(SDL_Surface *screen, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, Sint32 X3, Sint32 Y3, Sint32 X4, Sint32 Y4, SDL_Surface *pattern) { int cords1[1000]; int cords2[1000]; int i; memset(cords1, 0, sizeof(cords1)); memset(cords2, 0, sizeof(cords2)); PolyHelp (X1, Y1, X2, Y2, cords1); PolyHelp (X4, Y4, X1, Y1, cords1); PolyHelp (X2, Y2, X3, Y3, cords2); PolyHelp (X3, Y3, X4, Y4, cords2); for (i = 0; i < 1000; i++) { if (cords2[i] > 0) { SDL_Rect src; SDL_Rect dest; int w; src.y = i % pattern->h; src.h = 1; dest.y = i; dest.h = 1; src.x = cords1[i] % pattern->w; dest.x = cords1[i]; w = cords2[i] - cords1[i]; if (src.x + w > pattern->w) { src.w = dest.w = pattern->w - src.x; w -= src.w; } else { src.w = dest.w = w; w = 0; } SDL_BlitSurface(pattern, &src, screen, &dest); if (w) { src.x = 0; dest.x += dest.w; src.w = w; dest.w = w; SDL_BlitSurface(pattern, &src, screen, &dest); } } } return 0; } // Performs Callback at each line point. This came straight from the // asphyxia vga trainers int DoLine (SDL_Surface *Surface, Sint32 X1, Sint32 Y1, Sint32 X2, Sint32 Y2, Uint32 Color, int alpha) { Sint32 dx, dy, sdx, sdy, x, y, px, py; dx = X2 - X1; dy = Y2 - Y1; sdx = (dx < 0) ? -1 : 1; sdy = (dy < 0) ? -1 : 1; dx = sdx * dx + 1; dy = sdy * dy + 1; x = y = 0; px = X1; py = Y1; if (dx >= dy) { for (x = 0; x < dx; x++) { PutPixel(Surface, px, py, Color, alpha); y += dy; if (y >= dx) { y -= dx; py += sdy; } px += sdx; } } else { for (y = 0; y < dy; y++) { PutPixel(Surface, px, py, Color, alpha); x += dx; if (x >= dy) { x -= dy; px += sdx; } py += sdy; } } return 0; } void PutPixel(SDL_Surface *screen, int x, int y, Uint32 color, int alpha_i) { if (x < 0 || x >= screen->w || y < 0 || y >= screen->h) return; if ((alpha_i != 0) && (alpha_i != 255)) { Uint8 oldred; Uint8 oldgreen; Uint8 oldblue; Uint8 newred; Uint8 newgreen; Uint8 newblue; float alpha = ((float)(255-alpha_i))/((float)255); SDL_GetPixel(screen, x, y, &oldred, &oldgreen, &oldblue); SDL_GetRGB(color, screen->format, &newred, &newgreen, &newblue); /* * result color <- source color * alpha + dest color * (1-alpha) */ newred = oldred * alpha + newred * (1-alpha); newgreen = oldgreen * alpha + newgreen * (1-alpha); newblue = oldblue * alpha + newblue * (1-alpha); color = SDL_MapRGB(screen->format, newred, newgreen, newblue); } switch (screen->format->BytesPerPixel) { case 1: { /* Assuming 8-bpp */ Uint8 *bufp; bufp = (Uint8 *)screen->pixels + y*screen->pitch + x; *bufp = color; } break; case 2: { /* Probably 15-bpp or 16-bpp */ Uint16 *bufp; bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x; *bufp = color; } break; case 3: { /* Slow 24-bpp mode, usually not used */ Uint8 *bufp; bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3; if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { bufp[0] = color; bufp[1] = color >> 8; bufp[2] = color >> 16; } else { bufp[2] = color; bufp[1] = color >> 8; bufp[0] = color >> 16; } } break; case 4: { /* Probably 32-bpp */ Uint32 *bufp; bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x; *bufp = color; } break; } } /* The most pedantic-a%& getpixel and putpixel ever, hopefully. */ /* There may still be endianness bugs! These will be fixed after adequte testing. XXX XXX XXX */ int SDL_GetPixel (SDL_Surface *f, Uint32 x, Uint32 y, Uint8 *r, Uint8 *g, Uint8 *b) { /*const Uint32 mask[] = {0x0, 0xff, 0xffff, 0xffffff, 0xffffffff};*/ Uint32 pixel; Uint8 *pp; int n; /* general purpose 'n'. */ if (f == NULL) return -1; pp = (Uint8 *) f->pixels; if (x >= f->w || y >= f->h) return -1; pp += (f->pitch * y); pp += (x * f->format->BytesPerPixel); /* we do not lock the surface here, it would be inefficient XXX */ /* this reads the pixel as though it was a big-endian integer XXX */ /* I'm trying to avoid reading part the end of the pixel data by * using a data-type that's larger than the pixels */ for (n = 0, pixel = 0; n < f->format->BytesPerPixel; ++n, ++pp) { #if SDL_BYTEORDER == SDL_LIL_ENDIAN pixel >>= 8; pixel |= *pp << (f->format->BitsPerPixel - 8); #else pixel |= *pp; pixel <<= 8; #endif } SDL_GetRGB(pixel, f->format, r, g, b); return 0; } /* This function looks remarkably similar to the one above. Yes, it's cut * and paste. */ int SDL_PutPixel (SDL_Surface *f, Uint32 x, Uint32 y, Uint8 r, Uint8 g, Uint8 b) { Uint32 pixel; Uint8 *pp; int n; if (f == NULL) return -1; pp = (Uint8 *) f->pixels; if (x >= f->w || y >= f->h) return -1; pp += (f->pitch * y); pp += (x * f->format->BytesPerPixel); pixel = SDL_MapRGB(f->format, r, g, b); for (n = 0; n < f->format->BytesPerPixel; ++n, ++pp) { *pp = (Uint8) (pixel & 0xFF); pixel >>= 8; } return 0; }