graphics updates
[voxelands-alt.git] / src / graphics / render2d.c
blob2516f9bcfe1a3690e199af7efb383adc5cffdede
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;
148 if (!t || !t->length)
149 return;
151 render2d_get_section(NULL,RD2_TEXT);
153 render2d_data.current->itxt = t;
155 s = (((float)t->font_size)*0.15);
156 s /= (float)wm_data.size.height;
158 x = t->x;
159 y = wm_data.size.height-t->y;
161 x = (((x/(float)wm_data.size.width)*2.0)-1.0);
162 y = (((y/(float)wm_data.size.height)*2.0)-1.0);
164 render2d_data.current->box.x = x;
165 render2d_data.current->box.y = y;
166 render2d_data.current->box.w = s;
167 render2d_data.current->box.h = s;
170 /* render a textbuffer */
172 /* render 2d graphics to the frame */
173 void render2d()
175 int s = 0;
176 int b = 0;
177 int i;
178 rendertext_t *t;
179 textbuffer_t *txt;
180 matrix_t m;
182 glDisable(GL_DEPTH_TEST);
184 render2d_data.current = render2d_data.stack;
186 if (render2d_data.vao == 0) {
187 GLfloat vertices[8] = {-1.0,1.0, -1.0,-1.0, 1.0,1.0, 1.0,-1.0};
188 GLfloat texcoords[8] = {0.0,0.0, 0.0,1.0, 1.0,0.0, 1.0,1.0};
189 glGenVertexArrays(1,&render2d_data.vao);
190 glBindVertexArray(render2d_data.vao);
191 glGenBuffers(2, render2d_data.vbo);
192 glBindBuffer(GL_ARRAY_BUFFER, render2d_data.vbo[0]);
193 glBufferData(GL_ARRAY_BUFFER, 32, vertices, GL_STATIC_DRAW);
194 glEnableVertexAttribArray(0);
195 glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,0);
196 glBindBuffer(GL_ARRAY_BUFFER, render2d_data.vbo[1]);
197 glBufferData(GL_ARRAY_BUFFER, 32, texcoords, GL_STATIC_DRAW);
198 glEnableVertexAttribArray(1);
199 glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,0);
200 glBindBuffer(GL_ARRAY_BUFFER, 0);
203 /* shader */
204 if (!render2d_data.shader) {
205 render2d_data.shader = shader_create("ui");
206 shader_attribute(render2d_data.shader,0,"position");
207 shader_attribute(render2d_data.shader,1,"uvs");
210 shader_enable(render2d_data.shader);
212 glBindVertexArray(render2d_data.vao);
213 glEnableVertexAttribArray(0);
214 glEnableVertexAttribArray(1);
215 b = 0;
217 while (render2d_data.current && render2d_data.current->type != RD2_NONE) {
218 if (render2d_data.current->type == RD2_TEXT) {
219 txt = render2d_data.current->itxt;
220 if (!txt)
221 txt = &render2d_data.current->txt;
222 for (i=0; i<txt->data.length; i++) {
223 t = array_get_ptr(&txt->data,i);
224 switch (t->state) {
225 case 0:
226 glGenVertexArrays(1,&t->vao);
227 glBindVertexArray(t->vao);
228 glGenBuffers(2, t->vbo);
229 glBindBuffer(GL_ARRAY_BUFFER, t->vbo[0]);
230 glBufferData(GL_ARRAY_BUFFER, t->v.length*4, t->v.data, GL_STATIC_DRAW);
231 glEnableVertexAttribArray(0);
232 glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,0);
233 glBindBuffer(GL_ARRAY_BUFFER, t->vbo[1]);
234 glBufferData(GL_ARRAY_BUFFER, t->t.length*4, t->t.data, GL_STATIC_DRAW);
235 glEnableVertexAttribArray(1);
236 glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,0);
237 t->state = 1;
238 break;
239 case 1:
240 glBindVertexArray(t->vao);
241 glEnableVertexAttribArray(0);
242 glEnableVertexAttribArray(1);
243 break;
244 case 2:
245 glDeleteBuffers(2, t->vbo);
246 glGenBuffers(2, t->vbo);
247 glBindBuffer(GL_ARRAY_BUFFER, t->vbo[0]);
248 glBufferData(GL_ARRAY_BUFFER, t->v.length*4, t->v.data, GL_STATIC_DRAW);
249 glEnableVertexAttribArray(0);
250 glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,0);
251 glBindBuffer(GL_ARRAY_BUFFER, t->vbo[1]);
252 glBufferData(GL_ARRAY_BUFFER, t->t.length*4, t->t.data, GL_STATIC_DRAW);
253 glEnableVertexAttribArray(1);
254 glVertexAttribPointer(1,2,GL_FLOAT,GL_FALSE,0,0);
255 t->state = 1;
256 break;
257 default:;
259 mat_bind_with_opts(t->glid,MATOPT_ALPHA_BLEND|MATOPT_SDF_ALPHA);
260 matrix_init(&m);
261 matrix_scale(&m,render2d_data.current->box.w,render2d_data.current->box.h,1.0);
262 matrix_translate(&m,render2d_data.current->box.x,render2d_data.current->box.y,1.0);
263 shader_uniform_matrix(render2d_data.shader,"transformationMatrix",&m);
264 glDrawArrays(GL_TRIANGLES,0,t->v.length/2);
266 b = 1;
267 render2d_data.current->itxt = NULL;
268 textbuffer_clear(&render2d_data.current->txt);
269 }else if (render2d_data.current->type == RD2_QUAD) {
270 if (b != 0) {
271 glBindVertexArray(render2d_data.vao);
272 glEnableVertexAttribArray(0);
273 glEnableVertexAttribArray(1);
274 b = 0;
276 mat_use(render2d_data.current->mat,render2d_data.shader);
278 matrix_init(&m);
279 matrix_scale(&m,render2d_data.current->box.w,render2d_data.current->box.h,1.0);
280 matrix_translate(&m,render2d_data.current->box.x,render2d_data.current->box.y,1.0);
281 shader_uniform_matrix(render2d_data.shader,"transformationMatrix",&m);
283 glDrawArrays(GL_TRIANGLE_STRIP,0,4);
284 render2d_data.current->mat = NULL;
287 render2d_data.current->type = RD2_NONE;
288 render2d_data.current = render2d_data.current->next;
289 s++;
292 glDisableVertexAttribArray(0);
293 glDisableVertexAttribArray(1);
294 glBindVertexArray(0);
296 /* shader */
297 shader_disable(render2d_data.shader);
299 render2d_data.current = NULL;