moving along slowly
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 3 Jun 2023 17:06:37 +0000 (20:06 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 3 Jun 2023 17:06:37 +0000 (20:06 +0300)
.gitignore
GNUmakefile
src/app.c
src/gaw/gaw_gl.c
src/modern/main.c
src/options.c [new file with mode: 0644]
src/options.h [new file with mode: 0644]
src/scr_mod.c [new file with mode: 0644]
src/scr_rend.c [new file with mode: 0644]
src/util.c [new file with mode: 0644]
src/util.h [new file with mode: 0644]

index 4fcc586..c4b7b45 100644 (file)
@@ -3,4 +3,5 @@
 *.swp
 *.a
 *.lib
+retrorend
 *.exe
index f14e89a..9dbd84f 100644 (file)
@@ -12,7 +12,7 @@ gawsrc_sw = src/gaw/gaw_sw.c src/gaw/gawswtnl.c src/gaw/polyfill.c src/gaw/polyc
 src = $(wildcard src/*.c) $(wildcard src/modern/*.c) $(gawsrc_$(build_gfx))
 obj = $(src:.c=.o)
 dep = $(src:.c=.d)
-bin = game
+bin = retrorend
 
 warn = -pedantic -Wall
 dbg = -g
@@ -31,7 +31,7 @@ ifeq ($(sys), mingw)
        ldsys = -lopengl32 -lglu32 -lgdi32 -lwinmm
        ldsys_pre = -static-libgcc -lmingw32 -mconsole
 else
-       ldsys = -lGL -lGLU -lX11
+       ldsys = -lGL -lGLU -lX11 -lm
 endif
 
 $(bin): $(obj) libs
index 0a0af71..833ce5f 100644 (file)
--- a/src/app.c
+++ b/src/app.c
@@ -25,6 +25,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include "app.h"
 #include "options.h"
 #include "font.h"
+#include "util.h"
 
 static void txdraw(struct dtx_vertex *v, int vcount, struct dtx_pixmap *pixmap, void *cls);
 
@@ -38,7 +39,7 @@ long time_msec;
 
 struct app_screen *cur_scr;
 
-struct font *font;
+struct font *uifont;
 
 /* available screens */
 #define MAX_SCREENS    8
@@ -65,7 +66,7 @@ int app_init(void)
 
        dtx_target_user(txdraw, 0);
 
-       font = malloc_nf(sizeof *font);
+       uifont = malloc_nf(sizeof *uifont);
        if(load_font(uifont, "data/uifont.gmp") == -1) {
                free(uifont);
                return -1;
@@ -92,7 +93,7 @@ int app_init(void)
                }
        }
        if(!cur_scr) {
-               app_chscr(&scr_logo);
+               app_chscr(&scr_model);
        }
 
        return 0;
@@ -104,7 +105,7 @@ void app_shutdown(void)
 
        putchar('\n');
 
-       save_options(GAME_CFG_FILE);
+       save_options("retroray.cfg");
 
        for(i=0; i<num_screens; i++) {
                if(screens[i]->destroy) {
@@ -118,8 +119,6 @@ void app_shutdown(void)
 
 void app_display(void)
 {
-       static long nframes, interv, prev_msec;
-
        time_msec = app_getmsec();
 
        cur_scr->display();
@@ -151,8 +150,8 @@ void app_keyboard(int key, int press)
 
                case '\n':
                case '\r':
-                       if(modkeys & GKEY_MOD_ALT) {
-               case GKEY_F11:
+                       if(modkeys & KEY_MOD_ALT) {
+               case KEY_F11:
                                app_fullscreen(-1);
                                return;
                        }
@@ -229,6 +228,7 @@ void app_chscr(struct app_screen *scr)
 
 static void txdraw(struct dtx_vertex *v, int vcount, struct dtx_pixmap *pixmap, void *cls)
 {
+       /*
        int i, aref, npix;
        unsigned char *src, *dest;
        struct texture *tex = pixmap->udata;
@@ -278,4 +278,5 @@ static void txdraw(struct dtx_vertex *v, int vcount, struct dtx_pixmap *pixmap,
 
        gaw_restore();
        gaw_set_tex2d(0);
+       */
 }
index fbec9a8..7a58c1d 100644 (file)
@@ -18,7 +18,17 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include <string.h>
 #include "util.h"
 #include "gaw.h"
-#include "opengl.h"
+
+#if defined(WIN32) || defined(__WIN32)
+#include <windows.h>
+#endif
+#ifdef __APPLE__
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif
 
 
 static const float *vertex_ptr, *normal_ptr, *texcoord_ptr, *color_ptr;
index 3c3b146..d6682cc 100644 (file)
@@ -1,4 +1,232 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
 #include <stdio.h>
 #include <stdlib.h>
+#include <assert.h>
 #include "miniglut.h"
 #include "app.h"
+
+static void reshape(int x, int y);
+static void keydown(unsigned char key, int x, int y);
+static void keyup(unsigned char key, int x, int y);
+static void skeydown(int key, int x, int y);
+static void skeyup(int key, int x, int y);
+static void mouse(int bn, int st, int x, int y);
+static void motion(int x, int y);
+static int translate_skey(int key);
+
+#if defined(__unix__) || defined(unix)
+#include <GL/glx.h>
+static Display *xdpy;
+static Window xwin;
+
+static void (*glx_swap_interval_ext)();
+static void (*glx_swap_interval_sgi)();
+#endif
+#ifdef _WIN32
+#include <windows.h>
+static PROC wgl_swap_interval_ext;
+#endif
+
+
+
+int main(int argc, char **argv)
+{
+       glutInit(&argc, argv);
+       glutInitWindowSize(1024, 768);
+       glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+       glutCreateWindow("RetroRay");
+
+       glutDisplayFunc(app_display);
+       glutReshapeFunc(reshape);
+       glutKeyboardFunc(keydown);
+       glutKeyboardUpFunc(keyup);
+       glutSpecialFunc(skeydown);
+       glutSpecialUpFunc(skeyup);
+       glutMouseFunc(mouse);
+       glutMotionFunc(motion);
+       glutPassiveMotionFunc(motion);
+       glutSpaceballMotionFunc(app_sball_motion);
+       glutSpaceballRotateFunc(app_sball_rotate);
+       glutSpaceballButtonFunc(app_sball_button);
+
+#if defined(__unix__) || defined(unix)
+       xdpy = glXGetCurrentDisplay();
+       xwin = glXGetCurrentDrawable();
+
+       if(!(glx_swap_interval_ext = glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"))) {
+               glx_swap_interval_sgi = glXGetProcAddress((unsigned char*)"glXSwapIntervalSGI");
+       }
+#endif
+#ifdef _WIN32
+       wgl_swap_interval_ext = wglGetProcAddress("wglSwapIntervalEXT");
+#endif
+
+       app_reshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT));
+
+       if(app_init() == -1) {
+               return 1;
+       }
+       atexit(app_shutdown);
+       glutMainLoop();
+       return 0;
+}
+
+long app_getmsec(void)
+{
+       return glutGet(GLUT_ELAPSED_TIME);
+}
+
+void app_redisplay(void)
+{
+       glutPostRedisplay();
+}
+
+void app_swap_buffers(void)
+{
+       glutSwapBuffers();
+       assert(glGetError() == GL_NO_ERROR);
+}
+
+void app_quit(void)
+{
+       exit(0);
+}
+
+void app_resize(int x, int y)
+{
+       if(x == win_width && y == win_height) return;
+
+       glutReshapeWindow(x, y);
+}
+
+void app_fullscreen(int fs)
+{
+       static int prev_w, prev_h;
+
+       if(fs == -1) {
+               fs = !fullscr;
+       }
+
+       if(fs == fullscr) return;
+
+       if(fs) {
+               prev_w = glutGet(GLUT_WINDOW_WIDTH);
+               prev_h = glutGet(GLUT_WINDOW_HEIGHT);
+               glutFullScreen();
+       } else {
+               glutReshapeWindow(prev_w, prev_h);
+       }
+       fullscr = fs;
+}
+
+#if defined(__unix__) || defined(unix)
+void app_vsync(int vsync)
+{
+       vsync = vsync ? 1 : 0;
+       if(glx_swap_interval_ext) {
+               glx_swap_interval_ext(xdpy, xwin, vsync);
+       } else if(glx_swap_interval_sgi) {
+               glx_swap_interval_sgi(vsync);
+       }
+}
+#endif
+#ifdef WIN32
+void app_vsync(int vsync)
+{
+       if(wgl_swap_interval_ext) {
+               wgl_swap_interval_ext(vsync ? 1 : 0);
+       }
+}
+#endif
+
+
+
+static void reshape(int x, int y)
+{
+       app_reshape(x, y);
+}
+
+static void keydown(unsigned char key, int x, int y)
+{
+       modkeys = glutGetModifiers();
+       app_keyboard(key, 1);
+}
+
+static void keyup(unsigned char key, int x, int y)
+{
+       app_keyboard(key, 0);
+}
+
+static void skeydown(int key, int x, int y)
+{
+       int k;
+       modkeys = glutGetModifiers();
+       if((k = translate_skey(key)) >= 0) {
+               app_keyboard(k, 1);
+       }
+}
+
+static void skeyup(int key, int x, int y)
+{
+       int k = translate_skey(key);
+       if(k >= 0) {
+               app_keyboard(k, 0);
+       }
+}
+
+static void mouse(int bn, int st, int x, int y)
+{
+       modkeys = glutGetModifiers();
+       app_mouse(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y);
+}
+
+static void motion(int x, int y)
+{
+       app_motion(x, y);
+}
+
+static int translate_skey(int key)
+{
+       switch(key) {
+       case GLUT_KEY_LEFT:
+               return KEY_LEFT;
+       case GLUT_KEY_UP:
+               return KEY_UP;
+       case GLUT_KEY_RIGHT:
+               return KEY_RIGHT;
+       case GLUT_KEY_DOWN:
+               return KEY_DOWN;
+       case GLUT_KEY_PAGE_UP:
+               return KEY_PGUP;
+       case GLUT_KEY_PAGE_DOWN:
+               return KEY_PGDOWN;
+       case GLUT_KEY_HOME:
+               return KEY_HOME;
+       case GLUT_KEY_END:
+               return KEY_END;
+       case GLUT_KEY_INSERT:
+               return KEY_INS;
+       default:
+               if(key >= GLUT_KEY_F1 && key <= GLUT_KEY_F12) {
+                       return key - GLUT_KEY_F1 + KEY_F1;
+               }
+       }
+
+       return -1;
+}
diff --git a/src/options.c b/src/options.c
new file mode 100644 (file)
index 0000000..c61848b
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "options.h"
+#include "treestor.h"
+
+#define DEF_XRES               640
+#define DEF_YRES               480
+#define DEF_VSYNC              1
+#define DEF_FULLSCR            1
+#define DEF_MOUSE_SPEED        50
+#define DEF_SBALL_SPEED        50
+
+
+struct options opt = {
+       DEF_XRES, DEF_YRES,
+       DEF_VSYNC,
+       DEF_FULLSCR,
+       DEF_MOUSE_SPEED, DEF_SBALL_SPEED,
+};
+
+int load_options(const char *fname)
+{
+       struct ts_node *cfg;
+
+       if(!(cfg = ts_load(fname))) {
+               return -1;
+       }
+       printf("loaded config: %s\n", fname);
+
+       opt.xres = ts_lookup_int(cfg, "options.video.xres", DEF_XRES);
+       opt.yres = ts_lookup_int(cfg, "options.video.yres", DEF_YRES);
+       opt.vsync = ts_lookup_int(cfg, "options.video.vsync", DEF_VSYNC);
+       opt.fullscreen = ts_lookup_int(cfg, "options.video.fullscreen", DEF_FULLSCR);
+
+       opt.mouse_speed = ts_lookup_int(cfg, "options.input.mousespeed", DEF_MOUSE_SPEED);
+       opt.sball_speed = ts_lookup_int(cfg, "options.input.sballspeed", DEF_SBALL_SPEED);
+
+       ts_free_tree(cfg);
+       return 0;
+}
+
+#define WROPT(lvl, fmt, val, defval) \
+       do { \
+               int i; \
+               for(i=0; i<lvl; i++) fputc('\t', fp); \
+               if((val) == (defval)) fputc('#', fp); \
+               fprintf(fp, fmt "\n", val); \
+       } while(0)
+
+int save_options(const char *fname)
+{
+       FILE *fp;
+
+       printf("writing config: %s\n", fname);
+
+       if(!(fp = fopen(fname, "wb"))) {
+               fprintf(stderr, "failed to save options (%s): %s\n", fname, strerror(errno));
+       }
+       fprintf(fp, "options {\n");
+       fprintf(fp, "\tvideo {\n");
+       WROPT(2, "xres = %d", opt.xres, DEF_XRES);
+       WROPT(2, "yres = %d", opt.yres, DEF_YRES);
+       WROPT(2, "vsync = %d", opt.vsync, DEF_VSYNC);
+       WROPT(2, "fullscreen = %d", opt.fullscreen, DEF_FULLSCR);
+       fprintf(fp, "\t}\n");
+
+       fprintf(fp, "\tinput {\n");
+       WROPT(2, "mousespeed = %d", opt.mouse_speed, DEF_MOUSE_SPEED);
+       WROPT(2, "sballspeed = %d", opt.sball_speed, DEF_SBALL_SPEED);
+       fprintf(fp, "\t}\n");
+
+       fprintf(fp, "}\n");
+       fprintf(fp, "# v" "i:ts=4 sts=4 sw=4 noexpandtab:\n");
+
+       fclose(fp);
+       return 0;
+}
diff --git a/src/options.h b/src/options.h
new file mode 100644 (file)
index 0000000..0a97cc1
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef OPTIONS_H_
+#define OPTIONS_H_
+
+struct options {
+       int xres, yres;
+       int vsync;
+       int fullscreen;
+
+       int mouse_speed, sball_speed;
+};
+
+extern struct options opt;
+
+int load_options(const char *fname);
+int save_options(const char *fname);
+
+#endif /* OPTIONS_H_ */
diff --git a/src/scr_mod.c b/src/scr_mod.c
new file mode 100644 (file)
index 0000000..189e271
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#include "gaw/gaw.h"
+#include "app.h"
+
+static int mdl_init(void);
+static void mdl_destroy(void);
+static int mdl_start(void);
+static void mdl_stop(void);
+static void mdl_display(void);
+static void mdl_reshape(int x, int y);
+static void mdl_keyb(int key, int press);
+static void mdl_mouse(int bn, int press, int x, int y);
+static void mdl_motion(int x, int y);
+
+
+struct app_screen scr_model = {
+       "modeller",
+       mdl_init, mdl_destroy,
+       mdl_start, mdl_stop,
+       mdl_display, mdl_reshape,
+       mdl_keyb, mdl_mouse, mdl_motion
+};
+
+
+static int mdl_init(void)
+{
+       return 0;
+}
+
+static void mdl_destroy(void)
+{
+}
+
+static int mdl_start(void)
+{
+       return 0;
+}
+
+static void mdl_stop(void)
+{
+}
+
+static void mdl_display(void)
+{
+}
+
+static void mdl_reshape(int x, int y)
+{
+       gaw_matrix_mode(GAW_PROJECTION);
+       gaw_load_identity();
+       gaw_perspective(50, win_aspect, 0.5, 100.0);
+}
+
+static void mdl_keyb(int key, int press)
+{
+}
+
+static void mdl_mouse(int bn, int press, int x, int y)
+{
+}
+
+static void mdl_motion(int x, int y)
+{
+}
diff --git a/src/scr_rend.c b/src/scr_rend.c
new file mode 100644 (file)
index 0000000..40c83d9
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#include "gaw/gaw.h"
+#include "app.h"
+
+static int rend_init(void);
+static void rend_destroy(void);
+static int rend_start(void);
+static void rend_stop(void);
+static void rend_display(void);
+static void rend_reshape(int x, int y);
+static void rend_keyb(int key, int press);
+static void rend_mouse(int bn, int press, int x, int y);
+static void rend_motion(int x, int y);
+
+
+struct app_screen scr_rend = {
+       "renderer",
+       rend_init, rend_destroy,
+       rend_start, rend_stop,
+       rend_display, rend_reshape,
+       rend_keyb, rend_mouse, rend_motion
+};
+
+
+static int rend_init(void)
+{
+       return 0;
+}
+
+static void rend_destroy(void)
+{
+}
+
+static int rend_start(void)
+{
+       return 0;
+}
+
+static void rend_stop(void)
+{
+}
+
+static void rend_display(void)
+{
+}
+
+static void rend_reshape(int x, int y)
+{
+       gaw_matrix_mode(GAW_PROJECTION);
+       gaw_load_identity();
+       gaw_perspective(50, win_aspect, 0.5, 100.0);
+}
+
+static void rend_keyb(int key, int press)
+{
+}
+
+static void rend_mouse(int bn, int press, int x, int y)
+{
+}
+
+static void rend_motion(int x, int y)
+{
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644 (file)
index 0000000..d848bdc
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "util.h"
+
+void *malloc_nf_impl(size_t sz, const char *file, int line)
+{
+       void *p;
+       if(!(p = malloc(sz))) {
+               fprintf(stderr, "%s:%d failed to allocate %lu bytes\n", file, line, (unsigned long)sz);
+               abort();
+       }
+       return p;
+}
+
+void *calloc_nf_impl(size_t num, size_t sz, const char *file, int line)
+{
+       void *p;
+       if(!(p = calloc(num, sz))) {
+               fprintf(stderr, "%s:%d failed to allocate %lu bytes\n", file, line, (unsigned long)(num * sz));
+               abort();
+       }
+       return p;
+}
+
+void *realloc_nf_impl(void *p, size_t sz, const char *file, int line)
+{
+       if(!(p = realloc(p, sz))) {
+               fprintf(stderr, "%s:%d failed to realloc %lu bytes\n", file, line, (unsigned long)sz);
+               abort();
+       }
+       return p;
+}
+
+char *strdup_nf_impl(const char *s, const char *file, int line)
+{
+       int len;
+       char *res;
+
+       len = strlen(s);
+       if(!(res = malloc(len + 1))) {
+               fprintf(stderr, "%s:%d failed to duplicate string\n", file, line);
+               abort();
+       }
+       memcpy(res, s, len + 1);
+       return res;
+}
+
+
+int match_prefix(const char *str, const char *prefix)
+{
+       while(*str && *prefix) {
+               if(*str++ != *prefix++) {
+                       return 0;
+               }
+       }
+       return *prefix ? 0 : 1;
+}
+
+#if defined(__APPLE__) && !defined(TARGET_IPHONE)
+#include <xmmintrin.h>
+
+void enable_fpexcept(void)
+{
+       unsigned int bits;
+       bits = _MM_MASK_INVALID | _MM_MASK_DIV_ZERO | _MM_MASK_OVERFLOW | _MM_MASK_UNDERFLOW;
+       _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() & ~bits);
+}
+
+void disable_fpexcept(void)
+{
+       unsigned int bits;
+       bits = _MM_MASK_INVALID | _MM_MASK_DIV_ZERO | _MM_MASK_OVERFLOW | _MM_MASK_UNDERFLOW;
+       _MM_SET_EXCEPTION_MASK(_MM_GET_EXCEPTION_MASK() | bits);
+}
+
+#elif defined(__GLIBC__) && !defined(__MINGW32__)
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+#include <fenv.h>
+
+void enable_fpexcept(void)
+{
+       feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
+}
+
+void disable_fpexcept(void)
+{
+       fedisableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW);
+}
+
+#elif defined(_MSC_VER) || defined(__MINGW32__) || defined(__WATCOMC__)
+#include <float.h>
+
+#if defined(__MINGW32__) && !defined(_EM_OVERFLOW)
+/* if gcc's float.h gets precedence, the mingw MSVC includes won't be declared */
+#define _MCW_EM                        0x8001f
+#define _EM_INVALID            0x10
+#define _EM_ZERODIVIDE 0x08
+#define _EM_OVERFLOW   0x04
+unsigned int __cdecl _clearfp(void);
+unsigned int __cdecl _controlfp(unsigned int, unsigned int);
+#elif defined(__WATCOMC__)
+#define _clearfp       _clear87
+#define _controlfp     _control87
+#endif
+
+void enable_fpexcept(void)
+{
+       _clearfp();
+       _controlfp(_controlfp(0, 0) & ~(_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW), _MCW_EM);
+}
+
+void disable_fpexcept(void)
+{
+       _clearfp();
+       _controlfp(_controlfp(0, 0) | (_EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW), _MCW_EM);
+}
+#else
+void enable_fpexcept(void) {}
+void disable_fpexcept(void) {}
+#endif
diff --git a/src/util.h b/src/util.h
new file mode 100644 (file)
index 0000000..8eebd33
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+RetroRay - integrated standalone vintage modeller/renderer
+Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <https://www.gnu.org/licenses/>.
+*/
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <stdlib.h>
+#include "byteord.h"   /* from imago, to sort out the sized int types mess */
+
+#if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+
+/* Non-failing versions of malloc/calloc/realloc. They never return 0, they call
+ * demo_abort on failure. Use the macros, don't call the *_impl functions.
+ */
+#define malloc_nf(sz)  malloc_nf_impl(sz, __FILE__, __LINE__)
+void *malloc_nf_impl(size_t sz, const char *file, int line);
+#define calloc_nf(n, sz)       calloc_nf_impl(n, sz, __FILE__, __LINE__)
+void *calloc_nf_impl(size_t num, size_t sz, const char *file, int line);
+#define realloc_nf(p, sz)      realloc_nf_impl(p, sz, __FILE__, __LINE__)
+void *realloc_nf_impl(void *p, size_t sz, const char *file, int line);
+#define strdup_nf(s)   strdup_nf_impl(s, __FILE__, __LINE__)
+char *strdup_nf_impl(const char *s, const char *file, int line);
+
+int match_prefix(const char *str, const char *prefix);
+
+void enable_fpexcept(void);
+void disable_fpexcept(void);
+
+#endif /* UTIL_H_ */