#include #if !defined (__APPLE__) #include #else #include #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;yh;y++) { for(x=0;xw;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(); }