1201 lines
49 KiB
C
1201 lines
49 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"
|
|
|
|
#include "../net/sockets.h"
|
|
|
|
void interfaceSetInterval(const char *input_string) {
|
|
if (input_string) {
|
|
int new_tickrate = atoi(input_string);
|
|
SDL_RemoveTimer(timer_id);
|
|
if (new_tickrate > 0) {
|
|
tickrate = new_tickrate;
|
|
timer_id = SDL_AddTimer(tickrate, pushTickEvent, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int networkThread(void *nada) {
|
|
// initialize our network system (sockets, winsock, etc.)
|
|
netInit();
|
|
|
|
int reuse = 1;
|
|
int net_socket;
|
|
struct sockaddr_in server_address;
|
|
|
|
if ((net_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
|
|
consoleLog("socket() error'd");
|
|
return ERROR;
|
|
}
|
|
consoleLog("socket() success'd");
|
|
if (setsockopt(net_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&reuse, sizeof(reuse)) < 0) {
|
|
consoleLog("setsockopt() error'd");
|
|
}
|
|
consoleLog("setsockopt() success'd");
|
|
//fcntl(net_socket, F_SETFL, O_NONBLOCK);
|
|
memset(&server_address, 0, sizeof(server_address));
|
|
server_address.sin_family = AF_INET;
|
|
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
server_address.sin_port = htons(31337);
|
|
if (bind(net_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
|
|
consoleLog("bind() error'd");
|
|
return ERROR;
|
|
}
|
|
consoleLog("bind() success'd");
|
|
if (listen(net_socket, 32) < 0) {
|
|
consoleLog("listen() error'd");
|
|
return ERROR;
|
|
}
|
|
consoleLog("listen() success'd");
|
|
|
|
char test_string[31];
|
|
sprintf(test_string, "server running on fd %d!", net_socket);
|
|
consoleLog(test_string);
|
|
/******/
|
|
// fd_set master_fds;
|
|
// fd_set read_fds;
|
|
// int max_fd;
|
|
int i; // current fd in for
|
|
char data_buffer[2048];
|
|
/* set up our fds */
|
|
FD_ZERO(&master_fds);
|
|
FD_ZERO(&read_fds);
|
|
|
|
FD_SET(net_socket, &master_fds);
|
|
max_fd = net_socket;
|
|
|
|
SDL_Event event;
|
|
SDL_UserEvent user_event;
|
|
|
|
user_event.type = SDL_USEREVENT;
|
|
user_event.code = EVENT_NET;
|
|
user_event.data1 = NULL;
|
|
user_event.data2 = NULL;
|
|
event.type = SDL_USEREVENT;
|
|
event.user = user_event;
|
|
|
|
while(1 == 1) {
|
|
//while (is_networking) {
|
|
read_fds = master_fds;
|
|
if (select(max_fd+1, &read_fds, NULL, NULL, NULL) == -1) {
|
|
consoleLog("error on network select()");
|
|
}
|
|
// start at net_socket since the Unix Killer's start fd/sd starts at a large number
|
|
for (i=net_socket;i <= max_fd; i++) {
|
|
if (FD_ISSET(i, &read_fds)) {
|
|
if (i == net_socket) {
|
|
struct sockaddr_storage client_address;
|
|
socklen_t address_length = sizeof(client_address);
|
|
int new_fd = accept(net_socket, (struct sockaddr *)&client_address, &address_length);
|
|
if (new_fd == -1) {
|
|
consoleLog("accept() error'd");
|
|
} else {
|
|
FD_SET(new_fd, &master_fds);
|
|
if (new_fd > max_fd) {
|
|
max_fd = new_fd;
|
|
}
|
|
char remote_ip[INET6_ADDRSTRLEN];
|
|
event.user.data1 = (void *)new_fd;
|
|
event.user.data2 = (void *)inet_ntop(client_address.ss_family, get_in_addr((struct sockaddr *)&client_address), remote_ip, INET6_ADDRSTRLEN);
|
|
event.user.code = EVENT_NET_ACCEPT;
|
|
SDL_PushEvent(&event);
|
|
}
|
|
} else if (i == client_socket) {
|
|
int bytes = 0;
|
|
if((bytes = recv(i, data_buffer, sizeof data_buffer, 0)) <= 0) {
|
|
if (bytes == 0) {
|
|
event.user.code = EVENT_NET_CLIENT_LOST;
|
|
event.user.data1 = (void *)i;
|
|
} else {
|
|
event.user.code = EVENT_NET_CLIENT_ERROR;
|
|
event.user.data1 = (void *)i;
|
|
}
|
|
SDL_PushEvent(&event);
|
|
#if _WIN32 | _WIN64
|
|
closesocket(i);
|
|
#else
|
|
close(i);
|
|
#endif
|
|
FD_CLR(i, &master_fds);
|
|
} else {
|
|
data_buffer[bytes] = '\0'; // TEMP
|
|
struct NetMessage *net_message;
|
|
net_message = malloc(sizeof(struct NetMessage));
|
|
net_message->fd = i;
|
|
net_message->size = bytes;
|
|
net_message->data = (void *)data_buffer;
|
|
event.user.code = EVENT_NET_CLIENT_RECV;
|
|
event.user.data1 = (void *)i;
|
|
event.user.data2 = (void *)net_message;
|
|
SDL_PushEvent(&event);
|
|
}
|
|
} else if (i > net_socket) { // handle existing client data
|
|
int bytes = 0;
|
|
if((bytes = recv(i, data_buffer, sizeof data_buffer, 0)) <= 0) {
|
|
if (bytes == 0) {
|
|
event.user.code = EVENT_NET_LOST;
|
|
event.user.data1 = (void *)i;
|
|
} else {
|
|
event.user.code = EVENT_NET_ERROR;
|
|
event.user.data1 = (void *)i;
|
|
}
|
|
SDL_PushEvent(&event);
|
|
#if _WIN32 | _WIN64
|
|
closesocket(i);
|
|
#else
|
|
close(i);
|
|
#endif
|
|
FD_CLR(i, &master_fds);
|
|
} else { // good data
|
|
data_buffer[bytes] = '\0'; // TEMP
|
|
struct NetMessage *net_message;
|
|
net_message = malloc(sizeof(struct NetMessage));
|
|
net_message->fd = i;
|
|
net_message->size = bytes;
|
|
net_message->data = (void *)data_buffer;
|
|
event.user.code = EVENT_NET_RECV;
|
|
event.user.data1 = (void *)i;
|
|
event.user.data2 = (void *)net_message;
|
|
SDL_PushEvent(&event);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Uint32 pushTickEvent(Uint32 interval, void *param) {
|
|
SDL_Event event;
|
|
SDL_UserEvent user_event;
|
|
|
|
user_event.type = SDL_USEREVENT;
|
|
user_event.code = EVENT_TICK;
|
|
user_event.data1 = NULL;
|
|
user_event.data2 = NULL;
|
|
event.type = SDL_USEREVENT;
|
|
event.user = user_event;
|
|
SDL_PushEvent(&event);
|
|
return interval;
|
|
}
|
|
|
|
void interfaceSetScale(float scale_x, float scale_y) {
|
|
g_tile_scale_x = scale_x;
|
|
g_tile_scale_y = scale_y;
|
|
g_tile_width = g_tile_scale_x * TILE_WIDTH;
|
|
g_tile_height = g_tile_scale_y * TILE_HEIGHT;
|
|
}
|
|
|
|
void scaleTiles(float scale_x, float scale_y) {
|
|
setSpritesheetScale(&player_sprites, scale_x, scale_y);
|
|
setSpritesheetScale(&item_sprites, scale_x, scale_y);
|
|
setSpritesheetScale(&equip_sprites, scale_x, scale_y);
|
|
setSpritesheetScale(&shadow_sprites, scale_x, scale_y);
|
|
setSpritesheetScale(&door_sprites, scale_x, scale_y);
|
|
setSpritesheetScale(&npc_sprites, scale_x, scale_y);
|
|
setSpritesheetScale(&floor_sprites, scale_x, scale_y);
|
|
setSpritesheetScale(&wall_sprites, scale_x, scale_y);
|
|
}
|
|
|
|
int interfaceInit() {
|
|
// TODO: read OS's best fullscreen resolution and use it
|
|
g_video_width = 800;
|
|
g_video_height = 600;
|
|
// Load it up!
|
|
// since we use threads, Mac OS 10+ support only. Also threaded os.
|
|
#if _WIN32 | _WIN64 | __APPLE__
|
|
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER);
|
|
#else
|
|
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTTHREAD);
|
|
#endif
|
|
// Enable Unicode, for later text input
|
|
SDL_EnableUNICODE(SDL_ENABLE);
|
|
// Set up our SDL Window
|
|
if (interfaceVideoSet())
|
|
return ERROR;
|
|
// FIXME: this should be handled differently, but we need to set the window width/height to the surface's reported width/height, as some window managers will resize the SDL window.
|
|
SDL_Delay(100);
|
|
g_video_width = (SDL_GetVideoSurface())->w;
|
|
g_video_height = (SDL_GetVideoSurface())->h;
|
|
if (interfaceVideoSet())
|
|
return ERROR;
|
|
SDL_WM_SetCaption(NAME, NULL);
|
|
|
|
consoleAddCommand("quit", interfaceQuit);
|
|
consoleAddCommand("tickrate", interfaceSetInterval);
|
|
consoleAddCommand("set_video", interfaceVideoSetSize);
|
|
consoleAddCommand("tile_scale", consoleScaleTiles);
|
|
|
|
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);
|
|
/* tile specific stuff */
|
|
/* load our surfaces from memory */
|
|
font_spritesheet = IMG_Load_RW(SDL_RWFromMem(&font_images, font_images_length), 1);
|
|
loadFontFromMemory(&font_standard, font_images, font_images_length, 16, 32);
|
|
setFontScale(&font_standard, 1.0f, 1.0f);
|
|
loadFontFromMemory(&font_mini, font_mini_images, font_mini_images_length, 8, 8);
|
|
setFontScale(&font_mini, 2.0f, 2.0f);
|
|
|
|
ui_spritesheet = IMG_Load_RW(SDL_RWFromMem(&ui_images, ui_images_length), 1);
|
|
|
|
loadSpritesheetFromMemory(&player_sprites, player_images, player_images_length, 16, 32, TOTAL_CLASSES);
|
|
loadSpritesheetFromMemory(&item_sprites, item_images, item_images_length, 16, 32, 16);
|
|
loadSpritesheetFromMemory(&equip_sprites, equip_images, equip_images_length, 16, 32, 16);
|
|
loadSpritesheetFromMemory(&shadow_sprites, shadow_images, shadow_images_length, 16, 32, TOTAL_CLASSES);
|
|
loadSpritesheetFromMemory(&door_sprites, door_images, door_images_length, 16, 32, 16);
|
|
loadSpritesheetFromMemory(&npc_sprites, npc_images, npc_images_length, 16, 32, 16);
|
|
loadSpritesheetFromMemory(&floor_sprites, floor_images, floor_images_length, 16, 32, 16);
|
|
loadSpritesheetFromMemory(&wall_sprites, wall_images, wall_images_length, 16, 32, 16);
|
|
loadSpritesheetFromMemory(&ui_sprites, ui_images, ui_images_length, 32, 32, 6);
|
|
scaleTiles(2.0f, 2.0f);
|
|
/* set up our ui */
|
|
uiInit();
|
|
uiSetScale(2.0f, 2.0f);
|
|
// Fill our screen w/ black
|
|
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 32, 128, 64));
|
|
// Update!
|
|
SDL_Flip(screen);
|
|
|
|
/* now we load up our timer, woo */
|
|
tickrate = 500;
|
|
timer_id = SDL_AddTimer(tickrate, pushTickEvent, NULL);
|
|
/* now we spawn a network thread that will push user events to SDL */
|
|
network_thread = SDL_CreateThread(networkThread, NULL);
|
|
return SUCCESS;
|
|
}
|
|
|
|
int uiInit() {
|
|
int hotbar_count = 4;
|
|
/* init hotbar */
|
|
Uint32 rmask, gmask, bmask, amask;
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
|
rmask = 0xff000000;
|
|
gmask = 0x00ff0000;
|
|
bmask = 0x0000ff00;
|
|
amask = 0x000000ff;
|
|
#else
|
|
rmask = 0x000000ff;
|
|
gmask = 0x0000ff00;
|
|
bmask = 0x00ff0000;
|
|
amask = 0xff000000;
|
|
#endif
|
|
ui_hotbar_surface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA, UI_HOTBAR_ITEM_WIDTH*hotbar_count, UI_HOTBAR_ITEM_HEIGHT, 32, rmask, gmask, bmask, amask);
|
|
if(ui_hotbar_surface == NULL) {
|
|
consoleLog("SDL_CreateRGBSurface error'd on ui_hotbar_surface");
|
|
//fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
|
|
//exit(1);
|
|
}
|
|
SDL_Rect hotbar_item_rect = { 0, 0, UI_HOTBAR_ITEM_WIDTH, UI_HOTBAR_ITEM_HEIGHT };
|
|
int i = 0;
|
|
while (i < hotbar_count) {
|
|
SDL_Rect hotbar_target_rect = {i*UI_HOTBAR_ITEM_WIDTH, 0, UI_HOTBAR_ITEM_WIDTH+i*UI_HOTBAR_ITEM_WIDTH, UI_HOTBAR_ITEM_HEIGHT};
|
|
SDL_BlitSurface(ui_spritesheet, &hotbar_item_rect, ui_hotbar_surface, &hotbar_target_rect);
|
|
char label[2]; // max 99 hotbar_count then
|
|
itoa(i+1, label, 10);
|
|
interfaceDrawStringF(&font_standard, ui_hotbar_surface, label, i*UI_HOTBAR_ITEM_WIDTH + TILE_WIDTH/2 , 0);
|
|
i++;
|
|
}
|
|
SDL_SetOpacity(ui_hotbar_surface, 0.75);
|
|
// the rect for the actual on-screen position
|
|
/* messages window */
|
|
ui_messages_surface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA, screen->w, 5*(font_mini.height+1)*font_mini.scale_y, 32, rmask, gmask, bmask, amask);
|
|
SDL_FillRect(ui_messages_surface, NULL, SDL_MapRGB(ui_messages_surface->format, 0, 0, 0));
|
|
if(ui_messages_surface == NULL) {
|
|
consoleLog("SDL_CreateRGBSurface error'd on ui_messages_surface");
|
|
//fprintf(stderr, "CreateRGBSurface failed: %s\n", SDL_GetError());
|
|
//exit(1);
|
|
}
|
|
SDL_SetOpacity(ui_messages_surface, 0.75);
|
|
return 0;
|
|
}
|
|
|
|
void uiSetOpacity(double opacity) {
|
|
SDL_SetOpacity(ui_hotbar_surface, opacity);
|
|
}
|
|
|
|
void uiSetScale(float scale_x, float scale_y) {
|
|
g_ui_scale_x = scale_x;
|
|
g_ui_scale_y = scale_y;
|
|
ui_hotbar_surface = interfaceScaleSurface(ui_hotbar_surface, scale_x, scale_y);
|
|
setSpritesheetScale(&ui_sprites, scale_x, scale_y);
|
|
}
|
|
|
|
/* 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!
|
|
float camera_offset_x = (player->x+1)*floor_sprites.s_width - (camera_rect.w/2);
|
|
float camera_offset_y = (player->y+1)*(floor_sprites.s_height/2) - (camera_rect.h/2);
|
|
while (step_x < end_x) {
|
|
step_y = player->y - ((struct PlayerTile*)player->data)->vision;
|
|
while (step_y < end_y) {
|
|
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) {
|
|
switch (current_tile->tid) {
|
|
case WALL:
|
|
//drawScaledSprite(&wall_sprites, current_tile->id, camera_surface, (step_x*wall_sprites.s_width)-camera_offset_x, (step_y*wall_sprites.s_height/2)-camera_offset_y);
|
|
if (step_x == player->x && step_y == player->y+1)
|
|
drawScaledTransparentSprite(&wall_sprites, current_tile->id, 0.75f, camera_surface, (step_x*wall_sprites.s_width)-camera_offset_x, (step_y*wall_sprites.s_height/2)-camera_offset_y);
|
|
else
|
|
drawScaledSprite(&wall_sprites, current_tile->id, camera_surface, (step_x*wall_sprites.s_width)-camera_offset_x, (step_y*wall_sprites.s_height/2)-camera_offset_y);
|
|
break;
|
|
case FLOOR:
|
|
drawScaledSprite(&floor_sprites, current_tile->id, camera_surface, (step_x*floor_sprites.s_width)-camera_offset_x, (step_y*floor_sprites.s_height/2)-camera_offset_y);
|
|
break;
|
|
case NPC:
|
|
drawScaledSprite(&npc_sprites, current_tile->id, camera_surface, (step_x*npc_sprites.s_width)-camera_offset_x, (step_y*npc_sprites.s_height/2)-camera_offset_y);
|
|
break;
|
|
case DOOR:
|
|
tile_id = tile_id*4;
|
|
tile_id += ((struct DoorTile*)current_tile->data)->state;
|
|
if (step_x == player->x && step_y == player->y+1) {
|
|
drawScaledTransparentSprite(&door_sprites, tile_id, 0.75f, camera_surface, (step_x*door_sprites.s_width)-camera_offset_x, (step_y*door_sprites.s_height/2)-camera_offset_y);
|
|
} else {
|
|
drawScaledSprite(&door_sprites, tile_id, camera_surface, (step_x*door_sprites.s_width)-camera_offset_x, (step_y*door_sprites.s_height/2)-camera_offset_y);
|
|
}
|
|
break;
|
|
case PLAYER:
|
|
drawScaledSprite(&shadow_sprites, 0, camera_surface, (step_x*shadow_sprites.s_width)-camera_offset_x, (step_y*shadow_sprites.s_height/2)-camera_offset_y);
|
|
//drawScaledSpriteOutline(&player_sprites, current_tile->id, camera_surface, (step_x*player_sprites.s_width)-camera_offset_x, (step_y*player_sprites.s_height/2)-camera_offset_y);
|
|
drawScaledSprite(&player_sprites, current_tile->id, camera_surface, (step_x*player_sprites.s_width)-camera_offset_x, (step_y*player_sprites.s_height/2)-camera_offset_y);
|
|
break;
|
|
case ITEM:
|
|
drawScaledSprite(&item_sprites, current_tile->id, camera_surface, (step_x*item_sprites.s_width)-camera_offset_x, (step_y*item_sprites.s_height/2)-camera_offset_y);
|
|
break;
|
|
case EQUIP:
|
|
drawScaledSprite(&equip_sprites, current_tile->id, camera_surface, (step_x*equip_sprites.s_width)-camera_offset_x, (step_y*equip_sprites.s_height/2)-camera_offset_y);
|
|
break;
|
|
|
|
}
|
|
current_tile = current_tile->next;
|
|
}
|
|
} else {
|
|
SDL_Rect tile_rect = {(step_x*floor_sprites.s_width)-camera_offset_x, (step_y*floor_sprites.s_width)-camera_offset_y, floor_sprites.s_width, floor_sprites.s_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 uiDraw() {
|
|
// bottom-center:
|
|
//SDL_Rect ui_hotbar_target_rect = {(screen->w/2 - ui_hotbar_surface->w/2), screen->h-ui_hotbar_surface->h, (screen->w/2 - ui_hotbar_surface->w/2), screen->h};
|
|
// top-center:
|
|
SDL_Rect ui_hotbar_target_rect = {(screen->w/2 - ui_hotbar_surface->w/2), 0, (screen->w/2 - ui_hotbar_surface->w/2), NULL};
|
|
SDL_BlitSurface(ui_hotbar_surface, NULL, screen, &ui_hotbar_target_rect);
|
|
/* TODO: move the ui_messages_surface updating elsewhere and use non-ConsoleEntry system */
|
|
int line;
|
|
struct ConsoleEntry *entry;
|
|
entry = console_last_entry;
|
|
SDL_FillRect(ui_messages_surface, NULL, SDL_MapRGBA(ui_messages_surface->format, 196, 196, 196, 196));
|
|
for (line = 4;line >= 0;line--) {
|
|
if (entry->size > 0) {
|
|
interfaceDrawStringF(&font_mini, ui_messages_surface, entry->string, 0, line*((font_mini.height+1)*font_mini.scale_y));
|
|
}
|
|
if (entry->prev != NULL)
|
|
entry = entry->prev;
|
|
}
|
|
|
|
//SDL_Rect ui_messages_target_rect = {0, screen->h - (4*font_mini.height) - ui_hotbar_surface->h, font_mini.width * 24, font_mini.height * 4};
|
|
//SDL_Rect ui_messages_target_rect = {0, screen->h - (5*(font_mini.height+1)*font_mini.scale_y) - ui_hotbar_surface->h, ui_messages_surface->w, 5*(font_mini.height+1)*font_mini.scale_y};
|
|
SDL_Rect ui_messages_target_rect = {0, screen->h - (5*(font_mini.height+1)*font_mini.scale_y), ui_messages_surface->w, 5*(font_mini.height+1)*font_mini.scale_y};
|
|
SDL_BlitSurface(ui_messages_surface, NULL, screen, &ui_messages_target_rect);
|
|
|
|
/* draw tickrate (temporary) */
|
|
char test[12];
|
|
itoa(tickrate, test, 10);
|
|
interfaceDrawStringF(&font_mini, screen, test, screen->w-(strlen(test)*(font_mini.width*font_mini.scale_x)), 0);
|
|
}
|
|
|
|
int interfaceLoop() {
|
|
while (SDL_WaitEvent(&event)) {
|
|
switch(event.type) {
|
|
case SDL_USEREVENT:
|
|
if (event.user.code == EVENT_TICK) { // timer
|
|
gameLoop();
|
|
} else if (event.user.code == EVENT_NET_ACCEPT) { // net
|
|
char string[127];
|
|
sprintf(string, "net accept of %s on fd %d", (char*)event.user.data2, (int*)event.user.data1);
|
|
consoleLog(string);
|
|
} else if (event.user.code == EVENT_NET_RECV) {
|
|
char string[255];
|
|
struct NetMessage *net_message = (struct NetMessage*)event.user.data2;
|
|
sprintf(string, "client(%d): %s", net_message->fd, (char*)net_message->data);
|
|
consoleLog(string);
|
|
sendall(net_message->fd, net_message->data, net_message->size);
|
|
free(net_message);
|
|
} else if (event.user.code == EVENT_NET_LOST) {
|
|
char string[23];
|
|
sprintf(string, "net lost for fd %d", *(int*)event.user.data1);
|
|
consoleLog(string);
|
|
} else if (event.user.code == EVENT_NET_ERROR) {
|
|
char string[23];
|
|
sprintf(string, "net error for fd %d", *(int*)event.user.data1);
|
|
consoleLog(string);
|
|
} else if (event.user.code == EVENT_NET_CLIENT_RECV) {// begin client
|
|
char string[255];
|
|
struct NetMessage *net_message = (struct NetMessage*)event.user.data2;
|
|
sprintf(string, "server(%d): %s", net_message->fd, (char*)net_message->data);
|
|
consoleLog(string);
|
|
free(net_message);
|
|
}
|
|
break;
|
|
case SDL_QUIT:
|
|
return 0;
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
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:
|
|
g_video_width = event.resize.w;
|
|
g_video_height = event.resize.h;
|
|
interfaceVideoSet();
|
|
interfaceDraw(); // redraw
|
|
break;
|
|
case SDL_VIDEOEXPOSE:
|
|
g_video_width = (SDL_GetVideoSurface())->w;
|
|
g_video_height = (SDL_GetVideoSurface())->h;
|
|
interfaceVideoSet();
|
|
interfaceDraw(); // redraw
|
|
break;
|
|
}
|
|
interfaceDraw(); // redraw
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
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
|
|
uiDraw();
|
|
if (current_context == &consoleContext) {
|
|
interfaceDrawConsole();
|
|
} else if (current_context == &inventoryContext || current_context == &equipmentContext) {
|
|
interfaceDrawInventory();
|
|
}
|
|
SDL_Flip(screen); // redraw!
|
|
}
|
|
|
|
void interfaceDrawInventory() {
|
|
struct Inventory *inventory = &((struct PlayerTile*)player->data)->inventory;
|
|
int inventory_info = font_mini.height*font_mini.scale_y*2;
|
|
|
|
int inventory_height = ( (inventory->max_slots / inventory->slots_per_row) * item_sprites.s_height ) + inventory_info;
|
|
int inventory_width = ( inventory->slots_per_row * item_sprites.s_width );
|
|
if (inventory_width < (font_mini.width*font_mini.scale_x*16))
|
|
inventory_width = font_mini.width*font_mini.scale_x*16;
|
|
|
|
int equipment_width = ( 6 * item_sprites.s_width );
|
|
if (equipment_width < (font_mini.width*font_mini.scale_x*16))
|
|
equipment_width = font_mini.width*font_mini.scale_x*16;
|
|
int equipment_height = ( 4 * item_sprites.s_height ) + (3 * font_mini.height * font_mini.scale_y );
|
|
|
|
SDL_Surface *equipment_surface = SDL_CreateRGBSurface(screen->flags, equipment_width, equipment_height, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
|
|
SDL_Rect equipment_render_area = { (screen->w/2)-(equipment_width)-1, (screen->h/2)-(equipment_height/2), equipment_width, equipment_height };
|
|
SDL_FillRect(equipment_surface, NULL, SDL_MapRGB(equipment_surface->format, 196, 196, 196));
|
|
|
|
interfaceDrawStringF(&font_mini, equipment_surface, ((struct PlayerTile*)player->data)->name, 0, 0);
|
|
interfaceDrawStringF(&font_mini, equipment_surface, ((struct PlayerTile*)player->data)->stats, 0, 1*(font_mini.height*font_mini.scale_y));
|
|
|
|
//SDL_Surface *new_surface = SDL_CreateRGBSurface(screen->flags, (screen->w/6), screen->h/2, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
|
|
//SDL_Rect render_area = { screen->w-(screen->w/6), screen->h/8, screen->w/6, screen->h/2 };
|
|
SDL_Surface *new_surface = SDL_CreateRGBSurface(screen->flags, inventory_width, inventory_height, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
|
|
//SDL_Rect render_area = { (screen->w/2)-(inventory_width/2), (screen->h/2)-(inventory_height/2), inventory_width, inventory_height };
|
|
SDL_Rect render_area = { (screen->w/2)+1, (screen->h/2)-(inventory_height/2), inventory_width, inventory_height };
|
|
|
|
//SDL_FillRect(new_surface, NULL, SDL_MapRGB(new_surface->format, 196, 164, 64));
|
|
SDL_FillRect(new_surface, NULL, SDL_MapRGB(new_surface->format, 196, 196, 196));
|
|
struct Tile *current_item = ((struct PlayerTile*)player->data)->inventory.tile;
|
|
int i = 0;
|
|
int x;
|
|
int y;
|
|
while (current_item) {
|
|
y = i / inventory->slots_per_row;
|
|
x = i - (inventory->slots_per_row*y);
|
|
if (i == ((struct PlayerTile*)player->data)->inventory.selected) {
|
|
switch (current_item->tid) {
|
|
case ITEM:
|
|
drawScaledSprite(&item_sprites, current_item->id, new_surface, x*item_sprites.s_width, inventory_info+(y*item_sprites.s_width));
|
|
drawScaledSpriteOutline(&item_sprites, current_item->id, new_surface, x*item_sprites.s_width, inventory_info+(y*item_sprites.s_width));
|
|
|
|
interfaceDrawStringF(&font_mini, new_surface, ((struct ItemTile*)current_item->data)->name, inventory_width/2-(strlen(((struct ItemTile*)current_item->data)->name)*font_mini.width*font_mini.scale_x/2), 2);
|
|
break;
|
|
case EQUIP:
|
|
drawScaledSprite(&equip_sprites, current_item->id, new_surface, x*equip_sprites.s_width, inventory_info+(y*equip_sprites.s_width));
|
|
drawScaledSpriteOutline(&equip_sprites, current_item->id, new_surface, x*equip_sprites.s_width, inventory_info+(y*equip_sprites.s_width));
|
|
|
|
interfaceDrawStringF(&font_mini, new_surface, ((struct EquipTile*)current_item->data)->name, inventory_width/2-(strlen(((struct EquipTile*)current_item->data)->name)*font_mini.width*font_mini.scale_x/2), 2);
|
|
interfaceDrawStringF(&font_mini, new_surface, ((struct EquipTile*)current_item->data)->required_slots, 0, 1*(font_mini.width*font_mini.scale_y));
|
|
interfaceDrawStringF(&font_mini, new_surface, ((struct EquipTile*)current_item->data)->damage_mod, 0, 2*(font_mini.width*font_mini.scale_y));
|
|
interfaceDrawStringF(&font_mini, new_surface, ((struct EquipTile*)current_item->data)->armour_mod, (font_mini.width*font_mini.scale_x*(strlen(((struct EquipTile*)current_item->data)->damage_mod)+1)), 2*(font_mini.width*font_mini.scale_y));
|
|
|
|
break;
|
|
}
|
|
} else {
|
|
switch (current_item->tid) {
|
|
case ITEM:
|
|
drawScaledTransparentSprite(&item_sprites, current_item->id, 0.50f, new_surface, x*item_sprites.s_width, inventory_info+(y*item_sprites.s_width));
|
|
break;
|
|
case EQUIP:
|
|
drawScaledTransparentSprite(&equip_sprites, current_item->id, 0.50f, new_surface, x*equip_sprites.s_width, inventory_info+(y*equip_sprites.s_width));
|
|
break;
|
|
}
|
|
}
|
|
current_item = current_item->next;
|
|
i++;
|
|
}
|
|
|
|
/* Equipment overlay */
|
|
char *equipment_slots = slotsBuildTable(((struct PlayerTile*)player->data)->slots);
|
|
|
|
// TODO: have a slotsBuildSmallTable() that returns a shortened array of items.
|
|
i = 0;
|
|
x = 0;
|
|
y = 0;
|
|
while (i < 64) {
|
|
if (equipment_slots[i]) {
|
|
int j = 0;
|
|
while (j < equipment_slots[i]) {
|
|
if (x >= 6) {
|
|
y++;
|
|
x = 0;
|
|
}
|
|
interfaceDrawCharF(&font_mini, equipment_surface, i+64, x*item_sprites.s_width, (y+2)*item_sprites.s_width);
|
|
x++;
|
|
j++;
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
slotsFreeTable(equipment_slots);
|
|
|
|
/* Draw equipment */
|
|
current_item = ((struct PlayerTile*)player->data)->equipment.tile;
|
|
struct Inventory *equipment = &((struct PlayerTile*)player->data)->equipment;
|
|
i = 0;
|
|
char *current_item_slots;
|
|
while (current_item) {
|
|
current_item_slots = slotsBuildTable(((struct EquipTile*)current_item->data)->required_slots);
|
|
y = i / equipment->slots_per_row;
|
|
x = i - (equipment->slots_per_row*y);
|
|
//drawScaledSprite(&equip_sprites, current_item->id, equipment_surface, x*equip_sprites.s_width, (y*equip_sprites.s_width));
|
|
if (i == ((struct PlayerTile*)player->data)->equipment.selected) {
|
|
drawScaledSprite(&equip_sprites, current_item->id, equipment_surface, x*equip_sprites.s_width, (y*equip_sprites.s_width));
|
|
drawScaledSpriteOutline(&equip_sprites, current_item->id, equipment_surface, x*equip_sprites.s_width, (y*equip_sprites.s_width));
|
|
} else {
|
|
drawScaledTransparentSprite(&equip_sprites, current_item->id, 0.50f, equipment_surface, x*equip_sprites.s_width, (y*equip_sprites.s_width));
|
|
}
|
|
|
|
current_item = current_item->next;
|
|
i++;
|
|
}
|
|
|
|
while (current_item) {
|
|
y = i / equipment->slots_per_row;
|
|
x = i - (equipment->slots_per_row*y);
|
|
//drawScaledSprite(&item_sprites, current_item->id, equipment_surface, x*item_sprites.s_width, (y*item_sprites.s_width));
|
|
if (i == ((struct PlayerTile*)player->data)->equipment.selected) {
|
|
drawScaledSprite(&equip_sprites, current_item->id, equipment_surface, x*equip_sprites.s_width, (y*equip_sprites.s_width));
|
|
drawScaledSpriteOutline(&equip_sprites, current_item->id, equipment_surface, x*equip_sprites.s_width, (y*equip_sprites.s_width));
|
|
} else {
|
|
drawScaledTransparentSprite(&equip_sprites, current_item->id, 0.50f, equipment_surface, x*equip_sprites.s_width, (y*equip_sprites.s_width));
|
|
}
|
|
|
|
current_item = current_item->next;
|
|
i++;
|
|
}
|
|
|
|
//drawScaledSprite(&player_sprites, 0, new_surface, 0, 0);
|
|
if (current_context == &inventoryContext) {
|
|
SDL_SetAlpha(new_surface, SDL_SRCALPHA, 232);
|
|
SDL_SetAlpha(equipment_surface, SDL_SRCALPHA, 164);
|
|
} else if (current_context == &equipmentContext) {
|
|
SDL_SetAlpha(new_surface, SDL_SRCALPHA, 164);
|
|
SDL_SetAlpha(equipment_surface, SDL_SRCALPHA, 232);
|
|
}
|
|
SDL_BlitSurface(new_surface, NULL, screen, &render_area);
|
|
SDL_BlitSurface(equipment_surface, NULL, screen, &equipment_render_area);
|
|
SDL_FreeSurface(new_surface);
|
|
SDL_FreeSurface(equipment_surface);
|
|
}
|
|
|
|
void interfaceDrawConsole() {
|
|
int line;
|
|
struct ConsoleEntry *entry;
|
|
entry = console_last_entry;
|
|
SDL_Rect print_area = {0, 0, screen->w, 9*font_standard.s_height};
|
|
SDL_FillRect(screen, &print_area, SDL_MapRGB(screen->format, 0, 128, 28));
|
|
for (line = 7;line >= 0;line--) {
|
|
if (entry->size > 0) {
|
|
interfaceDrawStringF(&font_standard, screen, entry->string, 0, line*font_standard.s_height);
|
|
}
|
|
if (entry->prev != NULL)
|
|
entry = entry->prev;
|
|
}
|
|
interfaceDrawCharF(&font_standard, screen, '>', 0, 8*font_standard.s_height);
|
|
interfaceDrawStringF(&font_standard, screen, console_cmd, font_standard.s_width*2, 8*font_standard.s_height);
|
|
}
|
|
|
|
void interfaceDrawChar(SDL_Surface *to_surface, 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, to_surface, &render_position);
|
|
}
|
|
|
|
void interfaceDrawString(SDL_Surface *to_surface, const char *string, int start_x, int start_y) {
|
|
int i = 0;
|
|
while (string[i] != '\0') {
|
|
interfaceDrawChar(to_surface, string[i], (start_x)+i*TILE_WIDTH, start_y);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void interfaceDrawStringF(struct Font *font, SDL_Surface *to_surface, const char *string, int start_x, int start_y) {
|
|
int i = 0;
|
|
while (string[i] != '\0') {
|
|
interfaceDrawCharF(font, to_surface, string[i], (start_x)+i*(font->width*font->scale_x), start_y);
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void interfaceDrawCharF(struct Font *font, SDL_Surface *to_surface, 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*font->width*font->scale_x, y_offset*font->height*font->scale_y, font->width*font->scale_x, font->height*font->scale_y};
|
|
SDL_Rect render_position = {start_x, start_y, font->width*font->scale_x, font->height*font->scale_y};
|
|
SDL_BlitSurface(font->scaled_spritesheet, &character_offset, to_surface, &render_position);
|
|
}
|
|
|
|
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 combinepixels(Uint32 pixel_1, Uint32 pixel_2) {
|
|
Uint8 *p_1 = &pixel_1;
|
|
Uint8 *p_2 = &pixel_2;
|
|
#if SDL_BYTEORDER == SDL_BIGENDIAN
|
|
return ( ((p_1[0]/2)+(p_2[0]/2)) << 24 | ((p_1[1]/2)+(p_2[1]/2)) << 16 | ((p_1[2]/2)+(p_2[2]/2)) << 8 | ((p_1[3]/2)+(p_2[3]/2)) );
|
|
//return ( ((p_1[0]/2)+(p_2[0]/2)) << 16 | ((p_1[1]/2)+(p_2[1]/2)) << 8 | ((p_1[2]/2)+(p_2[2]/2)) );
|
|
#else
|
|
return ( ((p_1[0]/2)+(p_2[0]/2)) | ((p_1[1]/2)+(p_2[1]/2)) << 8 | ((p_1[2]/2)+(p_2[2]/2)) << 16 | ((p_1[3]/2)+(p_2[3]/2)) << 24 );
|
|
//return ( (p_1[0]/2)+(p_2[0]/2) | (p_1[1]/2)+(p_2[1]/2) << 8 | (p_1[2]/2)+(p_2[2]/2) << 16 );
|
|
#endif
|
|
}
|
|
|
|
Uint32 getpixel(SDL_Surface *surface, int x, int y) {
|
|
if (y >= 0 && x >= 0 && x <= surface->w && y <= surface->h) {
|
|
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 */
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel) {
|
|
if (y >= 0 && x >= 0 && x <= surface->w && y <= surface->h) {
|
|
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;
|
|
}*/
|
|
|
|
void SDL_SetOpacity(SDL_Surface *surface, double percent) {
|
|
Uint8 surface_bpp = surface->format->BytesPerPixel;
|
|
Uint8 *surface_bits;
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
|
int amask = 0x000000ff;
|
|
int cmask = 0xffffff00;
|
|
#else
|
|
int amask = 0xff000000;
|
|
int cmask = 0x00ffffff;
|
|
int shift = 24;
|
|
#endif
|
|
int x;
|
|
int y;
|
|
Uint32 pixels;
|
|
Uint32 alpha;
|
|
for(y=0;y<surface->h;y++) {
|
|
for(x=0;x<surface->w;x++) {
|
|
surface_bits = ((Uint8 *)surface->pixels+(y*surface->pitch)+(x*surface_bpp));
|
|
pixels = *((Uint32 *)(surface_bits));
|
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
|
// FIXME: Temporary replacement of amask with cmask below - THIS IS STUPID, as it shows erroneous colors, but I need partial opacity for the time being (and this allows for that).
|
|
alpha = pixels & cmask;
|
|
alpha *= percent;
|
|
*((Uint32 *)(surface_bits)) = (pixels & cmask) | alpha;
|
|
#else
|
|
alpha = (pixels & amask) >> shift;
|
|
alpha *= percent;
|
|
*((Uint32 *)(surface_bits)) = (pixels & cmask) | (alpha << shift);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void SDL_CopySurface(SDL_Surface *from_surface, SDL_Rect *from_rect, SDL_Surface *to_surface, SDL_Rect *to_rect) {
|
|
Sint16 x;
|
|
Sint16 y;
|
|
Sint16 from_x = from_rect->x;
|
|
Sint16 from_y = from_rect->y;
|
|
Sint16 to_x = to_rect->x;
|
|
Sint16 to_y = to_rect->y;
|
|
SDL_LockSurface(from_surface);
|
|
SDL_LockSurface(to_surface);
|
|
for (y = 0;y < from_rect->h;y++) {
|
|
for (x = 0;x < from_rect->w;x++) {
|
|
putpixel(to_surface, to_x+x, to_y+y, getpixel(from_surface, from_x+x, from_y+y));
|
|
}
|
|
}
|
|
SDL_UnlockSurface(from_surface);
|
|
SDL_UnlockSurface(to_surface);
|
|
}
|
|
|
|
SDL_Surface *SDL_ScaleSurface(SDL_Surface *surface, float scale_x, float scale_y) {
|
|
long x;
|
|
long y;
|
|
long output_x;
|
|
long output_y;
|
|
long new_width = (long)((float)surface->w * scale_x+0.5f);
|
|
long new_height = (long)((float)surface->h * scale_y+0.5f);
|
|
SDL_Surface *new_surface = SDL_CreateRGBSurface(surface->flags, new_width, new_height, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask);
|
|
|
|
for (y = 0;y < surface->h;y++) {
|
|
for (x = 0;x < surface->w;x++) {
|
|
for (output_y = 0;output_y < scale_y; ++output_y) {
|
|
for (output_x = 0;output_x < scale_x; ++output_x) {
|
|
putpixel(new_surface, (Sint32)(scale_x*x) + output_x, (Sint32)(scale_y*y)+output_y, getpixel(surface, x, y));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return new_surface;
|
|
}
|
|
|
|
|
|
SDL_Surface *interfaceSmoothScaleSurface(SDL_Surface *surface, float scale_x, float scale_y) {
|
|
long x;
|
|
long y;
|
|
long output_x;
|
|
long output_y;
|
|
long new_width = (long)((float)surface->w * scale_x+0.5f);
|
|
long new_height = (long)((float)surface->h * scale_y+0.5f);
|
|
SDL_Surface *new_surface = SDL_CreateRGBSurface(surface->flags, new_width, new_height, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask);
|
|
|
|
for (y = 0;y < surface->h;y++) {
|
|
for (x = 0;x < surface->w;x++) {
|
|
for (output_y = 0;output_y < scale_y; ++output_y) {
|
|
for (output_x = 0;output_x < scale_x; ++output_x) {
|
|
if (output_x > 0 && output_y > 0) {
|
|
//putpixel(new_surface, (Sint32)(scale_x*x) + output_x, (Sint32)(scale_y*y)+output_y, combinepixels(getpixel(surface, x, y), getpixel(surface, x-output_x, y-output_y)));
|
|
putpixel(new_surface, (Sint32)(scale_x*x) + output_x, (Sint32)(scale_y*y)+output_y, combinepixels(getpixel(surface, x, y), getpixel(surface, x, y)));
|
|
} else {
|
|
putpixel(new_surface, (Sint32)(scale_x*x) + output_x, (Sint32)(scale_y*y)+output_y, getpixel(surface, x, y));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// free our old surface and replace
|
|
SDL_FreeSurface(surface);
|
|
//surface = new_surface;
|
|
return new_surface;
|
|
}
|
|
|
|
|
|
SDL_Surface *interfaceScaleSurface(SDL_Surface *surface, float scale_x, float scale_y) {
|
|
long x;
|
|
long y;
|
|
long output_x;
|
|
long output_y;
|
|
long new_width = (long)((float)surface->w * scale_x+0.5f);
|
|
long new_height = (long)((float)surface->h * scale_y+0.5f);
|
|
SDL_Surface *new_surface = SDL_CreateRGBSurface(surface->flags, new_width, new_height, surface->format->BitsPerPixel, surface->format->Rmask, surface->format->Gmask, surface->format->Bmask, surface->format->Amask);
|
|
|
|
for (y = 0;y < surface->h;y++) {
|
|
for (x = 0;x < surface->w;x++) {
|
|
for (output_y = 0;output_y < scale_y; ++output_y) {
|
|
for (output_x = 0;output_x < scale_x; ++output_x) {
|
|
putpixel(new_surface, (Sint32)(scale_x*x) + output_x, (Sint32)(scale_y*y)+output_y, getpixel(surface, x, y));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// free our old surface and replace
|
|
SDL_FreeSurface(surface);
|
|
//surface = new_surface;
|
|
return new_surface;
|
|
}
|
|
|
|
int interfaceVideoSet() {
|
|
if ((screen = SDL_SetVideoMode(g_video_width, g_video_height, 32, SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_RESIZABLE|g_video_fullscreen)) == NULL) {
|
|
return ERROR;
|
|
}
|
|
SDL_FreeSurface(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++;
|
|
}
|
|
g_video_height = atoi(height); // ... had to reverse order for it to work on win...
|
|
g_video_width = atoi(width);
|
|
|
|
if (fullscreen[0] == '1') { // fullscreen
|
|
g_video_fullscreen = SDL_FULLSCREEN;
|
|
} else if (fullscreen[0] == '0') { // windowed
|
|
g_video_fullscreen = 0;
|
|
}
|
|
interfaceVideoSet();
|
|
} else {
|
|
consoleLog("Syntax: widthxheight 0|1");
|
|
}
|
|
}
|
|
|
|
void consoleScaleTiles(const char *input_string) {
|
|
if (input_string) {
|
|
int i = 0;
|
|
int j = 0;
|
|
char height[15];
|
|
char width[15];
|
|
int position = 0;
|
|
|
|
while(input_string[i] != '\0') {
|
|
if (input_string[i] == ' ') {
|
|
width[j] = '\0';
|
|
position = 1;
|
|
i++; // skip the x
|
|
j = 0;
|
|
//} else if (input_string[i] == ' ') {
|
|
// height[j] = '\0';
|
|
// i++; // skip the space
|
|
// j = 0;
|
|
// break;
|
|
}
|
|
if (position == 0) {
|
|
width[j] = input_string[i];
|
|
} else if (position == 1) {
|
|
height[j] = input_string[i];
|
|
}
|
|
j++;
|
|
i++;
|
|
}
|
|
float scale_x = atof(width); // ... had to reverse order for it to work on win...
|
|
float scale_y = atof(height);
|
|
if (scale_x <= 0)
|
|
scale_x = 2.0; // default to 2.0 if scale_x is 0/invalid
|
|
if (scale_y <= 0)
|
|
scale_y = scale_x; // copy scale_x if scale_y unset/0/invalid
|
|
scaleTiles(scale_x, scale_y);
|
|
} else {
|
|
consoleLog("Syntax: widthxheight");
|
|
}
|
|
}
|
|
|
|
|
|
void loadFontFromMemory(struct Font *font, unsigned char *memory, unsigned int length, int width, int height) {
|
|
font->scale_x = 1.0f;
|
|
font->scale_y = 1.0f;
|
|
font->width = width;
|
|
font->height = height;
|
|
font->s_width = width;
|
|
font->s_height = height;
|
|
font->spritesheet = IMG_Load_RW(SDL_RWFromMem(memory, length), 1);
|
|
font->scaled_spritesheet = SDL_ScaleSurface(font->spritesheet, 1.0f, 1.0f);
|
|
}
|
|
|
|
void freeFont(struct Font *font) {
|
|
SDL_FreeSurface(font->spritesheet);
|
|
SDL_FreeSurface(font->scaled_spritesheet);
|
|
}
|
|
|
|
void setFontScale(struct Font *font, float scale_x, float scale_y) {
|
|
font->scale_x = scale_x;
|
|
font->scale_y = scale_y;
|
|
SDL_FreeSurface(font->scaled_spritesheet);
|
|
font->scaled_spritesheet = interfaceScaleSurface(font->spritesheet, scale_x, scale_y);
|
|
font->s_width = font->width * scale_x;
|
|
font->s_height = font->height * scale_y;
|
|
}
|
|
|
|
void loadSpritesheetFromMemory(struct Spritesheet *spritesheet, unsigned char *memory, unsigned int length, int width, int height, int columns) {
|
|
spritesheet->width = width;
|
|
spritesheet->height = height;
|
|
spritesheet->columns = columns;
|
|
spritesheet->spritesheet = IMG_Load_RW(SDL_RWFromMem(memory, length), 1);
|
|
spritesheet->scale_x = 1.0f;
|
|
spritesheet->scale_y = 1.0f;
|
|
spritesheet->s_spritesheet = SDL_ScaleSurface(spritesheet->spritesheet, 1.0f, 1.0f);
|
|
spritesheet->s_width = width;
|
|
spritesheet->s_height = height;
|
|
}
|
|
|
|
void freeSpritesheet(struct Spritesheet *spritesheet) {
|
|
SDL_FreeSurface(spritesheet->s_spritesheet);
|
|
SDL_FreeSurface(spritesheet->spritesheet);
|
|
}
|
|
|
|
void setSpritesheetScale(struct Spritesheet *spritesheet, float scale_x, float scale_y) {
|
|
spritesheet->scale_x = scale_x;
|
|
spritesheet->scale_y = scale_y;
|
|
SDL_FreeSurface(spritesheet->s_spritesheet);
|
|
spritesheet->s_spritesheet = SDL_ScaleSurface(spritesheet->spritesheet, scale_x, scale_y);
|
|
spritesheet->s_width = spritesheet->width * scale_x;
|
|
spritesheet->s_height = spritesheet->height * scale_y;
|
|
}
|
|
|
|
void drawSprite(struct Spritesheet *spritesheet, int id, SDL_Surface *target_surface, int start_x, int start_y) {
|
|
int y_offset = id / spritesheet->columns;
|
|
int x_offset = id - (y_offset * spritesheet->columns);
|
|
|
|
SDL_Rect sprite_offset = { x_offset*spritesheet->width, y_offset*spritesheet->height, spritesheet->width, spritesheet->height};
|
|
SDL_Rect render_position = {start_x, start_y, spritesheet->width, spritesheet->height};
|
|
|
|
SDL_BlitSurface(spritesheet->spritesheet, &sprite_offset, target_surface, &render_position);
|
|
}
|
|
|
|
void drawScaledSprite(struct Spritesheet *spritesheet, int id, SDL_Surface *target_surface, int start_x, int start_y) {
|
|
int y_offset = id / spritesheet->columns;
|
|
int x_offset = id - (y_offset * spritesheet->columns);
|
|
|
|
SDL_Rect sprite_offset = { x_offset*spritesheet->s_width, y_offset*spritesheet->s_height, spritesheet->s_width, spritesheet->s_height};
|
|
SDL_Rect render_position = {start_x, start_y, spritesheet->s_width, spritesheet->s_height};
|
|
SDL_BlitSurface(spritesheet->s_spritesheet, &sprite_offset, target_surface, &render_position);
|
|
}
|
|
|
|
void drawScaledTransparentSprite(struct Spritesheet *spritesheet, int id, double opacity, SDL_Surface *target_surface, int start_x, int start_y) {
|
|
int y_offset = id / spritesheet->columns;
|
|
int x_offset = id - (y_offset * spritesheet->columns);
|
|
|
|
SDL_Rect sprite_offset = { x_offset*spritesheet->s_width, y_offset*spritesheet->s_height, spritesheet->s_width, spritesheet->s_height};
|
|
SDL_Rect render_position = {start_x, start_y, spritesheet->s_width, spritesheet->s_height};
|
|
//SDL_BlitSurface(spritesheet->s_spritesheet, &sprite_offset, target_surface, &render_position);
|
|
SDL_Surface *temp_sprite = SDL_CreateRGBSurface(spritesheet->spritesheet->flags, spritesheet->s_width, spritesheet->s_height, spritesheet->spritesheet->format->BitsPerPixel, spritesheet->s_spritesheet->format->Rmask, spritesheet->s_spritesheet->format->Gmask, spritesheet->s_spritesheet->format->Bmask, spritesheet->s_spritesheet->format->Amask);
|
|
|
|
// Why doesn't the following work:
|
|
//SDL_BlitSurface(spritesheet->s_spritesheet, &sprite_offset, temp_sprite, NULL);
|
|
// But this does:
|
|
SDL_Rect temp_offset = { 0, 0, spritesheet->s_width, spritesheet->s_height };
|
|
SDL_CopySurface(spritesheet->s_spritesheet, &sprite_offset, temp_sprite, &temp_offset);
|
|
// TODO: do not use copysurface, use blitsurface, as it (should) be faster.
|
|
SDL_SetOpacity(temp_sprite, opacity);
|
|
|
|
SDL_BlitSurface(temp_sprite, NULL, target_surface, &render_position);
|
|
//SDL_BlitSurface(spritesheet->s_spritesheet, &sprite_offset, target_surface, &render_position);
|
|
}
|
|
|
|
void drawScaledSpriteOutline(struct Spritesheet *spritesheet, int id, SDL_Surface *target_surface, int start_x, int start_y) {
|
|
int y_offset = id / spritesheet->columns;
|
|
int x_offset = id - (y_offset * spritesheet->columns);
|
|
|
|
SDL_Rect sprite_offset = { x_offset*spritesheet->s_width, y_offset*spritesheet->s_height, spritesheet->s_width, spritesheet->s_height};
|
|
SDL_Rect render_position = {start_x, start_y, spritesheet->s_width, spritesheet->s_height};
|
|
|
|
SDL_Surface *temp_sprite = SDL_CreateRGBSurface(spritesheet->spritesheet->flags, spritesheet->s_width, spritesheet->s_height, spritesheet->spritesheet->format->BitsPerPixel, spritesheet->s_spritesheet->format->Rmask, spritesheet->s_spritesheet->format->Gmask, spritesheet->s_spritesheet->format->Bmask, spritesheet->s_spritesheet->format->Amask);
|
|
|
|
int x = 0;
|
|
int y = 0;
|
|
SDL_LockSurface(temp_sprite);
|
|
SDL_LockSurface(spritesheet->s_spritesheet);
|
|
int bpp = spritesheet->s_spritesheet->format->BytesPerPixel;
|
|
for (y = 0;y < spritesheet->s_height;y++) {
|
|
for (x = 0;x < spritesheet->s_width;x++) {
|
|
// TODO: optimize!
|
|
Uint32 *p_l = getpixel(spritesheet->s_spritesheet, sprite_offset.x+x-1, sprite_offset.y+y);
|
|
Uint32 *p_u = getpixel(spritesheet->s_spritesheet, sprite_offset.x+x, sprite_offset.y+y-1);
|
|
Uint32 *p_r = getpixel(spritesheet->s_spritesheet, sprite_offset.x+x+1, sprite_offset.y+y);
|
|
Uint32 *p_d = getpixel(spritesheet->s_spritesheet, sprite_offset.x+x, sprite_offset.y+y+1);
|
|
// It's endian-ambiguous!
|
|
Uint32 p_o = 0xFFFFFFFF;
|
|
Uint8 *val = 128; // pixels under 128 opacity are considered empty
|
|
|
|
if ((Uint8 *)&p_l[3] < val && (Uint8 *)&p_u[3] < val && (Uint8*)&p_d[3] < val && (Uint8*)&p_r[3] > val) {
|
|
putpixel(temp_sprite, x, y, p_o);
|
|
}
|
|
if ((Uint8 *)&p_l[3] > val && (Uint8 *)&p_u[3] < val && (Uint8*)&p_d[3] < val && (Uint8*)&p_r[3] < val) {
|
|
putpixel(temp_sprite, x, y, p_o);
|
|
}
|
|
if ((Uint8 *)&p_l[3] < val && (Uint8 *)&p_u[3] > val && (Uint8*)&p_d[3] < val && (Uint8*)&p_r[3] < val) {
|
|
putpixel(temp_sprite, x, y, p_o);
|
|
}
|
|
if ((Uint8 *)&p_l[3] < val && (Uint8 *)&p_u[3] < val && (Uint8*)&p_d[3] > val && (Uint8*)&p_r[3] < val) {
|
|
putpixel(temp_sprite, x, y, p_o);
|
|
}
|
|
}
|
|
}
|
|
SDL_UnlockSurface(spritesheet->s_spritesheet);
|
|
SDL_UnlockSurface(temp_sprite);
|
|
|
|
SDL_BlitSurface(temp_sprite, NULL, target_surface, &render_position);
|
|
}
|
|
|
|
void interfaceQuit() {
|
|
SDL_Event event;
|
|
event.type = SDL_QUIT;
|
|
SDL_PushEvent(&event);
|
|
}
|
|
|
|
void interfaceClose() {
|
|
SDL_FreeSurface(camera_surface);
|
|
SDL_FreeSurface(font_spritesheet);
|
|
freeFont(&font_mini);
|
|
// freeFont(&font_standard); // FIXME: causes segfault
|
|
|
|
freeSpritesheet(&player_sprites);
|
|
freeSpritesheet(&shadow_sprites);
|
|
freeSpritesheet(&npc_sprites);
|
|
freeSpritesheet(&floor_sprites);
|
|
freeSpritesheet(&door_sprites);
|
|
freeSpritesheet(&wall_sprites);
|
|
freeSpritesheet(&item_sprites);
|
|
freeSpritesheet(&equip_sprites);
|
|
|
|
SDL_Quit();
|
|
}
|