dos port underway
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 14 Jun 2023 01:46:36 +0000 (04:46 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 14 Jun 2023 01:46:36 +0000 (04:46 +0300)
41 files changed:
.gitignore
Makefile [new file with mode: 0644]
libs/cgmath/cgmmisc.inl
libs/drawtext/Makefile [new file with mode: 0644]
libs/drawtext/draw.c
libs/drawtext/drawgl.c
libs/drawtext/drawrast.c
libs/drawtext/drawtext.dep [deleted file]
libs/drawtext/drawtext.dsp
libs/drawtext/drawtext_impl.h [deleted file]
libs/drawtext/dtximpl.h [new file with mode: 0644]
libs/drawtext/font.c
libs/imago/Makefile [new file with mode: 0644]
libs/treestor/Makefile [new file with mode: 0644]
libs/treestor/src/treestor.c
src/cmesh.c
src/dos/cdpmi.h [new file with mode: 0644]
src/dos/djdpmi.c [new file with mode: 0644]
src/dos/dosutil.h [new file with mode: 0644]
src/dos/gfx.c [new file with mode: 0644]
src/dos/gfx.h [new file with mode: 0644]
src/dos/keyb.c [new file with mode: 0644]
src/dos/keyb.h [new file with mode: 0644]
src/dos/logger.c [new file with mode: 0644]
src/dos/logger.h [new file with mode: 0644]
src/dos/main.c [new file with mode: 0644]
src/dos/mouse.h [new file with mode: 0644]
src/dos/pit8254.h [new file with mode: 0644]
src/dos/scancode.h [new file with mode: 0644]
src/dos/timer.c [new file with mode: 0644]
src/dos/vbe.c [new file with mode: 0644]
src/dos/vbe.h [new file with mode: 0644]
src/dos/vga.c [new file with mode: 0644]
src/dos/vga.h [new file with mode: 0644]
src/dos/vgaregs.h [new file with mode: 0644]
src/dos/watdpmi.c [new file with mode: 0644]
src/gaw/gawswtnl.c
src/gaw/gawswtnl.h
src/meshgen.c
src/rbtree.c
src/rtk_impl.h

index 01e8736..be7677e 100644 (file)
@@ -3,8 +3,21 @@
 *.swp
 *.a
 *.lib
+*.LIB
 retroray
 *.cfg
 data/
 *.exe
 config.mk
+*.obj
+*.OBJ
+*.err
+*.ERR
+*.lbc
+*.LBC
+*.occ
+*.OCC
+*.lnk
+*.LNK
+*.map
+*.MAP
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..fe31353
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,100 @@
+!ifdef __UNIX__
+dosobj = src/dos/djdpmi.obj src/dos/gfx.obj src/dos/keyb.obj src/dos/logger.obj &
+       src/dos/main.obj src/dos/timer.obj src/dos/vbe.obj src/dos/vga.obj src/dos/watdpmi.obj
+appobj = src/app.obj src/cmesh.obj src/darray.obj src/font.obj src/logger.obj &
+       src/meshgen.obj src/meshload.obj src/options.obj src/rbtree.obj src/rt.obj &
+       src/rtk.obj src/scene.obj src/scr_mod.obj src/scr_rend.obj src/util.obj
+gawobj = src/gaw/gaw_sw.obj src/gaw/gawswtnl.obj src/gaw/polyclip.obj src/gaw/polyfill.obj
+
+incpath = -Isrc -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/treestor/include -Ilibs/drawtext
+libpath = libpath libs/dos
+!else
+dosobj = src\dos\djdpmi.obj src\dos\gfx.obj src\dos\keyb.obj src\dos\logger.obj &
+       src\dos\main.obj src\dos\timer.obj src\dos\vbe.obj src\dos\vga.obj src\dos\watdpmi.obj
+appobj = src\app.obj src\cmesh.obj src\darray.obj src\font.obj src\logger.obj &
+       src\meshgen.obj src\meshload.obj src\options.obj src\rbtree.obj src\rt.obj &
+       src\rtk.obj src\scene.obj src\scr_mod.obj src\scr_rend.obj src\util.obj
+gawobj = src\gaw\gaw_sw.obj src\gaw\gawswtnl.obj src\gaw\polyclip.obj src\gaw\polyfill.obj
+
+incpath = -Isrc -Isrc\dos -Ilibs -Ilibs\imago\src -Ilibs\treestor\include -Ilibs\drawtext
+libpath = libpath libs\dos
+!endif
+
+obj = $(dosobj) $(appobj) $(gawobj)
+bin = retroray.exe
+
+opt = -otexan
+def = -DGFX_SW
+libs = imago.lib treestor.lib drawtext.lib
+
+AS = nasm
+CC = wcc386
+LD = wlink
+ASFLAGS = -fobj
+CFLAGS = -d3 -5 -fp5 $(opt) $(def) -s -zq -bt=dos $(incpath)
+LDFLAGS = option map $(libpath) library { $(libs) }
+
+$(bin): cflags.occ $(obj) $(libs)
+       %write objects.lnk $(obj)
+       %write ldflags.lnk $(LDFLAGS)
+       $(LD) debug all name $@ system dos4g file { @objects } @ldflags
+
+.c: src;src/dos;src/gaw
+.asm: src;src/dos;src/gaw
+
+cflags.occ: Makefile
+       %write $@ $(CFLAGS)
+
+.c.obj: .autodepend
+       $(CC) -fo=$@ @cflags.occ $[*
+
+.asm.obj:
+       nasm $(ASFLAGS) -o $@ $[*.asm
+
+
+!ifdef __UNIX__
+clean: .symbolic
+       rm -f $(obj)
+       rm -f $(bin)
+       rm -f cflags.occ *.lnk
+
+imago.lib:
+       cd libs/imago
+       wmake
+       cd ../..
+
+treestor.lib:
+       cd libs/treestor
+       wmake
+       cd ../..
+
+drawtext.lib:
+       cd libs/drawtext
+       wmake
+       cd ../..
+
+!else
+
+imago.lib:
+       cd libs\imago
+       wmake
+       cd ..\..
+
+treestor.lib:
+       cd libs\treestor
+       wmake
+       cd ..\..
+
+drawtext.lib:
+       cd libs\drawtext
+       wmake
+       cd ..\..
+
+clean: .symbolic
+       del src\*.obj
+       del src\dos\*.obj
+       del src\gaw\*.obj
+       del *.lnk
+       del cflags.occ
+       del $(bin)
+!endif
index a3cdfb5..0def727 100644 (file)
 
 static CGM_INLINE float cgm_deg_to_rad(float deg)
 {
-       return M_PI * deg / 180.0f;
+       return CGM_PI * deg / 180.0f;
 }
 
 static CGM_INLINE float cgm_rad_to_deg(float rad)
 {
-       return 180.0f * rad / M_PI;
+       return 180.0f * rad / CGM_PI;
 }
 
 static CGM_INLINE float cgm_smoothstep(float a, float b, float x)
@@ -87,7 +87,7 @@ static CGM_INLINE float cgm_spline(float a, float b, float c, float d, float t)
 
 static CGM_INLINE void cgm_discrand(cgm_vec3 *pt, float rad)
 {
-       float theta = 2.0f * M_PI * (float)rand() / RAND_MAX;
+       float theta = 2.0f * CGM_PI * (float)rand() / RAND_MAX;
        float r = sqrt((float)rand() / RAND_MAX) * rad;
        pt->x = cos(theta) * r;
        pt->y = sin(theta) * r;
@@ -101,7 +101,7 @@ static CGM_INLINE void cgm_sphrand(cgm_vec3 *pt, float rad)
        u = (float)rand() / RAND_MAX;
        v = (float)rand() / RAND_MAX;
 
-       theta = 2.0f * M_PI * u;
+       theta = 2.0f * CGM_PI * u;
        phi = acos(2.0f * v - 1.0f);
 
        pt->x = cos(theta) * sin(phi) * rad;
diff --git a/libs/drawtext/Makefile b/libs/drawtext/Makefile
new file mode 100644 (file)
index 0000000..d75d408
--- /dev/null
@@ -0,0 +1,30 @@
+obj = font.obj draw.obj drawgl.obj drawrast.obj utf8.obj
+
+!ifdef __UNIX__
+alib = ../../drawtext.lib
+!else
+alib = ..\..\drawtext.lib
+!endif
+
+CC = wcc386
+CFLAGS = -d1 -5 -fp5 -otexan -zq -DNO_FREETYPE -DNO_OPENGL
+
+$(alib): $(obj)
+       %write objects.lbc $(obj)
+       wlib -b -n $@ @objects
+
+.c.obj: .autodepend
+       %write cflags.occ $(CFLAGS)
+       $(CC) -fo=$@ @cflags.occ $[*
+
+!ifdef __UNIX__
+clean: .symbolic
+       rm -f $(obj)
+       rm -f $(alib)
+!else
+clean: .symbolic
+       del *.obj
+       del objects.lbc
+       del cflags.occ
+       del $(alib)
+!endif
index 523239f..02b83da 100644 (file)
@@ -18,13 +18,13 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
-#if defined(WIN32) || defined(__WIN32__)
+#if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__)
 #include <malloc.h>
 #else
 #include <alloca.h>
 #endif
 #include "drawtext.h"
-#include "drawtext_impl.h"
+#include "dtximpl.h"
 
 void dtx_position(float x, float y)
 {
index edcd56b..e20c8a8 100644 (file)
@@ -16,7 +16,7 @@ You should have received a copy of the GNU Lesser General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include "drawtext.h"
-#include "drawtext_impl.h"
+#include "dtximpl.h"
 
 struct quad {
        struct dtx_vertex v[6];
index 66543a5..99106c8 100644 (file)
@@ -19,7 +19,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <stdlib.h>
 #include <string.h>
 #include "drawtext.h"
-#include "drawtext_impl.h"
+#include "dtximpl.h"
 
 static const char *drawchar(const char *str, float *xpos, float *ypos, int *should_flush);
 static void flush(void);
diff --git a/libs/drawtext/drawtext.dep b/libs/drawtext/drawtext.dep
deleted file mode 100644 (file)
index 1d20c2a..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# Microsoft Developer Studio Generated Dependency File, included by drawtext.mak\r
-\r
-.\draw.c : \\r
-       ".\drawtext.h"\\r
-       ".\drawtext_impl.h"\\r
-       \r
-\r
-.\drawgl.c : \\r
-       ".\drawtext.h"\\r
-       ".\drawtext_impl.h"\\r
-       \r
-\r
-.\drawrast.c : \\r
-       ".\drawtext.h"\\r
-       ".\drawtext_impl.h"\\r
-       \r
-\r
-.\font.c : \\r
-       ".\drawtext.h"\\r
-       ".\drawtext_impl.h"\\r
-       \r
-\r
-.\utf8.c : \\r
-       ".\drawtext.h"\\r
-       \r
index 8af8890..aa33d14 100644 (file)
@@ -101,7 +101,7 @@ SOURCE=.\drawtext.h
 # End Source File\r
 # Begin Source File\r
 \r
-SOURCE=.\drawtext_impl.h\r
+SOURCE=.\dtximpl.h\r
 # End Source File\r
 # Begin Source File\r
 \r
diff --git a/libs/drawtext/drawtext_impl.h b/libs/drawtext/drawtext_impl.h
deleted file mode 100644 (file)
index a107873..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
-libdrawtext - a simple library for fast text rendering in OpenGL
-Copyright (C) 2011-2016  John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef DRAWTEXT_IMPL_H_
-#define DRAWTEXT_IMPL_H_
-
-#include "drawtext.h"
-
-struct glyph {
-       int code;
-       float x, y, width, height;
-       /* normalized coords [0, 1] */
-       float nx, ny, nwidth, nheight;
-       float orig_x, orig_y;
-       float advance;
-       struct glyph *next;
-};
-
-struct dtx_glyphmap {
-       int ptsize;
-
-       int xsz, ysz;
-       unsigned int xsz_shift;
-       unsigned char *pixels;
-       unsigned int tex;
-       int tex_valid;
-       void *udata;
-
-       int cstart, cend;       /* character range */
-       int crange;
-
-       float line_advance;
-       float baseline;
-
-       struct glyph *glyphs;
-       struct dtx_glyphmap *next;
-};
-
-struct dtx_font {
-       /* freetype FT_Face */
-       void *face;
-
-       /* list of glyphmaps */
-       struct dtx_glyphmap *gmaps;
-
-       /* last returned glyphmap (cache) */
-       struct dtx_glyphmap *last_gmap;
-};
-
-#ifdef DTX_DEFINE_COMMON
-#define DTX_COMMON
-#else
-#define DTX_COMMON extern
-#endif
-
-DTX_COMMON struct dtx_font *dtx_font;
-DTX_COMMON int dtx_font_sz;
-DTX_COMMON int dtx_buf_mode;   /* DTX_NBF is 0 */
-DTX_COMMON float dtx_cur_color[4];
-DTX_COMMON int dtx_cur_color_int[4];
-DTX_COMMON float dtx_cur_offset[2];
-
-#define fperror(str) \
-       fprintf(stderr, "%s: %s\n", (str), strerror(errno))
-
-/* returns zero if it should NOT be printed and modifies xpos/ypos */
-/* implemented in font.c */
-struct dtx_glyphmap *dtx_proc_char(int code, float *xpos, float *ypos);
-
-DTX_COMMON const char *(*dtx_drawchar)(const char*, float*, float*, int*);
-DTX_COMMON void (*dtx_drawflush)(void);
-
-int dtx_gl_setopt(enum dtx_option opt, int val);
-int dtx_gl_getopt(enum dtx_option opt, int *ret);
-int dtx_rast_setopt(enum dtx_option opt, int val);
-int dtx_rast_getopt(enum dtx_option opt, int *ret);
-
-#endif /* DRAWTEXT_IMPL_H_ */
diff --git a/libs/drawtext/dtximpl.h b/libs/drawtext/dtximpl.h
new file mode 100644 (file)
index 0000000..a107873
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+libdrawtext - a simple library for fast text rendering in OpenGL
+Copyright (C) 2011-2016  John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef DRAWTEXT_IMPL_H_
+#define DRAWTEXT_IMPL_H_
+
+#include "drawtext.h"
+
+struct glyph {
+       int code;
+       float x, y, width, height;
+       /* normalized coords [0, 1] */
+       float nx, ny, nwidth, nheight;
+       float orig_x, orig_y;
+       float advance;
+       struct glyph *next;
+};
+
+struct dtx_glyphmap {
+       int ptsize;
+
+       int xsz, ysz;
+       unsigned int xsz_shift;
+       unsigned char *pixels;
+       unsigned int tex;
+       int tex_valid;
+       void *udata;
+
+       int cstart, cend;       /* character range */
+       int crange;
+
+       float line_advance;
+       float baseline;
+
+       struct glyph *glyphs;
+       struct dtx_glyphmap *next;
+};
+
+struct dtx_font {
+       /* freetype FT_Face */
+       void *face;
+
+       /* list of glyphmaps */
+       struct dtx_glyphmap *gmaps;
+
+       /* last returned glyphmap (cache) */
+       struct dtx_glyphmap *last_gmap;
+};
+
+#ifdef DTX_DEFINE_COMMON
+#define DTX_COMMON
+#else
+#define DTX_COMMON extern
+#endif
+
+DTX_COMMON struct dtx_font *dtx_font;
+DTX_COMMON int dtx_font_sz;
+DTX_COMMON int dtx_buf_mode;   /* DTX_NBF is 0 */
+DTX_COMMON float dtx_cur_color[4];
+DTX_COMMON int dtx_cur_color_int[4];
+DTX_COMMON float dtx_cur_offset[2];
+
+#define fperror(str) \
+       fprintf(stderr, "%s: %s\n", (str), strerror(errno))
+
+/* returns zero if it should NOT be printed and modifies xpos/ypos */
+/* implemented in font.c */
+struct dtx_glyphmap *dtx_proc_char(int code, float *xpos, float *ypos);
+
+DTX_COMMON const char *(*dtx_drawchar)(const char*, float*, float*, int*);
+DTX_COMMON void (*dtx_drawflush)(void);
+
+int dtx_gl_setopt(enum dtx_option opt, int val);
+int dtx_gl_getopt(enum dtx_option opt, int *ret);
+int dtx_rast_setopt(enum dtx_option opt, int val);
+int dtx_rast_getopt(enum dtx_option opt, int *ret);
+
+#endif /* DRAWTEXT_IMPL_H_ */
index b66e917..b5ee0e6 100644 (file)
@@ -34,7 +34,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include FT_FREETYPE_H
 #endif
 #include "drawtext.h"
-#include "drawtext_impl.h"
+#include "dtximpl.h"
 
 struct io {
        void *data;
diff --git a/libs/imago/Makefile b/libs/imago/Makefile
new file mode 100644 (file)
index 0000000..4e8f410
--- /dev/null
@@ -0,0 +1,84 @@
+!ifdef __UNIX__
+libpng = libpng/png.obj libpng/pngerror.obj libpng/pngget.obj libpng/pngmem.obj &
+       libpng/pngpread.obj libpng/pngread.obj libpng/pngrio.obj libpng/pngrtran.obj &
+       libpng/pngrutil.obj libpng/pngset.obj libpng/pngtrans.obj libpng/pngwio.obj &
+       libpng/pngwrite.obj libpng/pngwtran.obj libpng/pngwutil.obj
+zlib = zlib/adler32.obj zlib/compress.obj zlib/crc32.obj zlib/deflate.obj &
+       zlib/gzio.obj zlib/infback.obj zlib/inffast.obj zlib/inflate.obj &
+       zlib/inftrees.obj zlib/trees.obj zlib/uncompr.obj zlib/zutil.obj
+jpeglib = jpeglib/jcapimin.obj jpeglib/jcapistd.obj jpeglib/jccoefct.obj &
+       jpeglib/jccolor.obj jpeglib/jcdctmgr.obj jpeglib/jchuff.obj jpeglib/jcinit.obj &
+       jpeglib/jcmainct.obj jpeglib/jcmarker.obj jpeglib/jcmaster.obj jpeglib/jcomapi.obj &
+       jpeglib/jcparam.obj jpeglib/jcphuff.obj jpeglib/jcprepct.obj jpeglib/jcsample.obj &
+       jpeglib/jctrans.obj jpeglib/jdapimin.obj jpeglib/jdapistd.obj jpeglib/jdatadst.obj &
+       jpeglib/jdatasrc.obj jpeglib/jdcoefct.obj jpeglib/jdcolor.obj jpeglib/jddctmgr.obj &
+       jpeglib/jdhuff.obj jpeglib/jdinput.obj jpeglib/jdmainct.obj jpeglib/jdmarker.obj &
+       jpeglib/jdmaster.obj jpeglib/jdmerge.obj jpeglib/jdphuff.obj jpeglib/jdpostct.obj &
+       jpeglib/jdsample.obj jpeglib/jdtrans.obj jpeglib/jerror.obj jpeglib/jfdctflt.obj &
+       jpeglib/jfdctfst.obj jpeglib/jfdctint.obj jpeglib/jidctflt.obj jpeglib/jidctfst.obj &
+       jpeglib/jidctint.obj jpeglib/jidctred.obj jpeglib/jmemmgr.obj jpeglib/jmemnobs.obj &
+       jpeglib/jquant1.obj jpeglib/jquant2.obj jpeglib/jutils.obj
+obj = src/conv.obj src/filejpeg.obj src/filepng.obj src/fileppm.obj src/filergbe.obj &
+       src/filetga.obj src/ftmodule.obj src/imago2.obj src/modules.obj &
+       $(libpng) $(zlib) $(jpeglib)
+
+alib = ../../imago.lib
+!else
+libpng = libpng\png.obj libpng\pngerror.obj libpng\pngget.obj libpng\pngmem.obj &
+       libpng\pngpread.obj libpng\pngread.obj libpng\pngrio.obj libpng\pngrtran.obj &
+       libpng\pngrutil.obj libpng\pngset.obj libpng\pngtrans.obj libpng\pngwio.obj &
+       libpng\pngwrite.obj libpng\pngwtran.obj libpng\pngwutil.obj
+zlib = zlib\adler32.obj zlib\compress.obj zlib\crc32.obj zlib\deflate.obj &
+       zlib\gzio.obj zlib\infback.obj zlib\inffast.obj zlib\inflate.obj &
+       zlib\inftrees.obj zlib\trees.obj zlib\uncompr.obj zlib\zutil.obj
+jpeglib = jpeglib\jcapimin.obj jpeglib\jcapistd.obj jpeglib\jccoefct.obj &
+       jpeglib\jccolor.obj jpeglib\jcdctmgr.obj jpeglib\jchuff.obj jpeglib\jcinit.obj &
+       jpeglib\jcmainct.obj jpeglib\jcmarker.obj jpeglib\jcmaster.obj jpeglib\jcomapi.obj &
+       jpeglib\jcparam.obj jpeglib\jcphuff.obj jpeglib\jcprepct.obj jpeglib\jcsample.obj &
+       jpeglib\jctrans.obj jpeglib\jdapimin.obj jpeglib\jdapistd.obj jpeglib\jdatadst.obj &
+       jpeglib\jdatasrc.obj jpeglib\jdcoefct.obj jpeglib\jdcolor.obj jpeglib\jddctmgr.obj &
+       jpeglib\jdhuff.obj jpeglib\jdinput.obj jpeglib\jdmainct.obj jpeglib\jdmarker.obj &
+       jpeglib\jdmaster.obj jpeglib\jdmerge.obj jpeglib\jdphuff.obj jpeglib\jdpostct.obj &
+       jpeglib\jdsample.obj jpeglib\jdtrans.obj jpeglib\jerror.obj jpeglib\jfdctflt.obj &
+       jpeglib\jfdctfst.obj jpeglib\jfdctint.obj jpeglib\jidctflt.obj jpeglib\jidctfst.obj &
+       jpeglib\jidctint.obj jpeglib\jidctred.obj jpeglib\jmemmgr.obj jpeglib\jmemnobs.obj &
+       jpeglib\jquant1.obj jpeglib\jquant2.obj jpeglib\jutils.obj
+obj = src\conv.obj src\filejpeg.obj src\filepng.obj src\fileppm.obj src\filergbe.obj &
+       src\filetga.obj src\ftmodule.obj src\imago2.obj src\modules.obj &
+       $(libpng) $(zlib) $(jpeglib)
+
+alib = ..\..\imago.lib
+!endif
+
+#opt = -5 -fp5 -od
+opt = -5 -fp5 -otexan
+dbg = -d1
+def = -DPNG_NO_SNPRINTF
+
+CC = wcc386
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos -Ilibpng -Izlib -Ijpeglib
+
+$(alib): $(obj)
+       %write objects.lbc $(obj)
+       wlib -b -n $@ @objects
+
+.c: src;libpng;jpeglib;zlib
+
+.c.obj: .autodepend
+       %write cflags.occ $(CFLAGS)
+       $(CC) -fo=$@ @cflags.occ $[*
+
+!ifdef __UNIX__
+clean: .symbolic
+       rm -f $(obj)
+       rm -f $(alib)
+!else
+clean: .symbolic
+       del src\*.obj
+       del zlib\*.obj
+       del libpng\*.obj
+       del jpeglib\*.obj
+       del objects.lbc
+       del cflags.occ
+       del $(alib)
+!endif
diff --git a/libs/treestor/Makefile b/libs/treestor/Makefile
new file mode 100644 (file)
index 0000000..0686cd6
--- /dev/null
@@ -0,0 +1,32 @@
+!ifdef __UNIX__
+obj = src/treestor.obj src/text.obj src/dynarr.obj
+alib = ../../treestor.lib
+!else
+obj = src\treestor.obj src\text.obj src\dynarr.obj
+alib = ..\..\treestor.lib
+!endif
+
+CC = wcc386
+CFLAGS = -d1 -5 -fp5 -otexan -zq -Iinclude
+
+$(alib): $(obj)
+       %write objects.lbc $(obj)
+       wlib -b -n $@ @objects
+
+.c: src
+
+.c.obj: .autodepend
+       %write cflags.occ $(CFLAGS)
+       $(CC) -fo=$@ @cflags.occ $[*
+
+!ifdef __UNIX__
+clean: .symbolic
+       rm -f $(obj)
+       rm -f $(alib)
+!else
+clean: .symbolic
+       del src\*.obj
+       del objects.lbc
+       del cflags.occ
+       del $(alib)
+!endif
index 115c2b4..5e00a80 100644 (file)
@@ -5,7 +5,7 @@
 #include <assert.h>
 #include "treestor.h"
 
-#ifdef WIN32
+#if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__)
 #include <malloc.h>
 #else
 #include <alloca.h>
index 9e9833e..d6b7912 100644 (file)
@@ -1,9 +1,9 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
 #include <limits.h>
 #include <float.h>
 #include <assert.h>
+#include "sizeint.h"
 #include "gaw/gaw.h"
 #include "cmesh.h"
 
@@ -1118,8 +1118,9 @@ void cmesh_flip_faces(struct cmesh *cm)
                nelem = cm->vattr[CMESH_ATTR_VERTEX].nelem;
                for(i=0; i<vnum; i+=3) {
                        for(j=0; j<nelem; j++) {
+                               float tmp;
                                vptr = verts + (i + 1) * nelem + j;
-                               float tmp = vptr[nelem];
+                               tmp = vptr[nelem];
                                vptr[nelem] = vptr[0];
                                vptr[0] = tmp;
                        }
diff --git a/src/dos/cdpmi.h b/src/dos/cdpmi.h
new file mode 100644 (file)
index 0000000..e8a6950
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef DPMI_H_
+#define DPMI_H_
+
+#ifdef __DJGPP__
+#include <dpmi.h>
+#include <sys/nearptr.h>
+
+#define virt_to_phys(v)        ((v) + __djgpp_base_address)
+#define phys_to_virt(p)        ((p) - __djgpp_base_address)
+
+#else  /* not djgpp (basically watcom) */
+
+#define virt_to_phys(v)        (v)
+#define phys_to_virt(p)        (p)
+
+#endif /* __DJGPP__ */
+
+#include "inttypes.h"
+#include "util.h"
+
+#pragma pack (push, 1)
+struct dpmi_regs {
+       uint32_t edi, esi, ebp;
+       uint32_t reserved;
+       uint32_t ebx, edx, ecx, eax;
+       uint16_t flags;
+       uint16_t es, ds, fs, gs;
+       uint16_t ip, cs, sp, ss;
+} PACKED;
+#pragma pack (pop)
+
+enum {
+       FLAGS_CF        = 0x000001,
+       FLAGS_PF        = 0x000004,
+       FLAGS_ZF        = 0x000040,
+       FLAGS_SF        = 0x000080,
+       FLAGS_IF        = 0x000020,
+       FLAGS_DF        = 0x000040,
+       FLAGS_VM        = 0x020000,
+       FLAGS_ID        = 0x200000,
+};
+
+uint16_t dpmi_alloc(unsigned int par, uint16_t *sel);
+void dpmi_free(uint16_t sel);
+void dpmi_int(int inum, struct dpmi_regs *regs);
+void *dpmi_mmap(uint32_t phys_addr, unsigned int size);
+void dpmi_munmap(void *addr);
+
+#ifdef __WATCOMC__
+#pragma aux dpmi_alloc = \
+               "mov ax, 0x100" \
+               "int 0x31" \
+               "mov [edi], dx" \
+               "jnc alloc_skip_err" \
+               "xor ax, ax" \
+               "alloc_skip_err:" \
+               value[ax] \
+               parm[ebx][edi] \
+               modify[dx];
+
+#pragma aux dpmi_free = \
+               "mov ax, 0x101" \
+               "int 0x31" \
+               parm[dx] \
+               modify[ax];
+
+#pragma aux dpmi_int = \
+               "mov ax, 0x300" \
+               "xor ecx, ecx" \
+               "int 0x31" \
+               parm[ebx][edi] \
+               modify[ax ecx];
+
+#pragma aux dpmi_mmap = \
+               "mov ax, 0x800" \
+               "mov cx, bx" \
+               "shr ebx, 16" \
+               "mov di, si" \
+               "shr esi, 16" \
+               "int 0x31" \
+               "jnc mmap_skip_err" \
+               "xor bx, bx" \
+               "xor cx, cx" \
+       "mmap_skip_err:" \
+               "mov ax, bx" \
+               "shl eax, 16" \
+               "mov ax, cx" \
+               value[eax] \
+               parm[ebx][esi] \
+               modify[bx cx di esi];
+
+#pragma aux dpmi_munmap = \
+               "mov ax, 0x801" \
+               "mov cx, bx" \
+               "shr ebx, 16" \
+               "int 0x31" \
+               parm[ebx] \
+               modify[ax cx ebx];
+#endif /* __WATCOMC__ */
+
+#ifdef __DJGPP__
+#define dpmi_int(inum, regs) __dpmi_int((inum), (__dpmi_regs*)(regs))
+#endif
+
+#endif /* DPMI_H_ */
diff --git a/src/dos/djdpmi.c b/src/dos/djdpmi.c
new file mode 100644 (file)
index 0000000..f3a06b9
--- /dev/null
@@ -0,0 +1,35 @@
+#ifdef __DJGPP__
+#include <dpmi.h>
+#include <sys/nearptr.h>
+#include "cdpmi.h"
+#include "inttypes.h"
+
+uint16_t dpmi_alloc(unsigned int par, uint16_t *sel)
+{
+       int tmp;
+       uint16_t seg = __dpmi_allocate_dos_memory(par, &tmp);
+       *sel = tmp;
+       return seg;
+}
+
+void dpmi_free(uint16_t sel)
+{
+       __dpmi_free_dos_memory(sel);
+}
+
+void *dpmi_mmap(uint32_t phys_addr, unsigned int size)
+{
+       __dpmi_meminfo mem;
+       mem.address = phys_addr;
+       mem.size = size;
+       __dpmi_physical_address_mapping(&mem);
+       return (void*)(mem.address - __djgpp_base_address);
+}
+
+void dpmi_munmap(void *addr)
+{
+       __dpmi_meminfo mem;
+       mem.address = (uint32_t)addr + __djgpp_base_address;
+       __dpmi_free_physical_address_mapping(&mem);
+}
+#endif /* __DJGPP__ */
diff --git a/src/dos/dosutil.h b/src/dos/dosutil.h
new file mode 100644 (file)
index 0000000..4e4c8c3
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef DOSUTIL_H_
+#define DOSUTIL_H_
+
+#include <dos.h>
+#include <conio.h>
+
+#ifdef __DJGPP__
+#include <pc.h>
+
+#define outp(p, v)     outportb(p, v)
+#define outpw(p, v)    outportw(p, v)
+#define outpd(p, v)    outportl(p, v)
+
+#define inp(p)         inportb(p)
+#define inpw(p)                inportw(p)
+#define inpd(p)                inportl(p)
+#endif
+
+#endif /* DOSUTIL_H_ */
diff --git a/src/dos/gfx.c b/src/dos/gfx.c
new file mode 100644 (file)
index 0000000..0a8a00c
--- /dev/null
@@ -0,0 +1,544 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dos.h>
+#include "app.h"
+#include "cdpmi.h"
+#include "gfx.h"
+#include "vbe.h"
+#include "vga.h"
+#include "util.h"
+#include "cpuid.h"
+
+#ifdef __DJGPP__
+#define VMEM_PTR       ((void*)(0xa0000 + __djgpp_conventional_base))
+#else
+#define VMEM_PTR       ((void*)0xa0000)
+#endif
+
+#define SAME_BPP(a, b) \
+       ((a) == (b) || ((a) == 16 && (b) == 15) || ((a) == 15 && (b) == 16) || \
+        ((a) == 32 && (b) == 24) || ((a) == 24 && (b) == 32))
+
+void (*blit_frame)(void*, int);
+
+extern int dblsize;
+
+static void blit_frame_lfb(void *pixels, int vsync);
+static void blit_frame_banked(void *pixels, int vsync);
+static void blit_frame_lfb_2x(void *pixels, int vsync);
+static void blit_frame_banked_2x(void *pixels, int vsync);
+static uint32_t calc_mask(int sz, int pos);
+
+static void enable_wrcomb(uint32_t addr, int len);
+static const char *mtrr_type_name(int type);
+static void print_mtrr(void);
+
+static struct video_mode *vmodes;
+static int num_vmodes;
+
+static int vbe_init_ver;
+static struct vbe_info vbe;
+
+/* current mode */
+static struct video_mode *curmode;
+static void *vpgaddr[2];
+static int frontidx, backidx;
+static int pgcount, pgsize, fbsize;
+
+
+int init_video(void)
+{
+       int i, num, max_modes;
+       struct video_mode *vmptr;
+
+       if(vbe_info(&vbe) == -1) {
+               fprintf(stderr, "failed to retrieve VBE information\n");
+               return -1;
+       }
+       vbe_print_info(stdout, &vbe);
+
+       num_vmodes = 0;
+       max_modes = 64;
+       if(!(vmodes = malloc(max_modes * sizeof *vmodes))) {
+               fprintf(stderr, "failed to allocate video modes list\n");
+               return -1;
+       }
+
+       num = vbe_num_modes(&vbe);
+       for(i=0; i<num; i++) {
+               struct vbe_mode_info minf;
+
+               if(vbe_mode_info(vbe.modes[i], &minf) == -1) {
+                       continue;
+               }
+
+               if(num_vmodes >= max_modes) {
+                       int newmax = max_modes ? (max_modes << 1) : 16;
+                       if(!(vmptr = realloc(vmodes, newmax * sizeof *vmodes))) {
+                               fprintf(stderr, "failed to grow video mode list (%d)\n", newmax);
+                               free(vmodes);
+                               return -1;
+                       }
+                       vmodes = vmptr;
+                       max_modes = newmax;
+               }
+
+               vmptr = vmodes + num_vmodes++;
+               memset(vmptr, 0, sizeof *vmptr);
+               vmptr->mode = vbe.modes[i];
+               vmptr->xsz = minf.xres;
+               vmptr->ysz = minf.yres;
+               vmptr->bpp = minf.bpp;
+               vmptr->pitch = minf.scanline_bytes;
+               if(minf.mem_model == VBE_TYPE_DIRECT) {
+                       vmptr->rbits = minf.rsize;
+                       vmptr->gbits = minf.gsize;
+                       vmptr->bbits = minf.bsize;
+                       vmptr->rshift = minf.rpos;
+                       vmptr->gshift = minf.gpos;
+                       vmptr->bshift = minf.bpos;
+                       vmptr->rmask = calc_mask(minf.rsize, minf.rpos);
+                       vmptr->gmask = calc_mask(minf.gsize, minf.gpos);
+                       vmptr->bmask = calc_mask(minf.bsize, minf.bpos);
+                       /*vmptr->bpp = vmptr->rbits + vmptr->gbits + vmptr->bbits;*/
+               }
+               if(minf.attr & VBE_ATTR_LFB) {
+                       vmptr->fb_addr = minf.fb_addr;
+               }
+               vmptr->max_pages = minf.num_img_pages;
+               vmptr->win_gran = minf.win_gran;
+
+               printf("%04x: ", vbe.modes[i]);
+               vbe_print_mode_info(stdout, &minf);
+       }
+       fflush(stdout);
+
+       vbe_init_ver = VBE_VER_MAJOR(vbe.ver);
+       return 0;
+}
+
+void cleanup_video(void)
+{
+       free(vmodes);
+}
+
+struct video_mode *video_modes(void)
+{
+       return vmodes;
+}
+
+int num_video_modes(void)
+{
+       return num_vmodes;
+}
+
+struct video_mode *get_video_mode(int idx)
+{
+       if(idx == VMODE_CURRENT) {
+               return curmode;
+       }
+       return vmodes + idx;
+}
+
+int match_video_mode(int xsz, int ysz, int bpp)
+{
+       int i, best = -1;
+       struct video_mode *vm;
+
+       for(i=0; i<num_vmodes; i++) {
+               vm = vmodes + i;
+               if(vm->xsz != xsz || vm->ysz != ysz) continue;
+               if(SAME_BPP(vm->bpp, bpp)) {
+                       best = i;
+               }
+               if(vm->bpp == bpp) break;
+       }
+
+       if(best == -1) {
+               fprintf(stderr, "failed to find video mode %dx%d %d bpp)\n", xsz, ysz, bpp);
+               return -1;
+       }
+       return best;
+}
+
+int find_video_mode(int mode)
+{
+       int i;
+       struct video_mode *vm;
+
+       vm = vmodes;
+       for(i=0; i<num_vmodes; i++) {
+               if(vm->mode == mode) return i;
+       }
+       return -1;
+}
+
+void *set_video_mode(int idx, int nbuf)
+{
+       unsigned int mode;
+       struct video_mode *vm = vmodes + idx;
+
+       if(curmode == vm) return vpgaddr[0];
+
+       printf("setting video mode %x (%dx%d %d bpp)\n", (unsigned int)vm->mode,
+                       vm->xsz, vm->ysz, vm->bpp);
+       fflush(stdout);
+
+       mode = vm->mode | VBE_MODE_LFB;
+       if(vbe_setmode(mode) == -1) {
+               mode = vm->mode;
+               if(vbe_setmode(mode) == -1) {
+                       fprintf(stderr, "failed to set video mode %x\n", (unsigned int)vm->mode);
+                       return 0;
+               }
+               printf("Warning: failed to get a linear framebuffer. falling back to banked mode\n");
+       }
+
+       /* unmap previous video memory mapping, if there was one (switching modes) */
+       if(vpgaddr[0] && vpgaddr[0] != VMEM_PTR) {
+               dpmi_munmap(vpgaddr[0]);
+               vpgaddr[0] = vpgaddr[1] = 0;
+       }
+
+       curmode = vm;
+       if(nbuf < 1) nbuf = 1;
+       if(nbuf > 2) nbuf = 2;
+       pgcount = nbuf > vm->max_pages + 1 ? vm->max_pages + 1 : nbuf;
+       pgsize = vm->ysz * vm->pitch;
+       fbsize = pgcount * pgsize;
+
+       if(vm->bpp > 8) {
+               printf("rgb mask: %x %x %x\n", (unsigned int)vm->rmask,
+                               (unsigned int)vm->gmask, (unsigned int)vm->bmask);
+               printf("rgb shift: %d %d %d\n", vm->rshift, vm->gshift, vm->bshift);
+       }
+       printf("pgcount: %d, pgsize: %d, fbsize: %d\n", pgcount, pgsize, fbsize);
+       if(vm->fb_addr) {
+               printf("phys addr: %p\n", (void*)vm->fb_addr);
+       }
+       fflush(stdout);
+
+       if(vm->fb_addr) {
+               vpgaddr[0] = (void*)dpmi_mmap(vm->fb_addr, fbsize);
+               if(!vpgaddr[0]) {
+                       fprintf(stderr, "failed to map framebuffer (phys: %lx, size: %d)\n",
+                                       (unsigned long)vm->fb_addr, fbsize);
+                       set_text_mode();
+                       return 0;
+               }
+               memset(vpgaddr[0], 0xaa, pgsize);
+
+               if(pgcount > 1) {
+                       vpgaddr[1] = (char*)vpgaddr[0] + pgsize;
+                       backidx = 1;
+                       page_flip(FLIP_NOW);    /* start with the second page visible */
+               } else {
+                       frontidx = backidx = 0;
+                       vpgaddr[1] = 0;
+               }
+
+               blit_frame = dblsize ? blit_frame_lfb_2x : blit_frame_lfb;
+
+               /* only attempt to set up write combining if the CPU we're running on
+                * supports memory type range registers, and we're running on ring 0
+                */
+               if(CPU_HAVE_MTRR) {
+                       int cpl = get_cpl();
+                       if(cpl > 0) {
+                               fprintf(stderr, "Can't set framebuffer range to write-combining, running in ring %d\n", cpl);
+                       } else {
+                               uint32_t len = (uint32_t)vbe.vmem_blk << 16;
+
+                               /* if vmem_blk is 0 or if the reported size is absurd (more than
+                                * 256mb), just use the framebuffer size for this mode to setup the
+                                * mtrr
+                                */
+                               if(!len || len > 0x10000000) {
+                                       printf("reported vmem too large or overflowed, using fbsize for wrcomb setup\n");
+                                       len = fbsize;
+                               }
+                               print_mtrr();
+                               enable_wrcomb(vm->fb_addr, len);
+                       }
+               }
+
+       } else {
+               vpgaddr[0] = VMEM_PTR;
+               vpgaddr[1] = 0;
+
+               blit_frame = dblsize ? blit_frame_banked_2x : blit_frame_banked;
+
+               /* calculate window granularity shift */
+               vm->win_gran_shift = 0;
+               vm->win_64k_step = 1;
+               if(vm->win_gran > 0 && vm->win_gran < 64) {
+                       int gran = vm->win_gran;
+                       while(gran < 64) {
+                               vm->win_gran_shift++;
+                               gran <<= 1;
+                       }
+                       vm->win_64k_step = 1 << vm->win_gran_shift;
+               }
+
+               printf("granularity: %dk (step: %d)\n", vm->win_gran, vm->win_64k_step);
+       }
+
+       /* allocate main memory framebuffer */
+       if(demo_resizefb(vm->xsz, vm->ysz, vm->bpp) == -1) {
+               fprintf(stderr, "failed to allocate %dx%d (%d bpp) framebuffer\n", vm->xsz,
+                               vm->ysz, vm->bpp);
+               set_text_mode();
+               return 0;
+       }
+
+       fflush(stdout);
+       return vpgaddr[0];
+}
+
+int set_text_mode(void)
+{
+       /* unmap previous video memory mapping, if there was one (switching modes) */
+       if(vpgaddr[0] && vpgaddr[0] != VMEM_PTR) {
+               dpmi_munmap(vpgaddr[0]);
+               vpgaddr[0] = vpgaddr[1] = 0;
+       }
+
+       vga_setmode(3);
+       curmode = 0;
+       return 0;
+}
+
+void *page_flip(int vsync)
+{
+       if(!vpgaddr[1]) {
+               /* page flipping not supported */
+               return vpgaddr[0];
+       }
+
+       vbe_swap(backidx ? pgsize : 0, vsync ? VBE_SWAP_VBLANK : VBE_SWAP_NOW);
+       frontidx = backidx;
+       backidx = (backidx + 1) & 1;
+
+       return vpgaddr[backidx];
+}
+
+
+static void blit_frame_lfb(void *pixels, int vsync)
+{
+       demo_post_draw(pixels);
+
+       if(vsync) wait_vsync();
+       memcpy64(vpgaddr[frontidx], pixels, pgsize >> 3);
+}
+
+static void blit_frame_banked(void *pixels, int vsync)
+{
+       int sz, offs, pending;
+       unsigned char *pptr = pixels;
+
+       demo_post_draw(pixels);
+
+       if(vsync) wait_vsync();
+
+       /* assume initial window offset at 0 */
+       offs = 0;
+       pending = pgsize;
+       while(pending > 0) {
+               sz = pending > 65536 ? 65536 : pending;
+               /*memcpy64(VMEM_PTR, pptr, sz >> 3);*/
+               memcpy(VMEM_PTR, pptr, sz);
+               pptr += sz;
+               pending -= sz;
+               offs += curmode->win_64k_step;
+               vbe_setwin(0, offs);
+       }
+       vbe_setwin(0, 0);
+}
+
+static void blit_frame_lfb_2x(void *pixels, int vsync)
+{
+       demo_post_draw(pixels);
+
+       if(vsync) wait_vsync();
+       memcpy64(vpgaddr[frontidx], pixels, pgsize >> 3);
+}
+
+static void blit_frame_banked_2x(void *pixels, int vsync)
+{
+       int sz, offs, pending;
+       unsigned char *pptr = pixels;
+
+       demo_post_draw(pixels);
+
+       if(vsync) wait_vsync();
+
+       /* assume initial window offset at 0 */
+       offs = 0;
+       pending = pgsize;
+       while(pending > 0) {
+               sz = pending > 65536 ? 65536 : pending;
+               /*memcpy64(VMEM_PTR, pptr, sz >> 3);*/
+               memcpy(VMEM_PTR, pptr, sz);
+               pptr += sz;
+               pending -= sz;
+               offs += curmode->win_64k_step;
+               vbe_setwin(0, offs);
+       }
+       vbe_setwin(0, 0);
+}
+
+static uint32_t calc_mask(int sz, int pos)
+{
+       uint32_t mask = 0;
+       while(sz-- > 0) {
+               mask = (mask << 1) | 1;
+       }
+       return mask << pos;
+}
+
+#define MSR_MTRRCAP                    0xfe
+#define MSR_MTRRDEFTYPE                0x2ff
+#define MSR_MTRRBASE(x)                (0x200 | ((x) << 1))
+#define MSR_MTRRMASK(x)                (0x201 | ((x) << 1))
+#define MTRRDEF_EN                     0x800
+#define MTRRCAP_HAVE_WC                0x400
+#define MTRRMASK_VALID         0x800
+
+#define MTRR_WC                                1
+
+static int get_page_memtype(uint32_t addr, int num_ranges)
+{
+       int i;
+       uint32_t rlow, rhigh;
+       uint32_t base, mask;
+
+       for(i=0; i<num_ranges; i++) {
+               get_msr(MSR_MTRRMASK(i), &rlow, &rhigh);
+               if(!(rlow & MTRRMASK_VALID)) {
+                       continue;
+               }
+               mask = rlow & 0xfffff000;
+
+               get_msr(MSR_MTRRBASE(i), &rlow, &rhigh);
+               base = rlow & 0xfffff000;
+
+               if((addr & mask) == (base & mask)) {
+                       return rlow & 0xff;
+               }
+       }
+
+       get_msr(MSR_MTRRDEFTYPE, &rlow, &rhigh);
+       return rlow & 0xff;
+}
+
+static int check_wrcomb_enabled(uint32_t addr, int len, int num_ranges)
+{
+       while(len > 0) {
+               if(get_page_memtype(addr, num_ranges) != MTRR_WC) {
+                       return 0;
+               }
+               addr += 4096;
+               len -= 4096;
+       }
+       return 1;
+}
+
+static int alloc_mtrr(int num_ranges)
+{
+       int i;
+       uint32_t rlow, rhigh;
+
+       for(i=0; i<num_ranges; i++) {
+               get_msr(MSR_MTRRMASK(i), &rlow, &rhigh);
+               if(!(rlow & MTRRMASK_VALID)) {
+                       return i;
+               }
+       }
+       return -1;
+}
+
+static void enable_wrcomb(uint32_t addr, int len)
+{
+       int num_ranges, mtrr;
+       uint32_t rlow, rhigh;
+       uint32_t def, mask;
+
+       if(len <= 0 || (addr | (uint32_t)len) & 0xfff) {
+               fprintf(stderr, "failed to enable write combining, unaligned range: %p/%x\n",
+                               (void*)addr, (unsigned int)len);
+               return;
+       }
+
+       get_msr(MSR_MTRRCAP, &rlow, &rhigh);
+       num_ranges = rlow & 0xff;
+
+       printf("enable_wrcomb: addr=%p len=%x\n", (void*)addr, (unsigned int)len);
+
+       if(!(rlow & MTRRCAP_HAVE_WC)) {
+               fprintf(stderr, "failed to enable write combining, processor doesn't support it\n");
+               return;
+       }
+
+       if(check_wrcomb_enabled(addr, len, num_ranges)) {
+               return;
+       }
+
+       if((mtrr = alloc_mtrr(num_ranges)) == -1) {
+               fprintf(stderr, "failed to enable write combining, no free MTRRs\n");
+               return;
+       }
+
+       mask = len - 1;
+       mask |= mask >> 1;
+       mask |= mask >> 2;
+       mask |= mask >> 4;
+       mask |= mask >> 8;
+       mask |= mask >> 16;
+       mask = ~mask & 0xfffff000;
+
+       printf("  ... mask: %08x\n", (unsigned int)mask);
+
+       _disable();
+       get_msr(MSR_MTRRDEFTYPE, &def, &rhigh);
+       set_msr(MSR_MTRRDEFTYPE, def & ~MTRRDEF_EN, rhigh);
+
+       set_msr(MSR_MTRRBASE(mtrr), addr | MTRR_WC, 0);
+       set_msr(MSR_MTRRMASK(mtrr), mask | MTRRMASK_VALID, 0);
+
+       set_msr(MSR_MTRRDEFTYPE, def | MTRRDEF_EN, 0);
+       _enable();
+}
+
+static const char *mtrr_names[] = { "N/A", "W C", "N/A", "N/A", "W T", "W P", "W B" };
+
+static const char *mtrr_type_name(int type)
+{
+       if(type < 0 || type >= sizeof mtrr_names / sizeof *mtrr_names) {
+               return mtrr_names[0];
+       }
+       return mtrr_names[type];
+}
+
+static void print_mtrr(void)
+{
+       int i, num_ranges;
+       uint32_t rlow, rhigh, base, mask;
+
+       get_msr(MSR_MTRRCAP, &rlow, &rhigh);
+       num_ranges = rlow & 0xff;
+
+       for(i=0; i<num_ranges; i++) {
+               get_msr(MSR_MTRRBASE(i), &base, &rhigh);
+               get_msr(MSR_MTRRMASK(i), &mask, &rhigh);
+
+               if(mask & MTRRMASK_VALID) {
+                       printf("mtrr%d: base %p, mask %08x type %s\n", i, (void*)(base & 0xfffff000),
+                                       (unsigned int)(mask & 0xfffff000), mtrr_type_name(base & 0xff));
+               } else {
+                       printf("mtrr%d unused (%08x/%08x)\n", i, (unsigned int)base,
+                                       (unsigned int)mask);
+               }
+       }
+       fflush(stdout);
+}
diff --git a/src/dos/gfx.h b/src/dos/gfx.h
new file mode 100644 (file)
index 0000000..4724f41
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef GFX_H_
+#define GFX_H_
+
+#include "inttypes.h"
+
+struct video_mode {
+       uint16_t mode;
+       short xsz, ysz, bpp, pitch;
+       short rbits, gbits, bbits;
+       short rshift, gshift, bshift;
+       uint32_t rmask, gmask, bmask;
+       uint32_t fb_addr;
+       short max_pages;
+       short win_gran, win_gran_shift, win_64k_step;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int init_video(void);
+void cleanup_video(void);
+
+struct video_mode *video_modes(void);
+int num_video_modes(void);
+
+#define VMODE_CURRENT  (-1)
+struct video_mode *get_video_mode(int idx);
+
+int match_video_mode(int xsz, int ysz, int bpp);
+int find_video_mode(int mode);
+
+/* argument is the mode list index [0, nmodes-1] */
+void *set_video_mode(int idx, int nbuf);
+int set_text_mode(void);
+
+void set_palette(int idx, int r, int g, int b);
+
+enum {
+       FLIP_NOW,
+       FLIP_VBLANK
+};
+/* page flip and return pointer to the start of the display area (front buffer) */
+void *page_flip(int vsync);
+extern void (*blit_frame)(void *pixels, int vsync);
+
+#ifdef __WATCOMC__
+void wait_vsync(void);
+#pragma aux wait_vsync = \
+       "mov dx, 0x3da" \
+       "l1:" \
+       "in al, dx" \
+       "and al, 0x8" \
+       "jnz l1" \
+       "l2:" \
+       "in al, dx" \
+       "and al, 0x8" \
+       "jz l2" \
+       modify[al dx];
+#endif
+
+#ifdef __DJGPP__
+#define wait_vsync()  asm volatile ( \
+       "mov $0x3da, %%dx\n\t" \
+       "0:\n\t" \
+       "in %%dx, %%al\n\t" \
+       "and $8, %%al\n\t" \
+       "jnz 0b\n\t" \
+       "0:\n\t" \
+       "in %%dx, %%al\n\t" \
+       "and $8, %%al\n\t" \
+       "jz 0b\n\t" \
+       :::"%eax","%edx")
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GFX_H_ */
diff --git a/src/dos/keyb.c b/src/dos/keyb.c
new file mode 100644 (file)
index 0000000..e35cb7b
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+DOS interrupt-based keyboard driver.
+Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
+
+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 the program. If not, see <http://www.gnu.org/licenses/>
+*/
+#define KEYB_C_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <conio.h>
+#include <dos.h>
+
+#ifdef __WATCOMC__
+#include <i86.h>
+#endif
+#ifdef __DJGPP__
+#include <dpmi.h>
+#include <go32.h>
+#include <pc.h>
+#endif
+
+#include "keyb.h"
+#include "scancode.h"
+#include "inttypes.h"
+#include "dosutil.h"
+
+#define KB_INTR                0x9
+#define KB_PORT                0x60
+
+#define PIC1_CMD_PORT  0x20
+#define OCW2_EOI               (1 << 5)
+
+#ifdef __WATCOMC__
+#define INTERRUPT __interrupt __far
+
+#define DONE_INIT      (prev_handler)
+static void (INTERRUPT *prev_handler)();
+#endif
+
+#ifdef __DJGPP__
+#define INTERRUPT
+
+#define DONE_INIT prev_intr.pm_offset
+static _go32_dpmi_seginfo intr, prev_intr;
+#endif
+
+static void INTERRUPT kbintr();
+
+static int *buffer;
+static int buffer_size, buf_ridx, buf_widx;
+static int last_key;
+
+static unsigned int num_pressed;
+static unsigned char keystate[256];
+
+#define ADVANCE(x)     ((x) = ((x) + 1) % buffer_size)
+
+int kb_init(int bufsz)
+{
+       if(DONE_INIT) {
+               fprintf(stderr, "keyboard driver already initialized!\n");
+               return 0;
+       }
+
+       buffer_size = bufsz;
+       if(buffer_size && !(buffer = malloc(buffer_size * sizeof *buffer))) {
+               fprintf(stderr, "failed to allocate input buffer, continuing without\n");
+               buffer_size = 0;
+       }
+       buf_ridx = buf_widx = 0;
+       last_key = -1;
+
+       memset(keystate, 0, sizeof keystate);
+       num_pressed = 0;
+
+       /* set our interrupt handler */
+       _disable();
+#ifdef __WATCOMC__
+       prev_handler = _dos_getvect(KB_INTR);
+       _dos_setvect(KB_INTR, kbintr);
+#endif
+#ifdef __DJGPP__
+       _go32_dpmi_get_protected_mode_interrupt_vector(KB_INTR, &prev_intr);
+       intr.pm_offset = (intptr_t)kbintr;
+       intr.pm_selector = _go32_my_cs();
+       _go32_dpmi_allocate_iret_wrapper(&intr);
+       _go32_dpmi_set_protected_mode_interrupt_vector(KB_INTR, &intr);
+#endif
+       _enable();
+
+       return 0;
+}
+
+void kb_shutdown(void)
+{
+       if(!DONE_INIT) {
+               return;
+       }
+
+       /* restore the original interrupt handler */
+       _disable();
+#ifdef __WATCOMC__
+       _dos_setvect(KB_INTR, prev_handler);
+#endif
+#ifdef __DJGPP__
+       _go32_dpmi_set_protected_mode_interrupt_vector(KB_INTR, &prev_intr);
+       _go32_dpmi_free_iret_wrapper(&intr);
+#endif
+       _enable();
+
+       free(buffer);
+}
+
+int kb_isdown(int key)
+{
+       switch(key) {
+       case KB_ANY:
+               return num_pressed;
+
+       case KB_ALT:
+               return keystate[KB_LALT] + keystate[KB_RALT];
+
+       case KB_CTRL:
+               return keystate[KB_LCTRL] + keystate[KB_RCTRL];
+       }
+
+       if(isalpha(key)) {
+               key = tolower(key);
+       }
+       return keystate[key];
+}
+
+#ifdef __WATCOMC__
+void halt(void);
+#pragma aux halt = \
+       "sti" \
+       "hlt";
+#endif
+
+#ifdef __DJGPP__
+#define halt() asm volatile("sti\n\thlt\n\t")
+#endif
+
+void kb_wait(void)
+{
+       int key;
+       while((key = kb_getkey()) == -1) {
+#ifdef USE_HLT
+               /* put the processor to sleep while waiting for keypresses, but first
+                * make sure interrupts are enabled, or we'll sleep forever
+                */
+               halt();
+#endif
+       }
+       kb_putback(key);
+}
+
+int kb_getkey(void)
+{
+       int res;
+
+       if(buffer) {
+               if(buf_ridx == buf_widx) {
+                       return -1;
+               }
+               res = buffer[buf_ridx];
+               ADVANCE(buf_ridx);
+       } else {
+               res = last_key;
+               last_key = -1;
+       }
+       return res;
+}
+
+void kb_putback(int key)
+{
+       if(buffer) {
+               /* go back a place */
+               if(--buf_ridx < 0) {
+                       buf_ridx += buffer_size;
+               }
+
+               /* if the write end hasn't caught up with us, go back one place
+                * and put it there, otherwise just overwrite the oldest key which
+                * is right where we were.
+                */
+               if(buf_ridx == buf_widx) {
+                       ADVANCE(buf_ridx);
+               }
+
+               buffer[buf_ridx] = key;
+       } else {
+               last_key = key;
+       }
+}
+
+static void INTERRUPT kbintr()
+{
+       unsigned char code;
+       int key, c, press;
+       static int ext;
+
+       code = inp(KB_PORT);
+
+       if(code == 0xe0) {
+               ext = 1;
+               goto eoi;
+       }
+
+       if(code & 0x80) {
+               press = 0;
+               code &= 0x7f;
+
+               if(num_pressed > 0) {
+                       num_pressed--;
+               }
+       } else {
+               press = 1;
+
+               num_pressed++;
+       }
+
+       if(ext) {
+               key = scantbl_ext[code];
+               c = key;
+               ext = 0;
+       } else {
+               key = scantbl[code];
+               c = (keystate[KB_LSHIFT] | keystate[KB_RSHIFT]) ? scantbl_shift[code] : key;
+       }
+
+       if(press) {
+               /* append to buffer */
+               last_key = c;
+               if(buffer_size > 0) {
+                       buffer[buf_widx] = c;
+                       ADVANCE(buf_widx);
+                       /* if the write end overtook the read end, advance the read end
+                        * too, to discard the oldest keypress from the buffer
+                        */
+                       if(buf_widx == buf_ridx) {
+                               ADVANCE(buf_ridx);
+                       }
+               }
+       }
+
+       /* and update keystate table */
+       keystate[key] = press;
+
+eoi:
+       outp(PIC1_CMD_PORT, OCW2_EOI);  /* send end-of-interrupt */
+}
diff --git a/src/dos/keyb.h b/src/dos/keyb.h
new file mode 100644 (file)
index 0000000..478d17e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+DOS interrupt-based keyboard driver.
+Copyright (C) 2013  John Tsiombikas <nuclear@member.fsf.org>
+
+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 the program. If not, see <http://www.gnu.org/licenses/>
+*/
+#ifndef KEYB_H_
+#define KEYB_H_
+
+#include "app.h"
+
+#define KB_ANY         (-1)
+#define KB_ALT         (-2)
+#define KB_CTRL                (-3)
+#define KB_SHIFT       (-4)
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int kb_init(int bufsz);        /* bufsz can be 0 for no buffered keys */
+void kb_shutdown(void); /* don't forget to call this at the end! */
+
+/* Boolean predicate for testing the current state of a particular key.
+ * You may also pass KB_ANY to test if any key is held down.
+ */
+int kb_isdown(int key);
+
+/* waits for any keypress */
+void kb_wait(void);
+
+/* removes and returns a single key from the input buffer.
+ * If buffering is disabled (initialized with kb_init(0)), then it always
+ * returns the last key pressed.
+ */
+int kb_getkey(void);
+
+void kb_putback(int key);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* KEYB_H_ */
diff --git a/src/dos/logger.c b/src/dos/logger.c
new file mode 100644 (file)
index 0000000..fe308e4
--- /dev/null
@@ -0,0 +1,172 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "logger.h"
+#include "util.h"
+
+#ifdef __WATCOMC__
+#include <i86.h>
+#endif
+#ifdef __DJGPP__
+#include <pc.h>
+#endif
+
+void ser_putchar(int c);
+void ser_puts(const char *s);
+void ser_printf(const char *fmt, ...);
+
+static int setup_serial(int sdev);
+
+static int logfd = -1, orig_fd1 = -1;
+static int log_isfile;
+
+int init_logger(const char *fname)
+{
+       int sdev;
+
+       if(logfd != -1) return -1;
+
+       log_isfile = 0;
+       if(strcasecmp(fname, "CON") == 0) {
+               return 0;
+       }
+
+       if((logfd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) {
+               fprintf(stderr, "init_logger: failed to open %s: %s\n", fname, strerror(errno));
+               return -1;
+       }
+
+       if(sscanf(fname, "COM%d", &sdev) == 1) {
+               setup_serial(sdev - 1);
+       } else {
+               log_isfile = 1;
+       }
+
+       orig_fd1 = dup(1);
+       close(1);
+       close(2);
+       dup(logfd);
+       dup(logfd);
+       return 0;
+}
+
+void stop_logger(void)
+{
+       if(logfd >= 0) {
+               close(logfd);
+               logfd = -1;
+       }
+       if(orig_fd1 >= 0) {
+               close(1);
+               close(2);
+               dup(orig_fd1);
+               dup(orig_fd1);
+               orig_fd1 = -1;
+
+               freopen("CON", "w", stdout);
+               freopen("CON", "w", stderr);
+       }
+}
+
+int print_tail(const char *fname)
+{
+       FILE *fp;
+       char buf[512];
+       long lineoffs[16];
+       int c, nlines;
+
+       if(!log_isfile) return 0;
+
+       printf("demo_abort called. see demo.log for details. Last lines:\n\n");
+
+       if(!(fp = fopen(fname, "rb"))) {
+               return -1;
+       }
+       nlines = 0;
+       lineoffs[nlines++] = 0;
+       while(fgets(buf, sizeof buf, fp)) {
+               lineoffs[nlines & 0xf] = ftell(fp);
+               nlines++;
+       }
+
+       if(nlines > 16) {
+               long offs = lineoffs[nlines & 0xf];
+               fseek(fp, offs, SEEK_SET);
+       }
+       while((c = fgetc(fp)) != -1) {
+               fputc(c, stdout);
+       }
+       fclose(fp);
+       return 0;
+}
+
+#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);
+}
diff --git a/src/dos/logger.h b/src/dos/logger.h
new file mode 100644 (file)
index 0000000..56f6be7
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef LOGGER_H_
+#define LOGGER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int init_logger(const char *fname);
+void stop_logger(void);
+
+int print_tail(const char *fname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LOGGER_H_ */
diff --git a/src/dos/main.c b/src/dos/main.c
new file mode 100644 (file)
index 0000000..b353f33
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+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 <time.h>
+#include "app.h"
+#include "keyb.h"
+#include "gfx.h"
+#include "cdpmi.h"
+#include "mouse.h"
+#include "options.h"
+
+static uint32_t *vmem;
+static int quit, disp_pending;
+
+int main(int argc, char **argv)
+{
+       int i;
+       int vmidx;
+       int mx, my, bnstate, bndiff;
+       static int prev_mx, prev_my, prev_bnstate;
+
+#ifdef __DJGPP__
+       __djgpp_nearptr_enable();
+#endif
+
+       kb_init(32);
+
+       if(!have_mouse()) {
+               fprintf(stderr, "No mouse detected. Make sure the mouse driver is installed\n");
+               return 1;
+       }
+       set_mouse_limits(0, 0, 639, 479);
+       set_mouse(320, 240);
+
+       if(init_video() == -1) {
+               return 1;
+       }
+
+       if((vmidx = match_video_mode(640, 480, 32)) == -1) {
+               return 1;
+       }
+       if(!(vmem = set_video_mode(vmidx, 1))) {
+               return 1;
+       }
+
+       win_width = 640;
+       win_height = 480;
+       win_aspect = (float)win_width / (float)win_height;
+
+       if(app_init() == -1) {
+               goto break_evloop;
+       }
+       disp_pending = 1;
+
+       for(;;) {
+               int key;
+               while((key = kb_getkey()) != -1) {
+                       app_keyboard(key, 1);
+                       if(quit) goto break_evloop;
+               }
+
+               bnstate = read_mouse(&mx, &my);
+               bndiff = bnstate ^ prev_bnstate;
+
+               if(bndiff & 1) app_mouse(0, bnstate & 1, mx, my);
+               if(bndiff & 2) app_mouse(1, bnstate & 2, mx, my);
+               if(bndiff & 4) app_mouse(3, bnstate & 4, mx, my);
+
+               if(disp_pending) {
+                       disp_pending = 0;
+                       app_display();
+               }
+       }
+
+break_evloop:
+       app_shutdown();
+       set_text_mode();
+       cleanup_video();
+       kb_shutdown();
+       return 0;
+}
+
+long app_getmsec(void)
+{
+       return time(0) * 1000;  /* TODO */
+}
+
+void app_redisplay(void)
+{
+       disp_pending = 1;
+}
+
+void app_swap_buffers(void)
+{
+       blit_frame(framebuf, opt.vsync);
+}
+
+void app_quit(void)
+{
+       quit = 1;
+}
+
+void app_resize(int x, int y)
+{
+}
+
+void app_fullscreen(int fs)
+{
+}
+
+void app_vsync(int vsync)
+{
+}
diff --git a/src/dos/mouse.h b/src/dos/mouse.h
new file mode 100644 (file)
index 0000000..b54f6a9
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef MOUSE_H_
+#define MOUSE_H_
+
+enum {
+       MOUSE_LEFT              = 1,
+       MOUSE_RIGHT             = 2,
+       MOUSE_MIDDLE    = 4
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int have_mouse(void);
+void show_mouse(int show);
+int read_mouse(int *xp, int *yp);
+void set_mouse(int x, int y);
+void set_mouse_limits(int xmin, int ymin, int xmax, int ymax);
+void set_mouse_rate(int xrate, int yrate);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MOUSE_H_ */
diff --git a/src/dos/pit8254.h b/src/dos/pit8254.h
new file mode 100644 (file)
index 0000000..4389883
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+colcycle - color cycling image viewer
+Copyright (C) 2016  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+#ifndef PIT8254_H_
+#define PIT8254_H_
+
+/* frequency of the oscillator driving the 8254 timer */
+#define OSC_FREQ_HZ            1193182
+
+/* I/O ports connected to the 8254 */
+#define PORT_DATA0     0x40
+#define PORT_DATA1     0x41
+#define PORT_DATA2     0x42
+#define PORT_CMD       0x43
+
+/* command bits */
+#define CMD_CHAN0                      0
+#define CMD_CHAN1                      (1 << 6)
+#define CMD_CHAN2                      (2 << 6)
+#define CMD_RDBACK                     (3 << 6)
+
+#define CMD_LATCH                      0
+#define CMD_ACCESS_LOW         (1 << 4)
+#define CMD_ACCESS_HIGH                (2 << 4)
+#define CMD_ACCESS_BOTH                (3 << 4)
+
+#define CMD_OP_INT_TERM                0
+#define CMD_OP_ONESHOT         (1 << 1)
+#define CMD_OP_RATE                    (2 << 1)
+#define CMD_OP_SQWAVE          (3 << 1)
+#define CMD_OP_SW_STROBE       (4 << 1)
+#define CMD_OP_HW_STROBE       (5 << 1)
+
+#define CMD_MODE_BIN           0
+#define CMD_MODE_BCD           1
+
+#endif /* PIT8254_H_ */
diff --git a/src/dos/scancode.h b/src/dos/scancode.h
new file mode 100644 (file)
index 0000000..b0e398c
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+colcycle - color cycling image viewer
+Copyright (C) 2016  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <http://www.gnu.org/licenses/>.
+*/
+#ifndef KEYB_C_
+#error "do not include scancode.h anywhere..."
+#endif
+
+/* table with rough translations from set 1 scancodes to ASCII-ish */
+static int scantbl[] = {
+       0, KB_ESC, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b',            /* 0 - e */
+       '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n',                 /* f - 1c */
+       KB_LCTRL, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`',                          /* 1d - 29 */
+       KB_LSHIFT, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', KB_RSHIFT,                   /* 2a - 36 */
+       KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,                     /* 37 - 44 */
+       KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS,      /* 45 - 4e */
+       KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,                                             /* 4d - 58 */
+       0, 0, 0, 0, 0, 0, 0,                                                                                                                    /* 59 - 5f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                                                 /* 60 - 6f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                                                                  /* 70 - 7f */
+};
+
+static int scantbl_shift[] = {
+       0, KB_ESC, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '\b',            /* 0 - e */
+       '\t', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n',                 /* f - 1c */
+       KB_LCTRL, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '"', '~',                           /* 1d - 29 */
+       KB_LSHIFT, '|', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', KB_RSHIFT,                    /* 2a - 36 */
+       KB_NUM_MUL, KB_LALT, ' ', KB_CAPSLK, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10,                     /* 37 - 44 */
+       KB_NUMLK, KB_SCRLK, KB_NUM_7, KB_NUM_8, KB_NUM_9, KB_NUM_MINUS, KB_NUM_4, KB_NUM_5, KB_NUM_6, KB_NUM_PLUS,      /* 45 - 4e */
+       KB_NUM_1, KB_NUM_2, KB_NUM_3, KB_NUM_0, KB_NUM_DOT, KB_SYSRQ, 0, 0, KB_F11, KB_F12,                                             /* 4d - 58 */
+       0, 0, 0, 0, 0, 0, 0,                                                                                                                    /* 59 - 5f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                                                                 /* 60 - 6f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0                                                                  /* 70 - 7f */
+};
+
+
+/* extended scancodes, after the 0xe0 prefix */
+static int scantbl_ext[] = {
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 0 - f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\r', KB_RCTRL, 0, 0,                       /* 10 - 1f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 20 - 2f */
+       0, 0, 0, 0, 0, KB_NUM_MINUS, 0, KB_SYSRQ, KB_RALT, 0, 0, 0, 0, 0, 0, 0,                 /* 30 - 3f */
+       0, 0, 0, 0, 0, 0, 0, KB_HOME, KB_UP, KB_PGUP, 0, KB_LEFT, 0, KB_RIGHT, 0, KB_END,       /* 40 - 4f */
+       KB_DOWN, KB_PGDN, KB_INSERT, KB_DEL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                        /* 50 - 5f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 60 - 6f */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,                 /* 70 - 7f */
+};
+
diff --git a/src/dos/timer.c b/src/dos/timer.c
new file mode 100644 (file)
index 0000000..5492f0b
--- /dev/null
@@ -0,0 +1,182 @@
+/* for sound we use MIDAS, which takes over the PIT and we can't use it
+ * therefore only compile this file for NO_SOUND builds.
+ */
+#ifdef NO_SOUND
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <conio.h>
+#include <dos.h>
+
+#ifdef __WATCOMC__
+#include <i86.h>
+#endif
+
+#ifdef __DJGPP__
+#include <dpmi.h>
+#include <go32.h>
+#include <pc.h>
+#endif
+
+#include "pit8254.h"
+#include "inttypes.h"
+#include "util.h"
+#include "dosutil.h"
+
+#define PIT_TIMER_INTR 8
+#define DOS_TIMER_INTR 0x1c
+
+/* macro to divide and round to the nearest integer */
+#define DIV_ROUND(a, b) \
+       ((a) / (b) + ((a) % (b)) / ((b) / 2))
+
+static void set_timer_reload(int reload_val);
+static void cleanup(void);
+
+#ifdef __WATCOMC__
+#define INTERRUPT      __interrupt __far
+
+static void INTERRUPT dos_timer_intr();
+
+static void (INTERRUPT *prev_timer_intr)();
+#endif
+
+#ifdef __DJGPP__
+#define INTERRUPT
+
+static _go32_dpmi_seginfo intr, prev_intr;
+#endif
+
+static void INTERRUPT timer_irq();
+
+static volatile unsigned long ticks;
+static unsigned long tick_interval, ticks_per_dos_intr;
+static int inum;
+
+void init_timer(int res_hz)
+{
+       _disable();
+
+       if(res_hz > 0) {
+               int reload_val = DIV_ROUND(OSC_FREQ_HZ, res_hz);
+               set_timer_reload(reload_val);
+
+               tick_interval = DIV_ROUND(1000, res_hz);
+               ticks_per_dos_intr = DIV_ROUND(65535L, reload_val);
+
+               inum = PIT_TIMER_INTR;
+#ifdef __WATCOMC__
+               prev_timer_intr = _dos_getvect(inum);
+               _dos_setvect(inum, timer_irq);
+#endif
+#ifdef __DJGPP__
+               _go32_dpmi_get_protected_mode_interrupt_vector(inum, &prev_intr);
+               intr.pm_offset = (intptr_t)timer_irq;
+               intr.pm_selector = _go32_my_cs();
+               _go32_dpmi_allocate_iret_wrapper(&intr);
+               _go32_dpmi_set_protected_mode_interrupt_vector(inum, &intr);
+#endif
+       } else {
+               tick_interval = 55;
+
+               inum = DOS_TIMER_INTR;
+#ifdef __WATCOMC__
+               prev_timer_intr = _dos_getvect(inum);
+               _dos_setvect(inum, dos_timer_intr);
+#endif
+#ifdef __DJGPP__
+               assert(0);
+#endif
+       }
+       _enable();
+
+       atexit(cleanup);
+}
+
+static void cleanup(void)
+{
+       if(!inum) {
+               return; /* init hasn't ran, there's nothing to cleanup */
+       }
+
+       _disable();
+       if(inum == PIT_TIMER_INTR) {
+               /* restore the original timer frequency */
+               set_timer_reload(65535);
+       }
+
+       /* restore the original interrupt handler */
+#ifdef __WATCOMC__
+       _dos_setvect(inum, prev_timer_intr);
+#endif
+#ifdef __DJGPP__
+       _go32_dpmi_set_protected_mode_interrupt_vector(inum, &prev_intr);
+       _go32_dpmi_free_iret_wrapper(&intr);
+#endif
+
+       _enable();
+}
+
+void reset_timer(void)
+{
+       ticks = 0;
+}
+
+unsigned long get_msec(void)
+{
+       return ticks * tick_interval;
+}
+
+void sleep_msec(unsigned long msec)
+{
+       unsigned long wakeup_time = ticks + msec / tick_interval;
+       while(ticks < wakeup_time) {
+#ifdef USE_HLT
+               halt();
+#endif
+       }
+}
+
+static void set_timer_reload(int reload_val)
+{
+       outp(PORT_CMD, CMD_CHAN0 | CMD_ACCESS_BOTH | CMD_OP_SQWAVE);
+       outp(PORT_DATA0, reload_val & 0xff);
+       outp(PORT_DATA0, (reload_val >> 8) & 0xff);
+}
+
+#ifdef __WATCOMC__
+static void INTERRUPT dos_timer_intr()
+{
+       ticks++;
+       _chain_intr(prev_timer_intr);   /* DOES NOT RETURN */
+}
+#endif
+
+/* first PIC command port */
+#define PIC1_CMD       0x20
+/* end of interrupt control word */
+#define OCW2_EOI       (1 << 5)
+
+static void INTERRUPT timer_irq()
+{
+       static unsigned long dos_ticks;
+
+       ticks++;
+
+#ifdef __WATCOMC__
+       if(++dos_ticks >= ticks_per_dos_intr) {
+               /* I suppose the dos irq handler does the EOI so I shouldn't
+                * do it if I am to call the previous function
+                */
+               dos_ticks = 0;
+               _chain_intr(prev_timer_intr);   /* XXX DOES NOT RETURN */
+               return; /* just for clarity */
+       }
+#endif
+
+       /* send EOI to the PIC */
+       outp(PIC1_CMD, OCW2_EOI);
+}
+
+#endif /* NO_SOUND */
diff --git a/src/dos/vbe.c b/src/dos/vbe.c
new file mode 100644 (file)
index 0000000..cb37ca1
--- /dev/null
@@ -0,0 +1,525 @@
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+#include <assert.h>
+#include "vbe.h"
+#include "cdpmi.h"
+
+
+#define FIXPTR(ptr) \
+       do { \
+               uint32_t paddr = (uint32_t)(ptr); \
+               uint16_t pseg = paddr >> 16; \
+               uint16_t poffs = paddr & 0xffff; \
+               if(pseg == seg && poffs < 512) { \
+                       paddr = ((uint32_t)seg << 4) + poffs; \
+               } else { \
+                       paddr = ((uint32_t)pseg << 4) + poffs; \
+               } \
+               (ptr) = (void*)phys_to_virt(paddr); \
+       } while(0)
+
+/* hijack the "VESA" sig field, to pre-cache number of modes */
+#define NMODES(inf) *(uint16_t*)((inf)->sig)
+#define NACCMODES(inf) *(uint16_t*)((inf)->sig + 2)
+
+static int cur_pitch;
+/* TODO update cur_pitch on mode-change and on setscanlen */
+
+
+int vbe_info(struct vbe_info *info)
+{
+       void *lowbuf;
+       uint16_t seg, sel;
+       uint16_t *modeptr;
+       uint32_t offs;
+       struct dpmi_regs regs = {0};
+
+       assert(sizeof *info == 512);
+
+       if(!(seg = dpmi_alloc(sizeof *info / 16, &sel))) {
+               return -1;
+       }
+       lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
+
+       memcpy(lowbuf, "VBE2", 4);
+
+       regs.eax = 0x4f00;
+       regs.es = seg;
+       regs.edi = 0;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               fprintf(stderr, "vbe_get_info (4f00) failed\n");
+               dpmi_free(sel);
+               return -1;
+       }
+
+       memcpy(info, lowbuf, sizeof *info);
+       dpmi_free(sel);
+
+       FIXPTR(info->oem_name);
+       FIXPTR(info->vendor);
+       FIXPTR(info->product);
+       FIXPTR(info->revstr);
+       FIXPTR(info->modes);
+       /* implementations without the accel capability, will use the space taken
+        * by the accel_modes pointer for other data (probably video modes). We
+        * need to check for the capability before "fixing" this pointer, otherwise
+        * we'll shuffle random data.
+        */
+       if(info->caps & VBE_ACCEL) {
+               FIXPTR(info->accel_modes);
+       }
+
+       /* info->modes should be pointing somewhere at the end of the original
+        * low memory buffer. make it point at the same offset in the info
+        * buffer where we copied everything instead.
+        */
+       offs = (char*)info->modes - (char*)lowbuf;
+       if(offs < sizeof *info) {       /* this should always be true */
+               info->modes = (uint16_t*)((char*)info + offs);
+       }
+
+       modeptr = info->modes;
+       while(*modeptr != 0xffff) {
+               if(modeptr - info->modes >= 256) {
+                       modeptr = info->modes;
+                       break;
+               }
+               modeptr++;
+       }
+       NMODES(info) = modeptr - info->modes;
+
+       if(info->caps & VBE_ACCEL) {
+               modeptr = info->accel_modes;
+               while(*modeptr != 0xffff) {
+                       if(modeptr - info->accel_modes >= 256) {
+                               modeptr = info->accel_modes;
+                               break;
+                       }
+                       modeptr++;
+               }
+               NACCMODES(info) = modeptr - info->accel_modes;
+       }
+       return 0;
+}
+
+int vbe_num_modes(struct vbe_info *info)
+{
+       return NMODES(info);
+}
+
+int vbe_mode_info(int mode, struct vbe_mode_info *minf)
+{
+       void *lowbuf;
+       uint16_t seg, sel;
+       struct dpmi_regs regs = {0};
+
+       assert(sizeof *minf == 256);
+       assert(offsetof(struct vbe_mode_info, max_pixel_clock) == 0x3e);
+
+       if(!(seg = dpmi_alloc(sizeof *minf / 16, &sel))) {
+               return -1;
+       }
+       lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
+
+       regs.eax = 0x4f01;
+       regs.ecx = mode;
+       regs.es = seg;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               fprintf(stderr, "vbe_mode_info (4f01) failed\n");
+               dpmi_free(sel);
+               return -1;
+       }
+
+       memcpy(minf, lowbuf, sizeof *minf);
+       dpmi_free(sel);
+       return 0;
+}
+
+void vbe_print_info(FILE *fp, struct vbe_info *vinf)
+{
+       fprintf(fp, "vbe version: %u.%u\n", VBE_VER_MAJOR(vinf->ver), VBE_VER_MINOR(vinf->ver));
+       if(VBE_VER_MAJOR(vinf->ver) >= 2) {
+               fprintf(fp, "%s - %s (%s)\n", vinf->vendor, vinf->product, vinf->revstr);
+               if(vinf->caps & VBE_ACCEL) {
+                       fprintf(fp, "vbe/af %d.%d\n", VBE_VER_MAJOR(vinf->accel_ver), VBE_VER_MINOR(vinf->accel_ver));
+               }
+       } else {
+               fprintf(fp, "oem: %s\n", vinf->oem_name);
+       }
+       fprintf(fp, "video memory: %dkb\n", vinf->vmem_blk * 64);
+
+       if(vinf->caps) {
+               fprintf(fp, "caps:");
+               if(vinf->caps & VBE_8BIT_DAC) fprintf(fp, " dac8");
+               if(vinf->caps & VBE_NON_VGA) fprintf(fp, " non-vga");
+               if(vinf->caps & VBE_DAC_BLANK) fprintf(fp, " dac-blank");
+               if(vinf->caps & VBE_ACCEL) fprintf(fp, " af");
+               if(vinf->caps & VBE_MUSTLOCK) fprintf(fp, " af-lock");
+               if(vinf->caps & VBE_HWCURSOR) fprintf(fp, " af-curs");
+               if(vinf->caps & VBE_HWCLIP) fprintf(fp, " af-clip");
+               if(vinf->caps & VBE_TRANSP_BLT) fprintf(fp, " af-tblt");
+               fprintf(fp, "\n");
+       }
+
+       fprintf(fp, "%d video modes available\n", NMODES(vinf));
+       if(vinf->caps & VBE_ACCEL) {
+               fprintf(fp, "%d accelerated (VBE/AF) modes available\n", NACCMODES(vinf));
+       }
+       fflush(fp);
+}
+
+void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf)
+{
+       fprintf(fp, "%dx%d %dbpp", minf->xres, minf->yres, minf->bpp);
+
+       switch(minf->mem_model) {
+       case VBE_TYPE_DIRECT:
+               fprintf(fp, " (rgb");
+               if(0) {
+       case VBE_TYPE_YUV:
+                       fprintf(fp, " (yuv");
+               }
+               fprintf(fp, " %d%d%d)", minf->rsize, minf->gsize, minf->bsize);
+               break;
+       case VBE_TYPE_PLANAR:
+               fprintf(fp, " (%d planes)", minf->num_planes);
+               break;
+       case VBE_TYPE_PACKED:
+               fprintf(fp, " (packed)");
+               break;
+       case VBE_TYPE_TEXT:
+               fprintf(fp, " (%dx%d cells)", minf->xcharsz, minf->ycharsz);
+               break;
+       case VBE_TYPE_CGA:
+               fprintf(fp, " (CGA)");
+               break;
+       case VBE_TYPE_UNCHAIN:
+               fprintf(fp, " (unchained-%d)", minf->num_planes);
+               break;
+       }
+       fprintf(fp, " %dpg", minf->num_img_pages);
+
+       if(minf->attr & VBE_ATTR_LFB) {
+               fprintf(fp, " lfb@%lx", (unsigned long)minf->fb_addr);
+       } else {
+               fprintf(fp, " (%dk gran)", (int)minf->win_gran);
+       }
+
+       fprintf(fp, " [");
+       if(minf->attr & VBE_ATTR_AVAIL) fprintf(fp, " avail");
+       if(minf->attr & VBE_ATTR_OPTINFO) fprintf(fp, " opt");
+       if(minf->attr & VBE_ATTR_TTY) fprintf(fp, " tty");
+       if(minf->attr & VBE_ATTR_COLOR) fprintf(fp, " color");
+       if(minf->attr & VBE_ATTR_GFX) fprintf(fp, " gfx");
+       if(minf->attr & VBE_ATTR_NOTVGA) fprintf(fp, " non-vga");
+       if(minf->attr & VBE_ATTR_BANKED) fprintf(fp, " banked");
+       if(minf->attr & VBE_ATTR_LFB) fprintf(fp, " lfb");
+       if(minf->attr & VBE_ATTR_DBLSCAN) fprintf(fp, " dblscan");
+       if(minf->attr & VBE_ATTR_ILACE) fprintf(fp, " ilace");
+       if(minf->attr & VBE_ATTR_TRIPLEBUF) fprintf(fp, " trplbuf");
+       if(minf->attr & VBE_ATTR_STEREO) fprintf(fp, " stereo");
+       if(minf->attr & VBE_ATTR_STEREO_2FB) fprintf(fp, " stdual");
+       fprintf(fp, " ]\n");
+       fflush(fp);
+}
+
+int vbe_setmode(uint16_t mode)
+{
+       struct dpmi_regs regs = {0};
+
+       regs.eax = 0x4f02;
+       regs.ebx = mode;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+
+       cur_pitch = vbe_getpitch();
+       return 0;
+}
+
+int vbe_setmode_crtc(uint16_t mode, struct vbe_crtc_info *crtc)
+{
+       void *lowbuf;
+       uint16_t seg, sel;
+       struct dpmi_regs regs = {0};
+
+       assert(sizeof *crtc == 59);
+
+       if(!(seg = dpmi_alloc((sizeof *crtc + 15) / 16, &sel))) {
+               return -1;
+       }
+       lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
+
+       memcpy(lowbuf, crtc, sizeof *crtc);
+
+       regs.eax = 0x4f02;
+       regs.ebx = mode;
+       regs.es = seg;
+       dpmi_int(0x10, &regs);
+
+       dpmi_free(sel);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+
+       cur_pitch = vbe_getpitch();
+       return 0;
+}
+
+int vbe_getmode(void)
+{
+       struct dpmi_regs regs = {0};
+
+       regs.eax = 0x4f03;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return regs.ebx & 0xffff;
+}
+
+int vbe_state_size(unsigned int flags)
+{
+       struct dpmi_regs regs = {0};
+
+       regs.eax = 0x4f04;
+       regs.edx = 0;
+       regs.ecx = flags;
+       dpmi_int(0x10, &regs);
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return (regs.ebx & 0xffff) * 64;
+}
+
+int vbe_save(void *stbuf, int sz, unsigned int flags)
+{
+       void *lowbuf;
+       uint16_t seg, sel;
+       struct dpmi_regs regs = {0};
+
+       if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) {
+               return -1;
+       }
+       lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
+
+       regs.eax = 0x4f04;
+       regs.edx = 1;   /* save */
+       regs.ecx = flags;
+       regs.es = seg;
+       dpmi_int(0x10, &regs);
+       if((regs.eax & 0xffff) != 0x4f) {
+               dpmi_free(sel);
+               return -1;
+       }
+
+       memcpy(stbuf, lowbuf, sz);
+       dpmi_free(sel);
+       return 0;
+}
+
+int vbe_restore(void *stbuf, int sz, unsigned int flags)
+{
+       void *lowbuf;
+       uint16_t seg, sel;
+       struct dpmi_regs regs = {0};
+
+       if(!(seg = dpmi_alloc((sz + 15) / 16, &sel))) {
+               return -1;
+       }
+       lowbuf = (void*)phys_to_virt((uint32_t)seg << 4);
+
+       memcpy(lowbuf, stbuf, sz);
+
+       regs.eax = 0x4f04;
+       regs.edx = 2;   /* restore */
+       regs.ecx = flags;
+       regs.es = seg;
+       dpmi_int(0x10, &regs);
+       dpmi_free(sel);
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return 0;
+}
+
+int vbe_setwin(int wid, int pos)
+{
+       struct dpmi_regs regs;
+
+       if(wid & ~1) return -1;
+
+       regs.eax = 0x4f05;
+       regs.ebx = wid;
+       regs.edx = pos;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return 0;
+}
+
+int vbe_getwin(int wid)
+{
+       struct dpmi_regs regs;
+
+       if(wid & ~1) return -1;
+
+       regs.eax = 0x4f05;
+       regs.ebx = wid;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+
+       return regs.edx & 0xffff;
+}
+
+int vbe_setscanlen(int len_pix)
+{
+       struct dpmi_regs regs;
+
+       regs.eax = 0x4f06;
+       regs.ebx = 0;   /* set scanline length in pixels */
+       regs.ecx = len_pix;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+
+       cur_pitch = vbe_getpitch();
+       return regs.ecx;
+}
+
+int vbe_getscanlen(void)
+{
+       struct dpmi_regs regs;
+
+       regs.eax = 0x4f06;
+       regs.ebx = 1;   /* get scanline length */
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return regs.ecx;
+}
+
+int vbe_getpitch(void)
+{
+       struct dpmi_regs regs;
+
+       regs.eax = 0x4f06;
+       regs.ebx = 1;   /* get scanline length */
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return regs.ebx;
+}
+
+int vbe_scanline_info(struct vbe_scanline_info *sinf)
+{
+       struct dpmi_regs regs;
+
+       regs.eax = 0x4f06;
+       regs.ebx = 1;   /* get scanline length */
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+
+       sinf->size = regs.ebx & 0xffff;
+       sinf->num_pixels = regs.ecx & 0xffff;
+       sinf->max_scanlines = regs.edx & 0xffff;
+       return 0;
+}
+
+enum {
+       SDISP_SET                       = 0x00,
+       SDISP_GET                       = 0x01,
+       SDISP_ALTSET            = 0x02,
+       SDISP_SET_STEREO        = 0x03,
+       SDISP_GETSCHED          = 0x04,
+       SDISP_STEREO_ON         = 0x05,
+       SDISP_STEREO_OFF        = 0x06,
+       SDISP_SET_VBLANK        = 0x80,
+       SDISP_ALTSET_VBLANK     = 0x82,
+       SDISP_SET_STEREO_VBLANK = 0x83
+};
+
+int vbe_setdisp(int x, int y, int when)
+{
+       struct dpmi_regs regs;
+
+       regs.eax = 0x4f07;
+       regs.ebx = (when == VBE_SWAP_VBLANK) ? SDISP_SET_VBLANK : SDISP_SET;
+       regs.ecx = x;
+       regs.edx = y;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return 0;
+}
+
+int vbe_swap(uint32_t voffs, int when)
+{
+       struct dpmi_regs regs;
+       int op;
+
+       switch(when) {
+       case VBE_SWAP_ASYNC:
+               op = SDISP_ALTSET;
+               break;
+
+       case VBE_SWAP_NOW:
+               /* XXX is this the only way? */
+               return vbe_setdisp(voffs % cur_pitch, voffs / cur_pitch, when);
+
+       case VBE_SWAP_VBLANK:
+       default:
+               op = SDISP_ALTSET_VBLANK;
+               break;
+       }
+
+
+       regs.eax = 0x4f07;
+       regs.ebx = op;
+       regs.ecx = voffs;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return -1;
+       }
+       return 0;
+}
+
+int vbe_swap_pending(void)
+{
+       struct dpmi_regs regs;
+
+       regs.eax = 0x4f07;
+       regs.ebx = SDISP_GETSCHED;
+       dpmi_int(0x10, &regs);
+
+       if((regs.eax & 0xffff) != 0x4f) {
+               return 0;
+       }
+       return regs.ecx;
+}
diff --git a/src/dos/vbe.h b/src/dos/vbe.h
new file mode 100644 (file)
index 0000000..4193d68
--- /dev/null
@@ -0,0 +1,242 @@
+#ifndef VBE_H_
+#define VBE_H_
+
+#include <stdio.h>
+#include "sizeint.h"
+#include "util.h"
+
+#pragma pack (push, 1)
+struct vbe_info {
+       char sig[4];
+       uint16_t ver;
+       char *oem_name;
+       uint32_t caps;
+       uint16_t *modes;
+       uint16_t vmem_blk;      /* video memory size in 64k blocks */
+       uint16_t oem_ver;
+       char *vendor;
+       char *product;
+       char *revstr;
+       uint16_t accel_ver;
+       uint16_t *accel_modes;
+       char reserved[216];
+       char oem_data[256];
+} PACKED;
+
+struct vbe_mode_info {
+       uint16_t attr;
+       uint8_t wina_attr, winb_attr;
+       uint16_t win_gran, win_size;
+       uint16_t wina_seg, winb_seg;
+       uint32_t win_func;
+       uint16_t scanline_bytes;
+
+       /* VBE 1.2 and above */
+       uint16_t xres, yres;
+       uint8_t xcharsz, ycharsz;
+       uint8_t num_planes;
+       uint8_t bpp;
+       uint8_t num_banks;
+       uint8_t mem_model;
+       uint8_t bank_size;              /* bank size in KB */
+       uint8_t num_img_pages;
+       uint8_t reserved1;
+
+       /* direct color fields */
+       uint8_t rsize, rpos;
+       uint8_t gsize, gpos;
+       uint8_t bsize, bpos;
+       uint8_t xsize, xpos;
+       uint8_t cmode_info;             /* direct color mode attributes */
+
+       /* VBE 2.0 and above */
+       uint32_t fb_addr;               /* physical address of the linear framebuffer */
+       uint32_t os_addr;               /* phys. address of off-screen memory */
+       uint16_t os_size;               /* size in KB of off-screen memory */
+
+       /* VBE 3.0 and above */
+       uint16_t lfb_scanline_bytes;
+       uint8_t banked_num_img_pages;
+       uint8_t lfb_num_img_pages;
+       uint8_t lfb_rsize, lfb_rpos;
+       uint8_t lfb_gsize, lfb_gpos;
+       uint8_t lfb_bsize, lfb_bpos;
+       uint8_t lfb_xsize, lfb_xpos;
+       uint32_t max_pixel_clock;
+
+       char reserved2[190];
+} PACKED;
+
+struct vbe_crtc_info {
+       uint16_t htotal, hsync_start, hsync_end;
+       uint16_t vtotal, vsync_start, vsync_end;
+       uint8_t flags;
+       uint32_t pixel_clock;
+       uint16_t rate_centihz;  /* refresh rate in 1/100 hz (pck / (htotal * vtotal)) */
+       char reserved[40];
+} PACKED;
+#pragma pack (pop)
+
+/* returned by vbe_scanline_info() */
+struct vbe_scanline_info {
+       int size;
+       int num_pixels;
+       int max_scanlines;
+};
+
+enum {
+       VBE_8BIT_DAC    = 0x01,
+       VBE_NON_VGA             = 0x02,
+       VBE_DAC_BLANK   = 0x04,
+       VBE_STEREO              = 0x08, /* ? */
+       VBE_ACCEL               = 0x08,
+       VBE_STEREO_VESA = 0x10, /* ? */
+       VBE_MUSTLOCK    = 0x10,
+       VBE_HWCURSOR    = 0x20,
+       VBE_HWCLIP              = 0x40,
+       VBE_TRANSP_BLT  = 0x80
+};
+
+#define VBE_VER_MAJOR(v)       (((v) >> 8) & 0xff)
+#define VBE_VER_MINOR(v)       ((v) & 0xff)
+
+/* VBE mode attribute flags (vbe_mode_info.attr) */
+enum {
+       VBE_ATTR_AVAIL          = 0x0001,
+       VBE_ATTR_OPTINFO        = 0x0002,
+       VBE_ATTR_TTY            = 0x0004,
+       VBE_ATTR_COLOR          = 0x0008,
+       VBE_ATTR_GFX            = 0x0010,
+       /* VBE 2.0 */
+       VBE_ATTR_NOTVGA         = 0x0020,
+       VBE_ATTR_BANKED         = 0x0040,
+       VBE_ATTR_LFB            = 0x0080,
+       VBE_ATTR_DBLSCAN        = 0x0100,
+       /* VBE 3.0 */
+       VBE_ATTR_ILACE          = 0x0200,       /* ! */
+       VBE_ATTR_TRIPLEBUF      = 0x0400,
+       VBE_ATTR_STEREO         = 0x0800,
+       VBE_ATTR_STEREO_2FB     = 0x1000,
+       /* VBE/AF */
+       VBE_ATTR_MUSTLOCK       = 0x0200        /* ! */
+};
+
+/* VBE memory model type (vbe_mode_info.mem_model) */
+enum {
+       VBE_TYPE_TEXT,
+       VBE_TYPE_CGA,
+       VBE_TYPE_HERCULES,
+       VBE_TYPE_PLANAR,
+       VBE_TYPE_PACKED,
+       VBE_TYPE_UNCHAIN,
+       VBE_TYPE_DIRECT,
+       VBE_TYPE_YUV
+};
+
+/* VBE window attribute (vbe_mode_info.win(a|b)_attr) */
+enum {
+       VBE_WIN_AVAIL   = 0x01,
+       VBE_WIN_RD              = 0x02,
+       VBE_WIN_WR              = 0x04
+};
+
+/* mode number flags */
+enum {
+       VBE_MODE_RATE           = 0x0800,       /* VBE 3.0+ user-specified refresh rate */
+       VBE_MODE_ACCEL          = 0x2000,       /* VBE/AF */
+       VBE_MODE_LFB            = 0x4000,       /* VBE 2.0+ */
+       VBE_MODE_PRESERVE       = 0x8000
+};
+
+/* standard mode numbers */
+enum {
+       VBE_640X400_8BPP        = 0x100,
+       VBE_640X480_8BPP        = 0x101,
+       VBE_800X600_4BPP        = 0x102,
+       VBE_800X600_8BPP        = 0x103,
+       VBE_1024X768_4BPP       = 0x104,
+       VBE_1024X768_8BPP       = 0x105,
+       VBE_1280X1024_4BPP      = 0x106,
+       VBE_1280X1024_8BPP      = 0x107,
+       VBE_80X60_TEXT          = 0x108,
+       VBE_132X25_TEXT         = 0x109,
+       VBE_132X43_TEXT         = 0x10a,
+       VBE_132X50_TEXT         = 0x10b,
+       VBE_132X60_TEXT         = 0x10c,
+       /* VBE 1.2 */
+       VBE_320X200_15BPP       = 0x10d,
+       VBE_320X200_16BPP       = 0x10e,
+       VBE_320X200_24BPP       = 0x10f,
+       VBE_640X480_15BPP       = 0x110,
+       VBE_640X480_16BPP       = 0x111,
+       VBE_640X480_24BPP       = 0x112,
+       VBE_800X600_15BPP       = 0x113,
+       VBE_800X600_16BPP       = 0x114,
+       VBE_800X600_24BPP       = 0x115,
+       VBE_1024X768_15BPP      = 0x116,
+       VBE_1024X768_16BPP      = 0x117,
+       VBE_1024X768_24BPP      = 0x118,
+       VBE_1280X1024_15BPP     = 0x119,
+       VBE_1280X1024_16BPP     = 0x11a,
+       VBE_1280X1024_24BPP     = 0x11b,
+       /* VBE 2.0 */
+       VBE_1600X1200_8BPP      = 0x120,
+       VBE_1600X1200_15BPP     = 0x121,
+       VBE_1600X1200_16BPP     = 0x122,
+
+       VBE_VMEM_MODE           = 0x81ff
+};
+
+/* VBE CRTC flags (vbe_crtc_info.flags) */
+enum {
+       VBE_CRTC_DBLSCAN        = 0x01,
+       VBE_CRTC_ILACE          = 0x02,
+       VBE_CRTC_HSYNC_NEG      = 0x04,
+       VBE_CRTC_VSYNC_NEG      = 0x08
+};
+
+enum {
+       VBE_STATE_CTRLHW        = 0x01,
+       VBE_STATE_BIOS          = 0x02,
+       VBE_STATE_DAC           = 0x04,
+       VBE_STATE_REGS          = 0x08,
+
+       VBE_STATE_ALL           = 0xffff
+};
+
+enum {
+       VBE_SWAP_NOW,
+       VBE_SWAP_VBLANK,
+       VBE_SWAP_ASYNC  /* schedule swap and return (triple-buffering) */
+};
+
+int vbe_info(struct vbe_info *info);
+int vbe_num_modes(struct vbe_info *info);
+int vbe_mode_info(int mode, struct vbe_mode_info *minf);
+
+void vbe_print_info(FILE *fp, struct vbe_info *info);
+void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf);
+
+int vbe_setmode(uint16_t mode);
+int vbe_setmode_crtc(uint16_t mode, struct vbe_crtc_info *crtc);
+int vbe_getmode(void);
+
+int vbe_state_size(unsigned int flags);
+int vbe_save(void *stbuf, int sz, unsigned int flags);
+int vbe_restore(void *stbuf, int sz, unsigned int flags);
+
+int vbe_setwin(int wid, int pos);
+int vbe_getwin(int wid);
+
+/* returns the actual length in pixels, which might not be what was requested */
+int vbe_setscanlen(int len_pix);
+int vbe_getscanlen(void);
+int vbe_getpitch(void);
+int vbe_scanline_info(struct vbe_scanline_info *sinf);
+
+int vbe_setdisp(int x, int y, int when);
+int vbe_swap(uint32_t voffs, int when);
+int vbe_swap_pending(void);    /* 0: not pending (done) or error, 1: pending swap */
+/* TODO add stereo swap */
+
+#endif /* VBE_H_ */
diff --git a/src/dos/vga.c b/src/dos/vga.c
new file mode 100644 (file)
index 0000000..f2f8142
--- /dev/null
@@ -0,0 +1,71 @@
+#include <string.h>
+#include "vga.h"
+#include "vgaregs.h"
+#include "cdpmi.h"
+#include "dosutil.h"
+
+static void crtc_write(int reg, unsigned char val);
+static unsigned char crtc_read(int reg);
+
+int vga_setmode(int mode)
+{
+       struct dpmi_regs regs = {0};
+
+       regs.eax = mode;        /* func 00 | mode */
+       dpmi_int(0x10, &regs);
+       return 0;
+}
+
+static unsigned short crtc_modex_regs[] = {
+       0x0d06, /* vertical total */
+       0x3e07, /* vcount overflow bit */
+       0x4109, /* double-scan */
+       0xea10, /* vsync start */
+       0xac11, /* vsync end & protect */
+       0xdf12, /* vertical visible */
+       0x0014, /* no dword mode */
+       0xe715, /* vblank start */
+       0x0616, /* vblank end */
+       0xe317, /* byte mode */
+       0
+};
+
+int vga_setmodex(void)
+{
+       int i;
+       unsigned char val;
+
+       vga_setmode(0x13);
+
+       /* disable chain-4 (C4=0, O/E=1 (sequential), EM=1 (extmem), A/G=0 (gfx) */
+       outpw(VGA_SC_ADDR_PORT, VGA_SC_MEMMODE_REG | 0x0600);
+       /* pull reset low */
+       outpw(VGA_SC_ADDR_PORT, VGA_SC_RESET_REG | 0x0100);
+       /* 25mhz dot clock, 60hz scan */
+       outp(VGA_MISC_PORT, VGA_MISC_480 | VGA_MISC_PG1 | VGA_MISC_CLK25 |
+                       VGA_MISC_CPUEN | VGA_MISC_COLOR);
+       /* return reset high */
+       outpw(VGA_SC_ADDR_PORT, VGA_SC_RESET_REG | 0x0300);
+
+       /* disable CRTC write-protect */
+       crtc_write(CRTC_VRETEND_REG, crtc_read(CRTC_VRETEND_REG) & ~CRTC_VRETEND_PR);
+       /* change CRTC registers */
+       for(i=0; crtc_modex_regs[i]; i++) {
+               outpw(VGA_CRTC_PORT, crtc_modex_regs[i]);
+       }
+
+       vga_planemask(0xf);
+       memset(VGA_FBADDR, 3, 320 * 240 / 4);
+       return 0;
+}
+
+static void crtc_write(int reg, unsigned char val)
+{
+       outpw(VGA_CRTC_ADDR_PORT, reg | ((unsigned int)val << 8));
+}
+
+static unsigned char crtc_read(int reg)
+{
+       outp(VGA_CRTC_ADDR_PORT, reg);
+       return inp(VGA_CRTC_DATA_PORT);
+}
diff --git a/src/dos/vga.h b/src/dos/vga.h
new file mode 100644 (file)
index 0000000..d8a341c
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef VGA_H_
+#define VGA_H_
+
+#include "inttypes.h"
+#include "dosutil.h"
+#include "cdpmi.h"
+#include "vgaregs.h"
+
+#define VGA_FBADDR     ((void*)phys_to_virt(0xa0000))
+
+int vga_setmode(int mode);
+int vga_setmodex(void);
+
+#define vga_planemask(mask)            vga_sc_write(VGA_SC_MAPMASK_REG, mask)
+
+#ifdef __WATCOMC__
+void vga_setpal(int16_t idx, uint8_t r, uint8_t g, uint8_t b);
+#pragma aux vga_setpal = \
+       "test ax, 0x8000" \
+       "jnz skip_dacaddr" \
+       "mov dx, 0x3c8" \
+       "out dx, al" \
+       "skip_dacaddr:" \
+       "mov dx, 0x3c9" \
+       "mov al, bl" \
+       "shr al, 2" \
+       "out dx, al" \
+       "mov al, bh" \
+       "shr al, 2" \
+       "out dx, al" \
+       "mov al, cl" \
+       "shr al, 2" \
+       "out dx, al" \
+       parm[ax][bl][bh][cl] \
+       modify[dx];
+#endif /* __WATCOMC__ */
+
+#define vga_sc_write(reg, data) \
+       outpw(VGA_SC_ADDR_PORT, (uint16_t)(reg) | ((uint16_t)(data) << 8))
+#define vga_sc_read(reg) \
+       (outp(VGA_SC_ADDR_PORT, reg), inp(VGA_SC_DATA_PORT))
+#define vga_crtc_write(reg, data) \
+       outpw(VGA_CRTC_PORT, (uint16_t)(reg) | ((uint16_t)(data) << 8))
+#define vga_crtc_read(reg) \
+       (outp(VGA_CRTC_ADDR_PORT, reg), inp(VGA_CRTC_DATA_PORT))
+#define vga_crtc_wrmask(reg, data, mask) \
+       outp(VGA_CRTC_DATA_PORT, (crtc_read(reg) & ~(mask)) | (data))
+
+#endif /* VGA_H_ */
diff --git a/src/dos/vgaregs.h b/src/dos/vgaregs.h
new file mode 100644 (file)
index 0000000..15c4090
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef VGAREGS_H_
+#define VGAREGS_H_
+
+/* ---- VGA registers ---- */
+#define VGA_AC_PORT            0x3c0
+#define VGA_AC_RD_PORT         0x3c1
+#define VGA_SC_ADDR_PORT       0x3c4
+#define VGA_SC_DATA_PORT       0x3c5
+#define VGA_GC_ADDR_PORT       0x3ce
+#define VGA_GC_DATA_PORT       0x3cf
+#define VGA_CRTC_PORT          0x3d4
+#define VGA_CRTC_ADDR_PORT     0x3d4
+#define VGA_CRTC_DATA_PORT     0x3d5
+#define VGA_STAT0_PORT         0x3c2
+#define VGA_STAT1_PORT         0x3da
+#define VGA_MISC_PORT          0x3c2
+#define VGA_MISC_RD_PORT       0x3cc
+
+/* attribute controller registers */
+#define VGA_AC_EN              0x20
+#define VGA_AC_MODE_REG                0x10
+
+/* sequence controller registers */
+#define VGA_SC_RESET_REG       0x00
+#define VGA_SC_CLOCK_REG       0x01
+#define VGA_SC_MAPMASK_REG     0x02
+#define VGA_SC_MEMMODE_REG     0x04
+
+/* graphics controller registers */
+#define VGA_GC_SR_REG          0x00
+#define VGA_GC_SREN_REG                0x01
+#define VGA_GC_ROT_REG         0x03
+#define VGA_GC_MODE_REG                0x05
+#define VGA_GC_MASK_REG                0x08
+
+/* attribute controller mode register (10h) bits */
+#define VGA_AC_MODE_GFX                0x01
+#define VGA_AC_MODE_MONO       0x02
+#define VGA_AC_MODE_LGE                0x04
+#define VGA_AC_MODE_BLINK      0x08
+#define VGA_AC_MODE_PIXPAN     0x20
+#define VGA_AC_MODE_8BIT       0x40
+
+/* misc register bits */
+#define VGA_MISC_COLOR         0x01
+#define VGA_MISC_CPUEN         0x02
+#define VGA_MISC_CLK25         0
+#define VGA_MISC_CLK28         0x04
+#define VGA_MISC_PG1           0x20
+#define VGA_MISC_400           0
+#define VGA_MISC_350           0x40
+#define VGA_MISC_480           0xc0
+
+
+/* CRTC registers */
+#define CRTC_HTOTAL_REG                0x00
+#define CRTC_HEND_REG          0x01
+#define CRTC_HBLSTART_REG      0x02
+#define CRTC_HBLEND_REG                0x03
+#define CRTC_HRETSTART_REG     0x04
+#define CRTC_HRETEND_REG       0x05
+#define CRTC_VTOTAL_REG                0x06
+#define CRTC_OVF_REG           0x07
+#define CRTC_PRESET_REG                0x08
+#define CRTC_MAXSCAN_REG       0x09
+#define CRTC_CURSTART_REG      0x0a
+#define CRTC_CUREND_REG                0x0b
+#define CRTC_STARTH_REG                0x0c
+#define CRTC_STARTL_REG                0x0d
+#define CRTC_CURH_REG          0x0e
+#define CRTC_CURL_REG          0x0f
+#define CRTC_VRETSTART_REG     0x10
+#define CRTC_VRETEND_REG       0x11
+#define CRTC_VEND_REG          0x12
+#define CRTC_OFFSET_REG                0x13
+#define CRTC_UL_REG            0x14
+#define CRTC_VBLSTART_REG      0x15
+#define CRTC_VBLEND_REG                0x16
+#define CRTC_MODE_REG          0x17
+#define CRTC_LCMP_REG          0x18
+
+/* CRTC register bits */
+#define CRTC_VRETEND_PR                0x80
+
+#endif /* VGAREGS_H_ */
diff --git a/src/dos/watdpmi.c b/src/dos/watdpmi.c
new file mode 100644 (file)
index 0000000..04d7b94
--- /dev/null
@@ -0,0 +1,59 @@
+#ifdef __WATCOMC__
+#include "cdpmi.h"
+
+void dpmi_real_int(int inum, struct dpmi_real_regs *regs)
+{
+       unsigned char int_num = (unsigned char)inum;
+       __asm {
+               mov eax, 0x300
+               mov edi, regs
+               mov bl, int_num
+               mov bh, 0
+               xor ecx, ecx
+               int 0x31
+       }
+}
+
+void *dpmi_mmap(uint32_t phys_addr, unsigned int size)
+{
+       uint16_t mem_high, mem_low;
+       uint16_t phys_high = phys_addr >> 16;
+       uint16_t phys_low = phys_addr & 0xffff;
+       uint16_t size_high = size >> 16;
+       uint16_t size_low = size & 0xffff;
+       unsigned int err, res = 0;
+
+       __asm {
+               mov eax, 0x800
+               mov bx, phys_high
+               mov cx, phys_low
+               mov si, size_high
+               mov di, size_low
+               int 0x31
+               add res, 1
+               mov err, eax
+               mov mem_high, bx
+               mov mem_low, cx
+       }
+
+       if(res == 2) {
+               return 0;
+       }
+       return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low));
+}
+
+void dpmi_munmap(void *addr)
+{
+       uint16_t mem_high = (uint32_t)addr >> 16;
+       uint16_t mem_low = (uint16_t)addr;
+
+       __asm {
+               mov eax, 0x801
+               mov bx, mem_high
+               mov cx, mem_low
+               int 0x31
+       }
+}
+#else
+int stop_gcc_crying_about_empty_translation_units = 0;
+#endif /* __WATCOM__ */
index a30d56c..c307f8a 100644 (file)
@@ -187,7 +187,7 @@ void gaw_rotate(float deg, float x, float y, float z)
 {
        static float m[16];
 
-       float angle = M_PI * deg / 180.0f;
+       float angle = CGM_PI * deg / 180.0f;
        float sina = sin(angle);
        float cosa = cos(angle);
        float one_minus_cosa = 1.0f - cosa;
@@ -266,7 +266,7 @@ void gaw_perspective(float vfov_deg, float aspect, float znear, float zfar)
 {
        static float m[16];
 
-       float vfov = M_PI * vfov_deg / 180.0f;
+       float vfov = CGM_PI * vfov_deg / 180.0f;
        float s = 1.0f / tan(vfov * 0.5f);
        float range = znear - zfar;
 
index 11d462b..d016291 100644 (file)
@@ -130,6 +130,15 @@ void gaw_swtnl_drawprim(int prim, struct vertex *v, int vnum);
 
 
 #if defined(__i386__) || defined(__386__) || defined(MSDOS)
+
+#ifndef INLINE
+#if (__STDC_VERSION__ >= 199901) || defined(__GNUC__)
+#define INLINE inline
+#else
+#define INLINE __inline
+#endif
+#endif
+
 /* fast conversion of double -> 32bit int
  * for details see:
  *  - http://chrishecker.com/images/f/fb/Gdmfp.pdf
index b9e394f..9804913 100644 (file)
@@ -5,8 +5,8 @@
 
 /* -------- sphere -------- */
 
-#define SURAD(u)       ((u) * 2.0 * M_PI)
-#define SVRAD(v)       ((v) * M_PI)
+#define SURAD(u)       ((u) * 2.0 * CGM_PI)
+#define SVRAD(v)       ((v) * CGM_PI)
 
 static void sphvec(cgm_vec3 *v, float theta, float phi)
 {
@@ -47,19 +47,19 @@ void gen_sphere(struct cmesh *mesh, float rad, int usub, int vsub, float urange,
 
        u = 0.0;
        for(i=0; i<uverts; i++) {
-               theta = u * 2.0 * M_PI;
+               theta = u * 2.0 * CGM_PI;
 
                v = 0.0;
                for(j=0; j<vverts; j++) {
-                       phi = v * M_PI;
+                       phi = v * CGM_PI;
 
                        sphvec(&pos, theta, phi);
 
                        *narr++ = pos;
                        cgm_vscale(&pos, rad);
                        *varr++ = pos;
-                       sphvec(&v0, theta - 0.1f, (float)M_PI / 2.0f);
-                       sphvec(&v1, theta + 0.1f, (float)M_PI / 2.0f);
+                       sphvec(&v0, theta - 0.1f, (float)CGM_PI / 2.0f);
+                       sphvec(&v1, theta + 0.1f, (float)CGM_PI / 2.0f);
                        cgm_vsub(&v1, &v0);
                        cgm_vnormalize(&v1);
                        *tarr++ = v1;
@@ -196,14 +196,14 @@ void gen_geosphere(struct cmesh *mesh, float rad, int subdiv, int hemi)
                theta = atan2(verts[i].z, verts[i].x);
                phi = acos(verts[i].y);
 
-               sphvec(&v0, theta - 0.1f, (float)M_PI / 2.0f);
-               sphvec(&v1, theta + 0.1f, (float)M_PI / 2.0f);
+               sphvec(&v0, theta - 0.1f, (float)CGM_PI / 2.0f);
+               sphvec(&v1, theta + 0.1f, (float)CGM_PI / 2.0f);
                cgm_vsub(&v1, &v0);
                cgm_vnormalize(&v1);
                *tarr++ = v1;
 
-               uvarr->x = 0.5 * theta / M_PI + 0.5;
-               uvarr->y = phi / M_PI;
+               uvarr->x = 0.5 * theta / CGM_PI + 0.5;
+               uvarr->y = phi / CGM_PI;
                uvarr++;
        }
 }
@@ -254,11 +254,11 @@ void gen_torus(struct cmesh *mesh, float mainrad, float ringrad, int usub, int v
 
        u = 0.0;
        for(i=0; i<uverts; i++) {
-               theta = u * 2.0 * M_PI;
+               theta = u * 2.0 * CGM_PI;
 
                v = 0.0;
                for(j=0; j<vverts; j++) {
-                       phi = v * 2.0 * M_PI;
+                       phi = v * 2.0 * CGM_PI;
 
                        torusvec(&pos, theta, phi, mainrad, ringrad);
                        torusvec(&cent, theta, phi, mainrad, 0.0);
@@ -675,11 +675,11 @@ void gen_box(struct cmesh *mesh, float xsz, float ysz, float zsz, int usub, int
 {
        static const float face_angles[][2] = {
                {0, 0},
-               {M_PI / 2.0, 0},
-               {M_PI, 0},
-               {3.0 * M_PI / 2.0, 0},
-               {0, M_PI / 2.0},
-               {0, -M_PI / 2.0}
+               {CGM_PI / 2.0, 0},
+               {CGM_PI, 0},
+               {3.0 * CGM_PI / 2.0, 0},
+               {0, CGM_PI / 2.0},
+               {0, -CGM_PI / 2.0}
        };
        int i;
        float xform[16], scale[16], idmat[16];
@@ -707,11 +707,11 @@ void gen_box(struct cmesh *mesh, float xsz, float ysz, float zsz, int usub, int
 }
 
 
-static inline void rev_vert(cgm_vec3 *res, float u, float v, cgm_vec2 (*rf)(float, float, void*), void *cls)
+static CGM_INLINE void rev_vert(cgm_vec3 *res, float u, float v, cgm_vec2 (*rf)(float, float, void*), void *cls)
 {
        cgm_vec2 pos = rf(u, v, cls);
 
-       float angle = u * 2.0 * M_PI;
+       float angle = u * 2.0 * CGM_PI;
        res->x = pos.x * cos(angle);
        res->y = pos.y;
        res->z = pos.x * sin(angle);
@@ -807,7 +807,7 @@ void gen_revol(struct cmesh *mesh, int usub, int vsub, cgm_vec2 (*rfunc)(float,
        }
 }
 
-static inline void sweep_vert(cgm_vec3 *res, float u, float v, float height,
+static CGM_INLINE void sweep_vert(cgm_vec3 *res, float u, float v, float height,
                cgm_vec2 (*sf)(float, float, void*), void *cls)
 {
        cgm_vec2 pos = sf(u, v, cls);
index 765e542..7bc97b3 100644 (file)
@@ -7,8 +7,8 @@ the terms of the 3-clause BSD license. See COPYING for details.
 */
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
 #include <string.h>
+#include "sizeint.h"
 #include "rbtree.h"
 
 #define INT2PTR(x)     ((void*)(intptr_t)(x))
index 1b53c5e..34afd0f 100644 (file)
@@ -2,7 +2,7 @@
 #define RTK_IMPL_H_
 
 #include <assert.h>
-#include "inttypes.h"
+#include "sizeint.h"
 #include "rtk.h"
 
 enum {