/* void gfx_calc_mono(fchar_t *glyphs, int width, int height) { fchar_t *ch; for(int z = 0; z < 256; z++) { ch = &glyphs[z]; if(ch->u) { ch->s = ch->t = 2; ch->u = width - 2; ch->v = height - 2; } } } */ byte gfx_font_special(int width, uint ch) { return ((ch == CHR_UNK) || (ch == CHR_WSPC)) ? width : ((ch == CHR_SPC) ? (width / 6) : 255); } void gfx_calc_font(byte *data, fchar_t *glyphs, int width, int height, int page) { int off; fchar_t *ch; for(int z = 0; z < 256; z++) { ch = &glyphs[z]; if((ch->u = gfx_font_special(width, (page << 8) + z)) != 255) { ch->s = ch->t = 0; ch->v = ((int)ch->u) * height / width; if(((page << 8) + z) != CHR_UNK) { for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { off = FONT_STRIDE(x, y, z); data[off+3] = 0; } } } continue; } ch->s = ch->t = 255; ch->u = ch->v = 0; for(int x = 0; x < width; x++) { for(int y = 0; y < height; y++) { off = FONT_STRIDE(x, y, z); if(data[off+3]) { ch->s = x < ch->s ? x : ch->s; ch->t = y < ch->t ? y : ch->t; ch->u = x > ch->u ? x : ch->u; ch->v = y > ch->v ? y : ch->v; } } } if(ch->s == 255 && ch->t == 255 && ch->u == 0 && ch->v == 0) { ch->s = ch->t = 0; } else { ch->u += 1; ch->v += 1; } } } int gfx_load_font(font_t *font, const char *path) { byte *data; int width, height; int pages = 0; font->xglyph = 0; // if(mono) // mono->xglyph = 0; for(int page = 0; page < UNI_MAX_PAGES; page++) { sprintf(sys.work_buf, "fonts/%s_%04x.png", path, page); if(!(data = img_load(sys.work_buf, &width, &height, 0, 1))) { if(!page) { return 0; } font->textures[page] = 0; font->sizes[page] = NULL; // if(mono) { // mono->textures[page] = 0; // mono->sizes[page] = NULL; // } continue; } if(page == 0) { if(width > 3968 || height > 3968) { mem_free(data); return 0; } else if((width % 16) || (height % 16)) { mem_free(data); return 0; } font->xsize = width; font->ysize = height; font->xglyph = width >> 4; font->yglyph = height >> 4; } else if(font->xsize != width || font->ysize != height) { font->textures[page] = 0; font->sizes[page] = NULL; // if(mono) { // mono->textures[page] = 0; // mono->sizes[page] = NULL; // } mem_free(data); continue; } pages += 1; font->sizes[page] = mem_alloc(256 * sizeof(fchar_t), MEM_FONT); gfx_calc_font(data, font->sizes[page], font->xglyph, font->yglyph, page); tex_push(&font->textures[page], data, width, height); // if(mono) { // mono->sizes[page] = mem_alloc(256 * sizeof(fchar_t), MEM_FONT); // memcpy(mono->sizes[page], font->sizes[page], 256 * sizeof(fchar_t)); // gfx_calc_mono(mono->sizes[page], font->xglyph, font->yglyph); // mono->textures[page] = font->textures[page]; // } logd(LOG_GFX, STR_TEX_ILOADED, sys.work_buf, font->textures[page]); mem_free(data); } // if(mono) { // mono->xsize = font->xsize; // mono->ysize = font->ysize; // mono->xglyph = font->xglyph; // mono->yglyph = font->yglyph; // } return pages; } /* int gfx_load_font_int(font_t *font, const byte **fdata, const byte **fsizes) { int pages = 0; byte *data = mem_alloc(12 * 16 * 18 * 16 * 4, MEM_IMAGE); font->xglyph = 12; font->yglyph = 18; font->xsize = 12 * 16; font->ysize = 18 * 16; for(int page = 0; page < UNI_MAX_PAGES; page++) { sprintf(sys.work_buf, "font_%04x", page); if(!fdata[page]) { font->textures[page] = 0; font->sizes[page] = NULL; continue; } pages += 1; font->sizes[page] = (fchar_t *)fsizes[page]; tex_unpack_1bit(data, fdata[page], 12 * 16 * 18 * 16); tex_push(&font->textures[page], data, 12 * 16, 18 * 16); // mono->sizes[page] = mem_alloc(256 * sizeof(fchar_t), MEM_FONT); // memcpy(mono->sizes[page], fsizes[page], 256 * sizeof(fchar_t)); // gfx_calc_mono(mono->sizes[page], font->xglyph, font->yglyph); // mono->textures[page] = font->textures[page]; logd(LOG_GFX, STR_TEX_ILOADED, sys.work_buf, font->textures[page]); } mem_free(data); return pages; } */ void gfx_free_font(font_t *font) { for(int page = 0; (page < UNI_MAX_PAGES) && font->xglyph; page++) { if(font->sizes[page]) { mem_free(font->sizes[page]); tex_delete(&font->textures[page]); } // if(mono && mono->sizes[page]) // mem_free(mono->sizes[page]); } } /* void gfx_free_font_int(font_t *font) { for(int page = 0; page < UNI_MAX_PAGES; page++) { if(font->sizes[page]) tex_delete(&font->textures[page]); // if(mono->sizes[page]) // mem_free(mono->sizes[page]); } } */ void gfx_aux_colors(const uint *colors) { memcpy(gdr.aux_colors, colors, sizeof(uint) * 8); } void gfx_back_color(uint color) { gdr.clear_r = (float)((uint)((color >> 16) & 0xff)) / 255.0f; gdr.clear_g = (float)((uint)((color >> 8) & 0xff)) / 255.0f; gdr.clear_b = (float)((uint)(color & 0xff)) / 255.0f; gdr.clear_a = (float)((uint)((color >> 24) & 0xff)) / 255.0f; } void shd_fnc_tex() { shd_int("tex", 0); } void shd_fnc_world() { shd_int("tex", 0); glUniformBlockBinding(gdr.shader, glGetUniformBlockIndex(gdr.shader, "light_block"), 0); } void gfx_view(camera_t *cam, mat4 mat, float x, float y, float z) { vec3 pos; vec3 center; VEC3_SET(pos, x, y, z); glm_vec3_add(pos, cam->front, center); glm_mat4_identity(mat); glm_lookat(pos, center, cam->up, mat); } void gfx_perspective(camera_t *cam, mat4 mat) { glm_mat4_identity(mat); glm_perspective(glm_rad(gdr.fov - (cam->zoom * (gdr.fov - 1.0f))), ((float)wcf.current->frame_x) / ((float)wcf.current->frame_y), gdr.clip_near, gdr.clip_far, mat); } void shd_pass_rect(void *u) { // shd_sel(gdr.shd_rect); shd_vec2v("screen", (float)wcf.current->fb_x, (float)wcf.current->fb_y); glBindVertexArray(gdr.vao_quad); glActiveTexture(GL_TEXTURE0); } void shd_pass_text(void *u) { // shd_sel(gdr.shd_text); shd_vec2v("screen", (float)wcf.current->fb_x, (float)wcf.current->fb_y); shd_float("time", tmr_ftime()); glBindVertexArray(gdr.vao_quad); glActiveTexture(GL_TEXTURE0); } void shd_pass_blit(void *u) { // shd_sel(gdr.shd_blit); glBindVertexArray(gdr.vao_quad); glActiveTexture(GL_TEXTURE0); } void shd_pass_world(world_t *world) { mat4 mat; // shd_sel(gdr.shd_world); shd_float("clip_near", gdr.clip_near); shd_float("clip_far", gdr.clip_far); shd_vec2v("screen", (float)wcf.current->frame_x, (float)wcf.current->frame_y); // shd_vec3v("world_size", (float)(TEMP_LM_SIZE * CHUNK_SIZE), (float)(TEMP_LM_SIZE * CHUNK_SIZE), (float)(TEMP_LM_SIZE * CHUNK_SIZE)); shd_vec3v("cam_pos", world->camera.pos_x, world->camera.pos_y, world->camera.pos_z); gfx_view(&world->camera, mat, world->camera.pos_x, world->camera.pos_y, world->camera.pos_z); shd_mat4("view", mat); gfx_perspective(&world->camera, mat); shd_mat4("projection", mat); /* glm_mat4_identity(mat); vec3 v; VEC3_SET(v, 100.0f, 0.5f, 100.0f); glm_scale(mat, v); VEC3_SET(v, 0.0f, -1.0f, 0.0f); glm_translate(mat, v); shd_mat4("model", mat); shd_scolor("specular", 0xffffff); shd_float("shine", 4.0f); */ shd_vec3v("dir_direction", gdr.ambient_x, gdr.ambient_y, gdr.ambient_z); // shd_vec3v("dir_ambient", 0.1f, 0.1f, 0.2f); shd_vec3v("dir_ambient", gdr.clear_r, gdr.clear_g, gdr.clear_b); shd_vec3v("dir_diffuse", gdr.clear_r * 1.25f, gdr.clear_g * 1.25f, gdr.clear_b * 1.25f); shd_vec3v("dir_specular", gdr.clear_r * 1.5f, gdr.clear_g * 1.5f, gdr.clear_b * 1.5f); shd_float("light_factor", gdr.light_blend); shd_float("max_vert_dist", gdr.light_dist_vert); shd_float("max_cam_dist", gdr.light_dist_cam); // shd_float("time", tmr_ftime()); // glBindVertexArray(gdr.vao_box); // glActiveTexture(GL_TEXTURE1); // glBindTexture(GL_TEXTURE_2D, gdr.fbtex_lightmap); shd_int("n_lights", world->s_lights); glActiveTexture(GL_TEXTURE0); glBindBufferBase(GL_UNIFORM_BUFFER, 0, world->light_buf); } void shd_pass_vis(world_t *world) { mat4 mat; gfx_view(&world->camera, mat, world->camera.pos_x, world->camera.pos_y, world->camera.pos_z); shd_mat4("view", mat); gfx_perspective(&world->camera, mat); shd_mat4("projection", mat); } void shd_pass_grid(world_t *world) { mat4 mat; // shd_sel(gdr.shd_vis); shd_float("clip_near", gdr.clip_near); shd_float("clip_far", gdr.clip_far); shd_vec2v("screen", (float)wcf.current->frame_x, (float)wcf.current->frame_y); gfx_view(&world->camera, mat, world->camera.pos_x, world->camera.pos_y, world->camera.pos_z); shd_mat4("view", mat); gfx_perspective(&world->camera, mat); shd_mat4("projection", mat); shd_float("time", tmr_ftime()); // glActiveTexture(GL_TEXTURE0); } byte gfx_init() { gdr.aniso_max = 1.0f; // if(gdr.aniso_avail = (GL_API_4_6 || gl_has_ext("GL_EXT_texture_filter_anisotropic") || gl_has_ext("GL_ARB_texture_filter_anisotropic"))) glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &gdr.aniso_max); tbl_init(&gdr.textures, 256, 64, sizeof(tex_t), MEM_DRAW); tbl_init(&gdr.buffers, 1024, 16, sizeof(buf_t), MEM_DRAW); tbl_init(&gdr.shaders, 1, 16, sizeof(shd_t), MEM_DRAW); tbl_init(&gdr.framebufs, 1, 16, sizeof(fbo_t), MEM_DRAW); tbl_init(&gdr.drawlists, 1, 16384, sizeof(drawlist_t), MEM_DRAW); tbl_init(&gdr.materials, 16, 32, sizeof(material_t), MEM_DRAW); shd_setvars(); LOAD_SHADER(text, shd_fnc_tex, shd_pass_text); LOAD_SHADER(rect, shd_fnc_tex, shd_pass_rect); LOAD_SHADER(blit, shd_fnc_tex, shd_pass_blit); LOAD_SHADER(world, shd_fnc_world, shd_pass_world); // LOAD_SHADER(lightmap, NULL, NULL); LOAD_SHADER(vis, NULL, shd_pass_vis); LOAD_SHADER(grid, NULL, shd_pass_grid); sys.font_pages = gfx_load_font(&sys.font, "font"); buf_init_sys(&gdr.vbo_quad, &gdr.vao_quad, vert_quad, sizeof(vert_quad), 2, 2); if(!fb_init_sys(&sys.console->fb_gui, &sys.console->fbtex_gui)) return 0; tex_gen_fallback(&gdr.tex_fallback, 8); gfx_aux_colors(aux_colors); // gfx_back_color(0x000000); // gfx_back_color(0xff20208f); gfx_back_color(0xff000000); // gui_style_default(&sys.style); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // gdr.buf_lightmap = buf_init(1, &gdr.vbo_lightmap, &gdr.vao_lightmap, NULL, 0, 2, 2); // gdr.fbt_lightmap = fb_init(&gdr.fb_lightmap, &gdr.fbtex_lightmap, NULL, 0, 1); // gfx_init_world(); return 1; } void gfx_end() { tex_clear(); buf_clear(); shd_clear(); fb_clear(); gfx_free_font(&sys.font); tex_delete(&gdr.tex_fallback); buf_delete(&gdr.vbo_quad, &gdr.vao_quad); // shd_delete(&gdr.shd_rect); // shd_delete(&gdr.shd_text); // shd_delete(&gdr.shd_blit); // shd_clearall(); // fb_delete(&sys.console->fb_gui, &sys.console->fbtex_gui); tbl_clear(&gdr.textures); tbl_clear(&gdr.buffers); tbl_clear(&gdr.shaders); tbl_clear(&gdr.framebufs); tbl_clear(&gdr.drawlists); tbl_clear(&gdr.materials); } void gfx_blit(uint tex) { shd_sel(gdr.shd_blit, NULL); glBindTexture(GL_TEXTURE_2D, tex); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } void gfx_draw_rect(int x, int y, int w, int h, int border, uint tex, uint top, uint bottom, uint b_top, uint b_bottom) { shd_sel(gdr.shd_rect, NULL); shd_vec2v("offset", (float)x, (float)y); shd_vec2v("size", (float)w, (float)h); shd_bool("use_tex", tex ? 1 : 0); shd_float("border", (float)border); shd_color("fill_t", top); shd_color("fill_b", bottom); shd_color("border_t", b_top); shd_color("border_b", b_bottom); if(tex) { glBindTexture(GL_TEXTURE_2D, tex); } glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } void gfx_draw_gui(window_t *win) { int x1, y1, x2, y2; gui_t *elem = win->selected; if(elem && elem->r_dirty && elem->type == GUI_DROPDOWN_HANDLE && !(elem->visible)) { glScissor(elem->pos_x, (win->fb_y - (elem->pos_y + elem->size_y)) < 0 ? 0 : (win->fb_y - (elem->pos_y + elem->size_y)), elem->size_x, elem->size_y); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); elem->r_dirty = elem->t_dirty = 0; win->selected = NULL; for(int z = 0; z < win->n_elems; z++) { if((win->elems[z].pos_y + win->elems[z].size_y) > elem->pos_y && win->elems[z].pos_y < (elem->pos_y + elem->size_y) && (win->elems[z].pos_x + win->elems[z].size_x) > elem->pos_x && win->elems[z].pos_x < (elem->pos_x + elem->size_x) && win->elems[z].visible) win->elems[z].r_dirty = 1; } } for(int z = 0; z < win->n_elems; z++) { elem = &win->elems[z]; if(elem->r_dirty || elem->t_dirty) { if(win->selected == elem && elem->type == GUI_DROPDOWN_HANDLE && elem->visible) continue; glScissor(elem->pos_x, (win->fb_y - (elem->pos_y + elem->size_y)) < 0 ? 0 : (win->fb_y - (elem->pos_y + elem->size_y)), elem->size_x, elem->size_y); // logd("DBG", "%d @ %d %d -> %d %d", elem->id, elem->pos_x, elem->pos_y, elem->pos_x + elem->size_x, elem->pos_y + elem->size_y); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); if(elem->type == GUI_CUSTOM) elem->func(elem, 0); glDisable(GL_SCISSOR_TEST); if(elem->visible && (elem->type != GUI_CUSTOM)) gfx_draw_rect(elem->pos_x, elem->pos_y, elem->size_x, elem->size_y, elem->border, elem->texture, elem->color_fill_t, elem->color_fill_b, elem->color_brdr_t, elem->color_brdr_b); if(elem->visible && (elem->type == GUI_SLIDER)) gfx_draw_rect(elem->pos_x + elem->sel_start - (elem->sel_end / 2), elem->pos_y, elem->sel_end, elem->size_y, elem->sel_drag, elem->texture, elem->margin_x1, elem->margin_y1, elem->margin_x2, elem->margin_y2); elem->r_dirty = 0; elem->t_dirty = elem->visible; // logd("DBG", "@ r"); } } // gfx_pass_text(); for(int z = 0; z < win->n_elems; z++) { elem = &win->elems[z]; if(elem->t_dirty && elem->visible) { if(win->selected == elem && elem->type == GUI_DROPDOWN_HANDLE) continue; x1 = elem->pos_x + ((elem->type != GUI_SLIDER) ? elem->margin_x1 : 0); y1 = elem->pos_y + ((elem->type != GUI_SLIDER) ? elem->margin_y1 : 0); x2 = elem->size_x - ((elem->type != GUI_SLIDER) ? (elem->margin_x1 + elem->margin_x2) : 0); y2 = elem->size_y - ((elem->type != GUI_SLIDER) ? (elem->margin_y1 + elem->margin_y2) : 0); // if(elem->type == GUI_FIELD) { glScissor(x1 < 0 ? 0 : x1, (win->fb_y - (y1 + y2)) < 0 ? 0 : (win->fb_y - (y1 + y2)), x2 < 0 ? 0 : x2, y2 < 0 ? 0 : y2); glEnable(GL_SCISSOR_TEST); // } if(elem->type == GUI_CUSTOM) elem->func(elem, 1); else elem->t_dirty = txt_draw(x1 + (elem->xbreak ? 0 : elem->text_x), y1 + elem->text_y, 0, elem->font_size * elem->font->yglyph, elem->font_size * (elem->font->yglyph + elem->line_space), x1 + elem->text_x, y1 + elem->text_y, elem->xbreak ? (elem->pos_x + x2) : 0x7fffffff, 0x7fffffff, elem->color_text, 0x00000000, elem->font, elem->text); if(elem->type == GUI_FIELD && elem->sel_start >= 0 && elem->sel_end != elem->sel_start) txt_draw_range(elem->sel_start, elem->sel_end, x1 + (elem->xbreak ? 0 : elem->text_x), y1 + elem->text_y, 0, elem->font_size * elem->font->yglyph, elem->font_size * elem->font->yglyph, x1 + elem->text_x, y1 + elem->text_y, elem->xbreak ? (elem->pos_x + x2) : 0x7fffffff, 0x7fffffff, 0x00000000, sys.style.select, elem->font, elem->text); // logd("DBG", "%d @ %d %d -> %d %d", elem->id, x1, y1, elem->pos_x + x2, elem->pos_y + y2); // if(elem->type == GUI_FIELD) { glDisable(GL_SCISSOR_TEST); // glScissor(0, 0, sys.fb_x, sys.fb_y); // } } } elem = win->selected; if(elem && (elem->r_dirty || elem->t_dirty) && elem->type == GUI_DROPDOWN_HANDLE && elem->visible) { // gfx_pass_rect(); glScissor(elem->pos_x, (win->fb_y - (elem->pos_y + elem->size_y)) < 0 ? 0 : (win->fb_y - (elem->pos_y + elem->size_y)), elem->size_x, elem->size_y); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); gfx_draw_rect(elem->pos_x, elem->pos_y, elem->size_x, elem->size_y, elem->border, elem->texture, elem->color_fill_t, elem->color_fill_b, elem->color_brdr_t, elem->color_brdr_b); elem->r_dirty = 0; // gfx_pass_text(); x1 = elem->pos_x + elem->margin_x1; y1 = elem->pos_y + elem->margin_y1; x2 = elem->size_x - (elem->margin_x1 + elem->margin_x2); y2 = elem->size_y - (elem->margin_y1 + elem->margin_y2); glScissor(x1 < 0 ? 0 : x1, (win->fb_y - (y1 + y2)) < 0 ? 0 : (win->fb_y - (y1 + y2)), x2 < 0 ? 0 : x2, y2 < 0 ? 0 : y2); glEnable(GL_SCISSOR_TEST); elem->t_dirty = txt_draw(x1 + elem->text_x, y1 + elem->text_y, 0, elem->font_size * elem->font->yglyph, elem->font_size * (elem->font->yglyph + elem->line_space), x1 + elem->text_x, y1 + elem->text_y, 0x7fffffff, 0x7fffffff, elem->color_text, 0x00000000, elem->font, elem->text); glDisable(GL_SCISSOR_TEST); } } byte gui_inside(gui_t *elem, int x, int y); gui_t *gui_clicked(window_t *win, int x, int y); void gfx_draw_gui_overlay(window_t *win) { gui_t *elem; if(win->open) { elem = win->selected; if(win->mouse && elem && elem->enabled && elem->visible && (elem->type != GUI_LABEL) && (elem->type != GUI_FIELD) && (elem->type != GUI_DROPDOWN_HANDLE) && (elem->type != GUI_CUSTOM)) { gfx_draw_rect(elem->pos_x, elem->pos_y, elem->size_x, elem->size_y, 0, 0, sys.style.press_top, sys.style.press_btm, 0x00000000, 0x00000000); return; } else if(elem && elem->enabled && elem->visible && (elem->type == GUI_FIELD)) { if(elem->value && elem->sel_start >= 0 && elem->sel_end == elem->sel_start && fmodf(tmr_ftime(), 1.0f) < 0.5f) { int x1 = elem->pos_x + elem->margin_x1; int y1 = elem->pos_y + elem->margin_y1; int x2 = elem->size_x - (elem->margin_x1 + elem->margin_x2); int y2 = elem->size_y - (elem->margin_y1 + elem->margin_y2); glScissor(x1 < 0 ? 0 : x1, (win->fb_y - (y1 + y2)) < 0 ? 0 : (win->fb_y - (y1 + y2)), x2 < 0 ? 0 : x2, y2 < 0 ? 0 : y2); glEnable(GL_SCISSOR_TEST); gfx_draw_rect(elem->min, elem->max, elem->font_size, elem->font->yglyph * elem->font_size, 0, 0, sys.style.cursor, sys.style.cursor, 0x00000000, 0x00000000); glDisable(GL_SCISSOR_TEST); } } elem = gui_clicked(win, win->mouse_x, win->mouse_y); if(elem && elem->enabled && elem->visible && (elem->type != GUI_LABEL) && /* ( */ (elem->type != GUI_FIELD) && (elem->type != GUI_CUSTOM) /* || (elem != gui.selected)) */ ) { if(elem->type == GUI_DROPDOWN_HANDLE) { int m = ((win->mouse_y - (elem->pos_y + elem->margin_y1)) * elem->max / (elem->size_y - (elem->margin_y1 + elem->margin_y2))); // if((sys.mouse_y - elem->pos_y) < (elem->size_y - elem->margin_y2)) gfx_draw_rect(elem->pos_x + elem->margin_x1, elem->pos_y + elem->margin_y1 + CLAMP_VALUE(m, 0, elem->max - 1) * ((elem->size_y - (elem->margin_y1 + elem->margin_y2)) / elem->max), elem->size_x - (elem->margin_x1 + elem->margin_x2), (elem->size_y - (elem->margin_y1 + elem->margin_y2)) / elem->max, 0, 0, sys.style.hover_top, sys.style.hover_btm, 0x00000000, 0x00000000); } else { gfx_draw_rect(elem->pos_x, elem->pos_y, elem->size_x, elem->size_y, 0, 0, sys.style.hover_top, sys.style.hover_btm, 0x00000000, 0x00000000); } } } } void gfx_draw_con_overlay(window_t *win) { if(sys.hud_size) { conmsg_t *con; ulong fade = 1000ULL * (ulong)(sys.hud_fadeout); font_t *font = &sys.font; int y = sys.hud_bottom ? (win->frame_y - font->yglyph) : 0; int pos = sys.hud_pos; for(int z = 0; z < sys.hud_size; z++) { if(--pos < 0) pos = sys.hud_size - 1; con = &sys.hud_msgs[pos]; if(con->message && (con->window == win)) { if((sys.tmr_current - con->time) <= fade) { txt_draw_range(0, con->length, win->offset_x, win->offset_y + y, 0, font->yglyph, font->yglyph, win->offset_x, win->offset_y + y, win->offset_x + win->frame_x, win->offset_y + win->frame_y, 0xffffffff, (uint)sys.hud_opacity << 24, font, con->message); y += sys.hud_bottom ? -(font->yglyph) : font->yglyph; } else { con->message = NULL; } } } } } material_t *gfx_add_material(uint texture, float density, uint spec_color, float shine, shd_t *shader) { material_t *mat = tbl_push(&gdr.materials); mat->texture = texture; mat->density = density; mat->spec_color = spec_color; mat->shine = shine; mat->shader = shader; return mat; } void gfx_clear_materials() { tbl_clear(&gdr.materials); }