integrating software renderer
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 7 Jun 2023 19:46:35 +0000 (22:46 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 7 Jun 2023 19:46:35 +0000 (22:46 +0300)
22 files changed:
GNUmakefile
src/app.c
src/app.h
src/gaw/gaw.h
src/gaw/gaw_gl.c
src/gaw/gaw_glide.c
src/gaw/gaw_glide.h
src/gaw/gaw_sw.c
src/gaw/gawswtnl.c
src/gaw/gawswtnl.h
src/gaw/polyclip.c
src/gaw/polyclip.h
src/gaw/polyfill.c
src/gaw/polyfill.h
src/gaw/polytmpl.h
src/logger.c [new file with mode: 0644]
src/logger.h [new file with mode: 0644]
src/modern/main.c
src/rtk.c
src/rtk.h
src/rtk_impl.h
src/scr_mod.c

index fb746ac..d897cc1 100644 (file)
@@ -9,6 +9,9 @@ build_dbg ?= true
 gawsrc_gl = src/gaw/gaw_gl.c
 gawsrc_sw = src/gaw/gaw_sw.c src/gaw/gawswtnl.c src/gaw/polyfill.c src/gaw/polyclip.c
 
+gawdef_gl = -DGFX_GL
+gawdef_sw = -DGFX_SW
+
 src = $(wildcard src/*.c) $(wildcard src/modern/*.c) $(gawsrc_$(build_gfx))
 obj = $(src:.c=.o)
 dep = $(src:.c=.d)
@@ -17,7 +20,7 @@ bin = retroray
 warn = -pedantic -Wall
 dbg = -g
 #opt = -O3
-def = -DMINIGLUT_USE_LIBC
+def = -DMINIGLUT_USE_LIBC $(gawdef_$(build_gfx))
 inc = -Isrc -Isrc/modern -Ilibs -Ilibs/imago/src -Ilibs/treestor/include -Ilibs/drawtext
 libs = libs/unix/imago.a libs/unix/treestor.a libs/unix/drawtext.a
 
index e3af5ab..fdcbe11 100644 (file)
--- a/src/app.c
+++ b/src/app.c
@@ -26,7 +26,16 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #include "options.h"
 #include "font.h"
 #include "util.h"
+#include "rtk.h"
 
+#ifdef GFX_SW
+#include "gaw/gaw_sw.h"
+#endif
+
+static void gui_fill(rtk_rect *rect, uint32_t color);
+static void gui_blit(int x, int y, rtk_icon *icon);
+static void gui_drawtext(int x, int y, const char *str);
+static void gui_textrect(const char *str, rtk_rect *rect);
 static void txdraw(struct dtx_vertex *v, int vcount, struct dtx_pixmap *pixmap, void *cls);
 
 int mouse_x, mouse_y, mouse_state[3];
@@ -41,6 +50,9 @@ struct app_screen *cur_scr;
 
 struct font *uifont;
 
+uint32_t *framebuf;
+
+
 /* available screens */
 #define MAX_SCREENS    8
 static struct app_screen *screens[MAX_SCREENS];
@@ -51,6 +63,9 @@ int app_init(void)
 {
        int i;
        char *start_scr_name;
+       static rtk_draw_ops guigfx = {gui_fill, gui_blit, gui_drawtext, gui_textrect};
+
+       init_logger();
 
 #if !defined(NDEBUG) && defined(DBG_FPEXCEPT)
        printf("floating point exceptions enabled\n");
@@ -72,6 +87,8 @@ int app_init(void)
                return -1;
        }
 
+       rtk_setup(&guigfx);
+
        /* initialize screens */
        screens[num_screens++] = &scr_model;
        screens[num_screens++] = &scr_rend;
@@ -115,6 +132,8 @@ void app_shutdown(void)
 
        destroy_font(uifont);
        free(uifont);
+
+       cleanup_logger();
 }
 
 void app_display(void)
@@ -128,6 +147,21 @@ void app_display(void)
 
 void app_reshape(int x, int y)
 {
+       int numpix = x * y;
+       int prev_numpix = win_width * win_height;
+
+       if(numpix > prev_numpix) {
+               void *tmp;
+               if(!(tmp = realloc(framebuf, numpix * sizeof *framebuf))) {
+                       errormsg("failed to resize framebuffer to %dx%d\n", x, y);
+                       return;
+               }
+               framebuf = tmp;
+       }
+#ifdef GFX_SW
+       gaw_sw_framebuffer(x, y, framebuf);
+#endif
+
        win_width = x;
        win_height = y;
        win_aspect = (float)x / (float)y;
@@ -226,57 +260,50 @@ void app_chscr(struct app_screen *scr)
        cur_scr = scr;
 }
 
-static void txdraw(struct dtx_vertex *v, int vcount, struct dtx_pixmap *pixmap, void *cls)
+static void gui_fill(rtk_rect *rect, uint32_t color)
 {
-       /*
-       int i, aref, npix;
-       unsigned char *src, *dest;
-       struct texture *tex = pixmap->udata;
-
-       if(!tex) {
-               struct img_pixmap *img = img_create();
-               img_set_pixels(img, pixmap->width, pixmap->height, IMG_FMT_RGBA32, 0);
-
-               npix = pixmap->width * pixmap->height;
-               src = pixmap->pixels;
-               dest = img->pixels;
-               for(i=0; i<npix; i++) {
-                       dest[0] = dest[1] = dest[2] = 0xff;
-                       dest[3] = *src++;
-                       dest += 4;
-               }
+       int i, j;
+       uint32_t *fb = framebuf + rect->y * win_width + rect->x;
 
-               if(!(tex = tex_image(img))) {
-                       return;
+       for(i=0; i<rect->height; i++) {
+               for(j=0; j<rect->width; j++) {
+                       fb[j] = color;
                }
-               pixmap->udata = tex;
+               fb += win_width;
        }
+}
 
-       gaw_save();
-       if(dtx_get(DTX_GL_BLEND)) {
-               gaw_enable(GAW_BLEND);
-               gaw_blend_func(GAW_SRC_ALPHA, GAW_ONE_MINUS_SRC_ALPHA);
-       } else {
-               gaw_disable(GAW_BLEND);
-       }
-       if((aref = dtx_get(DTX_GL_ALPHATEST))) {
-               gaw_enable(GAW_ALPHA_TEST);
-               gaw_alpha_func(GAW_GREATER, aref);
-       } else {
-               gaw_disable(GAW_ALPHA_TEST);
+static void gui_blit(int x, int y, rtk_icon *icon)
+{
+       int i, j;
+       uint32_t *dest, *src;
+
+       dest = framebuf + y * win_width + x;
+       src = icon->pixels;
+
+       for(i=0; i<icon->height; i++) {
+               for(j=0; j<icon->width; j++) {
+                       int r = src[j] & 0xff;
+                       int g = (src[j] >> 8) & 0xff;
+                       int b = (src[j] >> 16) & 0xff;
+                       dest[j] = 0xff000000 | (r << 16) | (g << 8) | b;
+               }
+               dest += win_width;
+               src += icon->scanlen;
        }
+}
 
-       gaw_set_tex2d(tex->texid);
+static void gui_drawtext(int x, int y, const char *str)
+{
+}
 
-       gaw_begin(GAW_TRIANGLES);
-       for(i=0; i<vcount; i++) {
-               gaw_texcoord2f(v->s, v->t);
-               gaw_vertex2f(v->x, v->y);
-               v++;
-       }
-       gaw_end();
+static void gui_textrect(const char *str, rtk_rect *rect)
+{
+       rect->x = rect->y = 0;
+       rect->width = 20;
+       rect->height = 10;/* TODO */
+}
 
-       gaw_restore();
-       gaw_set_tex2d(0);
-       */
+static void txdraw(struct dtx_vertex *v, int vcount, struct dtx_pixmap *pixmap, void *cls)
+{
 }
index c74bd02..96e6659 100644 (file)
--- a/src/app.h
+++ b/src/app.h
@@ -18,6 +18,9 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #ifndef APP_H_
 #define APP_H_
 
+#include "sizeint.h"
+#include "logger.h"
+
 enum {
        KEY_ESC = 27,
        KEY_DEL = 127,
@@ -67,6 +70,9 @@ extern struct app_screen scr_model, scr_rend;
 struct font;
 extern struct font *uifont;
 
+extern uint32_t *framebuf;
+
+
 int app_init(void);
 void app_shutdown(void);
 
index 37d5ca0..c43b648 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Deep Runner - 6dof shooter game for the SGI O2.
+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
@@ -144,6 +144,7 @@ void gaw_texcoord1f(float u);
 void gaw_texcoord2f(float u, float v);
 void gaw_vertex2f(float x, float y);
 void gaw_vertex3f(float x, float y, float z);
+void gaw_vertex4f(float x, float y, float z, float w);
 
 void gaw_rect(float x1, float y1, float x2, float y2);
 
index 7a58c1d..40f870c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Deep Runner - 6dof shooter game for the SGI O2.
+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
@@ -389,6 +389,11 @@ void gaw_vertex3f(float x, float y, float z)
        glVertex3f(x, y, z);
 }
 
+void gaw_vertex4f(float x, float y, float z, float w)
+{
+       glVertex4f(x, y, z, w);
+}
+
 void gaw_rect(float x1, float y1, float x2, float y2)
 {
        glRectf(x1, y1, x2, y2);
index 516570c..6fe8ccc 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Deep Runner - 6dof shooter game for the SGI O2.
+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
index 0bb3d1f..66b1a62 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Deep Runner - 6dof shooter game for the SGI O2.
+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
index de96cab..3df97f3 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Deep Runner - 6dof shooter game for the SGI O2.
+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
index 2df3ed3..5278754 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Deep Runner - 6dof shooter game for the SGI O2.
+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
@@ -617,18 +617,22 @@ void gaw_texcoord2f(float u, float v)
 
 void gaw_vertex2f(float x, float y)
 {
-       gaw_vertex3f(x, y, 0);
+       gaw_vertex4f(x, y, 0, 1);
 }
 
 void gaw_vertex3f(float x, float y, float z)
 {
+       gaw_vertex4f(x, y, z, 1);
+
+void gaw_vertex4f(float x, float y, float z, float w)
+{
        float *cptr = st.imm_cbuf + st.imm_numv * 4;
        struct vertex *vptr = st.imm_vbuf + st.imm_numv++;
        *vptr = st.imm_curv;
        vptr->x = x;
        vptr->y = y;
        vptr->z = z;
-       vptr->w = 1.0f;
+       vptr->w = w;
 
        cptr[0] = st.imm_curcol[0];
        cptr[1] = st.imm_curcol[1];
index 952f92c..7510f16 100644 (file)
@@ -1,5 +1,5 @@
 /*
-Deep Runner - 6dof shooter game for the SGI O2.
+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
index 4a203a8..e21051c 100644 (file)
@@ -1,3 +1,20 @@
+/*
+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 <math.h>
 #include <assert.h>
index e6c38fa..29e5ba2 100644 (file)
@@ -1,3 +1,20 @@
+/*
+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 POLYCLIP_H_
 #define POLYCLIP_H_
 
index 250c152..efdee71 100644 (file)
@@ -1,3 +1,20 @@
+/*
+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>
index ad2d5b3..b9173bc 100644 (file)
@@ -1,3 +1,20 @@
+/*
+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 POLYFILL_H_
 #define POLYFILL_H_
 
index 88be705..14e9b0f 100644 (file)
@@ -1,3 +1,20 @@
+/*
+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/>.
+*/
 #ifdef _MSC_VER
 #pragma warning (disable: 4101)
 #endif
diff --git a/src/logger.c b/src/logger.c
new file mode 100644 (file)
index 0000000..00d88b4
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+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 <stdarg.h>
+#include "logger.h"
+
+#if defined(__MSDOS__) || defined(MSDOS)
+static int setup_serial(int sdev);
+#else
+#define USE_STD
+#endif
+
+enum { LOG_FILE, LOG_STREAM, LOG_CON, LOG_CB };
+enum { LOG_DBG, LOG_INFO, LOG_WARN, LOG_ERR };
+
+struct log_callback {
+       void (*func)(const char*, void*);
+       void *cls;
+};
+
+struct log_output {
+       int type, level;
+       union {
+               FILE *fp;
+               int con;
+               struct log_callback cb;
+       } out;
+};
+
+#define MAX_OUTPUTS    8
+static struct log_output outputs[MAX_OUTPUTS];
+static int num_outputs;
+
+void init_logger(void)
+{
+       num_outputs = 0;
+}
+
+void cleanup_logger(void)
+{
+       int i;
+
+       for(i=0; i<num_outputs; i++) {
+               if(outputs[i].type == LOG_FILE) {
+                       fclose(outputs[i].out.fp);
+               }
+       }
+       num_outputs = 0;
+}
+
+int add_log_file(const char *fname)
+{
+       FILE *fp;
+       int idx;
+
+       if(num_outputs >= MAX_OUTPUTS) {
+               return -1;
+       }
+       if(!(fp = fopen(fname, "w"))) {
+               return -1;
+       }
+       idx = num_outputs++;
+
+       outputs[idx].type = LOG_FILE;
+       outputs[idx].out.fp = fp;
+       return 0;
+}
+
+int add_log_stream(FILE *fp)
+{
+       int idx;
+
+       if(num_outputs >= MAX_OUTPUTS) {
+               return -1;
+       }
+       idx = num_outputs++;
+
+       outputs[idx].type = LOG_STREAM;
+       outputs[idx].out.fp = fp;
+       return 0;
+}
+
+int add_log_console(const char *devname)
+{
+#if defined(MSDOS) || defined(__MSDOS__)
+       int i, comport;
+       if(sscanf(devname, "COM%d", &comport) != 1 || comport < 1 || comport > 2) {
+               return -1;
+       }
+       comport--;
+
+       if(num_outputs >= MAX_OUTPUTS) {
+               return -1;
+       }
+       for(i=0; i<num_outputs; i++) {
+               if(outputs[i].type == LOG_CON && outputs[i].out.con == comport) {
+                       return -1;
+               }
+       }
+       if(setup_serial(comport) == -1) {
+               return -1;
+       }
+
+       i = num_outputs++;
+       outputs[i].type = LOG_CON;
+       outputs[i].out.con = comport;
+       return 0;
+
+#elif defined(unix) || defined(__unix__)
+       /* TODO? */
+       return -1;
+#endif
+}
+
+int add_log_callback(void (*cbfunc)(const char*, void*), void *cls)
+{
+       int idx;
+
+       if(num_outputs >= MAX_OUTPUTS) {
+               return -1;
+       }
+       idx = num_outputs++;
+
+       outputs[idx].type = LOG_CB;
+       outputs[idx].out.cb.func = cbfunc;
+       outputs[idx].out.cb.cls = cls;
+       return 0;
+}
+
+#if defined(__WATCOMC__)
+#ifndef vsnprintf
+#define vsnprintf _vsnprintf
+#endif
+#endif
+
+static void logmsg(int type, const char *fmt, va_list ap)
+{
+       static char *buf;
+       static int bufsz;
+       int i, ret, newsz;
+       char *tmp;
+
+       while((ret = vsnprintf(buf, bufsz, fmt, ap)) > bufsz || ret < 0) {
+               if(ret > bufsz) {
+                       newsz = ret + 1;
+               } else {
+                       newsz = bufsz ? bufsz * 2 : 256;
+               }
+               if(!(tmp = realloc(buf, newsz))) {
+                       if(buf) {
+                               buf[bufsz - 1] = 0;
+                       }
+                       break;
+               }
+               buf = tmp;
+               bufsz = newsz;
+       }
+
+       if(!buf) return;
+
+       for(i=0; i<num_outputs; i++) {
+               switch(outputs[i].type) {
+               case LOG_FILE:
+               case LOG_STREAM:
+                       fputs(buf, outputs[i].out.fp);
+                       break;
+
+#if defined(MSDOS) || defined(__MSDOS__)
+               case LOG_CON:
+                       ser_puts(buf);
+                       break;
+#endif
+               case LOG_CB:
+                       outputs[i].out.cb.func(buf, outputs[i].out.cb.cls);
+                       break;
+
+               default:
+                       break;
+               }
+       }
+}
+
+void errormsg(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       logmsg(LOG_ERR, fmt, ap);
+       va_end(ap);
+}
+
+void warnmsg(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       logmsg(LOG_WARN, fmt, ap);
+       va_end(ap);
+}
+
+void infomsg(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       logmsg(LOG_INFO, fmt, ap);
+       va_end(ap);
+}
+
+void dbgmsg(const char *fmt, ...)
+{
+       va_list ap;
+       va_start(ap, fmt);
+       logmsg(LOG_DBG, fmt, ap);
+       va_end(ap);
+}
+
+void verrormsg(const char *fmt, va_list ap)
+{
+       logmsg(LOG_ERR, fmt, ap);
+}
+
+void vwarnmsg(const char *fmt, va_list ap)
+{
+       logmsg(LOG_ERR, fmt, ap);
+}
+
+void vinfomsg(const char *fmt, va_list ap)
+{
+       logmsg(LOG_ERR, fmt, ap);
+}
+
+void vdbgmsg(const char *fmt, va_list ap)
+{
+       logmsg(LOG_ERR, fmt, ap);
+}
+
+
+#if defined(MSDOS) || defined(__MSDOS__)
+#define UART1_BASE     0x3f8
+#define UART2_BASE     0x2f8
+
+#define UART_DATA      0
+#define UART_DIVLO     0
+#define UART_DIVHI     1
+#define UART_FIFO      2
+#define UART_LCTL      3
+#define UART_MCTL      4
+#define UART_LSTAT     5
+
+#define DIV_9600                       (115200 / 9600)
+#define DIV_38400                      (115200 / 38400)
+#define LCTL_8N1                       0x03
+#define LCTL_DLAB                      0x80
+#define FIFO_ENABLE_CLEAR      0x07
+#define MCTL_DTR_RTS_OUT2      0x0b
+#define LST_TRIG_EMPTY         0x20
+
+static unsigned int iobase;
+
+static int setup_serial(int sdev)
+{
+       if(sdev < 0 || sdev > 1) {
+               return -1;
+       }
+       iobase = sdev == 0 ? UART1_BASE : UART2_BASE;
+
+       /* set clock divisor */
+       outp(iobase | UART_LCTL, LCTL_DLAB);
+       outp(iobase | UART_DIVLO, DIV_9600 & 0xff);
+       outp(iobase | UART_DIVHI, DIV_9600 >> 8);
+       /* set format 8n1 */
+       outp(iobase | UART_LCTL, LCTL_8N1);
+       /* assert RTS and DTR */
+       outp(iobase | UART_MCTL, MCTL_DTR_RTS_OUT2);
+       return 0;
+}
+
+void ser_putchar(int c)
+{
+       if(c == '\n') {
+               ser_putchar('\r');
+       }
+
+       while((inp(iobase | UART_LSTAT) & LST_TRIG_EMPTY) == 0);
+       outp(iobase | UART_DATA, c);
+}
+
+void ser_puts(const char *s)
+{
+       while(*s) {
+               ser_putchar(*s++);
+       }
+}
+
+void ser_printf(const char *fmt, ...)
+{
+       va_list ap;
+       char buf[512];
+
+       va_start(ap, fmt);
+       vsprintf(buf, fmt, ap);
+       va_end(ap);
+
+       ser_puts(buf);
+}
+#endif
diff --git a/src/logger.h b/src/logger.h
new file mode 100644 (file)
index 0000000..29522da
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+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 LOGGER_H_
+#define LOGGER_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+
+void init_logger(void);
+void cleanup_logger(void);
+
+int add_log_file(const char *fname);
+int add_log_stream(FILE *fp);
+int add_log_console(const char *devname);
+int add_log_callback(void (*cbfunc)(const char*, void*), void *cls);
+
+void errormsg(const char *fmt, ...);
+void warnmsg(const char *fmt, ...);
+void infomsg(const char *fmt, ...);
+void dbgmsg(const char *fmt, ...);
+
+void verrormsg(const char *fmt, va_list ap);
+void vwarnmsg(const char *fmt, va_list ap);
+void vinfomsg(const char *fmt, va_list ap);
+void vdbgmsg(const char *fmt, va_list ap);
+
+#endif /* LOGGER_H_ */
index e511b65..066c431 100644 (file)
@@ -99,6 +99,23 @@ void app_redisplay(void)
 
 void app_swap_buffers(void)
 {
+       glMatrixMode(GL_PROJECTION);
+       glPushMatrix();
+       glLoadIdentity();
+       glMatrixMode(GL_MODELVIEW);
+       glLoadIdentity();
+
+       glRasterPos2i(-1, 1);
+       glPixelZoom(1, -1);
+       glEnable(GL_ALPHA_TEST);
+       glAlphaFunc(GL_GREATER, 0.5f);
+       glDrawPixels(win_width, win_height, GL_BGRA, GL_UNSIGNED_BYTE, framebuf);
+       glDisable(GL_ALPHA_TEST);
+
+       glMatrixMode(GL_PROJECTION);
+       glPopMatrix();
+       glMatrixMode(GL_MODELVIEW);
+
        glutSwapBuffers();
        assert(glGetError() == GL_NO_ERROR);
 }
index 43de80d..abd4244 100644 (file)
--- a/src/rtk.c
+++ b/src/rtk.c
@@ -6,6 +6,10 @@
 static rtk_draw_ops gfx;
 
 static void calc_widget_rect(rtk_widget *w, rtk_rect *rect);
+static void draw_window(rtk_widget *w);
+static void draw_button(rtk_widget *w);
+static void draw_checkbox(rtk_widget *w);
+static void draw_separator(rtk_widget *w);
 
 void rtk_setup(rtk_draw_ops *drawop)
 {
@@ -189,8 +193,13 @@ int rtk_win_has(rtk_widget *par, rtk_widget *child)
 
 void rtk_bn_set_icon(rtk_widget *w, rtk_icon *icon)
 {
+       rtk_rect rect;
+
        RTK_ASSERT_TYPE(w, RTK_BUTTON);
        w->bn.icon = icon;
+
+       calc_widget_rect(w, &rect);
+       rtk_resize(w, rect.width, rect.height);
 }
 
 rtk_icon *rtk_bn_get_icon(rtk_widget *w)
@@ -208,6 +217,7 @@ rtk_widget *rtk_create_window(rtk_widget *par, const char *title, int x, int y,
        if(!(w = rtk_create_widget())) {
                return 0;
        }
+       w->type = RTK_WIN;
        if(par) rtk_win_add(par, w);
        rtk_set_text(w, title);
        rtk_move(w, x, y);
@@ -222,6 +232,7 @@ rtk_widget *rtk_create_button(rtk_widget *par, const char *str, rtk_callback cbf
        if(!(w = rtk_create_widget())) {
                return 0;
        }
+       w->type = RTK_BUTTON;
        if(par) rtk_win_add(par, w);
        rtk_set_text(w, str);
        rtk_set_callback(w, cbfunc, 0);
@@ -235,6 +246,7 @@ rtk_widget *rtk_create_iconbutton(rtk_widget *par, rtk_icon *icon, rtk_callback
        if(!(w = rtk_create_widget())) {
                return 0;
        }
+       w->type = RTK_BUTTON;
        if(par) rtk_win_add(par, w);
        rtk_bn_set_icon(w, icon);
        rtk_set_callback(w, cbfunc, 0);
@@ -248,6 +260,7 @@ rtk_widget *rtk_create_label(rtk_widget *par, const char *text)
        if(!(w = rtk_create_widget())) {
                return 0;
        }
+       w->type = RTK_LABEL;
        if(par) rtk_win_add(par, w);
        rtk_set_text(w, text);
        return w;
@@ -260,6 +273,7 @@ rtk_widget *rtk_create_checkbox(rtk_widget *par, const char *text, int chk, rtk_
        if(!(w = rtk_create_widget())) {
                return 0;
        }
+       w->type = RTK_CHECKBOX;
        if(par) rtk_win_add(par, w);
        rtk_set_text(w, text);
        rtk_set_value(w, chk ? 1 : 0);
@@ -267,6 +281,19 @@ rtk_widget *rtk_create_checkbox(rtk_widget *par, const char *text, int chk, rtk_
        return w;
 }
 
+rtk_widget *rtk_create_separator(rtk_widget *par)
+{
+       rtk_widget *w;
+
+       if(!(w = rtk_create_widget())) {
+               return 0;
+       }
+       w->type = RTK_SEP;
+       if(par) rtk_win_add(par, w);
+       return w;
+}
+
+
 /* --- icon functions --- */
 rtk_iconsheet *rtk_load_iconsheet(const char *fname)
 {
@@ -354,6 +381,18 @@ static void calc_widget_rect(rtk_widget *w, rtk_rect *rect)
                rect->height = txrect.height + PAD * 2;
                break;
 
+       case RTK_SEP:
+               if(w->any.par->win.layout == RTK_VBOX) {
+                       rect->width = w->any.par->any.width - PAD * 2;
+                       rect->height = (PAD + BEVELSZ) * 2;
+               } else if(w->any.par->win.layout == RTK_HBOX) {
+                       rect->width = (PAD + BEVELSZ) * 2;
+                       rect->height = w->any.par->any.height - PAD * 2;
+               } else {
+                       rect->width = rect->height = 0;
+               }
+               break;
+
        default:
                rect->width = rect->height = 0;
        }
@@ -405,10 +444,6 @@ static void calc_layout(rtk_widget *w)
        w->any.flags = (w->any.flags & ~GEOMCHG) | DIRTY;
 }
 
-static void draw_window(rtk_widget *w);
-static void draw_button(rtk_widget *w);
-static void draw_checkbox(rtk_widget *w);
-
 void rtk_draw_widget(rtk_widget *w)
 {
        if(need_relayout(w)) {
@@ -428,6 +463,10 @@ void rtk_draw_widget(rtk_widget *w)
                draw_checkbox(w);
                break;
 
+       case RTK_SEP:
+               draw_separator(w);
+               break;
+
        default:
                break;
        }
@@ -460,17 +499,72 @@ static void abs_pos(rtk_widget *w, int *xpos, int *ypos)
        *ypos = y;
 }
 
-#define COL_BG         0xa0a0a0
-#define COL_LBEV       0xcccccc
-#define COL_SBEV       0x202020
-#define COL_TEXT       0
+#define COL_BG         0xff666666
+#define COL_LBEV       0xffaaaaaa
+#define COL_SBEV       0xff333333
+#define COL_TEXT       0xff000000
+
+static void hline(int x, int y, int sz, uint32_t col)
+{
+       rtk_rect rect;
+       rect.x = x;
+       rect.y = y;
+       rect.width = sz;
+       rect.height = 1;
+       gfx.fill(&rect, col);
+}
+
+static void vline(int x, int y, int sz, uint32_t col)
+{
+       rtk_rect rect;
+       rect.x = x;
+       rect.y = y;
+       rect.width = 1;
+       rect.height = sz;
+       gfx.fill(&rect, col);
+}
+
+enum {FRM_SOLID, FRM_OUTSET, FRM_INSET};
+
+static void draw_frame(rtk_rect *rect, int type)
+{
+       int tlcol, brcol;
+
+       switch(type) {
+       case FRM_SOLID:
+               tlcol = brcol = 0xff000000;
+               break;
+       case FRM_OUTSET:
+               tlcol = COL_LBEV;
+               brcol = COL_SBEV;
+               break;
+       case FRM_INSET:
+               tlcol = COL_SBEV;
+               brcol = COL_LBEV;
+               break;
+       default:
+               break;
+       }
+
+       hline(rect->x, rect->y, rect->width, tlcol);
+       vline(rect->x, rect->y + 1, rect->height - 2, tlcol);
+       hline(rect->x, rect->y + rect->height - 1, rect->width, brcol);
+       vline(rect->x + rect->width - 1, rect->y + 1, rect->height - 2, brcol);
+}
 
 static void draw_window(rtk_widget *w)
 {
        rtk_rect rect;
+       rtk_widget *c;
 
        widget_rect(w, &rect);
        gfx.fill(&rect, COL_BG);
+
+       c = w->win.clist;
+       while(c) {
+               rtk_draw_widget(c);
+               c = c->any.next;
+       }
 }
 
 static void draw_button(rtk_widget *w)
@@ -480,14 +574,34 @@ static void draw_button(rtk_widget *w)
        widget_rect(w, &rect);
        abs_pos(w, &rect.x, &rect.y);
 
+       if(rect.width > 2 && rect.height > 2) {
+               draw_frame(&rect, FRM_OUTSET);
+
+               rect.x++;
+               rect.y++;
+               rect.width -= 2;
+               rect.height -= 2;
+       }
+
        gfx.fill(&rect, COL_BG);
        if(w->bn.icon) {
                gfx.blit(rect.x + OFFS, rect.y + OFFS, w->bn.icon);
        } else {
-               gfx.fill(&rect, 0x802020);
+               gfx.fill(&rect, 0xff802020);
        }
 }
 
 static void draw_checkbox(rtk_widget *w)
 {
 }
+
+static void draw_separator(rtk_widget *w)
+{
+       rtk_widget *win = w->any.par;
+       rtk_rect rect;
+
+       widget_rect(w, &rect);
+       abs_pos(w, &rect.x, &rect.y);
+
+       draw_frame(&rect, FRM_INSET);
+}
index 58cccad..15b6c79 100644 (file)
--- a/src/rtk.h
+++ b/src/rtk.h
@@ -2,7 +2,7 @@
 #define RTK_H_
 
 /* widget type */
-enum { RTK_ANY, RTK_WIN, RTK_BUTTON, RTK_LABEL, RTK_CHECKBOX, RTK_SLIDER };
+enum { RTK_ANY, RTK_WIN, RTK_BUTTON, RTK_LABEL, RTK_CHECKBOX, RTK_SLIDER, RTK_SEP };
 /* window layout */
 enum { RTK_NONE, RTK_VBOX, RTK_HBOX };
 
@@ -14,6 +14,15 @@ typedef struct rtk_rect {
        int x, y, width, height;
 } rtk_rect;
 
+typedef struct rtk_icon {
+       char *name;
+       int width, height, scanlen;
+       uint32_t *pixels;
+
+       struct rtk_icon *next;
+} rtk_icon;
+
+
 typedef struct rtk_draw_ops {
        void (*fill)(rtk_rect *rect, uint32_t color);
        void (*blit)(int x, int y, rtk_icon *icon);
@@ -32,6 +41,7 @@ rtk_widget *rtk_create_widget(void);
 void rtk_free_widget(rtk_widget *w);
 
 int rtk_type(rtk_widget *w);
+rtk_widget *rtk_parent(rtk_widget *w);
 
 void rtk_move(rtk_widget *w, int x, int y);
 void rtk_pos(rtk_widget *w, int *xptr, int *yptr);
@@ -62,12 +72,14 @@ rtk_widget *rtk_create_button(rtk_widget *par, const char *str, rtk_callback cbf
 rtk_widget *rtk_create_iconbutton(rtk_widget *par, rtk_icon *icon, rtk_callback cbfunc);
 rtk_widget *rtk_create_label(rtk_widget *par, const char *text);
 rtk_widget *rtk_create_checkbox(rtk_widget *par, const char *text, int chk, rtk_callback cbfunc);
+rtk_widget *rtk_create_separator(rtk_widget *par);
 
 /* icon functions */
 rtk_iconsheet *rtk_load_iconsheet(const char *fname);
 void rtk_free_iconsheet(rtk_iconsheet *is);
 
 rtk_icon *rtk_define_icon(rtk_iconsheet *is, const char *name, int x, int y, int w, int h);
+rtk_icon *rtk_lookup_icon(rtk_iconsheet *is, const char *name);
 
 
 void rtk_draw_widget(rtk_widget *w);
index d9ee120..9afa913 100644 (file)
@@ -41,14 +41,6 @@ typedef union rtk_widget {
        rtk_button bn;
 } rtk_widget;
 
-typedef struct rtk_icon {
-       char *name;
-       int width, height, scanlen;
-       uint32_t *pixels;
-
-       struct rtk_icon *next;
-} rtk_icon;
-
 typedef struct rtk_iconsheet {
        int width, height;
        uint32_t *pixels;
index 189e271..29ce348 100644 (file)
@@ -17,6 +17,32 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
 #include "gaw/gaw.h"
 #include "app.h"
+#include "rtk.h"
+
+enum {
+       TBN_NEW, TBN_OPEN, TBN_SAVE, TBN_SEP1,
+       TBN_SEL, TBN_MOVE, TBL_ROT, TBN_SCALE, TBN_SEP2,
+       TBL_ADD, TBL_RM, TBN_SEP3,
+       TBN_MTL, TBN_REND, TBL_VIEWREND, TBN_SEP4, TBL_CFG,
+
+       NUM_TOOL_BUTTONS
+};
+static const char *tbn_icon_name[] = {
+       "new", "open", "save", 0,
+       "sel", "move", "rot", "scale", 0,
+       "add", "remove", 0,
+       "mtl", "rend", "viewrend", 0, "cfg"
+};
+static int tbn_icon_pos[][2] = {
+       {0,0}, {16,0}, {32,0}, {-1,-1},
+       {48,0}, {64,0}, {80,0}, {96,0}, {-1,-1},
+       {112,0}, {112,16}, {-1,-1},
+       {48,16}, {64,16}, {80,16}, {-1,-1}, {96,16}
+};
+static rtk_icon *tbn_icons[NUM_TOOL_BUTTONS];
+
+#define TOOLBAR_HEIGHT 26
+
 
 static int mdl_init(void);
 static void mdl_destroy(void);
@@ -28,6 +54,8 @@ 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);
 
+static void draw_grid(void);
+
 
 struct app_screen scr_model = {
        "modeller",
@@ -37,18 +65,53 @@ struct app_screen scr_model = {
        mdl_keyb, mdl_mouse, mdl_motion
 };
 
+static rtk_widget *toolbar;
+static rtk_iconsheet *icons;
+
+static float cam_theta, cam_phi = 20, cam_dist = 8;
+
 
 static int mdl_init(void)
 {
+       int i;
+       rtk_widget *w;
+
+       if(!(icons = rtk_load_iconsheet("data/icons.png"))) {
+               errormsg("failed to load iconsheet\n");
+               return -1;
+       }
+       for(i=0; i<NUM_TOOL_BUTTONS; i++) {
+               if(tbn_icon_name[i]) {
+                       tbn_icons[i] = rtk_define_icon(icons, tbn_icon_name[i],
+                                       tbn_icon_pos[i][0], tbn_icon_pos[i][1], 16, 16);
+               }
+       }
+
+       if(!(toolbar = rtk_create_window(0, "toolbar", 0, 0, win_width, TOOLBAR_HEIGHT))) {
+               return -1;
+       }
+       rtk_win_layout(toolbar, RTK_HBOX);
+
+       for(i=0; i<NUM_TOOL_BUTTONS; i++) {
+               if(!tbn_icons[i]) {
+                       rtk_create_separator(toolbar);
+               } else {
+                       if(!(w = rtk_create_iconbutton(toolbar, tbn_icons[i], 0))) {
+                               return -1;
+                       }
+               }
+       }
        return 0;
 }
 
 static void mdl_destroy(void)
 {
+       rtk_free_iconsheet(icons);
 }
 
 static int mdl_start(void)
 {
+       gaw_clear_color(0.125, 0.125, 0.125, 1);
        return 0;
 }
 
@@ -58,13 +121,59 @@ static void mdl_stop(void)
 
 static void mdl_display(void)
 {
+       gaw_clear(GAW_COLORBUF | GAW_DEPTHBUF);
+
+       rtk_draw_widget(toolbar);
+
+       gaw_viewport(0, TOOLBAR_HEIGHT, win_width, win_height - TOOLBAR_HEIGHT);
+
+       gaw_matrix_mode(GAW_MODELVIEW);
+       gaw_load_identity();
+       gaw_translate(0, 0, -cam_dist);
+       gaw_rotate(cam_phi, 1, 0, 0);
+       gaw_rotate(cam_theta, 0, 1, 0);
+
+       draw_grid();
+
+       gaw_begin(GAW_QUADS);
+       gaw_color3f(1, 0, 0);
+       gaw_vertex2f(-1, -1);
+       gaw_color3f(0, 1, 0);
+       gaw_vertex2f(1, -1);
+       gaw_color3f(0, 0, 1);
+       gaw_vertex2f(1, 1);
+       gaw_color3f(1, 1, 0);
+       gaw_vertex2f(-1, 1);
+       gaw_end();
+
+       gaw_viewport(0, 0, win_width, win_height);
+}
+
+static void draw_grid(void)
+{
+       gaw_begin(GAW_LINES);
+       gaw_color3f(0.5, 0, 0);
+       gaw_vertex4f(0, 0, 0, 1);
+       gaw_vertex4f(-1, 0, 0, 0);
+       gaw_vertex4f(0, 0, 0, 1);
+       gaw_vertex4f(1, 0, 0, 0);
+       gaw_color3f(0, 0.5, 0);
+       gaw_vertex4f(0, 0, 0, 1);
+       gaw_vertex4f(0, 0, -1, 0);
+       gaw_vertex4f(0, 0, 0, 1);
+       gaw_vertex4f(0, 0, 1, 0);
+       gaw_end();
 }
 
 static void mdl_reshape(int x, int y)
 {
+       float aspect = (float)x / (float)(y - TOOLBAR_HEIGHT);
+
        gaw_matrix_mode(GAW_PROJECTION);
        gaw_load_identity();
-       gaw_perspective(50, win_aspect, 0.5, 100.0);
+       gaw_perspective(50, aspect, 0.5, 100.0);
+
+       rtk_resize(toolbar, win_width, TOOLBAR_HEIGHT);
 }
 
 static void mdl_keyb(int key, int press)
@@ -77,4 +186,22 @@ static void mdl_mouse(int bn, int press, int x, int y)
 
 static void mdl_motion(int x, int y)
 {
+       int dx = x - mouse_x;
+       int dy = y - mouse_y;
+
+       if((dx | dy) == 0) return;
+
+       if(mouse_state[0]) {
+               cam_theta += dx * 0.5f;
+               cam_phi += dy * 0.5f;
+               if(cam_phi < -90) cam_phi = -90;
+               if(cam_phi > 90) cam_phi = 90;
+               app_redisplay();
+       }
+
+       if(mouse_state[2]) {
+               cam_dist += dy * 0.1f;
+               if(cam_dist < 0) cam_dist = 0;
+               app_redisplay();
+       }
 }