358 lines
12 KiB
C
358 lines
12 KiB
C
#include <SDL/SDL.h>
|
|
#if !defined (__APPLE__)
|
|
#include <SDL/SDL_image.h>
|
|
#else
|
|
#include <SDL_image.h>
|
|
#endif
|
|
|
|
#include "sdl.h"
|
|
#include "../stubs.h"
|
|
#include "../main.h"
|
|
#include "../common.h"
|
|
#include "../player.h"
|
|
#include "../game.h"
|
|
#include "../context.h"
|
|
#include "../tiles/tiles.h"
|
|
#include "../tile.h"
|
|
#include "../console.h"
|
|
|
|
int interfaceInit() {
|
|
// TODO: read OS's best fullscreen resolution and use it
|
|
video_width = 800;
|
|
video_height = 600;
|
|
video_mode = 0;
|
|
// Load it up!
|
|
SDL_Init(SDL_INIT_VIDEO);
|
|
// Enable Unicode, for later text input
|
|
SDL_EnableUNICODE(SDL_ENABLE);
|
|
// Set up our SDL Window
|
|
if (interfaceVideoSet())
|
|
return ERROR;
|
|
|
|
SDL_WM_SetCaption(NAME, NULL);
|
|
|
|
consoleAddCommand("set_video", interfaceVideoSetSize);
|
|
|
|
camera_surface = SDL_CreateRGBSurface(screen->flags, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
|
|
font_spritesheet = IMG_Load_RW(SDL_RWFromMem(&font_images, font_images_length), 1);
|
|
player_spritesheet = IMG_Load_RW(SDL_RWFromMem(&player_images, player_images_length), 1);
|
|
npc_spritesheet = IMG_Load_RW(SDL_RWFromMem(&npc_images, npc_images_length), 1);
|
|
wall_spritesheet = IMG_Load_RW(SDL_RWFromMem(&wall_images, wall_images_length), 1);
|
|
floor_spritesheet = IMG_Load_RW(SDL_RWFromMem(&floor_images, floor_images_length), 1);
|
|
door_spritesheet = IMG_Load_RW(SDL_RWFromMem(&door_images, door_images_length), 1);
|
|
shadow_spritesheet = IMG_Load_RW(SDL_RWFromMem(&shadow_images, shadow_images_length), 1);
|
|
int race, class;
|
|
SDL_Rect sprite_offset = {0, 0, TILE_WIDTH, TILE_HEIGHT};
|
|
for (race = 0; race < TOTAL_RACES;race++) {
|
|
for(class = 0; class < TOTAL_CLASSES;class++) {
|
|
player_sprites[race][class] = SDL_CreateRGBSurface(screen->flags, 16, 32, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
|
|
SDL_BlitSurface(player_spritesheet, &sprite_offset, player_sprites[race][class], NULL);
|
|
}
|
|
}
|
|
// Fill our screen w/ black
|
|
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 32, 128, 64));
|
|
// Update!
|
|
SDL_Flip(screen);
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
/* draw the player's current view */
|
|
void cameraDraw() {
|
|
SDL_Rect camera_rect = {0, 0, screen->w, screen->h};
|
|
int step_x = player->x - ((struct PlayerTile*)player->data)->vision;
|
|
int step_y = player->y - ((struct PlayerTile*)player->data)->vision;
|
|
int end_x = player->x + ((struct PlayerTile*)player->data)->vision;
|
|
int end_y = player->y + ((struct PlayerTile*)player->data)->vision;
|
|
// TODO: The camera's center offset should change based upon distance to the map's width/height!
|
|
// TODO: Use zoomed copies of spritesheets for tile zooming based on player vision.
|
|
float camera_offset_x = (player->x+1)*TILE_WIDTH - (camera_rect.w/2);
|
|
float camera_offset_y = (player->y+1)*TILE_WIDTH - (camera_rect.h/2);
|
|
while (step_x < end_x) {
|
|
step_y = player->y - ((struct PlayerTile*)player->data)->vision;
|
|
while (step_y < end_y) {
|
|
// TODO: draw the layer immediately in front of the player at partial translucency
|
|
if (step_x >= 0 && step_y >= 0 && step_x < current_map->width && step_y < current_map->height) {
|
|
struct Tile *current_tile;
|
|
current_tile = &(current_map)->matrix[step_x][step_y];
|
|
int tile_id = current_tile->id;
|
|
while(current_tile) {
|
|
int x_offset = current_tile->id / 16; // 16 tiles across in spritesheet
|
|
int y_offset = current_tile->id - (x_offset*16);
|
|
SDL_Rect sprite_offset = { x_offset*TILE_WIDTH, y_offset*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
|
|
SDL_Rect tile_rect = {(step_x*TILE_WIDTH)-camera_offset_x, (step_y*TILE_WIDTH)-camera_offset_y, TILE_WIDTH, TILE_HEIGHT};
|
|
switch (current_tile->tid) {
|
|
case WALL:
|
|
SDL_BlitSurface(wall_spritesheet, &sprite_offset, camera_surface, &tile_rect);
|
|
break;
|
|
case FLOOR:
|
|
SDL_BlitSurface(floor_spritesheet, &sprite_offset, camera_surface, &tile_rect);
|
|
break;
|
|
case NPC:
|
|
SDL_BlitSurface(npc_spritesheet, &sprite_offset, camera_surface, &tile_rect);
|
|
break;
|
|
case DOOR:
|
|
tile_id = tile_id*4;
|
|
tile_id += ((struct DoorTile*)current_tile->data)->state;
|
|
y_offset = tile_id / 16;
|
|
x_offset = tile_id - (y_offset*16);
|
|
sprite_offset.x = x_offset*TILE_WIDTH;
|
|
sprite_offset.y = y_offset*TILE_HEIGHT;
|
|
SDL_BlitSurface(door_spritesheet, &sprite_offset, camera_surface, &tile_rect);
|
|
break;
|
|
case PLAYER:
|
|
y_offset = current_tile->id / TOTAL_CLASSES;
|
|
x_offset = current_tile->id - (y_offset*TOTAL_CLASSES);
|
|
sprite_offset.x = x_offset*TILE_WIDTH;
|
|
sprite_offset.y = y_offset*TILE_HEIGHT;
|
|
SDL_BlitSurface(shadow_spritesheet, NULL, camera_surface, &tile_rect);
|
|
SDL_BlitSurface(player_spritesheet, &sprite_offset, camera_surface, &tile_rect);
|
|
break;
|
|
}
|
|
current_tile = current_tile->next;
|
|
}
|
|
} else {
|
|
SDL_Rect tile_rect = {(step_x*TILE_WIDTH)-camera_offset_x, (step_y*TILE_WIDTH)-camera_offset_y, TILE_WIDTH, TILE_HEIGHT};
|
|
SDL_FillRect(camera_surface, &tile_rect, SDL_MapRGB(camera_surface->format, 0, 0, 0));
|
|
}
|
|
step_y++; // move down
|
|
}
|
|
step_x++; // move right
|
|
}
|
|
//SDL_BlitSurface(interfaceScaleSurface(camera_surface, camera_surface->w*(camera_surface->w/camera_rect.w), camera_surface->h*(camera_surface->h/camera_rect.h)), NULL, screen, &camera_rect);
|
|
SDL_BlitSurface(camera_surface, NULL, screen, &camera_rect);
|
|
}
|
|
|
|
void interfaceLoop() {
|
|
//while (SDL_PollEvent(&event)) {
|
|
int stop_while = 0;
|
|
while (SDL_WaitEvent(&event)) {
|
|
switch(event.type) {
|
|
case SDL_QUIT:
|
|
appQuit();
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
stop_while = 1;
|
|
switch(event.key.keysym.sym) {
|
|
case 304:
|
|
case 306:
|
|
case 308:
|
|
case 310:
|
|
break;
|
|
default:
|
|
globalContext(event.key.keysym.unicode);
|
|
break;
|
|
}
|
|
break;
|
|
case SDL_VIDEORESIZE:
|
|
video_width = event.resize.w;
|
|
video_height = event.resize.h;
|
|
interfaceVideoSet();
|
|
interfaceDraw(); // redraw
|
|
break;
|
|
}
|
|
if (stop_while)
|
|
break;
|
|
}
|
|
}
|
|
|
|
void interfaceDraw() {
|
|
// TODO: instead of redrawing whole screen, redraw last positions of tiles
|
|
//SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
|
|
cameraDraw(); // draw our current view
|
|
if (current_context == &consoleContext) {
|
|
interfaceDrawConsole();
|
|
}
|
|
SDL_Flip(screen); // redraw!
|
|
}
|
|
|
|
void interfaceDrawConsole() {
|
|
int line;
|
|
struct ConsoleEntry *entry;
|
|
entry = console_last_entry;
|
|
SDL_Rect print_area = {0, 0, screen->w, 9*TILE_HEIGHT};
|
|
SDL_FillRect(screen, &print_area, SDL_MapRGB(screen->format, 0, 128, 28));
|
|
for (line = 7;line >= 0;line--) {
|
|
if (entry->size > 0) {
|
|
interfaceDrawString(entry->string, 0, line*TILE_HEIGHT);
|
|
}
|
|
if (entry->prev != NULL)
|
|
entry = entry->prev;
|
|
}
|
|
interfaceDrawChar('>', 0, 8*TILE_HEIGHT);
|
|
interfaceDrawString(console_cmd, TILE_WIDTH*2, 8*TILE_HEIGHT);
|
|
}
|
|
|
|
void interfaceDrawChar(char ch, int start_x, int start_y) {
|
|
int y_offset = ch / 16; // 16 tiles across in spritesheet
|
|
int x_offset = ch - (y_offset*16);
|
|
SDL_Rect character_offset = { x_offset*TILE_WIDTH, y_offset*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
|
|
SDL_Rect render_position = {start_x, start_y, TILE_WIDTH, TILE_HEIGHT};
|
|
SDL_BlitSurface(font_spritesheet, &character_offset, screen, &render_position);
|
|
}
|
|
|
|
void interfaceDrawString(const char *string, int start_x, int start_y) {
|
|
int i = 0;
|
|
while (string[i] != '\0') {
|
|
interfaceDrawChar(string[i], (start_x)+i*TILE_WIDTH, start_y);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void interfacePrint(const char *string) {
|
|
int i = 0;
|
|
SDL_Rect print_area = {0, screen->h-TILE_HEIGHT, screen->w, TILE_HEIGHT};
|
|
SDL_FillRect(screen, &print_area, SDL_MapRGB(screen->format,128, 128, 0));
|
|
while (string[i] != '\0') {
|
|
int y_offset = string[i] / 16; // 16 tiles across in spritesheet
|
|
int x_offset = string[i] - (y_offset*16);
|
|
SDL_Rect character_offset = { x_offset*TILE_WIDTH, y_offset*TILE_HEIGHT, TILE_WIDTH, TILE_HEIGHT};
|
|
SDL_Rect render_position = {i*TILE_WIDTH, 512, TILE_WIDTH, TILE_HEIGHT};
|
|
SDL_BlitSurface(font_spritesheet, &character_offset, screen, &render_position);
|
|
i++;
|
|
}
|
|
consoleLog(string);
|
|
}
|
|
|
|
Uint32 getpixel(SDL_Surface *surface, int x, int y)
|
|
{
|
|
int bpp = surface->format->BytesPerPixel;
|
|
/* Here p is the address to the pixel we want to retrieve */
|
|
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
|
|
|
|
switch(bpp) {
|
|
case 1:
|
|
return *p;
|
|
break;
|
|
|
|
case 2:
|
|
return *(Uint16 *)p;
|
|
break;
|
|
|
|
case 3:
|
|
if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
|
return p[0] << 16 | p[1] << 8 | p[2];
|
|
else
|
|
return p[0] | p[1] << 8 | p[2] << 16;
|
|
break;
|
|
|
|
case 4:
|
|
return *(Uint32 *)p;
|
|
break;
|
|
|
|
default:
|
|
return 0; /* shouldn't happen, but avoids warnings */
|
|
}
|
|
}
|
|
|
|
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
|
|
{
|
|
int bpp = surface->format->BytesPerPixel;
|
|
/* Here p is the address to the pixel we want to set */
|
|
Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
|
|
|
|
switch(bpp) {
|
|
case 1:
|
|
*p = pixel;
|
|
break;
|
|
|
|
case 2:
|
|
*(Uint16 *)p = pixel;
|
|
break;
|
|
|
|
case 3:
|
|
if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
|
|
p[0] = (pixel >> 16) & 0xff;
|
|
p[1] = (pixel >> 8) & 0xff;
|
|
p[2] = pixel & 0xff;
|
|
} else {
|
|
p[0] = pixel & 0xff;
|
|
p[1] = (pixel >> 8) & 0xff;
|
|
p[2] = (pixel >> 16) & 0xff;
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
*(Uint32 *)p = pixel;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SDL_Surface *interfaceScaleSurface(SDL_Surface *Surface, Uint16 Width, Uint16 Height) {
|
|
if(!Surface || !Width || !Height)
|
|
return 0;
|
|
|
|
SDL_Surface *_ret = SDL_CreateRGBSurface(Surface->flags, Width, Height, Surface->format->BitsPerPixel,
|
|
Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask);
|
|
|
|
double _stretch_factor_x = ((double)(Width) / (double)(Surface->w)),
|
|
_stretch_factor_y = ((double)(Height) / (double)(Surface->h));
|
|
Sint32 x, y, o_x, o_y;
|
|
for(y = 0; y < Surface->h; y++)
|
|
for(x = 0; x < Surface->w; x++)
|
|
for(o_y = 0; o_y < _stretch_factor_y; ++o_y)
|
|
for(o_x = 0; o_x < _stretch_factor_x; ++o_x)
|
|
putpixel(_ret, (Sint32)(_stretch_factor_x * x) + o_x, (Sint32)(_stretch_factor_y * y) + o_y, getpixel(Surface, x, y));
|
|
|
|
return _ret;
|
|
}
|
|
|
|
int interfaceVideoSet() {
|
|
if ((screen = SDL_SetVideoMode(video_width, video_height, 32, SDL_SWSURFACE|SDL_DOUBLEBUF|SDL_RESIZABLE|video_fullscreen)) == NULL) {
|
|
return ERROR;
|
|
}
|
|
free(camera_surface);
|
|
camera_surface = SDL_CreateRGBSurface(screen->flags, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
|
|
return SUCCESS;
|
|
}
|
|
|
|
void interfaceVideoSetSize(const char *input_string) {
|
|
if (input_string) {
|
|
int i = 0;
|
|
int j = 0;
|
|
char height[15];
|
|
char width[15];
|
|
char fullscreen[1];
|
|
int position = 0;
|
|
|
|
while(input_string[i] != '\0') {
|
|
if (input_string[i] == 'x') {
|
|
width[j] = '\0';
|
|
position = 1;
|
|
i++; // skip the x
|
|
j = 0;
|
|
} else if (input_string[i] == ' ') {
|
|
height[j] = '\0';
|
|
position = 2;
|
|
i++; // skip the space
|
|
j = 0;
|
|
}
|
|
if (position == 0) {
|
|
width[j] = input_string[i];
|
|
} else if (position == 1) {
|
|
height[j] = input_string[i];
|
|
} else if (position == 2) {
|
|
fullscreen[j] = input_string[i];
|
|
break; // just a boolean, so let's break
|
|
}
|
|
j++;
|
|
i++;
|
|
}
|
|
video_height = atoi(height); // ... had to reverse order for it to work on win...
|
|
video_width = atoi(width);
|
|
|
|
if (fullscreen[0] == '1') { // fullscreen
|
|
video_fullscreen = SDL_FULLSCREEN;
|
|
} else if (fullscreen[0] == '0') { // windowed
|
|
video_fullscreen = 0;
|
|
}
|
|
interfaceVideoSet();
|
|
} else {
|
|
consoleLog("Syntax: widthxheight 0|1");
|
|
}
|
|
}
|
|
|
|
void interfaceClose() {
|
|
SDL_Quit();
|
|
}
|