1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/text.c Wed Nov 15 22:51:40 2023 +0100 1.3 @@ -0,0 +1,129 @@ 1.4 +/* 1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 + * Copyright 2023 Mike Becker. All rights reserved. 1.7 + * 1.8 + * Redistribution and use in source and binary forms, with or without 1.9 + * modification, are permitted provided that the following conditions are met: 1.10 + * 1.11 + * 1. Redistributions of source code must retain the above copyright 1.12 + * notice, this list of conditions and the following disclaimer. 1.13 + * 1.14 + * 2. Redistributions in binary form must reproduce the above copyright 1.15 + * notice, this list of conditions and the following disclaimer in the 1.16 + * documentation and/or other materials provided with the distribution. 1.17 + * 1.18 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.19 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.20 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.21 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.22 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.23 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.24 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.25 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.26 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.27 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.28 + * POSSIBILITY OF SUCH DAMAGE. 1.29 + */ 1.30 + 1.31 +#include "ascension/text.h" 1.32 +#include "ascension/context.h" 1.33 +#include "ascension/error.h" 1.34 +#include "ascension/shader.h" 1.35 + 1.36 +#include <GL/glew.h> 1.37 + 1.38 +void asc_text_draw_lb( 1.39 + AscTextNode *node, 1.40 + asc_vec2i position, 1.41 + unsigned max_width, 1.42 + cxmutstr text) { 1.43 + 1.44 + // Generate new texture, if required 1.45 + if (node->tex_id == 0) { 1.46 + glGenTextures(1, &node->tex_id); 1.47 + glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 1.48 + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1.49 + glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1.50 + asc_dprintf("Generated new texture for text node: %u", node->tex_id); 1.51 + } 1.52 + 1.53 + // Render text onto a surface 1.54 + SDL_Surface *surface = TTF_RenderText_Blended_Wrapped( 1.55 + asc_context.active_font->ptr, 1.56 + text.ptr, 1.57 + (SDL_Color) { 1.58 + .r = asc_context.ink.red, 1.59 + .g = asc_context.ink.green, 1.60 + .b = asc_context.ink.blue, 1.61 + .a = asc_context.ink.alpha 1.62 + }, 1.63 + max_width 1.64 + ); 1.65 + if (surface == NULL) { 1.66 + asc_error(SDL_GetError()); 1.67 + return; 1.68 + } 1.69 + 1.70 + // Store basic node information 1.71 + node->position = position; 1.72 + node->dimension.width = surface->w; 1.73 + node->dimension.height = surface->h; 1.74 + 1.75 + // Transfer Image Data 1.76 + // TODO: move the image data transfer to a separate function - we will need it more often 1.77 + glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 1.78 + glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / surface->format->BytesPerPixel); 1.79 + glTexImage2D(GL_TEXTURE_RECTANGLE, 0, GL_RGBA, 1.80 + surface->w, surface->h, 1.81 + 0, GL_BGRA, GL_UNSIGNED_BYTE, surface->pixels); 1.82 + 1.83 + // Free the surface 1.84 + SDL_FreeSurface(surface); 1.85 + 1.86 + // Redraw the node 1.87 + asc_text_redraw(node); 1.88 +} 1.89 + 1.90 +void asc_text_draw( 1.91 + AscTextNode *node, 1.92 + asc_vec2i position, 1.93 + cxmutstr text) { 1.94 + unsigned max_width = asc_context.active_window->dimensions.width - position.width; 1.95 + asc_text_draw_lb(node, position, max_width, text); 1.96 +} 1.97 + 1.98 +void asc_text_redraw(AscTextNode *node) { 1.99 + if (node->tex_id == 0) { 1.100 + asc_error("Tried to redraw text node after destruction"); 1.101 + return; 1.102 + } 1.103 + 1.104 + glUseProgram(ASC_SHADER_FONT.base.id); 1.105 + 1.106 + // Upload projection 1.107 + // TODO: when we group UI draw calls, we don't need this 1.108 + glUniformMatrix4fv(ASC_SHADER_FONT.base.projection, 1, GL_FALSE, asc_context.active_window->projection); 1.109 + 1.110 + // Upload model matrix 1.111 + asc_mat4f model = {0}; 1.112 + model[asc_mat4_index(0, 0)] = node->dimension.width; 1.113 + model[asc_mat4_index(1, 1)] = node->dimension.height; 1.114 + model[asc_mat4_index(3, 0)] = node->position.x; 1.115 + model[asc_mat4_index(3, 1)] = node->position.y; 1.116 + model[asc_mat4_index(3, 3)] = 1; 1.117 + glUniformMatrix4fv(ASC_SHADER_FONT.base.model, 1, GL_FALSE, model); 1.118 + 1.119 + // Upload surface 1.120 + glActiveTexture(GL_TEXTURE0); 1.121 + glBindTexture(GL_TEXTURE_RECTANGLE, node->tex_id); 1.122 + glUniform1i(ASC_SHADER_FONT.surface, 0); 1.123 + 1.124 + // Draw mesh 1.125 + asc_primitives_draw_plane(); 1.126 +} 1.127 + 1.128 +void asc_text_destroy(AscTextNode *node) { 1.129 + asc_dprintf("Release text node texture: %u", node->tex_id); 1.130 + glDeleteTextures(1, &node->tex_id); 1.131 + node->tex_id = 0; 1.132 +} 1.133 \ No newline at end of file