/* * @brief The input line scrolls horizontally if typing goes beyond the right edge */ static void Cl_DrawConsole_Input(void) { r_pixel_t cw, ch; R_BindFont("small", &cw, &ch); r_pixel_t x = 1, y = cl_console.height * ch; // draw the prompt R_DrawChar(0, y, ']', CON_COLOR_ALT); // and the input buffer, scrolling horizontally if appropriate const char *s = cl_console.input.buffer; if (cl_console.input.pos > cl_console.width - 2) { s += 2 + cl_console.input.pos - cl_console.width; } while (*s) { R_DrawChar(x * cw, y, *s, CON_COLOR_DEFAULT); s++; x++; } // and lastly cursor R_DrawChar((cl_console.input.pos + 1) * cw, y, 0x0b, CON_COLOR_DEFAULT); }
/** * @brief */ static void Cl_DrawConsole_Buffer(void) { r_pixel_t cw, ch, height; R_BindFont("small", &cw, &ch); if (cls.state == CL_ACTIVE) { height = r_context.height * 0.5; R_DrawFill(0, 0, r_context.width, height, 7, 0.3); } else { height = r_context.height; R_DrawFill(0, 0, r_context.width, height, 0, 1.0); } cl_console.width = r_context.width / cw; cl_console.height = (height / ch) - 1; char *lines[cl_console.height]; const size_t count = Con_Tail(&cl_console, lines, cl_console.height); r_pixel_t y = (cl_console.height - count) * ch; for (size_t i = 0; i < count; i++) { R_DrawString(0, y, lines[i], CON_COLOR_DEFAULT); g_free(lines[i]); y += ch; } }
/* * @brief */ static void Cl_DrawCounters(void) { static vec3_t velocity; static char bps[8], pps[8], fps[8], spd[8]; static int32_t last_draw_time; r_pixel_t cw, ch; if (!cl_draw_counters->value) return; R_BindFont("small", &cw, &ch); const r_pixel_t x = r_context.width - 7 * cw; r_pixel_t y = r_context.height - 4 * ch; cl.frame_counter++; if (cls.real_time - last_draw_time >= 200) { UnpackVector(cl.frame.ps.pm_state.velocity, velocity); velocity[2] = 0.0; g_snprintf(spd, sizeof(spd), "%4.0fspd", VectorLength(velocity)); g_snprintf(fps, sizeof(fps), "%4ufps", cl.frame_counter * 5); g_snprintf(pps, sizeof(pps), "%4upps", cl.packet_counter * 5); g_snprintf(bps, sizeof(bps), "%4ubps", cl.byte_counter * 5); last_draw_time = quetoo.time; cl.frame_counter = 0; cl.packet_counter = 0; cl.byte_counter = 0; } R_DrawString(x, y, spd, CON_COLOR_DEFAULT); y += ch; R_DrawString(x, y, fps, CON_COLOR_DEFAULT); y += ch; R_DrawString(x, y, pps, CON_COLOR_DEFAULT); y += ch; R_DrawString(x, y, bps, CON_COLOR_DEFAULT); R_BindFont(NULL, NULL, NULL); }
/* * @brief */ void Cl_DrawConsole(void) { Cl_DrawConsole_Buffer(); Cl_DrawConsole_Input(); R_BindFont(NULL, NULL, NULL); }
/* * @brief Draws counters and performance information about the sound subsystem. */ static void Cl_DrawSoundStats(void) { r_pixel_t ch, y = cl_show_renderer_stats->value ? 400 : 64; if (!cl_show_sound_stats->value) return; if (cls.state != CL_ACTIVE) return; R_BindFont("small", NULL, &ch); R_DrawString(0, y, "Sound:", CON_COLOR_MAGENTA); y += ch; R_DrawString(0, y, va("%d channels", s_env.num_active_channels), CON_COLOR_MAGENTA); R_BindFont(NULL, NULL, NULL); }
/* * @brief */ void R_InitDraw(void) { memset(&r_draw, 0, sizeof(r_draw)); R_InitFont("small"); R_InitFont("medium"); R_InitFont("large"); R_BindFont(NULL, NULL, NULL); r_draw.cursor = R_LoadImage("fonts/cursor", IT_FONT); // set ABGR color values r_draw.colors[CON_COLOR_BLACK] = 0xff000000; r_draw.colors[CON_COLOR_RED] = 0xff0000ff; r_draw.colors[CON_COLOR_GREEN] = 0xff00ff00; r_draw.colors[CON_COLOR_YELLOW] = 0xff00ffff; r_draw.colors[CON_COLOR_BLUE] = 0xffff0000; r_draw.colors[CON_COLOR_CYAN] = 0xffffff00; r_draw.colors[CON_COLOR_MAGENTA] = 0xffff00ff; r_draw.colors[CON_COLOR_WHITE] = 0xffffffff; }
/* * @brief Draws counters and performance information about the renderer. */ static void Cl_DrawRendererStats(void) { r_pixel_t ch, y = 64; if (!cl_show_renderer_stats->value) return; if (cls.state != CL_ACTIVE) return; R_BindFont("small", NULL, &ch); R_DrawString(0, y, "Materials:", CON_COLOR_GREEN); y += ch; const uint32_t num_bind_diffuse = r_view.num_bind_texture - r_view.num_bind_lightmap - r_view.num_bind_deluxemap - r_view.num_bind_normalmap - r_view.num_bind_specularmap; R_DrawString(0, y, va("%d diffuse", num_bind_diffuse), CON_COLOR_GREEN); y += ch; R_DrawString(0, y, va("%d lightmap", r_view.num_bind_lightmap), CON_COLOR_GREEN); y += ch; R_DrawString(0, y, va("%d deluxemap", r_view.num_bind_deluxemap), CON_COLOR_GREEN); y += ch; R_DrawString(0, y, va("%d normalmap", r_view.num_bind_normalmap), CON_COLOR_GREEN); y += ch; R_DrawString(0, y, va("%d specularmap", r_view.num_bind_specularmap), CON_COLOR_GREEN); y += ch; y += ch; R_DrawString(0, y, "BSP:", CON_COLOR_YELLOW); y += ch; R_DrawString(0, y, va("%d clusters", r_view.num_bsp_clusters), CON_COLOR_YELLOW); y += ch; R_DrawString(0, y, va("%d leafs", r_view.num_bsp_leafs), CON_COLOR_YELLOW); y += ch; R_DrawString(0, y, va("%d surfaces", r_view.num_bsp_surfaces), CON_COLOR_YELLOW); y += ch; y += ch; R_DrawString(0, y, "Mesh:", CON_COLOR_CYAN); y += ch; R_DrawString(0, y, va("%d models", r_view.num_mesh_models), CON_COLOR_CYAN); y += ch; R_DrawString(0, y, va("%d tris", r_view.num_mesh_tris), CON_COLOR_CYAN); y += ch; y += ch; R_DrawString(0, y, "Other:", CON_COLOR_WHITE); y += ch; R_DrawString(0, y, va("%d lights", r_view.num_lights), CON_COLOR_WHITE); y += ch; R_DrawString(0, y, va("%d coronas", r_view.num_coronas), CON_COLOR_WHITE); y += ch; R_DrawString(0, y, va("%d particles", r_view.num_particles), CON_COLOR_WHITE); R_BindFont(NULL, NULL, NULL); }
/** * @brief Draws the last few lines of output transparently over the game top */ void Cl_DrawNotify(void) { r_pixel_t cw, ch; if (!cl_draw_notify->value) { return; } R_BindFont("small", &cw, &ch); console_t con = { .width = r_context.width / cw, .height = Clamp(cl_notify_lines->integer, 1, 12), .level = (PRINT_MEDIUM | PRINT_HIGH), }; if (cl.systime > cl_notify_time->value * 1000) { con.whence = cl.systime - cl_notify_time->value * 1000; } char *lines[con.height]; const size_t count = Con_Tail(&con, lines, con.height); r_pixel_t y = 0; for (size_t i = 0; i < count; i++) { R_DrawString(0, y, lines[i], CON_COLOR_DEFAULT); g_free(lines[i]); y += ch; } R_BindFont(NULL, NULL, NULL); } /** * @brief Draws the chat history and, optionally, the chat input string. */ void Cl_DrawChat(void) { r_pixel_t cw, ch; R_BindFont("small", &cw, &ch); r_pixel_t x = 1, y = r_view.y + r_view.height * 0.66; cl_chat_console.width = r_context.width / cw / 3; cl_chat_console.height = Clamp(cl_chat_lines->integer, 0, 8); if (cl_draw_chat->value && cl_chat_console.height) { if (cl.systime > cl_chat_time->value * 1000) { cl_chat_console.whence = cl.systime - cl_chat_time->value * 1000; } char *lines[cl_chat_console.height]; const size_t count = Con_Tail(&cl_chat_console, lines, cl_chat_console.height); for (size_t i = 0; i < count; i++) { R_DrawString(0, y, lines[i], CON_COLOR_DEFAULT); g_free(lines[i]); y += ch; } } if (cls.key_state.dest == KEY_CHAT) { const int32_t color = cls.chat_state.team_chat ? CON_COLOR_TEAMCHAT : CON_COLOR_CHAT; // draw the prompt R_DrawChar(0, y, ']', color); // and the input, scrolling horizontally if appropriate const char *s = cl_chat_console.input.buffer; if (cl_chat_console.input.pos > cl_chat_console.width - 2) { s += 2 + cl_chat_console.input.pos - cl_chat_console.width; } while (*s) { R_DrawChar(x * cw, y, *s, CON_COLOR_DEFAULT); s++; x++; } // and lastly cursor R_DrawChar(x * cw, y, 0x0b, CON_COLOR_DEFAULT); } }