/* * Copyright (C) 2013 Patrick "P. J." McDermott * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ #include #include "area.h" #include "viewport.h" #include "resources/map.h" #include "resources/tileset.h" #include "logging.h" static void init_map_layers(struct area *); static void blit_map_layers(struct area *); static void blit_map_layer(struct area *, enum map_layer, enum area_layer); struct area * area_new(struct map *map, SDL_Palette *pal) { struct area *a; if (map == NULL) { return NULL; } a = malloc(sizeof(*a)); if (a == NULL) { return NULL; } a->map = map; init_map_layers(a); set_area_palette(a, pal); blit_map_layers(a); return a; } void set_area_palette(struct area *area, SDL_Palette *pal) { enum area_layer l; for (l = 0; l < AREA_LAYERS_MAX; ++l) { SDL_SetPalette(area->map_layers[l], SDL_LOGPAL, pal->colors, 0, pal->ncolors); } } static void init_map_layers(struct area *area) { SDL_Rect dstrect; enum area_layer l; dstrect.x = 0; dstrect.y = 0; dstrect.w = area->map->width * area->map->tilewidth; dstrect.h = area->map->height * area->map->tileheight; for (l = 0; l < AREA_LAYERS_MAX; ++l) { area->map_layers[l] = SDL_CreateRGBSurface( SDL_HWSURFACE | SDL_SRCCOLORKEY, area->map->width * area->map->tilewidth, area->map->height * area->map->tileheight, 8, 0x00, 0x00, 0x00, 0x00); SDL_FillRect(area->map_layers[l], &dstrect, SDL_MapRGB(area->map_layers[l]->format, 0xFC, 0x00, 0xFF)); SDL_SetColorKey(area->map_layers[l], SDL_SRCCOLORKEY, SDL_MapRGB(area->map_layers[l]->format, 0xFC, 0x00, 0xFF)); } } static void blit_map_layers(struct area *area) { blit_map_layer(area, MAP_LAYER_GROUND, AREA_LAYER_BOT); blit_map_layer(area, MAP_LAYER_OBJ_LOW, AREA_LAYER_BOT); blit_map_layer(area, MAP_LAYER_OBJ_MID, AREA_LAYER_MID); blit_map_layer(area, MAP_LAYER_OBJ_HIGH, AREA_LAYER_TOP); } static void blit_map_layer(struct area *area, enum map_layer map_layer, enum area_layer area_layer) { int i; Uint32 gid; int tile_found; struct map_tileset *mts; Uint32 mts_lastgid; SDL_Rect tilerect, layerrect; for (i = 0; i < area->map->width * area->map->height; ++i) { gid = area->map->layers[map_layer].tiles[i]; if (gid == 0) { continue; } tile_found = 0; for (mts = area->map->tilesets_head; mts != NULL; mts = mts->next) { mts_lastgid = mts->firstgid + mts->tileset->width * mts->tileset->height; if (gid >= mts->firstgid && gid < mts_lastgid) { gid -= mts->firstgid; tilerect.x = gid % mts->tileset->width; tilerect.y = gid / mts->tileset->width; tilerect.w = mts->tileset->tilewidth; tilerect.h = mts->tileset->tileheight; tilerect.x *= tilerect.w; tilerect.y *= tilerect.h; layerrect.x = i % area->map->width; layerrect.y = i / area->map->width; layerrect.w = mts->tileset->tilewidth; layerrect.h = mts->tileset->tileheight; layerrect.x *= layerrect.w; layerrect.y *= layerrect.h; #ifdef DEBUG_RENDER debug("Blitting %dx%d tile at (%d,%d) " "onto layer at (%d,%d)...", tilerect.w, tilerect.h, tilerect.x, tilerect.y, layerrect.x, layerrect.y); #endif SDL_BlitSurface(mts->tileset->image->image, &tilerect, area->map_layers[area_layer], &layerrect); tile_found = 1; break; } } if (!tile_found) { warn("Tile with gid 0x%8.8x not found", gid); } } } void render_area_to_viewport(struct area *area, struct viewport *vp) { SDL_Rect srcrect; SDL_Rect dstrect; if (area == NULL || vp == NULL) { return; } srcrect.x = vp->x; srcrect.y = vp->y; srcrect.w = vp->w; srcrect.h = vp->h; dstrect.x = 0; dstrect.y = 0; dstrect.w = vp->w; dstrect.h = vp->h; render_area_to_surface(area, &srcrect, vp->screen, &dstrect); } void render_area_to_surface(struct area *area, SDL_Rect *arearect, SDL_Surface *surface, SDL_Rect *surfacerect) { SDL_Rect srcrect, dstrect; /* For demo */ SDL_Rect tmprect; if (area == NULL || arearect == NULL) { return; } if (surface == NULL || surfacerect == NULL) { return; } memcpy(&srcrect, arearect, sizeof(srcrect)); memcpy(&dstrect, surfacerect, sizeof(dstrect)); /* Fast fill with black to avoid artifacts in off-map pixels. */ /* NB: This is gray, at least temporarily. */ SDL_FillRect(surface, &dstrect, SDL_MapRGB(surface->format, 0, 0, 0)); /* For demo */ tmprect.x = dstrect.x + 160 - 8; tmprect.y = dstrect.y + 120 - 12; tmprect.w = 16; tmprect.h = 20; /* Avoid fun glitches due to negative coordinates in source * rectangles. */ if (srcrect.x < 0) { srcrect.x = 0; dstrect.x = surfacerect->x - arearect->x; } if (srcrect.y < 0) { srcrect.y = 0; dstrect.y = surfacerect->y - arearect->y; } #ifdef DEBUG_RENDER debug("Rendering %dx%d area rect at (%d,%d) " "onto %dx%d surface rect at (%d,%d)...", srcrect.w, srcrect.h, srcrect.x, srcrect.y, dstrect.w, dstrect.h, dstrect.x, dstrect.y); #endif /* Blit bottom layer. */ SDL_BlitSurface(area->map_layers[AREA_LAYER_BOT], &srcrect, surface, &dstrect); /* return;*/ /* TODO: Blit low sprites. */ /* For demo */ SDL_FillRect(surface, &tmprect, SDL_MapRGB(surface->format, 255, 0, 255)); /* Blit middle layer. */ SDL_BlitSurface(area->map_layers[AREA_LAYER_MID], &srcrect, surface, &dstrect); /* TODO: Blit high sprites. */ /* Blit top layer. */ SDL_BlitSurface(area->map_layers[AREA_LAYER_TOP], &srcrect, surface, &dstrect); }