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