font rendering... mostly
[voxelands-alt.git] / src / graphics / render2d.c
blob125ab353ba9bbbf38370e29b8fe8b2a4f5329c5c
1 /************************************************************************
2 * render2d.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 #include "graphics.h"
22 #include "list.h"
23 #include "array.h"
25 #include <string.h>
26 #include <ctype.h>
28 typedef struct obj2d_s {
29 struct obj2d_s *prev;
30 struct obj2d_s *next;
31 int type;
32 rectf_t box;
33 material_t *mat;
34 textbuffer_t txt;
35 textbuffer_t *itxt;
36 } obj2d_t;
38 static struct {
39 GLuint vao;
40 GLuint vbo[2];
41 shader_t *shader;
42 obj2d_t *stack;
43 obj2d_t *current;
44 } render2d_data = {
46 {0,0},
47 NULL,
48 NULL,
49 NULL
52 static obj2d_t *render2d_section_create()
54 obj2d_t *r = malloc(sizeof(obj2d_t));
55 r->type = RD2_NONE;
56 r->mat = NULL;
57 r->itxt = NULL;
59 textbuffer_init(&r->txt,NULL,0,0,0,0,0,0,0);
61 return r;
64 static void render2d_get_section(material_t *m, int t)
66 if (!render2d_data.current) {
67 if (!render2d_data.stack) {
68 render2d_data.current = render2d_section_create();
69 render2d_data.stack = list_push(&render2d_data.stack,render2d_data.current);
70 }else{
71 render2d_data.current = render2d_data.stack;
75 if (render2d_data.current->type != RD2_NONE) {
76 if (
77 t == RD2_TEXT
78 || render2d_data.current->type != t
79 || (
81 && m != render2d_data.current->mat
83 ) {
84 if (!render2d_data.current->next) {
85 render2d_data.current = render2d_section_create();
86 render2d_data.stack = list_push(&render2d_data.stack,render2d_data.current);
87 }else{
88 render2d_data.current = render2d_data.current->next;
92 if (m)
93 render2d_data.current->mat = m;
95 render2d_data.current->type = t;
98 /* render a 2d line */
99 void render2d_line(material_t *m, float x, float y, float ex, float ey)
102 render2d_get_section(m,RD2_LINE);
104 render2d_data.current->box.x = x;
105 render2d_data.current->box.y = y;
106 render2d_data.current->box.w = ex;
107 render2d_data.current->box.h = ey;
111 /* render a 2d quad of material */
112 void render2d_quad_mat(material_t *m, float x, float y, float w, float h)
114 render2d_get_section(m,RD2_QUAD);
116 y = wm_data.size.height-y;
118 w /= (float)wm_data.size.width;
119 h /= (float)wm_data.size.height;
120 x = (((x/(float)wm_data.size.width)*2.0)-1.0)+w;
121 y = (((y/(float)wm_data.size.height)*2.0)-1.0)-h;
123 render2d_data.current->box.x = x;
124 render2d_data.current->box.y = y;
125 render2d_data.current->box.w = w;
126 render2d_data.current->box.h = h;
129 /* render text */
130 void render2d_text(float x, float y, int w, int h, int font, int size, char* str)
132 font_t *f;
133 render2d_get_section(NULL,RD2_TEXT);
135 f = font_get(font);
137 textbuffer_adjust(&render2d_data.current->txt,f,size,x,y,w,h,0,0);
138 textbuffer_addstr(&render2d_data.current->txt,str);
141 /* render a pregenerated textbuffer */
142 void render2d_textbuffer(textbuffer_t *t)
144 float x;
145 float y;
146 float s;
147 render2d_get_section(NULL,RD2_TEXT);
149 render2d_data.current->itxt = t;
151 s = (((float)t->font_size)*0.15);
152 s /= (float)wm_data.size.height;
154 x = t->x;
155 y = wm_data.size.height-t->y;
157 x = (((x/(float)wm_data.size.width)*2.0)-1.0);
158 y = (((y/(float)wm_data.size.height)*2.0)-1.0);
160 render2d_data.current->box.x = x;
161 render2d_data.current->box.y = y;
162 render2d_data.current->box.w = s;
163 render2d_data.current->box.h = s;
166 /* render a textbuffer */
168 /* render 2d graphics to the frame */
169 void render2d()
171 int s = 0;
172 int b = 0;
173 int i;
174 rendertext_t *t;
175 textbuffer_t *txt;
176 matrix_t m;
178 glDisable(GL_DEPTH_TEST);
180 render2d_data.current = render2d_data.stack;
182 if (render2d_data.vao == 0) {
183 GLfloat vertices[8] = {-1.0,1.0, -1.0,-1.0, 1.0,1.0, 1.0,-1.0};
184 GLfloat texcoords[8] = {0.0,0.0, 0.0,1.0, 1.0,0.0, 1.0,1.0};
185 glGenVertexArrays(1,&render2d_data.vao);
186 glBindVertexArray(render2d_data.vao);
187 glGenBuffers(2, render2d_data.vbo);
188 glBindBuffer(GL_ARRAY_BUFFER, render2d_data.vbo[0]);
189 glBufferData(GL_ARRAY_BUFFER, 32, vertices, GL_STATIC_DRAW);
190 glEnableVertexAttribArray(0);
191 glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,0);
192 glBindBuffer(GL_ARRAY_BUFFER, render2d_data.vbo[1]);
193 glBufferData(GL_ARRAY_BUFFER, 32, texcoords, GL_STATIC_DRAW);
194 glEnableVertexAttribArray(1);
195 glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,0);
196 glBindBuffer(GL_ARRAY_BUFFER, 0);
199 /* shader */
200 if (!render2d_data.shader) {
201 render2d_data.shader = shader_create("ui");
202 shader_attribute(render2d_data.shader,0,"position");
203 shader_attribute(render2d_data.shader,1,"uvs");
206 shader_enable(render2d_data.shader);
208 glBindVertexArray(render2d_data.vao);
209 glEnableVertexAttribArray(0);
210 glEnableVertexAttribArray(1);
211 b = 0;
213 while (render2d_data.current && render2d_data.current->type != RD2_NONE) {
214 if (render2d_data.current->type == RD2_TEXT) {
215 txt = render2d_data.current->itxt;
216 if (!txt)
217 txt = &render2d_data.current->txt;
218 for (i=0; i<txt->data.length; i++) {
219 t = array_get_ptr(&txt->data,i);
220 switch (t->state) {
221 case 0:
222 glGenVertexArrays(1,&t->vao);
223 glBindVertexArray(t->vao);
224 glGenBuffers(2, t->vbo);
225 glBindBuffer(GL_ARRAY_BUFFER, t->vbo[0]);
226 glBufferData(GL_ARRAY_BUFFER, t->v.length*4, t->v.data, GL_STATIC_DRAW);
227 glEnableVertexAttribArray(0);
228 glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,0);
229 glBindBuffer(GL_ARRAY_BUFFER, t->vbo[1]);
230 glBufferData(GL_ARRAY_BUFFER, t->t.length*4, t->t.data, GL_STATIC_DRAW);
231 glEnableVertexAttribArray(1);
232 glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,0);
233 t->state = 1;
234 break;
235 case 1:
236 glBindVertexArray(t->vao);
237 glEnableVertexAttribArray(0);
238 glEnableVertexAttribArray(1);
239 break;
240 case 2:
241 glDeleteBuffers(2, t->vbo);
242 glGenBuffers(2, t->vbo);
243 glBindBuffer(GL_ARRAY_BUFFER, t->vbo[0]);
244 glBufferData(GL_ARRAY_BUFFER, t->v.length*4, t->v.data, GL_STATIC_DRAW);
245 glEnableVertexAttribArray(0);
246 glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,0);
247 glBindBuffer(GL_ARRAY_BUFFER, t->vbo[1]);
248 glBufferData(GL_ARRAY_BUFFER, t->t.length*4, t->t.data, GL_STATIC_DRAW);
249 glEnableVertexAttribArray(1);
250 glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,0);
251 t->state = 1;
252 break;
253 default:;
255 glBindTexture(GL_TEXTURE_2D,t->glid);
256 matrix_init(&m);
257 matrix_scale(&m,render2d_data.current->box.w,render2d_data.current->box.h,1.0);
258 matrix_translate(&m,render2d_data.current->box.x,render2d_data.current->box.y,1.0);
259 shader_uniform_matrix(render2d_data.shader,"transformationMatrix",&m);
260 glDrawArrays(GL_TRIANGLES,0,t->v.length/2);
262 b = 1;
263 render2d_data.current->itxt = NULL;
264 textbuffer_clear(&render2d_data.current->txt);
265 }else if (render2d_data.current->type == RD2_QUAD) {
266 if (b != 0) {
267 glBindVertexArray(render2d_data.vao);
268 glEnableVertexAttribArray(0);
269 glEnableVertexAttribArray(1);
270 b = 0;
272 mat_use(render2d_data.current->mat,render2d_data.shader);
274 matrix_init(&m);
275 matrix_scale(&m,render2d_data.current->box.w,render2d_data.current->box.h,1.0);
276 matrix_translate(&m,render2d_data.current->box.x,render2d_data.current->box.y,1.0);
277 shader_uniform_matrix(render2d_data.shader,"transformationMatrix",&m);
279 glDrawArrays(GL_TRIANGLE_STRIP,0,4);
280 render2d_data.current->mat = NULL;
283 render2d_data.current->type = RD2_NONE;
284 render2d_data.current = render2d_data.current->next;
285 s++;
288 glDisableVertexAttribArray(0);
289 glDisableVertexAttribArray(1);
290 glBindVertexArray(0);
292 /* shader */
293 shader_disable(render2d_data.shader);
295 render2d_data.current = NULL;