initial commit
[shapestoy] / src / sanegl.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include <assert.h>
6 #include "cgmath/cgmath.h"
7
8 #include "opengl.h"
9
10 #ifdef GLDEF
11 #undef GLDEF
12 #endif
13 #include "sanegl.h"
14
15 #define MMODE_IDX(x)    ((x) - GL_MODELVIEW)
16 #define MAT_STACK_SIZE  32
17 #define MAT_IDENT       {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}
18
19 #define MAX_VERTS       512
20
21 static void gl_draw_immediate(void);
22
23 typedef struct { float x, y; } vec2_t;
24 typedef struct { float x, y, z; } vec3_t;
25 typedef struct { float x, y, z, w; } vec4_t;
26
27 static int mm_idx = 0;
28 static float mat_stack[3][MAT_STACK_SIZE][16] = {{MAT_IDENT}, {MAT_IDENT}, {MAT_IDENT}};
29 static int stack_top[3];
30 static float mat_mvp[16];
31 static int mvp_valid;
32 static int prim = -1;
33
34 static vec3_t cur_normal = {0, 0, 1};
35 static vec4_t cur_color = {1, 1, 1, 1}, cur_attrib;
36 static vec2_t cur_texcoord;
37
38 static vec4_t *vert_arr, *col_arr, *attr_arr;
39 static vec3_t *norm_arr;
40 static vec2_t *texc_arr;
41 /*static unsigned int vbuf, cbuf, nbuf, tbuf, abuf;*/
42 static int vloc, nloc, cloc, tloc, aloc = -1;
43
44 static int num_verts, vert_calls;
45 static int cur_prog;
46
47
48 void gl_matrix_mode(int mm)
49 {
50         mm_idx = MMODE_IDX(mm);
51 }
52
53 void gl_push_matrix(void)
54 {
55         int top = stack_top[mm_idx];
56
57         memcpy(mat_stack[mm_idx][top + 1], mat_stack[mm_idx][top], 16 * sizeof(float));
58         stack_top[mm_idx]++;
59         mvp_valid = 0;
60 }
61
62 void gl_pop_matrix(void)
63 {
64         stack_top[mm_idx]--;
65         mvp_valid = 0;
66 }
67
68 void gl_load_identity(void)
69 {
70         static const float idmat[] = MAT_IDENT;
71         int top = stack_top[mm_idx];
72         float *mat = mat_stack[mm_idx][top];
73
74         memcpy(mat, idmat, sizeof idmat);
75         mvp_valid = 0;
76 }
77
78 void gl_load_matrixf(const float *m)
79 {
80         int top = stack_top[mm_idx];
81         float *mat = mat_stack[mm_idx][top];
82
83         memcpy(mat, m, 16 * sizeof *mat);
84         mvp_valid = 0;
85 }
86
87 #define M(i, j) ((i << 2) + j)
88
89 void gl_mult_matrixf(const float *m2)
90 {
91         int top = stack_top[mm_idx];
92         float *m1 = mat_stack[mm_idx][top];
93
94         cgm_mpremul(m1, m2);
95         mvp_valid = 0;
96 }
97
98 void gl_translatef(float x, float y, float z)
99 {
100         float mat[16];
101         cgm_mtranslation(mat, x, y, z);
102         gl_mult_matrixf(mat);
103 }
104
105 void gl_rotatef(float angle, float x, float y, float z)
106 {
107         float mat[16];
108         cgm_mrotation(mat, cgm_deg_to_rad(angle), x, y, z);
109         gl_mult_matrixf(mat);
110 }
111
112 void gl_scalef(float x, float y, float z)
113 {
114         float mat[16];
115         cgm_mscaling(mat, x, y, z);
116         gl_mult_matrixf(mat);
117 }
118
119 void gl_ortho(float left, float right, float bottom, float top, float znear, float zfar)
120 {
121         float mat[16];
122         cgm_mortho(mat, left, right, bottom, top, znear, zfar);
123         gl_mult_matrixf(mat);
124 }
125
126 void gl_frustum(float left, float right, float bottom, float top, float znear, float zfar)
127 {
128         float mat[16];
129         cgm_mfrustum(mat, left, right, bottom, top, znear, zfar);
130         gl_mult_matrixf(mat);
131 }
132
133 void glu_perspective(float vfov, float aspect, float znear, float zfar)
134 {
135         float mat[16];
136         cgm_mperspective(mat, cgm_deg_to_rad(vfov), aspect, znear, zfar);
137         gl_mult_matrixf(mat);
138 }
139
140 void gl_apply_xform(unsigned int prog)
141 {
142         int loc, mvidx, pidx, tidx, mvtop, ptop, ttop;
143
144         mvidx = MMODE_IDX(GL_MODELVIEW);
145         pidx = MMODE_IDX(GL_PROJECTION);
146         tidx = MMODE_IDX(GL_TEXTURE);
147
148         mvtop = stack_top[mvidx];
149         ptop = stack_top[pidx];
150         ttop = stack_top[tidx];
151
152         assert(prog);
153
154         if((loc = glGetUniformLocation(prog, "matrix_modelview")) != -1) {
155                 glUniformMatrix4fv(loc, 1, 0, mat_stack[mvidx][mvtop]);
156         }
157
158         if((loc = glGetUniformLocation(prog, "matrix_projection")) != -1) {
159                 glUniformMatrix4fv(loc, 1, 0, mat_stack[pidx][ptop]);
160         }
161
162         if((loc = glGetUniformLocation(prog, "matrix_texture")) != -1) {
163                 glUniformMatrix4fv(loc, 1, 0, mat_stack[tidx][ttop]);
164         }
165
166         if((loc = glGetUniformLocation(prog, "matrix_normal")) != -1) {
167                 float nmat[9];
168
169                 nmat[0] = mat_stack[mvidx][mvtop][0];
170                 nmat[1] = mat_stack[mvidx][mvtop][1];
171                 nmat[2] = mat_stack[mvidx][mvtop][2];
172                 nmat[3] = mat_stack[mvidx][mvtop][4];
173                 nmat[4] = mat_stack[mvidx][mvtop][5];
174                 nmat[5] = mat_stack[mvidx][mvtop][6];
175                 nmat[6] = mat_stack[mvidx][mvtop][8];
176                 nmat[7] = mat_stack[mvidx][mvtop][9];
177                 nmat[8] = mat_stack[mvidx][mvtop][10];
178                 glUniformMatrix3fv(loc, 1, 0, nmat);
179         }
180
181         if((loc = glGetUniformLocation(prog, "matrix_modelview_projection")) != -1) {
182                 if(!mvp_valid) {
183                         cgm_mcopy(mat_mvp, mat_stack[mvidx][mvtop]);
184                         cgm_mmul(mat_mvp, mat_stack[pidx][ptop]);
185                 }
186                 glUniformMatrix4fv(loc, 1, 0, mat_mvp);
187         }
188 }
189
190
191 /* immediate mode rendering */
192 void gl_begin(int p)
193 {
194         if(!vert_arr) {
195                 vert_arr = malloc(MAX_VERTS * sizeof *vert_arr);
196                 norm_arr = malloc(MAX_VERTS * sizeof *norm_arr);
197                 texc_arr = malloc(MAX_VERTS * sizeof *texc_arr);
198                 col_arr = malloc(MAX_VERTS * sizeof *col_arr);
199                 attr_arr = malloc(MAX_VERTS * sizeof *attr_arr);
200                 assert(vert_arr && norm_arr && texc_arr && col_arr && attr_arr);
201         }
202
203         prim = p;
204         num_verts = vert_calls = 0;
205
206         glGetIntegerv(GL_CURRENT_PROGRAM, &cur_prog);
207         assert(cur_prog);
208
209         gl_apply_xform(cur_prog);
210
211         vloc = glGetAttribLocation(cur_prog, "attr_vertex");
212         nloc = glGetAttribLocation(cur_prog, "attr_normal");
213         cloc = glGetAttribLocation(cur_prog, "attr_color");
214         tloc = glGetAttribLocation(cur_prog, "attr_texcoord");
215 }
216
217 void gl_end(void)
218 {
219         if(num_verts > 0) {
220                 gl_draw_immediate();
221         }
222         aloc = -1;
223 }
224
225 static void gl_draw_immediate(void)
226 {
227         int glprim;
228
229         if(vloc == -1) {
230                 fprintf(stderr, "gl_draw_immediate call with vloc == -1\n");
231                 return;
232         }
233
234         glprim = prim == GL_QUADS ? GL_TRIANGLES : prim;
235
236         glVertexAttribPointer(vloc, 4, GL_FLOAT, 0, 0, vert_arr);
237         glEnableVertexAttribArray(vloc);
238
239         if(nloc != -1) {
240                 glVertexAttribPointer(nloc, 3, GL_FLOAT, 0, 0, norm_arr);
241                 glEnableVertexAttribArray(nloc);
242         }
243
244         if(cloc != -1) {
245                 glVertexAttribPointer(cloc, 4, GL_FLOAT, 1, 0, col_arr);
246                 glEnableVertexAttribArray(cloc);
247         }
248
249         if(tloc != -1) {
250                 glVertexAttribPointer(tloc, 2, GL_FLOAT, 0, 0, texc_arr);
251                 glEnableVertexAttribArray(tloc);
252         }
253
254         if(aloc != -1) {
255                 glVertexAttribPointer(aloc, 4, GL_FLOAT, 0, 0, attr_arr);
256                 glEnableVertexAttribArray(aloc);
257         }
258
259         glDrawArrays(glprim, 0, num_verts);
260
261         glDisableVertexAttribArray(vloc);
262         if(nloc != -1) {
263                 glDisableVertexAttribArray(nloc);
264         }
265         if(cloc != -1) {
266                 glDisableVertexAttribArray(cloc);
267         }
268         if(tloc != -1) {
269                 glDisableVertexAttribArray(tloc);
270         }
271         if(aloc != -1) {
272                 glDisableVertexAttribArray(aloc);
273         }
274 }
275
276
277 void gl_vertex2f(float x, float y)
278 {
279         gl_vertex4f(x, y, 0.0f, 1.0f);
280 }
281
282 void gl_vertex3f(float x, float y, float z)
283 {
284         gl_vertex4f(x, y, z, 1.0f);
285 }
286
287 void gl_vertex4f(float x, float y, float z, float w)
288 {
289         int i, buffer_full;
290
291         if(prim == GL_QUADS && vert_calls % 4 == 3) {
292                 for(i=0; i<2; i++) {
293                         if(aloc != -1) {
294                                 attr_arr[num_verts] = attr_arr[num_verts - 3 + i];
295                         }
296                         if(cloc != -1) {
297                                 col_arr[num_verts] = col_arr[num_verts - 3 + i];
298                         }
299                         if(tloc != -1) {
300                                 texc_arr[num_verts] = texc_arr[num_verts - 3 + i];
301                         }
302                         if(nloc != -1) {
303                                 norm_arr[num_verts] = norm_arr[num_verts - 3 + i];
304                         }
305                         vert_arr[num_verts] = vert_arr[num_verts - 3 + i];
306                         num_verts++;
307                 }
308         }
309
310         vert_arr[num_verts].x = x;
311         vert_arr[num_verts].y = y;
312         vert_arr[num_verts].z = z;
313         vert_arr[num_verts].w = w;
314
315         if(cloc != -1) {
316                 col_arr[num_verts] = cur_color;
317         }
318         if(nloc != -1) {
319                 norm_arr[num_verts] = cur_normal;
320         }
321         if(tloc != -1) {
322                 texc_arr[num_verts] = cur_texcoord;
323         }
324         if(aloc != -1) {
325                 attr_arr[num_verts] = cur_attrib;
326         }
327
328         vert_calls++;
329         num_verts++;
330
331         if(prim == GL_QUADS) {
332                 /* leave space for 6 more worst-case and don't allow flushes mid-quad */
333                 buffer_full = num_verts >= MAX_VERTS - 6 && vert_calls % 4 == 0;
334         } else {
335                 buffer_full = num_verts >= MAX_VERTS - prim;
336         }
337
338         if(buffer_full) {
339                 gl_draw_immediate();
340                 gl_begin(prim); /* reset everything */
341         }
342 }
343
344
345 void gl_normal3f(float x, float y, float z)
346 {
347         cur_normal.x = x;
348         cur_normal.y = y;
349         cur_normal.z = z;
350 }
351
352
353 void gl_color3f(float r, float g, float b)
354 {
355         cur_color.x = r;
356         cur_color.y = g;
357         cur_color.z = b;
358         cur_color.w = 1.0f;
359 }
360
361 void gl_color4f(float r, float g, float b, float a)
362 {
363         cur_color.x = r;
364         cur_color.y = g;
365         cur_color.z = b;
366         cur_color.w = a;
367 }
368
369
370 void gl_texcoord1f(float s)
371 {
372         cur_texcoord.x = s;
373         cur_texcoord.y = 0.0f;
374 }
375
376 void gl_texcoord2f(float s, float t)
377 {
378         cur_texcoord.x = s;
379         cur_texcoord.y = t;
380 }
381
382 void gl_vertex_attrib2f(int loc, float x, float y)
383 {
384         aloc = loc;
385         cur_attrib.x = x;
386         cur_attrib.y = y;
387         cur_attrib.z = 0.0f;
388         cur_attrib.w = 1.0f;
389 }
390
391 void gl_vertex_attrib3f(int loc, float x, float y, float z)
392 {
393         aloc = loc;
394         cur_attrib.x = x;
395         cur_attrib.y = y;
396         cur_attrib.z = z;
397         cur_attrib.w = 1.0f;
398 }
399
400 void gl_vertex_attrib4f(int loc, float x, float y, float z, float w)
401 {
402         aloc = loc;
403         cur_attrib.x = x;
404         cur_attrib.y = y;
405         cur_attrib.z = z;
406         cur_attrib.w = w;
407 }