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