1.1 --- a/src/text.c Sun Nov 19 13:27:08 2023 +0100 1.2 +++ b/src/text.c Thu Nov 23 23:08:57 2023 +0100 1.3 @@ -32,38 +32,49 @@ 1.4 1.5 #include <GL/glew.h> 1.6 1.7 -void asc_text_draw_lb( 1.8 - AscTextNode *node, 1.9 - asc_vec2i position, 1.10 - unsigned max_width, 1.11 - cxmutstr text) { 1.12 +AscTextNode *asc_text(int x, int y, char const *text) { 1.13 + AscTextNode *node = calloc(1, sizeof(AscTextNode)); 1.14 + if (node == NULL) { 1.15 + asc_error("Out of memory."); 1.16 + return NULL; 1.17 + } 1.18 1.19 - // short circuit - if fully transparent, just hide it 1.20 - if (asc_context.ink.alpha == 0) { 1.21 - node->hidden = true; 1.22 + node->position = (asc_vec2i) {x, y}; 1.23 + node->font = asc_context.active_font; 1.24 + node->color = asc_context.ink; 1.25 + cxBufferInit(&node->text, NULL, strlen(text)+8, 1.26 + cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND); 1.27 + cxBufferPutString(&node->text, text); 1.28 + 1.29 + return node; 1.30 +} 1.31 + 1.32 +void asc_text_update(AscTextNode *node) { 1.33 + // short circuit if fully transparent or hidden, we don't need anything 1.34 + if (node->color.alpha == 0 || node->hidden) { 1.35 return; 1.36 } 1.37 1.38 // Generate new texture, if required 1.39 - if (node->tex_id == 0) { 1.40 - glGenTextures(1, &node->tex_id); 1.41 - glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 1.42 + if (node->internal.tex_id == 0) { 1.43 + glGenTextures(1, &node->internal.tex_id); 1.44 + glBindTexture(GL_TEXTURE_RECTANGLE, node->internal.tex_id); 1.45 glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1.46 glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1.47 - asc_dprintf("Generated new texture for text node: %u", node->tex_id); 1.48 + asc_dprintf("Generated new texture for text node: %u", node->internal.tex_id); 1.49 } 1.50 1.51 + // ensure the text is zero-terminated 1.52 + CxBuffer* text = &(node->text); 1.53 + cxBufferMinimumCapacity(text, text->size+1); 1.54 + text->space[text->size] = '\0'; 1.55 + 1.56 // Render text onto a surface 1.57 SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped( 1.58 - asc_context.active_font->ptr, 1.59 - text.ptr, 1.60 - (SDL_Color) { 1.61 - .r = asc_context.ink.red, 1.62 - .g = asc_context.ink.green, 1.63 - .b = asc_context.ink.blue, 1.64 - .a = asc_context.ink.alpha 1.65 - }, 1.66 - max_width 1.67 + asc_font_cache_validate(node->font)->ptr, 1.68 + text->space, 1.69 + asc_col_sdl(node->color), 1.70 + node->max_width 1.71 ); 1.72 if (surface == NULL) { 1.73 asc_error(SDL_GetError()); 1.74 @@ -71,13 +82,13 @@ 1.75 } 1.76 1.77 // Store basic node information 1.78 - node->position = position; 1.79 - node->dimension.width = surface->w; 1.80 - node->dimension.height = surface->h; 1.81 + node->position = node->position; 1.82 + node->internal.dimension.width = surface->w; 1.83 + node->internal.dimension.height = surface->h; 1.84 1.85 // Transfer Image Data 1.86 // TODO: move the image data transfer to a separate function - we will need it more often 1.87 - glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 1.88 + glBindTexture(GL_TEXTURE_RECTANGLE, node->internal.tex_id); 1.89 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / surface->format->BytesPerPixel); 1.90 glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, 1.91 surface->w, surface->h, 1.92 @@ -85,23 +96,14 @@ 1.93 1.94 // Free the surface 1.95 SDL_FreeSurface(surface); 1.96 - 1.97 - // Redraw the node 1.98 - asc_text_redraw(node); 1.99 } 1.100 1.101 -void asc_text_draw( 1.102 - AscTextNode *node, 1.103 - asc_vec2i position, 1.104 - cxmutstr text) { 1.105 - unsigned max_width = asc_context.active_window->dimensions.width - position.width; 1.106 - asc_text_draw_lb(node, position, max_width, text); 1.107 -} 1.108 +void asc_text_draw(AscTextNode *node) { 1.109 + if (node->color.alpha == 0 || node->hidden) { 1.110 + return; 1.111 + } 1.112 1.113 -void asc_text_redraw(AscTextNode *node) { 1.114 - if (node->hidden) return; 1.115 - 1.116 - if (node->tex_id == 0) { 1.117 + if (node->internal.tex_id == 0) { 1.118 asc_error("Tried to redraw text node after destruction"); 1.119 return; 1.120 } 1.121 @@ -110,12 +112,13 @@ 1.122 1.123 // Upload projection 1.124 // TODO: when we group UI draw calls, we don't need this 1.125 - glUniformMatrix4fv(ASC_SHADER_FONT.base.projection, 1, GL_FALSE, asc_context.active_window->projection); 1.126 + glUniformMatrix4fv(ASC_SHADER_FONT.base.projection, 1, 1.127 + GL_FALSE, asc_context.active_window->projection); 1.128 1.129 // Upload model matrix 1.130 asc_mat4f model = {0}; 1.131 - model[asc_mat4_index(0, 0)] = node->dimension.width; 1.132 - model[asc_mat4_index(1, 1)] = node->dimension.height; 1.133 + model[asc_mat4_index(0, 0)] = node->internal.dimension.width; 1.134 + model[asc_mat4_index(1, 1)] = node->internal.dimension.height; 1.135 model[asc_mat4_index(3, 0)] = node->position.x; 1.136 model[asc_mat4_index(3, 1)] = node->position.y; 1.137 model[asc_mat4_index(3, 3)] = 1; 1.138 @@ -123,15 +126,16 @@ 1.139 1.140 // Upload surface 1.141 glActiveTexture(GL_TEXTURE0); 1.142 - glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 1.143 + glBindTexture(GL_TEXTURE_RECTANGLE, node->internal.tex_id); 1.144 glUniform1i(ASC_SHADER_FONT.surface, 0); 1.145 1.146 // Draw mesh 1.147 asc_primitives_draw_plane(); 1.148 } 1.149 1.150 -void asc_text_destroy(AscTextNode *node) { 1.151 - asc_dprintf("Release text node texture: %u", node->tex_id); 1.152 - glDeleteTextures(1, &node->tex_id); 1.153 - node->tex_id = 0; 1.154 +void asc_text_free(AscTextNode *node) { 1.155 + asc_dprintf("Release text node texture: %u", node->internal.tex_id); 1.156 + glDeleteTextures(1, &node->internal.tex_id); 1.157 + cxBufferDestroy(&node->text); 1.158 + free(node); 1.159 } 1.160 \ No newline at end of file