some meshgen and map rendering updates
[voxelands-alt.git] / src / graphics / textbuffer.c
blob60b8660ae9e3306aa42b88ce187d1d1de68ecaf4
1 /************************************************************************
2 * textbuffer.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "common.h"
21 #define _WM_EXPOSE_ALL
22 #include "wm.h"
23 #include "graphics.h"
25 #include <wctype.h>
27 static rendertext_t *textbuffer_get_rendertext(textbuffer_t *t, uint32_t page)
29 rendertext_t *ft;
31 ft = malloc(sizeof(rendertext_t));
32 if (!ft)
33 return NULL;
35 ft->page = page;
36 ft->state = 0;
37 ft->vao = 0;
38 ft->vbo[0] = 0;
39 ft->vbo[1] = 0;
40 array_init(&ft->v,ARRAY_TYPE_FLOAT);
41 array_init(&ft->t,ARRAY_TYPE_FLOAT);
43 array_push_ptr(&t->data,ft);
45 return ft;
48 /* initialise a textbuffer */
49 void textbuffer_init(textbuffer_t *t, font_t *f, int size, float x, float y, int max_x, int max_y, int max_c, uint32_t options)
51 if (!t)
52 return;
54 t->mx = max_x;
55 t->my = max_y;
56 t->mc = max_c;
57 t->options = options;
58 t->str = NULL;
59 t->length = 0;
60 t->size = 0;
61 t->x = x;
62 t->y = y;
63 t->nx = 0;
64 t->ny = 0;
65 t->cw = 0;
66 t->ch = 0;
67 t->ch = size;
68 t->font = f;
69 t->font_size = size;
71 array_init(&t->data,ARRAY_TYPE_PTR);
73 if (!t->mc)
74 return;
76 t->str = malloc(sizeof(uint32_t)*t->mc);
77 if (!t->str)
78 return;
80 t->size = t->mc;
81 t->str[0] = 0;
84 /* create and initialise a textbuffer */
85 textbuffer_t *textbuffer_create(font_t *f, int size, float x, float y, int max_x, int max_y, int max_c, uint32_t options)
87 textbuffer_t *t = malloc(sizeof(textbuffer_t));
88 if (!t)
89 return NULL;
91 textbuffer_init(t,f,size,x,y,max_x,max_y, max_c, options);
93 return t;
96 /* clear the current string from a textbuffer */
97 void textbuffer_clear(textbuffer_t *t)
99 rendertext_t *rt;
100 if (!t)
101 return;
103 if (!t->mc && t->str) {
104 free(t->str);
105 t->str = NULL;
106 t->size = 0;
109 t->length = 0;
110 t->nx = 0;
111 t->ny = 0;
112 t->cw = 0;
113 t->ch = t->font_size;
115 while ((rt = array_pop_ptr(&t->data))) {
116 array_free(&rt->v,0);
117 array_free(&rt->t,0);
118 if (rt->state) {
119 glDeleteBuffers(2, rt->vbo);
120 glDeleteVertexArrays(1,&rt->vao);
123 free(rt);
127 /* clear and free a textbuffer */
128 void textbuffer_free(textbuffer_t *t)
130 if (!t)
131 return;
133 textbuffer_clear(t);
134 array_free(&t->data,0);
135 if (t->str)
136 free(t->str);
137 free(t);
140 /* adjust the settings of a textbuffer, and regen gl data if necessary */
141 int textbuffer_adjust(textbuffer_t *t, font_t *f, int size, float x, float y, int max_x, int max_y, int max_c, uint32_t options)
143 uint32_t *str;
144 uint32_t len;
145 uint32_t i;
146 uint8_t redo = 0;
147 if (!t)
148 return 1;
150 if (f && f != t->font) {
151 t->font = f;
152 redo = 1;
155 t->x = x;
156 t->y = y;
158 if (t->mx != max_x) {
159 t->mx = max_x;
160 redo = 1;
163 if (t->my != max_y) {
164 t->my = max_y;
165 redo = 1;
168 if (t->mc != max_c) {
169 if (t->mc > max_c)
170 redo = 1;
171 t->mc = max_c;
174 if (size != t->font_size) {
175 t->font_size = size;
176 redo = 1;
179 if (t->options != options) {
180 if ((t->options&TB_OPT_NUMERIC) == 0 && (options&TB_OPT_NUMERIC) == TB_OPT_NUMERIC)
181 redo = 1;
182 t->options = options;
185 if (!redo)
186 return 0;
188 t->cw = 0;
189 t->ch = t->font_size;
191 str = t->str;
192 len = t->length;
193 t->str = NULL;
194 t->size = 0;
195 t->length = 0;
197 textbuffer_clear(t);
199 if (!str)
200 return 0;
202 for (i=0; i<len; i++) {
203 textbuffer_addchar(t,str[i]);
206 free(str);
208 return 0;
211 /* add a string to a textbuffer */
212 int textbuffer_addstr(textbuffer_t *t, char* str)
214 int r = 0;
215 int i = 0;
216 uint32_t ch;
217 if (!t)
218 return 1;
220 while ((ch = utf8_nextchar(str,&i))) {
221 r = textbuffer_addchar(t,ch);
222 if (r)
223 break;
226 return r;
229 /* add a single utf32 character to a textbuffer */
230 int textbuffer_addchar(textbuffer_t *t, uint32_t ch)
232 rendertext_t *rt = NULL;
233 fontchar_t *fc;
234 uint32_t page;
235 float sf;
236 v2_t v;
237 v2_t tc;
238 float w;
239 float h;
240 if (!t)
241 return 1;
243 if ((t->options&TB_OPT_NUMERIC) == TB_OPT_NUMERIC && !iswdigit(ch))
244 return -1;
246 if (t->mc && t->length == t->mc)
247 return -1;
249 page = ch/256;
251 if (t->data.length) {
252 rt = array_get_ptr(&t->data,t->data.length-1);
253 if (rt && rt->page != page)
254 rt = NULL;
257 if (!rt)
258 rt = textbuffer_get_rendertext(t,page);
260 if (!rt)
261 return 1;
263 if (font_ttf_get_char(t->font,ch,&fc,&rt->glid))
264 return 1;
266 sf = (float)t->font_size/fc->h;
268 w = sf*fc->w;
269 h = sf*fc->h;
271 if (t->mx && t->nx+w > t->mx) {
272 t->nx = 0;
273 t->ny += t->font_size;
274 t->ch += t->font_size;
277 if (t->my && t->ny+h > t->my)
278 return -1;
280 v.x = t->nx;
281 v.y = t->ny-h;
282 tc.x = fc->x[0];
283 tc.y = fc->y[1];
284 array_push_v2t(&rt->v,&v);
285 array_push_v2t(&rt->t,&tc);
286 v.x = t->nx+w;
287 v.y = t->ny-h;
288 tc.x = fc->x[1];
289 tc.y = fc->y[1];
290 array_push_v2t(&rt->v,&v);
291 array_push_v2t(&rt->t,&tc);
292 v.x = t->nx;
293 v.y = t->ny;
294 tc.x = fc->x[0];
295 tc.y = fc->y[0];
296 array_push_v2t(&rt->v,&v);
297 array_push_v2t(&rt->t,&tc);
298 array_push_v2t(&rt->v,&v);
299 array_push_v2t(&rt->t,&tc);
300 v.x = t->nx+w;
301 v.y = t->ny-h;
302 tc.x = fc->x[1];
303 tc.y = fc->y[1];
304 array_push_v2t(&rt->v,&v);
305 array_push_v2t(&rt->t,&tc);
306 v.x = t->nx+w;
307 v.y = t->ny;
308 tc.x = fc->x[1];
309 tc.y = fc->y[0];
310 array_push_v2t(&rt->v,&v);
311 array_push_v2t(&rt->t,&tc);
313 t->nx += (sf*fc->a);
314 if (t->nx > t->cw)
315 t->cw = t->nx;
317 if (t->size <= t->length+2) {
318 uint32_t *s;
319 uint32_t nl = t->size+16;
321 s = realloc(t->str,sizeof(uint32_t)*nl);
322 if (!s)
323 return 1;
324 t->str = s;
325 t->size = nl;
328 t->str[t->length++] = ch;
329 t->str[t->length] = 0;
331 return 0;
334 /* get the current draw dimensions for a textbuffer */
335 int textbuffer_get_dimensions(textbuffer_t *t, int sizes[2])
337 if (!t)
338 return 1;
340 sizes[0] = t->cw;
341 sizes[1] = t->ch;
342 return 0;