#include "SDL/SDL_stdinc.h" #include "SDL/SDL_image.h" #include "graphic.h" #include "utils.h" #define ccc_nooverride 0x00cc0000 #define ccc_terrain 0x0000cc00 #define ccc_nothing 0x00000000 Uint32 getPixel(SDL_Surface *s, int x, int y) { /* 24 bits retournés Uint32 res=0; //FIXME : Big Endian res |= ((Uint8 *)s->pixels)[y*s->pitch + x*s->format->BytesPerPixel+0] << 0; res |= ((Uint8 *)s->pixels)[y*s->pitch + x*s->format->BytesPerPixel+1] << 8; res |= ((Uint8 *)s->pixels)[y*s->pitch + x*s->format->BytesPerPixel+2] << 16; return res; */ return ((Uint32 *)s->pixels)[y*s->w + x]; } Uint32 getPixel8BitPalette(SDL_Surface *s, int x, int y) { Uint8 index; SDL_Color c; Uint32 res=0; index=((Uint8 *)s->pixels)[y*s->pitch + x]; c=s->format->palette->colors[index]; //FIXME : Big Endian res |= c.r << 0; res |= c.g << 8; res |= c.b << 16; return res; } int isTransparent(SDL_Surface *s, int x, int y) { Uint8 index; index=((Uint8 *)s->pixels)[y*s->pitch + x]; return (index == s->format->colorkey); } void putPixel(SDL_Surface *s, int x, int y, Uint32 p) { ((Uint32 *)s->pixels)[y*s->w + x]=p; } SDL_Surface * createSurface(int width, int height) { Uint32 rmask, gmask, bmask, amask; /* SDL interprets each pixel as a 32-bit number, so our masks must depend on the endianness (byte order) of the machine */ #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x00000000; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0x00000000; #endif return SDL_CreateRGBSurface(MY_SDLSURFACE_OPTS, width, height, SCREEN_BPP, rmask, gmask, bmask, amask); } SDL_Surface * loadGif(char *filePath) { return IMG_Load(filePath); } int init(char *winCaption, gameConfig_t *conf, gameGraphics_t *gGraph) { int result; memset(gGraph,0,sizeof(gameGraphics_t)); // SDL subsystems initialization result = SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO ); if ( result != 0 ) { logs2(LOG_ERROR, "init(), SDL_Init()", SDL_GetError()); return 1; } // Screen setup gGraph->screen = SDL_SetVideoMode(conf->screen.w, conf->screen.h, 32, SDL_HWSURFACE | SDL_ASYNCBLIT); if( gGraph->screen == NULL ) { logs2(LOG_ERROR, "init(), SDL_SetVideoMode()", SDL_GetError()); return 2; } gGraph->viewport.w = gGraph->screen->clip_rect.w; gGraph->viewport.h = LEVEL_HEIGHT; // SDL main window caption SDL_WM_SetCaption(winCaption, NULL); // We dont want to see the standard mouse cursor in our main window //TODO: SDL_ShowCursor(0); // Memory allocation and initialization for all display layers gGraph->surfaces.terrain = createSurface(LEVEL_WIDTH, LEVEL_HEIGHT); if( gGraph->surfaces.terrain == NULL ) { logs2(LOG_ERROR, "init(), SDL_createSurface()", SDL_GetError()); return 3; } gGraph->surfaces.stencil = createSurface(LEVEL_WIDTH, LEVEL_HEIGHT); if( gGraph->surfaces.stencil == NULL ) { logs2(LOG_ERROR, "init(), SDL_createSurface()", SDL_GetError()); return 3; } gGraph->surfaces.tmpSurf = createSurface(LEVEL_WIDTH, LEVEL_HEIGHT); if( gGraph->surfaces.tmpSurf == NULL ) { logs2(LOG_ERROR, "init(), SDL_createSurface()", SDL_GetError()); return 3; } SDL_FillRect(gGraph->surfaces.tmpSurf, &(gGraph->surfaces.tmpSurf->clip_rect), 0xcccccccc); return 0; } int paintTerrain(gameIni_t *gIni, gameRess_t *gRess, gameGraphics_t *gGraph) { int res, i, modifier; int x,y,xmin,xmax,ymin,ymax,y2,xdst,ydst; Uint32 dstPixel, dstStencil; SDL_Surface *tile; gGraph->surfaces.terrain=createSurface(LEVEL_WIDTH, LEVEL_HEIGHT); if (gGraph->surfaces.terrain==NULL) { logs(LOG_ERROR, "paintTerrain(), SDL_CreateRGBSurface() returns NULL"); return 1; } gGraph->surfaces.stencil=createSurface(LEVEL_WIDTH, LEVEL_HEIGHT); if (gGraph->surfaces.stencil==NULL) { logs(LOG_ERROR, "paintTerrain(), SDL_CreateRGBSurface() returns NULL"); return 2; } res=SDL_FillRect(gGraph->surfaces.terrain, &(gGraph->surfaces.terrain->clip_rect), gIni->style.bgColor); if (res!=0) { logs(LOG_WARN, "paintTerrain(), SDL_FillRect() failed"); return 3; } res=SDL_FillRect(gGraph->surfaces.stencil, &(gGraph->surfaces.stencil->clip_rect), ccc_nothing); if (res!=0) { logs(LOG_WARN, "paintTerrain(), SDL_FillRect() failed"); return 4; } SDL_LockSurface(gGraph->surfaces.terrain); SDL_LockSurface(gGraph->surfaces.stencil); for(i=0 ; i < gIni->level.terrainCount ; i++) { //FIXME : check sanity for id value tile=gRess->style.tiles[gIni->level.terrains[i].id]; if (tile==NULL) { logs(LOG_ERROR, "paintTerrain(), tile==NULL"); return 5; } // Special modifier values : // 15 : Hidden : Lemini hack. Seems to be the same as NO_OVERRIDE // Combinable modifier : // 8 : NO_OVERRIDE : marquer les pixels comme indestructibles pour les prochains plaquages // 4 : Upside Down // 2 : REMOVE : oublier (rendre transparent) tous les pixels qu'on a déjà plaqué modifier=gIni->level.terrains[i].modifier; // If we match the Lemini hack, change the value to NO_OVERRIDE if (modifier == 15) { modifier=8; } // If both REMOVE and NO_OVERRIDE is enabled, prefer NO_OVERRIDE (turn off REMOVE flag) if ( (modifier & 10) == 10) { modifier &= ~2; } // For each tile pixel, without going outside of the terrain ymin=(gIni->level.terrains[i].ypos>=0)?0:-gIni->level.terrains[i].ypos; ymax=min(tile->clip_rect.h, gGraph->surfaces.terrain->clip_rect.h - gIni->level.terrains[i].ypos); xmin=(gIni->level.terrains[i].xpos>=0)?0:-gIni->level.terrains[i].xpos; xmax=min(tile->clip_rect.w, gGraph->surfaces.terrain->clip_rect.w - gIni->level.terrains[i].xpos); SDL_LockSurface(tile); for (y=ymin; yclip_rect.h-1-y; } else { y2=y; } ydst=gIni->level.terrains[i].ypos+y; xdst=gIni->level.terrains[i].xpos+x; // Act only if current pixel in tile is not transparent if ( ! isTransparent(tile, x, y2) ) { // Always paint pixel, except in one case: // If we are in NO_OVERRIDE mode and there is already a terrain on the current (source) pixel if ( !( (modifier & 8) == 8 && getPixel(gGraph->surfaces.stencil, xdst, ydst) == ccc_terrain ) ) { // If we have REMOVE modifier, dstPixel will be rolled back to bgColor, else, it will be identical to the source pixel. We have to update stencil consistenly. if ( (modifier & 2) == 2 ) { dstPixel=gIni->style.bgColor; dstStencil=ccc_nothing; } else { dstPixel=getPixel8BitPalette(tile, x, y2); dstStencil=ccc_terrain; } putPixel(gGraph->surfaces.terrain,xdst,ydst,dstPixel); putPixel(gGraph->surfaces.stencil,xdst,ydst,dstStencil); } } } } SDL_UnlockSurface(tile); } SDL_UnlockSurface(gGraph->surfaces.stencil); SDL_UnlockSurface(gGraph->surfaces.terrain); return 0; } int repaint(gameObjectsState_t *objStates, gameGraphSurfaces_t *srcSurfs, SDL_Rect *srcRect, SDL_Surface *dstSurf) { int res; gameObjectsState_t objToRepaint; int i; ///findAndZSortObjects(objStates, srcRect, &objToRepaint); objToRepaint=*objStates; for(i=0;i0) break; res=paintObject(objToRepaint.allObj+i, dstSurf, *srcRect); if ( res!=0 ) { logs(LOG_DEBUG, "repaint(), paintObject() failed"); } } printf("res=SDL_BlitSurface(%p, %p, %p, %p);\n", (void*)srcSurfs->terrain, (void*)srcRect, (void*)dstSurf, (void*)srcRect); res=SDL_BlitSurface(srcSurfs->terrain, srcRect, dstSurf, srcRect); if ( res!=0 ) { logs2(LOG_DEBUG, "repaint(), SDL_BlitSurface()", SDL_GetError()); } for(;iobjCount=0; return 0; } int paintObject(struct gameObjectState *obj, SDL_Surface *dstSurf, SDL_Rect dstRect) { //TODO SDL_Rect dstRect; dstRect.x = obj->pos.x; dstRect.y = obj->pos.y; // TODO : blitter tous les objets dans le zOrder, pas que l'objet a rafraichir return SDL_BlitSurface(obj->s, NULL, dstSurf, &dstRect); } int refresh(SDL_Surface *tmpSurf, SDL_Rect *srcRect, SDL_Surface *screen, SDL_Rect dstRect) { int res; res=SDL_BlitSurface(tmpSurf, srcRect, screen, &dstRect); if ( res!=0 ) { logs2(LOG_DEBUG, "refresh(), SDL_BlitSurface()", SDL_GetError()); } SDL_UpdateRect(screen, dstRect.x, dstRect.y, dstRect.w, dstRect.h); return res; }