7a58c1db9d90b263fe17bb8f84412f45fc6b9dd9
[retroray] / src / gaw / gaw_gl.c
1 /*
2 Deep Runner - 6dof shooter game for the SGI O2.
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_rect(float x1, float y1, float x2, float y2)
393 {
394         glRectf(x1, y1, x2, y2);
395 }
396
397 void gaw_pointsize(float sz)
398 {
399         glPointSize(sz);
400 }
401
402 void gaw_linewidth(float w)
403 {
404         glLineWidth(w);
405 }
406
407 int gaw_compile_begin(void)
408 {
409         int dlist = glGenLists(1);
410         glNewList(dlist, GL_COMPILE);
411         return dlist;
412 }
413
414 void gaw_compile_end(void)
415 {
416         glEndList();
417 }
418
419 void gaw_draw_compiled(int id)
420 {
421         glCallList(id);
422 }
423
424 void gaw_free_compiled(int id)
425 {
426         glDeleteLists(id, 1);
427 }
428
429 void gaw_mtl_diffuse(float r, float g, float b, float a)
430 {
431         float v[4];
432         v[0] = r;
433         v[1] = g;
434         v[2] = b;
435         v[3] = a;
436         glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, v);
437 }
438
439 void gaw_mtl_specular(float r, float g, float b, float shin)
440 {
441         float v[4];
442         v[0] = r;
443         v[1] = g;
444         v[2] = b;
445         v[3] = 1.0f;
446         glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, v);
447         glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shin);
448 }
449
450 void gaw_mtl_emission(float r, float g, float b)
451 {
452         float v[4];
453         v[0] = r;
454         v[1] = g;
455         v[2] = b;
456         v[3] = 1.0f;
457         glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, v);
458 }
459
460 void gaw_texenv_sphmap(int enable)
461 {
462         if(enable) {
463                 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
464                 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
465                 glEnable(GL_TEXTURE_GEN_S);
466                 glEnable(GL_TEXTURE_GEN_T);
467         } else {
468                 glDisable(GL_TEXTURE_GEN_S);
469                 glDisable(GL_TEXTURE_GEN_T);
470         }
471 }
472
473 unsigned int gaw_create_tex1d(int texfilter)
474 {
475         unsigned int tex;
476         glGenTextures(1, &tex);
477         glBindTexture(GL_TEXTURE_1D, tex);
478         gaw_texfilter1d(texfilter);
479         return tex;
480 }
481
482 unsigned int gaw_create_tex2d(int texfilter)
483 {
484         unsigned int tex;
485         glGenTextures(1, &tex);
486         glBindTexture(GL_TEXTURE_2D, tex);
487         gaw_texfilter2d(texfilter);
488         return tex;
489 }
490
491 void gaw_destroy_tex(unsigned int tex)
492 {
493         glDeleteTextures(1, &tex);
494 }
495
496 void gaw_bind_tex1d(int tex)
497 {
498         glBindTexture(GL_TEXTURE_1D, tex);
499 }
500
501 void gaw_bind_tex2d(int tex)
502 {
503         glBindTexture(GL_TEXTURE_2D, tex);
504 }
505
506 void gaw_texfilter1d(int texfilter)
507 {
508         switch(texfilter) {
509         case GAW_NEAREST:
510                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
511                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
512                 break;
513
514         case GAW_BILINEAR:
515                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
516                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
517                 break;
518
519         case GAW_TRILINEAR:
520                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
521                 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
522                 break;
523
524         default:
525                 break;
526         }
527 }
528
529 void gaw_texfilter2d(int texfilter)
530 {
531         switch(texfilter) {
532         case GAW_NEAREST:
533                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
534                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
535                 break;
536
537         case GAW_BILINEAR:
538                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
539                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
540                 break;
541
542         case GAW_TRILINEAR:
543                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
544                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
545                 break;
546
547         default:
548                 break;
549         }
550 }
551
552 static int glwrap(int wrap)
553 {
554         if(have_edgeclamp == -1) {
555                 if(!glextstr) {
556                         glextstr = strdup_nf((char*)glGetString(GL_EXTENSIONS));
557                 }
558                 have_edgeclamp = strstr(glextstr, "SGIS_texture_edge_clamp") != 0;
559         }
560
561         switch(wrap) {
562         case GAW_CLAMP:
563                 if(have_edgeclamp) {
564                         return GL_CLAMP_TO_EDGE;
565                 } else {
566                         return GL_CLAMP;
567                 }
568                 break;
569
570         case GAW_REPEAT:
571         default:
572                 break;
573         }
574         return GL_REPEAT;
575 }
576
577 void gaw_texwrap1d(int wrap)
578 {
579         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, glwrap(wrap));
580 }
581
582 void gaw_texwrap2d(int uwrap, int vwrap)
583 {
584         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glwrap(uwrap));
585         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glwrap(vwrap));
586 }
587
588
589 static const int glfmt[] = {GL_LUMINANCE, GL_RGB, GL_RGBA};
590
591 void gaw_tex1d(int ifmt, int xsz, int fmt, void *pix)
592 {
593         gluBuild1DMipmaps(GL_TEXTURE_1D, glfmt[ifmt], xsz, glfmt[fmt], GL_UNSIGNED_BYTE, pix);
594 }
595
596 void gaw_tex2d(int ifmt, int xsz, int ysz, int fmt, void *pix)
597 {
598         gluBuild2DMipmaps(GL_TEXTURE_2D, glfmt[ifmt], xsz, ysz, glfmt[fmt], GL_UNSIGNED_BYTE, pix);
599 }
600
601 void gaw_subtex2d(int lvl, int x, int y, int xsz, int ysz, int fmt, void *pix)
602 {
603         glTexSubImage2D(GL_TEXTURE_2D, lvl, x, y, xsz, ysz, glfmt[fmt], GL_UNSIGNED_BYTE, pix);
604 }
605
606 void gaw_set_tex1d(unsigned int texid)
607 {
608         if(texid) {
609                 glEnable(GL_TEXTURE_1D);
610                 glBindTexture(GL_TEXTURE_1D, texid);
611         } else {
612                 glDisable(GL_TEXTURE_1D);
613         }
614 }
615
616 void gaw_set_tex2d(unsigned int texid)
617 {
618         if(texid) {
619                 glEnable(GL_TEXTURE_2D);
620                 glBindTexture(GL_TEXTURE_2D, texid);
621         } else {
622                 glDisable(GL_TEXTURE_2D);
623         }
624 }
625
626 void gaw_ambient(float r, float g, float b)
627 {
628         float amb[4];
629         amb[0] = r;
630         amb[1] = g;
631         amb[2] = b;
632         amb[3] = 1.0f;
633         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, amb);
634 }
635
636 void gaw_light_dir(int idx, float x, float y, float z)
637 {
638         float pos[4];
639         pos[0] = x;
640         pos[1] = y;
641         pos[2] = z;
642         pos[3] = 0;
643         glLightfv(GL_LIGHT0 + idx, GL_POSITION, pos);
644
645 }
646
647 void gaw_light_color(int idx, float r, float g, float b, float s)
648 {
649         float color[4];
650         color[0] = r * s;
651         color[1] = g * s;
652         color[2] = b * s;
653         color[3] = 1;
654         glLightfv(GL_LIGHT0 + idx, GL_DIFFUSE, color);
655         glLightfv(GL_LIGHT0 + idx, GL_SPECULAR, color);
656 }
657
658 void gaw_lighting_fast(void)
659 {
660         glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 0);
661         glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
662 }
663
664
665 void gaw_fog_color(float r, float g, float b)
666 {
667         float col[4];
668         col[0] = r;
669         col[1] = g;
670         col[2] = b;
671         col[3] = 1.0f;
672         glFogfv(GL_FOG_COLOR, col);
673 }
674
675 void gaw_fog_linear(float z0, float z1)
676 {
677         glFogi(GL_FOG_MODE, GL_LINEAR);
678         glFogf(GL_FOG_START, z0);
679         glFogf(GL_FOG_END, z1);
680 }
681
682 void gaw_fog_fast(void)
683 {
684         glHint(GL_FOG_HINT, GL_FASTEST);
685 }
686
687 void gaw_poly_wire(void)
688 {
689         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
690 }
691
692 void gaw_poly_flat(void)
693 {
694         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
695         glShadeModel(GL_FLAT);
696 }
697
698 void gaw_poly_gouraud(void)
699 {
700         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
701         glShadeModel(GL_SMOOTH);
702 }