diff --git a/src/common.h b/src/common.h index ea4752b..02d1884 100644 --- a/src/common.h +++ b/src/common.h @@ -82,7 +82,7 @@ #define rgba(r, g, b, a) (((int)(a) << 24) | ((int)(b) << 16) | ((int)(g) << 8) | (int)(r)) #define rgb(r, g, b) (((b) << 16) | ((g) << 8) | (r)) #define rgb2bgr(col) rgb(blue(col), green(col), red(col)) -#define red(col) ((col)&0xFF) +#define red(col) ((col) & 0xFF) #define green(col) (((col) >> 8) & 0xFF) #define blue(col) (((col) >> 16) & 0xFF) #define alpha(col) (((col) >> 24) & 0xFF) @@ -98,6 +98,8 @@ #define CHAT_ALL_INPUT 1 #define CHAT_TEAM_INPUT 2 +#define BIG_TEXT_SIZE 53.0F + extern int chat_input_mode; extern float last_cy; @@ -107,6 +109,7 @@ extern char chat[2][10][256]; extern unsigned int chat_color[2][10]; extern float chat_timer[2][10]; extern char chat_popup[256]; +extern float chat_popup_height; extern float chat_popup_timer; extern float chat_popup_duration; extern int chat_popup_color; diff --git a/src/font.c b/src/font.c index 548974b..8fb6cc1 100644 --- a/src/font.c +++ b/src/font.c @@ -151,6 +151,22 @@ float font_length(float h, char* text) { return fmax(length, x) + h * 0.125F; } +// font_fit_height (int max_width, text, starting_height) - get height such that text fits in max_width ie. +// window/screen width returns -1 if text is too long (ie. height is smaller than 16.0F) and needs to be broken up with +// newlines + +float font_fit_height(int max_width, float starting_height, char* text) { + float scalex = max_width / 800.0F; // not sure if I should consider this a hacky solution + + float h = starting_height * scalex; + float length = font_length_internal(h, text, true); + + float target = max_width < length ? h / (length / max_width) : h; + + // text under 16pt is unreadable + return target < 16.0F ? -1.0F : target; +} + bool font_remove_callback(void* key, void* value, void* user) { struct font_backed_data* f = (struct font_backed_data*)value; diff --git a/src/font.h b/src/font.h index 0319032..c97c526 100644 --- a/src/font.h +++ b/src/font.h @@ -28,6 +28,7 @@ enum font_type { void font_init(void); void font_reset(void); float font_length(float h, char* text); +float font_fit_height(int max_width, float starting_height, char* text); void font_render(float x, float y, float h, char* text); void font_centered(float x, float y, float h, char* text); void font_select(enum font_type type); diff --git a/src/hud.c b/src/hud.c index b512128..d16bd1f 100644 --- a/src/hud.c +++ b/src/hud.c @@ -580,9 +580,9 @@ static void hud_ingame_render(mu_Context* ctx, float scalex, float scalef) { break; } } - font_centered(settings.window_width * 0.25F, 487 * scalef, 53.0F * scalef, score_str); + font_centered(settings.window_width * 0.25F, 487 * scalef, BIG_TEXT_SIZE * scalef, score_str); font_render(settings.window_width * 0.25F - font_length(18.0F * scalef, gamestate.team_1.name) - - font_length(53.0F * scalef, score_str) / 2, + - font_length(BIG_TEXT_SIZE * scalef, score_str) / 2, 460 * scalef, 18.0F * scalef, gamestate.team_1.name); glColor3ub(gamestate.team_2.red, gamestate.team_2.green, gamestate.team_2.blue); @@ -600,9 +600,9 @@ static void hud_ingame_render(mu_Context* ctx, float scalex, float scalef) { break; } } - font_centered(settings.window_width * 0.75F, 487 * scalef, 53.0F * scalef, score_str); + font_centered(settings.window_width * 0.75F, 487 * scalef, BIG_TEXT_SIZE * scalef, score_str); font_render(settings.window_width * 0.75F - font_length(18.0F * scalef, gamestate.team_2.name) - - font_length(53.0F * scalef, score_str) / 2, + - font_length(BIG_TEXT_SIZE * scalef, score_str) / 2, 460 * scalef, 18.0F * scalef, gamestate.team_2.name); struct player_table pt[PLAYERS_MAX]; @@ -679,7 +679,8 @@ static void hud_ingame_render(mu_Context* ctx, float scalex, float scalef) { char coin[16]; sprintf(coin, "INSERT COIN:%i", cnt); font_centered(settings.window_width / 2.0F, - 53.0F * scalef * (cameracontroller_bodyview_mode ? 2.0F : 1.0F), 53.0F * scalef, coin); + BIG_TEXT_SIZE * scalef * (cameracontroller_bodyview_mode ? 2.0F : 1.0F), + BIG_TEXT_SIZE * scalef, coin); if(local_player_respawn_cnt_last != cnt) { if(cnt < 4) { sound_create(SOUND_LOCAL, (cnt == 1) ? &sound_beep1 : &sound_beep2, 0.0F, 0.0F, 0.0F); @@ -742,8 +743,8 @@ static void hud_ingame_render(mu_Context* ctx, float scalex, float scalef) { glColor3f(1, 1, 1); char hp[4]; sprintf(hp, "%i", health); - font_render(settings.window_width / 2.0F - font_length(53.0F * scalef, hp), 53.0F * scalef, 53.0F * scalef, - hp); + font_render(settings.window_width / 2.0F - font_length(BIG_TEXT_SIZE * scalef, hp), BIG_TEXT_SIZE * scalef, + BIG_TEXT_SIZE * scalef, hp); texture_draw(&texture_health, settings.window_width / 2.0F, 44.0F * scalef, 32.0F * scalef, 32.0F * scalef); char item_mini_str[32]; @@ -778,8 +779,9 @@ static void hud_ingame_render(mu_Context* ctx, float scalex, float scalef) { texture_draw(item_mini, settings.window_width - 44.0F * scalef - off, 44.0F * scalef, 32.0F * scalef, 32.0F * scalef); - font_render(settings.window_width - font_length(53.0F * scalef, item_mini_str) - 44.0F * scalef - off, - 53.0F * scalef, 53.0F * scalef, item_mini_str); + font_render(settings.window_width - font_length(BIG_TEXT_SIZE * scalef, item_mini_str) - 44.0F * scalef + - off, + BIG_TEXT_SIZE * scalef, BIG_TEXT_SIZE * scalef, item_mini_str); glColor3f(1.0F, 1.0F, 1.0F); if(players[local_id].held_item == TOOL_BLOCK) { @@ -1177,8 +1179,9 @@ static void hud_ingame_render(mu_Context* ctx, float scalex, float scalef) { if(show_exit) { glColor3f(1.0F, 0.0F, 0.0F); - font_render((settings.window_width - font_length(53.0F * scalef, "EXIT GAME? Y/N")) / 2.0F, - settings.window_height / 2.0F + 53.0F * scalef, 53.0F * scalef, "EXIT GAME? Y/N"); + font_render((settings.window_width - font_length(BIG_TEXT_SIZE * scalef, "EXIT GAME? Y/N")) / 2.0F, + settings.window_height / 2.0F + BIG_TEXT_SIZE * scalef, BIG_TEXT_SIZE * scalef, + "EXIT GAME? Y/N"); char play_time[128]; sprintf(play_time, "Playing for %im%is", (int)window_time() / 60, (int)window_time() % 60); @@ -1187,8 +1190,32 @@ static void hud_ingame_render(mu_Context* ctx, float scalex, float scalef) { } if(window_time() - chat_popup_timer < chat_popup_duration) { glColor3ub(red(chat_popup_color), green(chat_popup_color), blue(chat_popup_color)); - font_render((settings.window_width - font_length(53.0F * scalef, chat_popup)) / 2.0F, - settings.window_height / 2.0F, 53.0F * scalef, chat_popup); + + // Renders each string on a new line + // read chat_popup until the next new line + // then copy that string into a temporary string and increas i by 1 + // then render the temporary string + // repeat until the end of chat_popup + char* chat_popup_line = chat_popup; + int i = 0; + while(chat_popup_line != NULL) { + char* next_line = strchr(chat_popup_line, '\n'); + char chat_popup_temp[256]; + if(next_line != NULL) { + strncpy(chat_popup_temp, chat_popup_line, next_line - chat_popup_line); + chat_popup_temp[next_line - chat_popup_line] = '\0'; + chat_popup_line = next_line + 1; + } else { + strcpy(chat_popup_temp, chat_popup_line); + chat_popup_line = NULL; + } + float text_pixel_width = font_length(chat_popup_height, chat_popup_temp); + + font_render((settings.window_width - text_pixel_width) / 2.0F, + settings.window_height * 2.0F / 3.0F - (chat_popup_height * i), chat_popup_height, + chat_popup_temp); + i++; + } } glColor3f(1.0F, 1.0F, 1.0F); } diff --git a/src/main.c b/src/main.c index 7a1f924..c690575 100644 --- a/src/main.c +++ b/src/main.c @@ -74,12 +74,42 @@ void chat_add(int channel, unsigned int color, const char* msg) { } char chat_popup[256] = {}; int chat_popup_color; +float chat_popup_height = 0.0F; float chat_popup_timer = 0.0F; float chat_popup_duration = 0.0F; void chat_showpopup(const char* msg, float duration, int color) { strcpy(chat_popup, msg); chat_popup_timer = window_time(); + + chat_popup_height = font_fit_height(settings.window_width, BIG_TEXT_SIZE, chat_popup); + + int len = strlen(chat_popup); + char tmp[len + 1]; + strcpy(tmp, chat_popup); + + char* tmp_offset = tmp; + while(chat_popup_height == -1.0F) { + // break up chat_popup into multiple lines + + // find first space from the left of the middle of chat_popup + // replace with newline + char* pos = tmp_offset + len / 2; + while(*pos != ' ' && pos != tmp_offset) + pos--; + + if(pos != tmp_offset) + *pos = '\n'; + else { + chat_popup_height = 16.0F; + break; + } + + chat_popup_height = fmin(chat_popup_height, font_fit_height(settings.window_width, BIG_TEXT_SIZE, pos)); + tmp_offset = pos; + } + strcpy(chat_popup, tmp); + chat_popup_duration = duration; chat_popup_color = color; } @@ -506,8 +536,11 @@ void init() { } void reshape(struct window_instance* window, int width, int height) { + if(width == 0 || height == 0) + return; font_reset(); glViewport(0, 0, width, height); + log_info("window size: %i:%ipx", width, height); settings.window_width = width; settings.window_height = height; if(settings.vsync < 2) @@ -583,6 +616,9 @@ void keys(struct window_instance* window, int key, int scancode, int action, int if(!settings.fullscreen) { glfwSetWindowMonitor(window->impl, glfwGetPrimaryMonitor(), 0, 0, mode->width, mode->height, mode->refreshRate); + log_info("Switched to fullscreen mode, %ix%i", mode->width, mode->height); + settings.window_width = mode->width; + settings.window_height = mode->height; settings.fullscreen = 1; } else { glfwSetWindowMonitor(window->impl, NULL, (mode->width - 800) / 2, (mode->height - 600) / 2, 800, 600, 0); diff --git a/src/network.c b/src/network.c index dd24416..4bac1f9 100644 --- a/src/network.c +++ b/src/network.c @@ -107,10 +107,10 @@ void read_PacketMapChunk(void* data, int len) { compressed_chunk_data_offset += len; } -void read_PacketChatMessage(void* data, int len) { - struct PacketChatMessage* p = (struct PacketChatMessage*)data; +void read_PacketChatMessage_internal(struct PacketChatMessage* p, int len) { char n[32] = {0}; char m[256]; + switch(p->chat_type) { case CHAT_ERROR: sound_create(SOUND_LOCAL, &sound_beep2, 0.0F, 0.0F, 0.0F); case CHAT_BIG: chat_showpopup(p->message, 5.0F, rgb(255, 0, 0)); return; @@ -165,6 +165,20 @@ void read_PacketChatMessage(void* data, int len) { chat_add(0, color, m); } +void read_PacketChatMessage(void* data, int len) { + struct PacketChatMessage* p = (struct PacketChatMessage*)data; + + // terminate the message string, len is message plus two byte chars (player id and chat type) + // however, enet actually needs whatever data is after the message to properly free the packet data + // so we have to return it to the original state in the end + char original_byte = p->message[len - 2]; + p->message[len - 2] = 0; + + read_PacketChatMessage_internal(p, len); + + p->message[len - 2] = original_byte; +} + void read_PacketBlockAction(void* data, int len) { struct PacketBlockAction* p = (struct PacketBlockAction*)data; switch(p->action_type) { @@ -308,14 +322,11 @@ void read_PacketStateData(void* data, int len) { } if(r == LIBDEFLATE_SUCCESS) { map_vxl_load(decompressed, decompressed_size); -/*#ifndef USE_TOUCH - char filename[128]; - sprintf(filename, "cache/%08X.vxl", libdeflate_crc32(0, decompressed, decompressed_size)); - log_info("%s", filename); - FILE* f = fopen(filename, "wb"); - fwrite(decompressed, 1, decompressed_size, f); - fclose(f); -#endif*/ + /*#ifndef USE_TOUCH + char filename[128]; + sprintf(filename, "cache/%08X.vxl", libdeflate_crc32(0, decompressed, + decompressed_size)); log_info("%s", filename); FILE* f = fopen(filename, "wb"); fwrite(decompressed, 1, + decompressed_size, f); fclose(f); #endif*/ chunk_rebuild_all(); break; } diff --git a/src/network.h b/src/network.h index 74200f4..e0a2d4a 100644 --- a/src/network.h +++ b/src/network.h @@ -323,7 +323,7 @@ struct PacketSetTool { struct PacketChatMessage { unsigned char player_id; unsigned char chat_type; - char message[255]; + char message[255 + 1]; // msg is limited to 255 chars but we manually terminate it }; #define CHAT_ALL 0 #define CHAT_TEAM 1