stop appending repeat keys to the input buffer
[retroray] / src / gaw / gaw_gl.c
1 /*
2 RetroRay - integrated standalone vintage modeller/renderer
3 Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include <string.h>
19 #include "util.h"
20 #include "gaw.h"
21
22 #if defined(WIN32) || defined(__WIN32)
23 #include <windows.h>
24 #endif
25 #ifdef __APPLE__
26 #include <OpenGL/gl.h>
27 #include <OpenGL/glu.h>
28 #else
29 #include <GL/gl.h>
30 #include <GL/glu.h>
31 #endif
32
33
34 static const float *vertex_ptr, *normal_ptr, *texcoord_ptr, *color_ptr;
35 static int vertex_nelem, texcoord_nelem, color_nelem;
36 static int vertex_stride, normal_stride, texcoord_stride, color_stride;
37
38 static char *glextstr;
39 static int have_edgeclamp = -1;
40
41
42 void gaw_viewport(int x, int y, int w, int h)
43 {
44         glViewport(x, y, w, h);
45 }
46
47 void gaw_get_viewport(int *vp)
48 {
49         glGetIntegerv(GL_VIEWPORT, vp);
50 }
51
52 void gaw_matrix_mode(int mode)
53 {
54         mode += GL_MODELVIEW;
55         glMatrixMode(mode);
56 }
57
58 void gaw_load_identity(void)
59 {
60         glLoadIdentity();
61 }
62
63 void gaw_load_matrix(const float *m)
64 {
65         glLoadMatrixf(m);
66 }
67
68 void gaw_mult_matrix(const float *m)
69 {
70         glMultMatrixf(m);
71 }
72
73 void gaw_push_matrix(void)
74 {
75         glPushMatrix();
76 }
77
78 void gaw_pop_matrix(void)
79 {
80         glPopMatrix();
81 }
82
83 void gaw_get_modelview(float *m)
84 {
85         glGetFloatv(GL_MODELVIEW_MATRIX, m);
86 }
87
88 void gaw_get_projection(float *m)
89 {
90         glGetFloatv(GL_PROJECTION_MATRIX, m);
91 }
92
93 void gaw_translate(float x, float y, float z)
94 {
95         glTranslatef(x, y, z);
96 }
97
98 void gaw_rotate(float angle, float x, float y, float z)
99 {
100         glRotatef(angle, x, y, z);
101 }
102
103 void gaw_scale(float sx, float sy, float sz)
104 {
105         glScalef(sx, sy, sz);
106 }
107
108 void gaw_ortho(float l, float r, float b, float t, float n, float f)
109 {
110         glOrtho(l, r, b, t, n, f);
111 }
112
113 void gaw_frustum(float l, float r, float b, float t, float n, float f)
114 {
115         glFrustum(l, r, b, t, n, f);
116 }
117
118 void gaw_perspective(float vfov, float aspect, float znear, float zfar)
119 {
120         gluPerspective(vfov, aspect, znear, zfar);
121 }
122
123 void gaw_save(void)
124 {
125         glPushAttrib(GL_ENABLE_BIT);
126 }
127
128 void gaw_restore(void)
129 {
130         glPopAttrib();
131 }
132
133 void gaw_enable(int st)
134 {
135         switch(st) {
136         case GAW_CULL_FACE:
137                 glEnable(GL_CULL_FACE);
138                 break;
139         case GAW_DEPTH_TEST:
140                 glEnable(GL_DEPTH_TEST);
141                 break;
142         case GAW_ALPHA_TEST:
143                 glEnable(GL_ALPHA_TEST);
144                 break;
145         case GAW_BLEND:
146                 glEnable(GL_BLEND);
147                 break;
148         case GAW_FOG:
149                 glEnable(GL_FOG);
150                 break;
151         case GAW_DITHER:
152                 glEnable(GL_DITHER);
153                 break;
154         case GAW_LIGHTING:
155                 glEnable(GL_LIGHTING);
156                 break;
157         case GAW_LIGHT0:
158                 glEnable(GL_LIGHT0);
159                 break;
160         case GAW_LIGHT1:
161                 glEnable(GL_LIGHT1);
162                 break;
163         case GAW_LIGHT2:
164                 glEnable(GL_LIGHT2);
165                 break;
166         case GAW_LIGHT3:
167                 glEnable(GL_LIGHT3);
168                 break;
169         case GAW_TEXTURE_1D:
170                 glEnable(GL_TEXTURE_1D);
171                 break;
172         case GAW_TEXTURE_2D:
173                 glEnable(GL_TEXTURE_2D);
174                 break;
175         case GAW_POLYGON_OFFSET:
176                 glEnable(GL_POLYGON_OFFSET_FILL);
177                 break;
178         default:
179                 break;
180         }
181 }
182
183 void gaw_disable(int st)
184 {
185         switch(st) {
186         case GAW_CULL_FACE:
187                 glDisable(GL_CULL_FACE);
188                 break;
189         case GAW_DEPTH_TEST:
190                 glDisable(GL_DEPTH_TEST);
191                 break;
192         case GAW_ALPHA_TEST:
193                 glDisable(GL_ALPHA_TEST);
194                 break;
195         case GAW_BLEND:
196                 glDisable(GL_BLEND);
197                 break;
198         case GAW_FOG:
199                 glDisable(GL_FOG);
200                 break;
201         case GAW_DITHER:
202                 glDisable(GL_DITHER);
203                 break;
204         case GAW_LIGHTING:
205                 glDisable(GL_LIGHTING);
206                 break;
207         case GAW_LIGHT0:
208                 glDisable(GL_LIGHT0);
209                 break;
210         case GAW_LIGHT1:
211                 glDisable(GL_LIGHT1);
212                 break;
213         case GAW_LIGHT2:
214                 glDisable(GL_LIGHT2);
215                 break;
216         case GAW_LIGHT3:
217                 glDisable(GL_LIGHT3);
218                 break;
219         case GAW_TEXTURE_1D:
220                 glDisable(GL_TEXTURE_1D);
221                 break;
222         case GAW_TEXTURE_2D:
223                 glDisable(GL_TEXTURE_2D);
224                 break;
225         case GAW_POLYGON_OFFSET:
226                 glDisable(GL_POLYGON_OFFSET_FILL);
227                 break;
228         default:
229                 break;
230         }
231 }
232
233 void gaw_depth_func(int func)
234 {
235         glDepthFunc(func + GL_NEVER);
236 }
237
238 void gaw_blend_func(int src, int dest)
239 {
240         static const int glbf[] = {GL_ZERO, GL_ONE, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA};
241         glBlendFunc(glbf[src], glbf[dest]);
242 }
243
244 void gaw_alpha_func(int func, float ref)
245 {
246         glAlphaFunc(func + GL_NEVER, ref);
247 }
248
249 void gaw_zoffset(float offs)
250 {
251         glPolygonOffset(1, offs);
252 }
253
254 void gaw_clear_color(float r, float g, float b, float a)
255 {
256         glClearColor(r, g, b, a);
257 }
258
259 void gaw_clear(unsigned int flags)
260 {
261         unsigned int glflags = 0;
262         if(flags & GAW_COLORBUF) {
263                 glflags |= GL_COLOR_BUFFER_BIT;
264         }
265         if(flags & GAW_DEPTHBUF) {
266                 glflags |= GL_DEPTH_BUFFER_BIT;
267         }
268         if(flags & GAW_STENCILBUF) {
269                 glflags |= GL_STENCIL_BUFFER_BIT;
270         }
271         glClear(glflags);
272 }
273
274 void gaw_depth_mask(int mask)
275 {
276         glDepthMask(mask);
277 }
278
279 void gaw_vertex_array(int nelem, int stride, const void *ptr)
280 {
281         vertex_nelem = nelem;
282         vertex_stride = stride;
283         vertex_ptr = ptr;
284 }
285
286 void gaw_normal_array(int stride, const void *ptr)
287 {
288         normal_stride = stride;
289         normal_ptr = ptr;
290 }
291
292 void gaw_texcoord_array(int nelem, int stride, const void *ptr)
293 {
294         texcoord_nelem = nelem;
295         texcoord_stride = stride;
296         texcoord_ptr = ptr;
297 }
298
299 void gaw_color_array(int nelem, int stride, const void *ptr)
300 {
301         color_nelem = nelem;
302         color_stride = stride;
303         color_ptr = ptr;
304 }
305
306 static int glprim[] = {GL_POINTS, GL_LINES, GL_TRIANGLES, GL_QUADS, GL_QUAD_STRIP};
307
308 void gaw_draw(int prim, int nverts)
309 {
310         glEnableClientState(GL_VERTEX_ARRAY);
311         glVertexPointer(vertex_nelem, GL_FLOAT, vertex_stride, vertex_ptr);
312         if(normal_ptr) {
313                 glEnableClientState(GL_NORMAL_ARRAY);
314                 glNormalPointer(GL_FLOAT, normal_stride, normal_ptr);
315         }
316         if(texcoord_ptr) {
317                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
318                 glTexCoordPointer(texcoord_nelem, GL_FLOAT, texcoord_stride, texcoord_ptr);
319         }
320         if(color_ptr) {
321                 glEnableClientState(GL_COLOR_ARRAY);
322                 glTexCoordPointer(color_nelem, GL_FLOAT, color_stride, color_ptr);
323         }
324
325         glDrawArrays(glprim[prim], 0, nverts);
326
327         glDisableClientState(GL_VERTEX_ARRAY);
328         glDisableClientState(GL_NORMAL_ARRAY);
329         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
330         glDisableClientState(GL_COLOR_ARRAY);
331 }
332
333 void gaw_draw_indexed(int prim, const unsigned int *idxarr, int nidx)
334 {
335         glEnableClientState(GL_VERTEX_ARRAY);
336         glVertexPointer(3, GL_FLOAT, 0, vertex_ptr);
337         if(normal_ptr) {
338                 glEnableClientState(GL_NORMAL_ARRAY);
339                 glNormalPointer(GL_FLOAT, 0, normal_ptr);
340         }
341         if(texcoord_ptr) {
342                 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
343                 glTexCoordPointer(2, GL_FLOAT, 0, texcoord_ptr);
344         }
345         if(color_ptr) {
346                 glEnableClientState(GL_COLOR_ARRAY);
347                 glTexCoordPointer(color_nelem, GL_FLOAT, color_stride, color_ptr);
348         }
349
350         glDrawElements(glprim[prim], nidx, GL_UNSIGNED_INT, idxarr);
351
352         glDisableClientState(GL_VERTEX_ARRAY);
353         glDisableClientState(GL_NORMAL_ARRAY);
354         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
355         glDisableClientState(GL_COLOR_ARRAY);
356 }
357
358 void gaw_begin(int prim)
359 {
360         glBegin(glprim[prim]);
361 }
362
363 void gaw_end(void)
364 {
365         glEnd();
366 }
367
368 void gaw_color3f(float r, float g, float b)
369 {
370         glColor3f(r, g, b);
371 }
372
373 void gaw_color4f(float r, float g, float b, float a)
374 {
375         glColor4f(r, g, b, a);
376 }
377
378 void gaw_color3ub(int r, int g, int b)
379 {
380         glColor3ub(r, g, b);
381 }
382
383 void gaw_normal(float x, float y, float z)
384 {
385         glNormal3f(x, y, z);
386 }
387
388 void gaw_texcoord1f(float u)
389 {
390         glTexCoord1f(u);
391 }
392
393 void gaw_texcoord2f(float u, float v)
394 {
395         glTexCoord2f(u, v);
396 }
397
398 void gaw_vertex2f(float x, float y)
399 {
400         glVertex2f(x, y);
401 }
402
403 void gaw_vertex3f(float x, float y, float z)
404 {
405         glVertex3f(x, y, z);
406 }
407
408 void gaw_vertex4f(float x, float y, float z, float w)
409 {
410         glVertex4f(x, y, z, w);
411 }
412
413 void gaw_rect(float x1, float y1, float x2, float y2)
414 {
415         glRectf(x1, y1, x2, y2);
416 }
417
418 void gaw_pointsize(float sz)
419 {
420         glPointSize(sz);
421 }
422
423 void gaw_linewidth(float w)
424 {
425         glLineWidth(w);
426 }
427
428 int gaw_compile_begin(void)
429 {
430         int dlist = glGenLists(1);
431         glNewList(dlist, GL_COMPILE);
432         return dlist;
433 }
434
435 void gaw_compile_end(void)
436 {
437         glEndList();
438 }
439
440 void gaw_draw_compiled(int id)
441 {
442         glCallList(id);
443 }
444
445 void gaw_free_compiled(int id)
446 {
447         glDeleteLists(id, 1);
448 }
449
450 void gaw_mtl_diffuse(float r, float g, float b, float a)
451 {
452         float v[4];
453         v[0] = r;
454         v[1] = g;
455         v[2] = b;
456         v[3] = a;
457         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, v);
458 }
459
460 void gaw_mtl_specular(float r, float g, float b, float shin)
461 {
462         float v[4];
463         v[0] = r;
464         v[1] = g;
465         v[2] = b;
466         v[3] = 1.0f;
467         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
468         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shin);
469 }
470
471 void gaw_mtl_emission(float r, float g, float b)
472 {
473         float v[4];
474         v[0] = r;
475         v[1] = g;
476         v[2] = b;
477         v[3] = 1.0f;
478         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, v);
479 }
480
481 void gaw_texenv_sphmap(int enable)
482 {
483         if(enable) {
484                 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
485                 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
486                 glEnable(GL_TEXTURE_GEN_S);
487                 glEnable(GL_TEXTURE_GEN_T);
488         } else {
489                 glDisable(GL_TEXTURE_GEN_S);
490                 glDisable(GL_TEXTURE_GEN_T);
491         }
492 }
493
494 unsigned int gaw_create_tex1d(int texfilter)
495 {
496         unsigned int tex;
497         glGenTextures(1, &tex);
498         glBindTexture(GL_TEXTURE_1D, tex);
499         gaw_texfilter1d(texfilter);
500         return tex;
501 }
502
503 unsigned int gaw_create_tex2d(int texfilter)
504 {
505         unsigned int tex;
506         glGenTextures(1, &tex);
507         glBindTexture(GL_TEXTURE_2D, tex);
508         gaw_texfilter2d(texfilter);
509         return tex;
510 }
511
512 void gaw_destroy_tex(unsigned int tex)
513 {
514         glDeleteTextures(1, &tex);
515 }
516
517 void gaw_bind_tex1d(int tex)
518 {
519         glBindTexture(GL_TEXTURE_1D, tex);
520 }
521
522 void gaw_bind_tex2d(int tex)
523 {
524         glBindTexture(GL_TEXTURE_2D, tex);
525 }
526
527 void gaw_texfilter1d(int texfilter)
528 {
529         switch(texfilter) {
530         case GAW_NEAREST:
531                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
532                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
533                 break;
534
535         case GAW_BILINEAR:
536                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
537                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
538                 break;
539
540         case GAW_TRILINEAR:
541                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
542                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
543                 break;
544
545         default:
546                 break;
547         }
548 }
549
550 void gaw_texfilter2d(int texfilter)
551 {
552         switch(texfilter) {
553         case GAW_NEAREST:
554                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
555                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
556                 break;
557
558         case GAW_BILINEAR:
559                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
560                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
561                 break;
562
563         case GAW_TRILINEAR:
564                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
565                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
566                 break;
567
568         default:
569                 break;
570         }
571 }
572
573 static int glwrap(int wrap)
574 {
575         if(have_edgeclamp == -1) {
576                 if(!glextstr) {
577                         glextstr = strdup_nf((char*)glGetString(GL_EXTENSIONS));
578                 }
579                 have_edgeclamp = strstr(glextstr, "SGIS_texture_edge_clamp") != 0;
580         }
581
582         switch(wrap) {
583         case GAW_CLAMP:
584                 if(have_edgeclamp) {
585                         return GL_CLAMP_TO_EDGE;
586                 } else {
587                         return GL_CLAMP;
588                 }
589                 break;
590
591         case GAW_REPEAT:
592         default:
593                 break;
594         }
595         return GL_REPEAT;
596 }
597
598 void gaw_texwrap1d(int wrap)
599 {
600         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, glwrap(wrap));
601 }
602
603 void gaw_texwrap2d(int uwrap, int vwrap)
604 {
605         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glwrap(uwrap));
606         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glwrap(vwrap));
607 }
608
609
610 static const int glfmt[] = {GL_LUMINANCE, GL_RGB, GL_RGBA};
611
612 void gaw_tex1d(int ifmt, int xsz, int fmt, void *pix)
613 {
614         gluBuild1DMipmaps(GL_TEXTURE_1D, glfmt[ifmt], xsz, glfmt[fmt], GL_UNSIGNED_BYTE, pix);
615 }
616
617 void gaw_tex2d(int ifmt, int xsz, int ysz, int fmt, void *pix)
618 {
619         gluBuild2DMipmaps(GL_TEXTURE_2D, glfmt[ifmt], xsz, ysz, glfmt[fmt], GL_UNSIGNED_BYTE, pix);
620 }
621
622 void gaw_subtex2d(int lvl, int x, int y, int xsz, int ysz, int fmt, void *pix)
623 {
624         glTexSubImage2D(GL_TEXTURE_2D, lvl, x, y, xsz, ysz, glfmt[fmt], GL_UNSIGNED_BYTE, pix);
625 }
626
627 void gaw_set_tex1d(unsigned int texid)
628 {
629         if(texid) {
630                 glEnable(GL_TEXTURE_1D);
631                 glBindTexture(GL_TEXTURE_1D, texid);
632         } else {
633                 glDisable(GL_TEXTURE_1D);
634         }
635 }
636
637 void gaw_set_tex2d(unsigned int texid)
638 {
639         if(texid) {
640                 glEnable(GL_TEXTURE_2D);
641                 glBindTexture(GL_TEXTURE_2D, texid);
642         } else {
643                 glDisable(GL_TEXTURE_2D);
644         }
645 }
646
647 void gaw_ambient(float r, float g, float b)
648 {
649         float amb[4];
650         amb[0] = r;
651         amb[1] = g;
652         amb[2] = b;
653         amb[3] = 1.0f;
654         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
655 }
656
657 void gaw_light_dir(int idx, float x, float y, float z)
658 {
659         float pos[4];
660         pos[0] = x;
661         pos[1] = y;
662         pos[2] = z;
663         pos[3] = 0;
664         glLightfv(GL_LIGHT0 + idx, GL_POSITION, pos);
665
666 }
667
668 void gaw_light_color(int idx, float r, float g, float b, float s)
669 {
670         float color[4];
671         color[0] = r * s;
672         color[1] = g * s;
673         color[2] = b * s;
674         color[3] = 1;
675         glLightfv(GL_LIGHT0 + idx, GL_DIFFUSE, color);
676         glLightfv(GL_LIGHT0 + idx, GL_SPECULAR, color);
677 }
678
679 void gaw_lighting_fast(void)
680 {
681         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0);
682         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
683 }
684
685
686 void gaw_fog_color(float r, float g, float b)
687 {
688         float col[4];
689         col[0] = r;
690         col[1] = g;
691         col[2] = b;
692         col[3] = 1.0f;
693         glFogfv(GL_FOG_COLOR, col);
694 }
695
696 void gaw_fog_linear(float z0, float z1)
697 {
698         glFogi(GL_FOG_MODE, GL_LINEAR);
699         glFogf(GL_FOG_START, z0);
700         glFogf(GL_FOG_END, z1);
701 }
702
703 void gaw_fog_fast(void)
704 {
705         glHint(GL_FOG_HINT, GL_FASTEST);
706 }
707
708 void gaw_poly_wire(void)
709 {
710         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
711 }
712
713 void gaw_poly_flat(void)
714 {
715         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
716         glShadeModel(GL_FLAT);
717 }
718
719 void gaw_poly_gouraud(void)
720 {
721         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
722         glShadeModel(GL_SMOOTH);
723 }