src/text.c

changeset 19
d0e88022e209
parent 18
00c0632f0f40
child 23
ab07757004b4
equal deleted inserted replaced
18:00c0632f0f40 19:d0e88022e209
30 #include "ascension/error.h" 30 #include "ascension/error.h"
31 #include "ascension/shader.h" 31 #include "ascension/shader.h"
32 32
33 #include <GL/glew.h> 33 #include <GL/glew.h>
34 34
35 void asc_text_draw_lb( 35 AscTextNode *asc_text(int x, int y, char const *text) {
36 AscTextNode *node, 36 AscTextNode *node = calloc(1, sizeof(AscTextNode));
37 asc_vec2i position, 37 if (node == NULL) {
38 unsigned max_width, 38 asc_error("Out of memory.");
39 cxmutstr text) { 39 return NULL;
40 }
40 41
41 // short circuit - if fully transparent, just hide it 42 node->position = (asc_vec2i) {x, y};
42 if (asc_context.ink.alpha == 0) { 43 node->font = asc_context.active_font;
43 node->hidden = true; 44 node->color = asc_context.ink;
45 cxBufferInit(&node->text, NULL, strlen(text)+8,
46 cxDefaultAllocator, CX_BUFFER_AUTO_EXTEND);
47 cxBufferPutString(&node->text, text);
48
49 return node;
50 }
51
52 void asc_text_update(AscTextNode *node) {
53 // short circuit if fully transparent or hidden, we don't need anything
54 if (node->color.alpha == 0 || node->hidden) {
44 return; 55 return;
45 } 56 }
46 57
47 // Generate new texture, if required 58 // Generate new texture, if required
48 if (node->tex_id == 0) { 59 if (node->internal.tex_id == 0) {
49 glGenTextures(1, &node->tex_id); 60 glGenTextures(1, &node->internal.tex_id);
50 glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 61 glBindTexture(GL_TEXTURE_RECTANGLE, node->internal.tex_id);
51 glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 62 glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
52 glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 63 glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
53 asc_dprintf("Generated new texture for text node: %u", node->tex_id); 64 asc_dprintf("Generated new texture for text node: %u", node->internal.tex_id);
54 } 65 }
66
67 // ensure the text is zero-terminated
68 CxBuffer* text = &(node->text);
69 cxBufferMinimumCapacity(text, text->size+1);
70 text->space[text->size] = '\0';
55 71
56 // Render text onto a surface 72 // Render text onto a surface
57 SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped( 73 SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(
58 asc_context.active_font->ptr, 74 asc_font_cache_validate(node->font)->ptr,
59 text.ptr, 75 text->space,
60 (SDL_Color) { 76 asc_col_sdl(node->color),
61 .r = asc_context.ink.red, 77 node->max_width
62 .g = asc_context.ink.green,
63 .b = asc_context.ink.blue,
64 .a = asc_context.ink.alpha
65 },
66 max_width
67 ); 78 );
68 if (surface == NULL) { 79 if (surface == NULL) {
69 asc_error(SDL_GetError()); 80 asc_error(SDL_GetError());
70 return; 81 return;
71 } 82 }
72 83
73 // Store basic node information 84 // Store basic node information
74 node->position = position; 85 node->position = node->position;
75 node->dimension.width = surface->w; 86 node->internal.dimension.width = surface->w;
76 node->dimension.height = surface->h; 87 node->internal.dimension.height = surface->h;
77 88
78 // Transfer Image Data 89 // Transfer Image Data
79 // TODO: move the image data transfer to a separate function - we will need it more often 90 // TODO: move the image data transfer to a separate function - we will need it more often
80 glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 91 glBindTexture(GL_TEXTURE_RECTANGLE, node->internal.tex_id);
81 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / surface->format->BytesPerPixel); 92 glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / surface->format->BytesPerPixel);
82 glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, 93 glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA,
83 surface->w, surface->h, 94 surface->w, surface->h,
84 0, GL_BGRA, GL_UNSIGNED_BYTE, surface->pixels); 95 0, GL_BGRA, GL_UNSIGNED_BYTE, surface->pixels);
85 96
86 // Free the surface 97 // Free the surface
87 SDL_FreeSurface(surface); 98 SDL_FreeSurface(surface);
88
89 // Redraw the node
90 asc_text_redraw(node);
91 } 99 }
92 100
93 void asc_text_draw( 101 void asc_text_draw(AscTextNode *node) {
94 AscTextNode *node, 102 if (node->color.alpha == 0 || node->hidden) {
95 asc_vec2i position, 103 return;
96 cxmutstr text) { 104 }
97 unsigned max_width = asc_context.active_window->dimensions.width - position.width;
98 asc_text_draw_lb(node, position, max_width, text);
99 }
100 105
101 void asc_text_redraw(AscTextNode *node) { 106 if (node->internal.tex_id == 0) {
102 if (node->hidden) return;
103
104 if (node->tex_id == 0) {
105 asc_error("Tried to redraw text node after destruction"); 107 asc_error("Tried to redraw text node after destruction");
106 return; 108 return;
107 } 109 }
108 110
109 glUseProgram(ASC_SHADER_FONT.base.id); 111 glUseProgram(ASC_SHADER_FONT.base.id);
110 112
111 // Upload projection 113 // Upload projection
112 // TODO: when we group UI draw calls, we don't need this 114 // TODO: when we group UI draw calls, we don't need this
113 glUniformMatrix4fv(ASC_SHADER_FONT.base.projection, 1, GL_FALSE, asc_context.active_window->projection); 115 glUniformMatrix4fv(ASC_SHADER_FONT.base.projection, 1,
116 GL_FALSE, asc_context.active_window->projection);
114 117
115 // Upload model matrix 118 // Upload model matrix
116 asc_mat4f model = {0}; 119 asc_mat4f model = {0};
117 model[asc_mat4_index(0, 0)] = node->dimension.width; 120 model[asc_mat4_index(0, 0)] = node->internal.dimension.width;
118 model[asc_mat4_index(1, 1)] = node->dimension.height; 121 model[asc_mat4_index(1, 1)] = node->internal.dimension.height;
119 model[asc_mat4_index(3, 0)] = node->position.x; 122 model[asc_mat4_index(3, 0)] = node->position.x;
120 model[asc_mat4_index(3, 1)] = node->position.y; 123 model[asc_mat4_index(3, 1)] = node->position.y;
121 model[asc_mat4_index(3, 3)] = 1; 124 model[asc_mat4_index(3, 3)] = 1;
122 glUniformMatrix4fv(ASC_SHADER_FONT.base.model, 1, GL_FALSE, model); 125 glUniformMatrix4fv(ASC_SHADER_FONT.base.model, 1, GL_FALSE, model);
123 126
124 // Upload surface 127 // Upload surface
125 glActiveTexture(GL_TEXTURE0); 128 glActiveTexture(GL_TEXTURE0);
126 glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 129 glBindTexture(GL_TEXTURE_RECTANGLE, node->internal.tex_id);
127 glUniform1i(ASC_SHADER_FONT.surface, 0); 130 glUniform1i(ASC_SHADER_FONT.surface, 0);
128 131
129 // Draw mesh 132 // Draw mesh
130 asc_primitives_draw_plane(); 133 asc_primitives_draw_plane();
131 } 134 }
132 135
133 void asc_text_destroy(AscTextNode *node) { 136 void asc_text_free(AscTextNode *node) {
134 asc_dprintf("Release text node texture: %u", node->tex_id); 137 asc_dprintf("Release text node texture: %u", node->internal.tex_id);
135 glDeleteTextures(1, &node->tex_id); 138 glDeleteTextures(1, &node->internal.tex_id);
136 node->tex_id = 0; 139 cxBufferDestroy(&node->text);
140 free(node);
137 } 141 }

mercurial