src/text.c

changeset 196
ac2ade047d5b
parent 194
7985c3b64460
equal deleted inserted replaced
195:f9e9b7425ed3 196:ac2ade047d5b
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE. 25 * POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28 #include "ascension/ui/text.h"
29
28 #include "ascension/error.h" 30 #include "ascension/error.h"
29 #include "ascension/context.h" 31 #include "ascension/context.h"
30 #include "ascension/ui/text.h" 32 #include "ascension/shader.h"
33 #include "ascension/constants.h"
31 34
32 #include <assert.h> 35 #include <assert.h>
33 #include <cx/printf.h> 36 #include <cx/printf.h>
34 37
35 #include <GL/glew.h> 38 typedef struct asc_text_shader_s {
39 AscShaderProgram program;
40 asc_uniform_loc tex;
41 } AscTextShader;
42
43 AscShaderProgram *asc_text_shader_create(cx_attr_unused int unused) {
44 AscShaderCodes codes;
45 // TODO: with more advanced feature we want to create specific text shaders
46 if (asc_shader_load_code_files((AscShaderCodeInfo){
47 .files.vtx = "sprite_vtx.glsl",
48 .files.frag = "sprite_frag.glsl",
49 .defines.frag = "#define USE_RECT",
50 }, &codes)) {
51 asc_error("Loading text shader failed.");
52 return NULL;
53 }
54 AscShaderProgram *shader = asc_shader_create(codes, sizeof(*shader));
55 if (asc_shader_invalid(shader)) {
56 asc_shader_free_codes(codes);
57 return shader;
58 }
59 asc_ptr_cast(AscTextShader, text_shader, shader);
60 text_shader->tex = asc_shader_get_uniform_loc(shader, "tex");
61 asc_shader_free_codes(codes);
62
63 asc_error_catch_all_gl();
64
65 return shader;
66 }
36 67
37 static void asc_text_update(AscSceneNode *node) { 68 static void asc_text_update(AscSceneNode *node) {
38 AscSprite *sprite = (AscSprite*) node; 69 asc_ptr_cast(AscText, text, node);
39 AscText *text = (AscText*) node;
40 70
41 // Render text onto a surface 71 // Render text onto a surface
42 TTF_Font *font = asc_font_load(text->font); 72 TTF_Font *font = asc_font_load(text->font);
43 if (font == NULL) return; 73 if (font == NULL) return;
44 static int alignments[] = { 74 static int alignments[] = {
45 TTF_WRAPPED_ALIGN_LEFT, 75 TTF_WRAPPED_ALIGN_LEFT,
46 TTF_WRAPPED_ALIGN_CENTER, 76 TTF_WRAPPED_ALIGN_CENTER,
47 TTF_WRAPPED_ALIGN_RIGHT 77 TTF_WRAPPED_ALIGN_RIGHT
48 }; 78 };
49 TTF_SetFontWrappedAlign( 79 TTF_SetFontWrappedAlign(
50 font, alignments[text->base.data.flags & ASC_TEXT_ALIGNMENT_MASK]); 80 font, alignments[text->base.flags & ASC_TEXT_ALIGNMENT_MASK]);
51 SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped( 81 SDL_Surface *surface = TTF_RenderUTF8_Blended_Wrapped(
52 font, text->text.ptr, asc_col_sdl(text->color), text->max_width 82 font, text->text.ptr, asc_col_sdl(text->color), text->max_width
53 ); 83 );
54 if (surface == NULL) { 84 if (surface == NULL) {
55 asc_error("Rendering TTF surface failed: %s", SDL_GetError()); 85 asc_error("Rendering TTF surface failed: %s", SDL_GetError());
56 return; 86 return;
57 } 87 }
58 if (asc_test_flag(text->base.data.flags, ASC_TEXT_CENTERED_FLAG)) { 88 if (asc_test_flag(text->base.flags, ASC_TEXT_CENTERED_FLAG)) {
59 unsigned short newoffx = surface->w / 2; 89 unsigned short newoffx = surface->w / 2;
60 asc_transform_translate2f(node->transform, ASC_VEC2F(text->offx - newoffx, 0)); 90 asc_transform_translate2f(node->transform, ASC_VEC2F(text->offx - newoffx, 0));
61 text->offx = newoffx; 91 text->offx = newoffx;
62 } 92 }
63 93
64 // Transfer Image Data 94 // Transfer Image Data
65 asc_texture_from_surface(sprite->texture, surface); 95 asc_texture_from_surface(text->texture, surface);
66 96
67 // If dimensions changed, update the mesh 97 // If dimensions changed, update the mesh
68 if (text->dimension.x != (unsigned)surface->w || text->dimension.y != (unsigned)surface->h) { 98 if (text->dimension.x != (unsigned)surface->w || text->dimension.y != (unsigned)surface->h) {
69 text->dimension.x = surface->w; 99 text->dimension.x = surface->w;
70 text->dimension.y = surface->h; 100 text->dimension.y = surface->h;
71 const asc_vec2f uv_scale = asc_texture_calculate_uv_scale(sprite->texture, text->dimension, ASC_VEC2F_1); 101 const asc_vec2f uv_scale = asc_texture_calculate_uv_scale(text->texture, text->dimension, ASC_VEC2F_1);
72 asc_mesh_plane_2d(&text->base.mesh, 102 asc_mesh_plane_2d(&text->mesh,
73 .size = ASC_VEC2F(surface->w, surface->h), 103 .size = ASC_VEC2F(surface->w, surface->h),
74 .uv_scale = uv_scale 104 .uv_scale = uv_scale
75 ); 105 );
76 } 106 }
77 107
80 110
81 // Schedule for transform update 111 // Schedule for transform update
82 asc_node_update_transform(node); 112 asc_node_update_transform(node);
83 } 113 }
84 114
115 static void asc_text_draw(const AscCamera *camera, const AscSceneNode *node) {
116 asc_cptr_cast(AscText, text, node);
117
118 // Activate shader
119 // TODO: scene should know which shader we are going to activate s.t. it can pre-sort nodes
120 const AscShaderProgram *shader = asc_shader_lookup_or_create(
121 ASC_SHADER_TEXT, asc_text_shader_create, 0);
122 if (asc_shader_use(shader, camera)) return;
123 asc_cptr_cast(AscTextShader, text_shader, shader);
124
125 // Upload model matrix
126 asc_shader_upload_model_matrix(shader, node);
127
128 // Bind texture
129 asc_texture_bind(text->texture, text_shader->tex, 0);
130
131 // Draw mesh
132 asc_mesh_draw_triangle_strip(&text->mesh);
133 }
134
85 static void asc_text_destroy(AscSceneNode *node) { 135 static void asc_text_destroy(AscSceneNode *node) {
86 AscText *text = (AscText*) node; 136 asc_ptr_cast(AscText, text, node);
87 AscSprite *sprite = (AscSprite*) node; 137 asc_mesh_destroy(&text->mesh);
88 asc_mesh_destroy(&sprite->mesh); 138 asc_texture_destroy(text->texture, 1);
89 asc_texture_destroy(sprite->texture, 1); 139 assert(text->texture->refcount == 0);
90 assert(sprite->texture->refcount == 0); 140 cxFreeDefault(text->texture);
91 cxFreeDefault(sprite->texture);
92 cx_strfree(&text->text); 141 cx_strfree(&text->text);
93 } 142 }
94 143
95 AscSceneNode *asc_text_create(struct asc_text_create_args args) { 144 AscSceneNode *asc_text_create(struct asc_text_create_args args) {
96 AscText *text = cxZallocDefault(sizeof(AscText)); 145 AscText *text = cxZallocDefault(sizeof(AscText));
97 AscSceneNode *node = &text->base.data; 146 AscSceneNode *node = &text->base;
98 147
99 // node properties 148 // node properties
100 asc_scene_node_name(node, args.name); 149 asc_scene_node_name(node, args.name);
101 node->render_group = ASC_RENDER_GROUP_2D_BLEND; 150 node->render_group = ASC_RENDER_GROUP_2D_BLEND;
102 node->destroy_func = asc_text_destroy; 151 node->destroy_func = asc_text_destroy;
103 node->update_func = asc_text_update; 152 node->update_func = asc_text_update;
104 node->draw_func = asc_sprite_draw; 153 node->draw_func = asc_text_draw;
105 asc_transform_identity(node->transform); 154 asc_transform_identity(node->transform);
106 asc_transform_translate3f(node->transform, 155 asc_transform_translate3f(node->transform,
107 ASC_VEC3F(args.x, args.y, ASC_SCENE_2D_DEPTH_OFFSET)); 156 ASC_VEC3F(args.x, args.y, ASC_SCENE_2D_DEPTH_OFFSET));
108 157
109 // text properties 158 // text properties
117 text->text = cx_mutstr(strdup(args.text)); 166 text->text = cx_mutstr(strdup(args.text));
118 } 167 }
119 168
120 // initialize texture 169 // initialize texture
121 // mesh will be created in the update func 170 // mesh will be created in the update func
122 text->base.texture = cxMallocDefault(sizeof(AscTexture)); 171 text->texture = cxMallocDefault(sizeof(AscTexture));
123 asc_texture_init_rectangle(text->base.texture, 1); 172 asc_texture_init_rectangle(text->texture, 1);
124 asc_text_update(node); 173 asc_text_update(node);
125 174
126 return node; 175 return node;
127 } 176 }
128 177

mercurial