initial commit
authorJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 22 Nov 2023 23:55:41 +0000 (01:55 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Wed, 22 Nov 2023 23:55:41 +0000 (01:55 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
src/3dgfx.c [new file with mode: 0644]
src/3dgfx.h [new file with mode: 0644]
src/3dgfx_s.asm [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/polyfill.asm [new file with mode: 0644]
src/types.h [new file with mode: 0644]
src/video.c [new file with mode: 0644]
src/video.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..85af462
--- /dev/null
@@ -0,0 +1,10 @@
+*.o
+*.swp
+*.obj
+*.OBJ
+*.exe
+*.EXE
+*.map
+*.MAP
+*.lnk
+*.LNK
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..15e0118
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,43 @@
+
+!ifdef __UNIX__
+obj = src/main.obj src/video.obj src/3dgfx.obj src/3dgfx_s.obj src/polyfill.obj
+!else
+obj = src\main.obj src\video.obj src\3dgfx.obj src\3dgfx_s.obj src\polyfill.obj
+!endif
+bin = low3d.exe
+
+opt = -3 -otexan
+dbg = -d3
+
+incpath = -Isrc
+
+AS = nasm
+CC = wcc386
+ASFLAGS = -fobj
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath)
+LDFLAGS = option map
+LD = wlink
+
+$(bin): $(obj)
+       %write objlist.lnk $(obj)
+       $(LD) debug all name $@ system dos4g file { @objlist } $(LDFLAGS)
+
+.c: src
+.asm: src
+
+.c.obj: .autodepend
+       $(CC) -fo=$@ $(CFLAGS) $[*
+
+.asm.obj:
+       $(AS) $(ASFLAGS) -o $@ $[*.asm
+
+!ifdef __UNIX__
+clean: .symbolic
+       rm -f $(obj) $(bin)
+!else
+clean: .symbolic
+       del src\*.obj
+       del *.lnk
+       del *.map
+       del $(bin)
+!endif
diff --git a/src/3dgfx.c b/src/3dgfx.c
new file mode 100644 (file)
index 0000000..8dee789
--- /dev/null
@@ -0,0 +1,37 @@
+#include <stdlib.h>
+#include <string.h>
+#include "3dgfx.h"
+
+static int32_t mvmat[16];
+static int32_t pmat[16];
+
+int g3d_init(void)
+{
+       memset(mvmat, 0, sizeof mvmat);
+       memset(pmat, 0, sizeof pmat);
+       mvmat[0] = mvmat[5] = mvmat[10] = mvmat[15] = 0;
+       pmat[0] = pmat[5] = pmat[10] = pmat[15] = 0;
+       return 0;
+}
+
+void g3d_shutdown(void)
+{
+}
+
+void g3d_framebuf(int width, int height, void *fb)
+{
+}
+
+void g3d_modelview(const int32_t *m)
+{
+       memcpy(mvmat, m, sizeof mvmat);
+}
+
+void g3d_projection(const int32_t *m)
+{
+       memcpy(pmat, m, sizeof pmat);
+}
+
+void g3d_draw(int prim, struct g3d_vertex *varr, int vcount)
+{
+}
diff --git a/src/3dgfx.h b/src/3dgfx.h
new file mode 100644 (file)
index 0000000..f143f24
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef GFX3D_H_
+#define GFX3D_H_
+
+#include "types.h"
+
+struct g3d_vertex {
+       int32_t x, y, z;
+};
+
+enum {
+       G3D_POINTS,
+       G3D_LINES,
+       G3D_TRIANGLES
+};
+
+int g3d_init(void);
+void g3d_shutdown(void);
+
+void g3d_framebuf(int width, int height, void *fb);
+
+void g3d_modelview(const int32_t *m);
+void g3d_projection(const int32_t *m);
+
+void g3d_xform(struct g3d_vertex *v, const int32_t *m);
+
+void g3d_draw(int prim, struct g3d_vertex *varr, int vcount);
+
+#endif /* GFX3D_H_ */
diff --git a/src/3dgfx_s.asm b/src/3dgfx_s.asm
new file mode 100644 (file)
index 0000000..8147e7a
--- /dev/null
@@ -0,0 +1,54 @@
+       bits 32
+       section .text
+
+       ; eax: vertex ptr, edx: matrix ptr
+       global g3d_xform_
+g3d_xform_:
+       push ebp
+       mov ebp, esp
+       sub esp, 8
+       push ebx
+       push esi
+       push edi
+
+       mov ebx, edx    ; matrix to ebx
+       mov edi, eax    ; vertex to edi
+
+%macro MULROW 0
+       mov eax, [edi]          ; eax <- X
+       imul dword [ebx]
+       mov ecx, eax
+       mov eax, [edi + 4]      ; eax <- Y
+       imul dword [ebx + 4]
+       add ecx, eax
+       mov eax, [edi + 8]      ; eax <- Z
+       imul dword [ebx + 8]
+       add ecx, eax
+       mov eax, [edi + 12]     ; eax <- W
+       imul dword [ebx + 12]
+       add eax, ecx
+%endmacro
+
+       MULROW
+       mov [ebp - 12], eax
+       add ebx, 16     ; next matrix row
+       MULROW
+       mov [ebp - 8], eax
+       add ebx, 16
+       MULROW
+       mov [ebp - 4], eax
+       add ebx, 16
+       MULROW
+       mov [edi + 12], eax     ; move W into place
+       ; move XYZ into place
+       mov esi, [ebp - 12]
+       movsd
+       movsd
+       movsd
+
+       pop edi
+       pop esi
+       pop ebx
+       mov esp, ebp
+       pop ebp
+       ret
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..26bc2aa
--- /dev/null
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#include <dos.h>
+#include "video.h"
+#include "3dgfx.h"
+
+void update(void);
+void wait_vsync(void);
+void handle_key(int key);
+void interrupt timer_intr();
+
+static int quit;
+static unsigned char *fb;
+
+static volatile unsigned long nticks;
+
+static void interrupt (*prev_timer_intr)();
+
+int main(void)
+{
+       long rate, nframes = 0;
+       long tstart, tdur;
+
+       if(!(fb = malloc(64000))) {
+               fprintf(stderr, "failed to allocate framebuffer\n");
+               return 1;
+       }
+
+       init_video();
+
+       prev_timer_intr = _dos_getvect(0x1c);
+       _dos_setvect(0x1c, timer_intr);
+       _disable();
+       tstart = nticks;
+       _enable();
+
+       for(;;) {
+               while(kbhit()) {
+                       int c = getch();
+                       handle_key(c);
+                       if(quit) goto end;
+               }
+
+               update();
+               nframes++;
+       }
+
+end:
+       _disable();
+       tdur = nticks - tstart;
+       _enable();
+       _dos_setvect(0x1c, prev_timer_intr);
+
+       close_video();
+       free(fb);
+
+       rate = nframes * 100 * 18 / tdur;
+       printf("%ld frames in %ld sec, rate: %ld.%ld\n", nframes, tdur / 18,
+                       rate / 100, rate % 100);
+       return 0;
+}
+
+void update(void)
+{
+       memset(fb, 0, 64000);
+
+       wait_vsync();
+       memcpy((void*)0xa0000, fb, 64000);
+}
+
+void handle_key(int key)
+{
+       switch(key) {
+       case 27:
+               quit = 1;
+               break;
+       }
+}
+
+void interrupt timer_intr()
+{
+       nticks++;
+       _chain_intr(prev_timer_intr);
+}
diff --git a/src/polyfill.asm b/src/polyfill.asm
new file mode 100644 (file)
index 0000000..1459ffd
--- /dev/null
@@ -0,0 +1,8 @@
+       bits 32
+       section .text
+
+       global polyfill_
+polyfill_:
+       ret
+
+; vi:ft=nasm ts=8 sts=8 sw=8:
diff --git a/src/types.h b/src/types.h
new file mode 100644 (file)
index 0000000..2a747c3
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef TYPES_H_
+#define TYPES_H_
+
+typedef signed char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+
+#endif /* TYPES_H_ */
diff --git a/src/video.c b/src/video.c
new file mode 100644 (file)
index 0000000..9adaf2f
--- /dev/null
@@ -0,0 +1,18 @@
+#include <dos.h>
+#include "video.h"
+
+void init_video(void)
+{
+       union REGS regs = {0};
+
+       regs.w.ax = 0x13;
+       int386(0x10, &regs, &regs);
+}
+
+void close_video(void)
+{
+       union REGS regs = {0};
+
+       regs.w.ax = 3;
+       int386(0x10, &regs, &regs);
+}
diff --git a/src/video.h b/src/video.h
new file mode 100644 (file)
index 0000000..672eb6a
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef VIDEO_H_
+#define VIDEO_H_
+
+void init_video(void);
+void close_video(void);
+
+void wait_vsync(void);
+#pragma aux wait_vsync = \
+       "mov dx, 0x3da" \
+       "invb:" \
+       "in al, dx" \
+       "and al, 8" \
+       "jnz invb" \
+       "waitvb:" \
+       "in al, dx" \
+       "and al, 8" \
+       "jz waitvb" \
+       modify [eax edx];
+
+#endif /* VIDEO_H_ */