-src = $(wildcard src/*.c) $(wildcard src/scr/*.c) $(wildcard src/dos/*.c)
-asmsrc = $(wildcard src/*.asm) $(wildcard src/scr/*.asm) $(wildcard src/dos/*.asm)
-obj = $(src:.c=.odj) $(asmsrc:.asm=.odj)
-dep = $(obj:.odj=.dep)
+!ifdef __UNIX__
+dosobj = src/dos/audos.obj src/dos/djdpmi.obj src/dos/gfx.obj src/dos/keyb.obj &
+ src/dos/logger.obj src/dos/main.obj src/dos/sball.obj src/dos/timer.obj &
+ src/dos/vbe.obj src/dos/vga.obj src/dos/watdpmi.obj
+3dobj = src/3dgfx/3dgfx.obj src/3dgfx/mesh.obj src/3dgfx/meshload.obj &
+ src/3dgfx/polyclip.obj src/3dgfx/polyfill.obj
+srcobj = src/bsptree.obj src/cfgopt.obj src/console.obj &
+ src/demo.obj src/dynarr.obj src/gfxutil.obj &
+ src/metasurf.obj src/noise.obj &
+ src/rbtree.obj src/screen.obj src/tinyfps.obj src/treestor.obj &
+ src/ts_text.obj src/util.obj
+scrobj = src/scr/bump.obj src/scr/fract.obj src/scr/greets.obj &
+ src/scr/grise.obj src/scr/hairball.obj src/scr/infcubes.obj &
+ src/scr/metaball.obj src/scr/plasma.obj src/scr/polytest.obj &
+ src/scr/smoketxt.obj src/scr/thunder.obj src/scr/tilemaze.obj &
+ src/scr/tunnel.obj
+
+incpath = -Isrc -Isrc/dos -Isrc/3dgfx -Ilibs -Ilibs/imago/src -Ilibs/anim/src &
+ -Ilibs/midas
+libpath = libpath libs/imago libpath libs/anim libpath libs/midas
+!else
+
+dosobj = src\dos\audos.obj src\dos\djdpmi.obj src\dos\gfx.obj src\dos\keyb.obj &
+ src\dos\logger.obj src\dos\main.obj src\dos\sball.obj src\dos\timer.obj &
+ src\dos\vbe.obj src\dos\vga.obj src\dos\watdpmi.obj
+3dobj = src\3dgfx\3dgfx.obj src\3dgfx\mesh.obj src\3dgfx\meshload.obj &
+ src\3dgfx\polyclip.obj src\3dgfx\polyfill.obj
+srcobj = src\3dgfx.obj src\bsptree.obj src\cfgopt.obj src\console.obj &
+ src\demo.obj src\dynarr.obj src\gfxutil.obj src\mesh.obj src\meshload.obj &
+ src\metasurf.obj src\noise.obj src\polyclip.obj src\polyfill.obj &
+ src\rbtree.obj src\screen.obj src\tinyfps.obj src\treestor.obj &
+ src\ts_text.obj src\util.obj
+scrobj = src\scr\bump.obj src\scr\fract.obj src\scr\greets.obj &
+ src\scr\grise.obj src\scr\hairball.obj src\scr\infcubes.obj &
+ src\scr\metaball.obj src\scr\plasma.obj src\scr\polytest.obj &
+ src\scr\smoketxt.obj src\scr\thunder.obj src\scr\tilemaze.obj &
+ src\scr\tunnel.obj
+
+incpath = -Isrc -Isrc\dos -Isrc\3dgfx -Ilibs -Ilibs\imago\src -Ilibs\anim\src &
+ -Ilibs\midas
+libpath = libpath libs\imago libpath libs\anim libpath libs\midas
+!endif
+
+obj = $(dosobj) $(3dobj) $(scrobj) $(srcobj)
bin = demo.exe
-asmsrc += cspr/dbgfont.asm cspr/confont.asm
-bindata = data/loading.img
-
-ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)
- hostsys = dos
-else
- hostsys = unix
- TOOLPREFIX = i586-pc-msdosdjgpp-
-endif
-
-inc = -Isrc -Isrc/scr -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/anim/src
-opt = -O3 -ffast-math -fno-strict-aliasing
-warn = -pedantic -Wall -Wno-unused-function -Wno-unused-variable
-
-ifdef RELEASE
- dbg = -g
- def = -DNDEBUG -DNO_MUSIC
-else
- def = -DNO_MUSIC
-endif
-#prof = -pg
-
-CC = $(TOOLPREFIX)gcc
-AR = $(TOOLPREFIX)ar
-CFLAGS = $(warn) -march=pentium $(dbg) $(opt) $(prof) $(inc) $(def)
-LDFLAGS = libs/imago/imago.dja libs/anim/anim.dja
-
-ifneq ($(hostsys), dos)
-.PHONY: all
-all: data $(bin)
-endif
-
-$(bin): $(obj) imago anim
- $(CC) -o $@ -Wl,-Map=ld.map $(prof) $(obj) $(LDFLAGS)
-
-%.odj: %.asm
- nasm -f coff -o $@ $<
-
-src/data.odj: src/data.asm $(bindata)
-
-ifneq ($(hostsys), dos)
--include $(dep)
-endif
-
-%.odj: %.c
- $(CC) $(CFLAGS) -o $@ -c $<
-
-%.dep: %.c
- @echo dep $@
- @$(CPP) $(CFLAGS) $< -MM -MT $(@:.dep=.odj) >$@
-
-.PHONY: imago
-imago:
- $(MAKE) -C libs/imago -f Makefile
-
-.PHONY: anim
-anim:
- $(MAKE) -C libs/anim -f Makefile
-
-.PHONY: cleanlibs
-cleanlibs:
- $(MAKE) -C libs/imago -f Makefile clean
- $(MAKE) -C libs/anim -f Makefile clean
-
-.PHONY: clean
-.PHONY: cleandep
-
-ifeq ($(hostsys), dos)
-clean:
- del src\*.odj
- del src\dos\*.odj
+opt = -otexan
+#opt = -od
+def = -dM_PI=3.141592653589793 -dUSE_HLT
+libs = imago.lib anim.lib midas.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/imago/imago.lib libs/anim/anim.lib
+ %write objects.lnk $(obj)
+ %write ldflags.lnk $(LDFLAGS)
+ $(LD) debug all name $@ system dos4g file { @objects } @ldflags
+
+.c: src;src/dos;src/3dgfx;src/scr
+.asm: src;src/dos;src/3dgfx;src/scr
+
+cflags.occ: Makefile
+ %write $@ $(CFLAGS)
+
+!ifdef __UNIX__
+src/dos/audos.obj: src/dos/audos.c
+!else
+src\dos\audos.obj: src\dos\audos.c
+!endif
+ $(CC) -fo=$@ @cflags.occ -zu $[*
+
+.c.obj: .autodepend
+ $(CC) -fo=$@ @cflags.occ $[*
+
+.asm.obj:
+ nasm -f obj -o $@ $[*.asm
+
+!ifdef __UNIX__
+clean: .symbolic
+ rm -f $(obj)
+ rm -f $(bin)
+ rm -f cflags.occ *.lnk
+!else
+clean: .symbolic
+ del src\*.obj
+ del src\dos\*.obj
+ del src\3dgfx\*.obj
+ del src\scr\*.obj
+ del *.lnk
+ del cflags.occ
del $(bin)
-
-cleandep:
- del src\*.dep
- del src\dos\*.dep
-else
-clean:
- rm -f $(obj) $(bin)
-
-cleandep:
- rm -f $(dep)
-
-.PHONY: data
-data:
- @tools/procdata
-endif
-
-.PHONY: strip
-strip: $(bin)
- $(TOOLPREFIX)strip $(bin)
+!endif
--- /dev/null
+src = $(wildcard src/*.c) $(wildcard src/scr/*.c) $(wildcard src/dos/*.c)
+asmsrc = $(wildcard src/*.asm) $(wildcard src/scr/*.asm) $(wildcard src/dos/*.asm)
+obj = $(src:.c=.odj) $(asmsrc:.asm=.odj)
+dep = $(obj:.odj=.dep)
+bin = demo.exe
+
+asmsrc += cspr/dbgfont.asm cspr/confont.asm
+bindata = data/loading.img
+
+ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)
+ hostsys = dos
+else
+ hostsys = unix
+ TOOLPREFIX = i586-pc-msdosdjgpp-
+endif
+
+inc = -Isrc -Isrc/scr -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/anim/src
+opt = -O3 -ffast-math -fno-strict-aliasing
+warn = -pedantic -Wall -Wno-unused-function -Wno-unused-variable
+
+ifdef RELEASE
+ dbg = -g
+ def = -DNDEBUG -DNO_MUSIC
+else
+ def = -DNO_MUSIC
+endif
+#prof = -pg
+
+CC = $(TOOLPREFIX)gcc
+AR = $(TOOLPREFIX)ar
+CFLAGS = $(warn) -march=pentium $(dbg) $(opt) $(prof) $(inc) $(def)
+LDFLAGS = libs/imago/imago.dja libs/anim/anim.dja
+
+ifneq ($(hostsys), dos)
+.PHONY: all
+all: data $(bin)
+endif
+
+$(bin): $(obj) imago anim
+ $(CC) -o $@ -Wl,-Map=ld.map $(prof) $(obj) $(LDFLAGS)
+
+%.odj: %.asm
+ nasm -f coff -o $@ $<
+
+src/data.odj: src/data.asm $(bindata)
+
+ifneq ($(hostsys), dos)
+-include $(dep)
+endif
+
+%.odj: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+%.dep: %.c
+ @echo dep $@
+ @$(CPP) $(CFLAGS) $< -MM -MT $(@:.dep=.odj) >$@
+
+.PHONY: imago
+imago:
+ $(MAKE) -C libs/imago -f Makefile
+
+.PHONY: anim
+anim:
+ $(MAKE) -C libs/anim -f Makefile
+
+.PHONY: cleanlibs
+cleanlibs:
+ $(MAKE) -C libs/imago -f Makefile clean
+ $(MAKE) -C libs/anim -f Makefile clean
+
+.PHONY: clean
+.PHONY: cleandep
+
+ifeq ($(hostsys), dos)
+clean:
+ del src\*.odj
+ del src\dos\*.odj
+ del $(bin)
+
+cleandep:
+ del src\*.dep
+ del src\dos\*.dep
+else
+clean:
+ rm -f $(obj) $(bin)
+
+cleandep:
+ rm -f $(dep)
+
+.PHONY: data
+data:
+ @tools/procdata
+endif
+
+.PHONY: strip
+strip: $(bin)
+ $(TOOLPREFIX)strip $(bin)
+++ /dev/null
-obj = 3dgfx.obj bsptree.obj bump.obj cfgopt.obj demo.obj djdpmi.obj dynarr.obj &
-fract.obj gfx.obj gfxutil.obj greets.obj grise.obj hairball.obj infcubes.obj &
-keyb.obj logger.obj main.obj mesh.obj meshload.obj metaball.obj metasurf.obj &
-mouse.obj audos.obj noise.obj plasma.obj polyclip.obj polyfill.obj polytest.obj &
-rbtree.obj sball.obj screen.obj smoketxt.obj thunder.obj tilemaze.obj timer.obj &
-tinyfps.obj treestor.obj ts_text.obj tunnel.obj util.obj vbe.obj vga.obj
-
-bin = demo.exe
-
-libs = imago.lib anim.lib midas.lib
-
-def = -dM_PI=3.141592653589793 -dUSE_HLT
-opt = -5 -fp5 -otexan -oh -oi -ei
-dbg = -d2
-
-!ifdef __UNIX__
-incpath = -Isrc -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/anim/src -Ilibs/midas
-libpath = libpath libs/imago libpath libs/anim libpath libs/midas
-RM = rm -f
-!else
-incpath = -Isrc -Isrc\dos -Ilibs -Ilibs\imago\src -Ilibs\anim\src -Ilibs\midas
-libpath = libpath libs\imago libpath libs\anim libpath libs\midas
-RM = del
-!endif
-
-AS = nasm
-CC = wcc386
-CXX = wpp386
-ASFLAGS = -fobj
-CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath)
-CXXFLAGS = $(CFLAGS)
-LDFLAGS = option stack=16k option map $(libpath) library { $(libs) }
-LD = wlink
-
-$(bin): cflags.occ $(obj) libs/imago/imago.lib
- %write objects.lnk $(obj)
- %write ldflags.lnk $(LDFLAGS)
- $(LD) debug all name $@ system dos4g file { @objects } @ldflags
-
-.c: src;src/dos;src/scr
-.cc: src;src/dos;src/scr
-.asm: src;src/dos;src/scr
-
-cflags.occ: Makefile
- %write $@ $(CFLAGS)
-
-cxxflags.occ: Makefile
- %write $@ $(CXXFLAGS)
-
-.c.obj: .autodepend
- $(CC) -fo=$@ @cflags.occ $[*
-
-.cc.obj: .autodepend
- $(CXX) -fo=$@ @cxxflags.occ $[*
-
-.asm.obj:
- $(AS) $(ASFLAGS) -o $@ $[*.asm
-
-clean: .symbolic
- $(RM) *.obj
- $(RM) *.occ
- $(RM) *.lnk
- $(RM) $(bin)
-src = $(wildcard src/*.c)
-obj = $(src:.c=.odj)
-alib = anim.dja
+obj = anim.obj track.obj
+alib = anim.lib
-ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)
- hostsys = dos
-else
- hostsys = unix
- TOOLPREFIX = i586-pc-msdosdjgpp-
-endif
+def = -dM_PI=3.141592653589793
+opt = -5 -fp5 -otexan -I.. -I../../src $(def)
+dbg = -d1
-CC = $(TOOLPREFIX)gcc
-AR = $(TOOLPREFIX)ar
-CFLAGS = -Wno-main -march=pentium -O3 -ffast-math -I.. -I../../src
+!ifdef __UNIX__
+RM = rm -f
+!else
+RM = del
+!endif
+
+CC = wcc386
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos
$(alib): $(obj)
- $(AR) rcs $@ $(obj)
+ wlib -b -n $@ $(obj)
+
+.c: src
-%.odj: %.c
- $(CC) $(CFLAGS) -o $@ -c $<
+.c.obj: .autodepend
+ $(CC) -fo=$@ $(CFLAGS) $[*
-.PHONY: clean
-ifeq ($(hostsys), dos)
-clean:
- del src\*.odj
- del $(alib)
-else
-clean:
- rm -f $(obj) $(alib)
-endif
+clean: .symbolic
+ $(RM) *.obj
+ $(RM) $(alib)
--- /dev/null
+src = $(wildcard src/*.c)
+obj = $(src:.c=.odj)
+alib = anim.dja
+
+ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)
+ hostsys = dos
+else
+ hostsys = unix
+ TOOLPREFIX = i586-pc-msdosdjgpp-
+endif
+
+CC = $(TOOLPREFIX)gcc
+AR = $(TOOLPREFIX)ar
+CFLAGS = -Wno-main -march=pentium -O3 -ffast-math -I.. -I../../src
+
+$(alib): $(obj)
+ $(AR) rcs $@ $(obj)
+
+%.odj: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+.PHONY: clean
+ifeq ($(hostsys), dos)
+clean:
+ del src\*.odj
+ del $(alib)
+else
+clean:
+ rm -f $(obj) $(alib)
+endif
+++ /dev/null
-obj = anim.obj track.obj
-alib = anim.lib
-
-def = -dM_PI=3.141592653589793
-opt = -5 -fp5 -otexan -I.. -I../../src $(def)
-dbg = -d1
-
-!ifdef __UNIX__
-RM = rm -f
-!else
-RM = del
-!endif
-
-CC = wcc386
-CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos
-
-$(alib): $(obj)
- wlib -b -n $@ $(obj)
-
-.c: src
-
-.c.obj: .autodepend
- $(CC) -fo=$@ $(CFLAGS) $[*
-
-clean: .symbolic
- $(RM) *.obj
- $(RM) $(alib)
-src = $(wildcard src/*.c) \
- $(wildcard zlib/*.c) \
- $(wildcard libpng/*.c) \
- $(wildcard jpeglib/*.c)
-obj = $(src:.c=.odj)
-alib = imago.dja
-
-ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)
- hostsys = dos
-else
- hostsys = unix
- TOOLPREFIX = i586-pc-msdosdjgpp-
-endif
-
-CC = $(TOOLPREFIX)gcc
-AR = $(TOOLPREFIX)ar
-CFLAGS = -Wno-main -march=pentium -O3 -ffast-math -Izlib -Ilibpng -Ijpeglib
-
-$(alib): $(obj)
- $(AR) rcs $@ $(obj)
-
-%.odj: %.c
- $(CC) $(CFLAGS) -o $@ -c $<
-
-.PHONY: clean
-ifeq ($(hostsys), dos)
-clean:
- del src\*.odj
- del zlib\*.odj
- del libpng\*.odj
- del jpeglib\*.odj
- del $(alib)
-else
-clean:
- rm -f $(obj) $(alib)
-endif
+libpng = png.obj pngerror.obj pngget.obj pngmem.obj pngpread.obj pngread.obj &
+pngrio.obj pngrtran.obj pngrutil.obj pngset.obj pngtrans.obj pngwio.obj &
+pngwrite.obj pngwtran.obj pngwutil.obj
+zlib = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj &
+inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+jpeglib = jcapimin.obj jcapistd.obj jccoefct.obj jccolor.obj jcdctmgr.obj &
+jchuff.obj jcinit.obj jcmainct.obj jcmarker.obj jcmaster.obj jcomapi.obj &
+jcparam.obj jcphuff.obj jcprepct.obj jcsample.obj jctrans.obj jdapimin.obj &
+jdapistd.obj jdatadst.obj jdatasrc.obj jdcoefct.obj jdcolor.obj jddctmgr.obj &
+jdhuff.obj jdinput.obj jdmainct.obj jdmarker.obj jdmaster.obj jdmerge.obj &
+jdphuff.obj jdpostct.obj jdsample.obj jdtrans.obj jerror.obj jfdctflt.obj &
+jfdctfst.obj jfdctint.obj jidctflt.obj jidctfst.obj jidctint.obj jidctred.obj &
+jmemmgr.obj jmemnobs.obj jquant1.obj jquant2.obj jutils.obj
+
+obj = conv.obj filejpeg.obj filepng.obj fileppm.obj filergbe.obj &
+filetga.obj ftmodule.obj imago2.obj imago_gl.obj modules.obj &
+$(libpng) $(zlib) $(jpeglib)
+
+alib = imago.lib
+
+opt = -5 -fp5 -otexan
+dbg = -d1
+def = -DPNG_NO_SNPRINTF
+
+!ifdef __UNIX__
+RM = rm -f
+!else
+RM = del
+!endif
+
+CC = wcc386
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos -Ilibpng -Izlib -Ijpeglib
+
+$(alib): cflags.occ $(obj)
+ %write objects.lbc $(obj)
+ wlib -b -n $@ @objects
+
+.c: src;libpng;jpeglib;zlib
+
+cflags.occ: Makefile
+ %write $@ $(CFLAGS)
+
+.c.obj: .autodepend
+ $(CC) -fo=$@ @cflags.occ $[*
+
+clean: .symbolic
+ $(RM) *.obj
+ $(RM) *.occ
+ $(RM) *.lbc
+ $(RM) $(alib)
--- /dev/null
+src = $(wildcard src/*.c) \
+ $(wildcard zlib/*.c) \
+ $(wildcard libpng/*.c) \
+ $(wildcard jpeglib/*.c)
+obj = $(src:.c=.odj)
+alib = imago.dja
+
+ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)
+ hostsys = dos
+else
+ hostsys = unix
+ TOOLPREFIX = i586-pc-msdosdjgpp-
+endif
+
+CC = $(TOOLPREFIX)gcc
+AR = $(TOOLPREFIX)ar
+CFLAGS = -Wno-main -march=pentium -O3 -ffast-math -Izlib -Ilibpng -Ijpeglib
+
+$(alib): $(obj)
+ $(AR) rcs $@ $(obj)
+
+%.odj: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+.PHONY: clean
+ifeq ($(hostsys), dos)
+clean:
+ del src\*.odj
+ del zlib\*.odj
+ del libpng\*.odj
+ del jpeglib\*.odj
+ del $(alib)
+else
+clean:
+ rm -f $(obj) $(alib)
+endif
+++ /dev/null
-libpng = png.obj pngerror.obj pngget.obj pngmem.obj pngpread.obj pngread.obj &
-pngrio.obj pngrtran.obj pngrutil.obj pngset.obj pngtrans.obj pngwio.obj &
-pngwrite.obj pngwtran.obj pngwutil.obj
-zlib = adler32.obj compress.obj crc32.obj deflate.obj gzio.obj infback.obj &
-inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
-jpeglib = jcapimin.obj jcapistd.obj jccoefct.obj jccolor.obj jcdctmgr.obj &
-jchuff.obj jcinit.obj jcmainct.obj jcmarker.obj jcmaster.obj jcomapi.obj &
-jcparam.obj jcphuff.obj jcprepct.obj jcsample.obj jctrans.obj jdapimin.obj &
-jdapistd.obj jdatadst.obj jdatasrc.obj jdcoefct.obj jdcolor.obj jddctmgr.obj &
-jdhuff.obj jdinput.obj jdmainct.obj jdmarker.obj jdmaster.obj jdmerge.obj &
-jdphuff.obj jdpostct.obj jdsample.obj jdtrans.obj jerror.obj jfdctflt.obj &
-jfdctfst.obj jfdctint.obj jidctflt.obj jidctfst.obj jidctint.obj jidctred.obj &
-jmemmgr.obj jmemnobs.obj jquant1.obj jquant2.obj jutils.obj
-
-obj = conv.obj filejpeg.obj filepng.obj fileppm.obj filergbe.obj &
-filetga.obj ftmodule.obj imago2.obj imago_gl.obj modules.obj &
-$(libpng) $(zlib) $(jpeglib)
-
-alib = imago.lib
-
-opt = -5 -fp5 -otexan
-dbg = -d1
-def = -DPNG_NO_SNPRINTF
-
-!ifdef __UNIX__
-RM = rm -f
-!else
-RM = del
-!endif
-
-CC = wcc386
-CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos -Ilibpng -Izlib -Ijpeglib
-
-$(alib): cflags.occ $(obj)
- %write objects.lbc $(obj)
- wlib -b -n $@ @objects
-
-.c: src;libpng;jpeglib;zlib
-
-cflags.occ: Makefile
- %write $@ $(CFLAGS)
-
-.c.obj: .autodepend
- $(CC) -fo=$@ @cflags.occ $[*
-
-clean: .symbolic
- $(RM) *.obj
- $(RM) *.occ
- $(RM) *.lbc
- $(RM) $(alib)
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__)
-#include <malloc.h>
-#else
-#include <alloca.h>
-#endif
-#include "3dgfx.h"
-#include "gfxutil.h"
-#include "polyfill.h"
-#include "polyclip.h"
-#include "inttypes.h"
-#include "demo.h"
-#include "util.h"
-
-#define STACK_SIZE 8
-typedef float g3d_matrix[16];
-
-#define MAX_LIGHTS 4
-
-#define IMM_VBUF_SIZE 256
-
-#define NORMALIZE(v) \
- do { \
- float len = sqrt((v)[0] * (v)[0] + (v)[1] * (v)[1] + (v)[2] * (v)[2]); \
- if(len != 0.0) { \
- float s = 1.0 / len; \
- (v)[0] *= s; \
- (v)[1] *= s; \
- (v)[2] *= s; \
- } \
- } while(0)
-
-enum {LT_POS, LT_DIR};
-struct light {
- int type;
- float x, y, z;
- float r, g, b;
-};
-
-struct material {
- float kd[3];
- float ks[3];
- float shin;
-};
-
-struct g3d_state {
- unsigned int opt;
- int frontface;
- int polymode;
-
- g3d_matrix mat[G3D_NUM_MATRICES][STACK_SIZE];
- int mtop[G3D_NUM_MATRICES];
- int mmode;
-
- g3d_matrix norm_mat;
-
- float ambient[3];
- struct light lt[MAX_LIGHTS];
- struct material mtl;
-
- int width, height;
- g3d_pixel *pixels;
-
- int vport[4];
-
- /* immediate mode */
- int imm_prim;
- int imm_numv, imm_pcount;
- struct g3d_vertex imm_curv;
- struct g3d_vertex imm_vbuf[IMM_VBUF_SIZE];
-};
-
-static void imm_flush(void);
-static __inline void xform4_vec3(const float *mat, float *vec);
-static __inline void xform3_vec3(const float *mat, float *vec);
-static void shade(struct g3d_vertex *v);
-
-static struct g3d_state *st;
-static const float idmat[] = {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1
-};
-
-int g3d_init(void)
-{
- int i;
-
- if(!(st = calloc(1, sizeof *st))) {
- fprintf(stderr, "failed to allocate G3D context\n");
- return -1;
- }
- st->opt = G3D_CLIP_FRUSTUM;
- st->polymode = POLYFILL_FLAT;
-
- for(i=0; i<G3D_NUM_MATRICES; i++) {
- g3d_matrix_mode(i);
- g3d_load_identity();
- }
-
- for(i=0; i<MAX_LIGHTS; i++) {
- g3d_light_color(i, 1, 1, 1);
- }
- g3d_light_ambient(0.1, 0.1, 0.1);
-
- g3d_mtl_diffuse(1, 1, 1);
- return 0;
-}
-
-void g3d_destroy(void)
-{
- free(st);
-}
-
-void g3d_framebuffer(int width, int height, void *pixels)
-{
- st->width = width;
- st->height = height;
- st->pixels = pixels;
-
- pfill_fb.pixels = pixels;
- pfill_fb.width = width;
- pfill_fb.height = height;
-
- g3d_viewport(0, 0, width, height);
-}
-
-/* set the framebuffer pointer, without resetting the size */
-void g3d_framebuffer_addr(void *pixels)
-{
- st->pixels = pixels;
- pfill_fb.pixels = pixels;
-}
-
-void g3d_viewport(int x, int y, int w, int h)
-{
- st->vport[0] = x;
- st->vport[1] = y;
- st->vport[2] = w;
- st->vport[3] = h;
-}
-
-void g3d_enable(unsigned int opt)
-{
- st->opt |= opt;
-}
-
-void g3d_disable(unsigned int opt)
-{
- st->opt &= ~opt;
-}
-
-void g3d_setopt(unsigned int opt, unsigned int mask)
-{
- st->opt = (st->opt & ~mask) | (opt & mask);
-}
-
-unsigned int g3d_getopt(unsigned int mask)
-{
- return st->opt & mask;
-}
-
-void g3d_front_face(unsigned int order)
-{
- st->frontface = order;
-}
-
-void g3d_polygon_mode(int pmode)
-{
- st->polymode = pmode;
-}
-
-void g3d_matrix_mode(int mmode)
-{
- st->mmode = mmode;
-}
-
-void g3d_load_identity(void)
-{
- int top = st->mtop[st->mmode];
- memcpy(st->mat[st->mmode][top], idmat, 16 * sizeof(float));
-}
-
-void g3d_load_matrix(const float *m)
-{
- int top = st->mtop[st->mmode];
- memcpy(st->mat[st->mmode][top], m, 16 * sizeof(float));
-}
-
-#define M(i,j) (((i) << 2) + (j))
-void g3d_mult_matrix(const float *m2)
-{
- int i, j, top = st->mtop[st->mmode];
- float m1[16];
- float *dest = st->mat[st->mmode][top];
-
- memcpy(m1, dest, sizeof m1);
-
- for(i=0; i<4; i++) {
- for(j=0; j<4; j++) {
- *dest++ = m1[M(0,j)] * m2[M(i,0)] +
- m1[M(1,j)] * m2[M(i,1)] +
- m1[M(2,j)] * m2[M(i,2)] +
- m1[M(3,j)] * m2[M(i,3)];
- }
- }
-}
-
-void g3d_push_matrix(void)
-{
- int top = st->mtop[st->mmode];
- if(top >= G3D_NUM_MATRICES) {
- fprintf(stderr, "g3d_push_matrix overflow\n");
- return;
- }
- memcpy(st->mat[st->mmode][top + 1], st->mat[st->mmode][top], 16 * sizeof(float));
- st->mtop[st->mmode] = top + 1;
-}
-
-void g3d_pop_matrix(void)
-{
- if(st->mtop[st->mmode] <= 0) {
- fprintf(stderr, "g3d_pop_matrix underflow\n");
- return;
- }
- --st->mtop[st->mmode];
-}
-
-void g3d_translate(float x, float y, float z)
-{
- float m[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
- m[12] = x;
- m[13] = y;
- m[14] = z;
- g3d_mult_matrix(m);
-}
-
-void g3d_rotate(float deg, float x, float y, float z)
-{
- float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- float angle = M_PI * deg / 180.0f;
- float sina = sin(angle);
- float cosa = cos(angle);
- float one_minus_cosa = 1.0f - cosa;
- float nxsq = x * x;
- float nysq = y * y;
- float nzsq = z * z;
-
- m[0] = nxsq + (1.0f - nxsq) * cosa;
- m[4] = x * y * one_minus_cosa - z * sina;
- m[8] = x * z * one_minus_cosa + y * sina;
- m[1] = x * y * one_minus_cosa + z * sina;
- m[5] = nysq + (1.0 - nysq) * cosa;
- m[9] = y * z * one_minus_cosa - x * sina;
- m[2] = x * z * one_minus_cosa - y * sina;
- m[6] = y * z * one_minus_cosa + x * sina;
- m[10] = nzsq + (1.0 - nzsq) * cosa;
- m[15] = 1.0f;
-
- g3d_mult_matrix(m);
-}
-
-void g3d_scale(float x, float y, float z)
-{
- float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- m[0] = x;
- m[5] = y;
- m[10] = z;
- m[15] = 1.0f;
- g3d_mult_matrix(m);
-}
-
-void g3d_ortho(float left, float right, float bottom, float top, float znear, float zfar)
-{
- float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- float dx = right - left;
- float dy = top - bottom;
- float dz = zfar - znear;
-
- m[0] = 2.0 / dx;
- m[5] = 2.0 / dy;
- m[10] = -2.0 / dz;
- m[12] = -(right + left) / dx;
- m[13] = -(top + bottom) / dy;
- m[14] = -(zfar + znear) / dz;
-
- g3d_mult_matrix(m);
-}
-
-void g3d_frustum(float left, float right, float bottom, float top, float nr, float fr)
-{
- float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- float dx = right - left;
- float dy = top - bottom;
- float dz = fr - nr;
-
- float a = (right + left) / dx;
- float b = (top + bottom) / dy;
- float c = -(fr + nr) / dz;
- float d = -2.0 * fr * nr / dz;
-
- m[0] = 2.0 * nr / dx;
- m[5] = 2.0 * nr / dy;
- m[8] = a;
- m[9] = b;
- m[10] = c;
- m[11] = -1.0f;
- m[14] = d;
-
- g3d_mult_matrix(m);
-}
-
-void g3d_perspective(float vfov_deg, float aspect, float znear, float zfar)
-{
- float m[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- float vfov = M_PI * vfov_deg / 180.0f;
- float s = 1.0f / tan(vfov * 0.5f);
- float range = znear - zfar;
-
- m[0] = s / aspect;
- m[5] = s;
- m[10] = (znear + zfar) / range;
- m[11] = -1.0f;
- m[14] = 2.0f * znear * zfar / range;
-
- g3d_mult_matrix(m);
-}
-
-const float *g3d_get_matrix(int which, float *m)
-{
- int top = st->mtop[which];
-
- if(m) {
- memcpy(m, st->mat[which][top], 16 * sizeof(float));
- }
- return st->mat[which][top];
-}
-
-void g3d_light_pos(int idx, float x, float y, float z)
-{
- int mvtop = st->mtop[G3D_MODELVIEW];
-
- st->lt[idx].type = LT_POS;
- st->lt[idx].x = x;
- st->lt[idx].y = y;
- st->lt[idx].z = z;
-
- xform4_vec3(st->mat[G3D_MODELVIEW][mvtop], &st->lt[idx].x);
-}
-
-void g3d_light_dir(int idx, float x, float y, float z)
-{
- int mvtop = st->mtop[G3D_MODELVIEW];
-
- st->lt[idx].type = LT_DIR;
- st->lt[idx].x = x;
- st->lt[idx].y = y;
- st->lt[idx].z = z;
-
- /* calc the normal matrix */
- memcpy(st->norm_mat, st->mat[G3D_MODELVIEW][mvtop], 16 * sizeof(float));
- st->norm_mat[12] = st->norm_mat[13] = st->norm_mat[14] = 0.0f;
-
- xform4_vec3(st->norm_mat, &st->lt[idx].x);
-
- NORMALIZE(&st->lt[idx].x);
-}
-
-void g3d_light_color(int idx, float r, float g, float b)
-{
- st->lt[idx].r = r;
- st->lt[idx].g = g;
- st->lt[idx].b = b;
-}
-
-void g3d_light_ambient(float r, float g, float b)
-{
- st->ambient[0] = r;
- st->ambient[1] = g;
- st->ambient[2] = b;
-}
-
-void g3d_mtl_diffuse(float r, float g, float b)
-{
- st->mtl.kd[0] = r;
- st->mtl.kd[1] = g;
- st->mtl.kd[2] = b;
-}
-
-void g3d_mtl_specular(float r, float g, float b)
-{
- st->mtl.ks[0] = r;
- st->mtl.ks[1] = g;
- st->mtl.ks[2] = b;
-}
-
-void g3d_mtl_shininess(float shin)
-{
- st->mtl.shin = shin;
-}
-
-static INLINE int calc_shift(unsigned int x)
-{
- int res = -1;
- while(x) {
- x >>= 1;
- ++res;
- }
- return res;
-}
-
-static INLINE int calc_mask(unsigned int x)
-{
- return x - 1;
-}
-
-void g3d_set_texture(int xsz, int ysz, void *pixels)
-{
- pfill_tex.pixels = pixels;
- pfill_tex.width = xsz;
- pfill_tex.height = ysz;
-
- pfill_tex.xshift = calc_shift(xsz);
- pfill_tex.yshift = calc_shift(ysz);
- pfill_tex.xmask = calc_mask(xsz);
- pfill_tex.ymask = calc_mask(ysz);
-}
-
-void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size)
-{
- g3d_draw_indexed(prim, varr, varr_size, 0, 0);
-}
-
-void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
- const uint16_t *iarr, int iarr_size)
-{
- int i, j, vnum, nfaces, fill_mode;
- struct pvertex pv[16];
- struct g3d_vertex v[16];
- int mvtop = st->mtop[G3D_MODELVIEW];
- int ptop = st->mtop[G3D_PROJECTION];
- struct g3d_vertex *tmpv;
-
- tmpv = alloca(prim * 6 * sizeof *tmpv);
-
- /* calc the normal matrix */
- memcpy(st->norm_mat, st->mat[G3D_MODELVIEW][mvtop], 16 * sizeof(float));
- st->norm_mat[12] = st->norm_mat[13] = st->norm_mat[14] = 0.0f;
-
- nfaces = (iarr ? iarr_size : varr_size) / prim;
-
- for(j=0; j<nfaces; j++) {
- vnum = prim; /* reset vnum for each iteration */
-
- for(i=0; i<vnum; i++) {
- v[i] = iarr ? varr[*iarr++] : *varr++;
-
- xform4_vec3(st->mat[G3D_MODELVIEW][mvtop], &v[i].x);
- xform3_vec3(st->norm_mat, &v[i].nx);
-
- if(st->opt & G3D_LIGHTING) {
- shade(v + i);
- }
- if(st->opt & G3D_TEXTURE_GEN) {
- v[i].u = v[i].nx * 0.5 + 0.5;
- v[i].v = v[i].ny * 0.5 + 0.5;
- }
- if(st->opt & G3D_TEXTURE_MAT) {
- float *mat = st->mat[G3D_TEXTURE][st->mtop[G3D_TEXTURE]];
- float x = mat[0] * v[i].u + mat[4] * v[i].v + mat[12];
- float y = mat[1] * v[i].u + mat[5] * v[i].v + mat[13];
- float w = mat[3] * v[i].u + mat[7] * v[i].v + mat[15];
- v[i].u = x / w;
- v[i].v = y / w;
- }
- xform4_vec3(st->mat[G3D_PROJECTION][ptop], &v[i].x);
- }
-
- /* clipping */
- if(st->opt & G3D_CLIP_FRUSTUM) {
- for(i=0; i<6; i++) {
- memcpy(tmpv, v, vnum * sizeof *v);
-
- if(clip_frustum(v, &vnum, tmpv, vnum, i) < 0) {
- /* polygon completely outside of view volume. discard */
- vnum = 0;
- break;
- }
- }
-
- if(!vnum) continue;
- }
-
- for(i=0; i<vnum; i++) {
- if(v[i].w != 0.0f) {
- v[i].x /= v[i].w;
- v[i].y /= v[i].w;
- /*v[i].z /= v[i].w;*/
- }
-
- /* viewport transformation */
- v[i].x = (v[i].x * 0.5f + 0.5f) * (float)st->vport[2] + st->vport[0];
- v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->vport[3] + st->vport[1];
-
- /* convert pos to 24.8 fixed point */
- pv[i].x = cround64(v[i].x * 256.0f);
- pv[i].y = cround64(v[i].y * 256.0f);
- /* convert tex coords to 16.16 fixed point */
- pv[i].u = cround64(v[i].u * 65536.0f);
- pv[i].v = cround64(v[i].v * 65536.0f);
- /* pass the color through as is */
- pv[i].r = v[i].r;
- pv[i].g = v[i].g;
- pv[i].b = v[i].b;
- pv[i].a = v[i].a;
- }
-
- /* backface culling */
- if(vnum > 2 && st->opt & G3D_CULL_FACE) {
- int32_t ax = pv[1].x - pv[0].x;
- int32_t ay = pv[1].y - pv[0].y;
- int32_t bx = pv[2].x - pv[0].x;
- int32_t by = pv[2].y - pv[0].y;
- int32_t cross_z = (ax >> 4) * (by >> 4) - (ay >> 4) * (bx >> 4);
- int sign = (cross_z >> 31) & 1;
-
- if(!(sign ^ st->frontface)) {
- continue; /* back-facing */
- }
- }
-
- switch(vnum) {
- case 1:
- if(st->opt & G3D_BLEND) {
- int r, g, b;
- int inv_alpha = 255 - pv[0].a;
- g3d_pixel *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
- r = ((int)pv[0].r * pv[0].a + G3D_UNPACK_R(*dest) * inv_alpha) >> 8;
- g = ((int)pv[0].g * pv[0].a + G3D_UNPACK_G(*dest) * inv_alpha) >> 8;
- b = ((int)pv[0].b * pv[0].a + G3D_UNPACK_B(*dest) * inv_alpha) >> 8;
- *dest++ = G3D_PACK_RGB(r, g, b);
- } else {
- g3d_pixel *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
- *dest = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
- }
- break;
-
- case 2:
- {
- g3d_pixel col = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
- draw_line(pv[0].x >> 8, pv[0].y >> 8, pv[1].x >> 8, pv[1].y >> 8, col);
- }
- break;
-
- default:
- fill_mode = st->polymode;
- if(st->opt & G3D_TEXTURE_2D) {
- fill_mode |= POLYFILL_TEX_BIT;
- }
- if(st->opt & G3D_BLEND) {
- fill_mode |= POLYFILL_BLEND_BIT;
- }
- polyfill(fill_mode, pv, vnum);
- }
- }
-}
-
-void g3d_begin(int prim)
-{
- st->imm_prim = prim;
- st->imm_pcount = prim;
- st->imm_numv = 0;
-}
-
-void g3d_end(void)
-{
- imm_flush();
-}
-
-static void imm_flush(void)
-{
- int numv = st->imm_numv;
- st->imm_numv = 0;
- g3d_draw_indexed(st->imm_prim, st->imm_vbuf, numv, 0, 0);
-}
-
-void g3d_vertex(float x, float y, float z)
-{
- struct g3d_vertex *vptr = st->imm_vbuf + st->imm_numv++;
- *vptr = st->imm_curv;
- vptr->x = x;
- vptr->y = y;
- vptr->z = z;
- vptr->w = 1.0f;
-
- if(!--st->imm_pcount) {
- if(st->imm_numv >= IMM_VBUF_SIZE - st->imm_prim) {
- imm_flush();
- }
- st->imm_pcount = st->imm_prim;
- }
-}
-
-void g3d_normal(float x, float y, float z)
-{
- st->imm_curv.nx = x;
- st->imm_curv.ny = y;
- st->imm_curv.nz = z;
-}
-
-#define CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
-#define MIN(a, b) ((a) < (b) ? (a) : (b))
-
-void g3d_color3b(unsigned char r, unsigned char g, unsigned char b)
-{
- st->imm_curv.r = MIN(r, 255);
- st->imm_curv.g = MIN(g, 255);
- st->imm_curv.b = MIN(b, 255);
- st->imm_curv.a = 255;
-}
-
-void g3d_color4b(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
-{
- st->imm_curv.r = MIN(r, 255);
- st->imm_curv.g = MIN(g, 255);
- st->imm_curv.b = MIN(b, 255);
- st->imm_curv.a = MIN(a, 255);
-}
-
-void g3d_color3f(float r, float g, float b)
-{
- int ir = r * 255.0f;
- int ig = g * 255.0f;
- int ib = b * 255.0f;
- st->imm_curv.r = CLAMP(ir, 0, 255);
- st->imm_curv.g = CLAMP(ig, 0, 255);
- st->imm_curv.b = CLAMP(ib, 0, 255);
- st->imm_curv.a = 255;
-}
-
-void g3d_color4f(float r, float g, float b, float a)
-{
- int ir = r * 255.0f;
- int ig = g * 255.0f;
- int ib = b * 255.0f;
- int ia = a * 255.0f;
- st->imm_curv.r = CLAMP(ir, 0, 255);
- st->imm_curv.g = CLAMP(ig, 0, 255);
- st->imm_curv.b = CLAMP(ib, 0, 255);
- st->imm_curv.a = CLAMP(ia, 0, 255);
-}
-
-void g3d_texcoord(float u, float v)
-{
- st->imm_curv.u = u;
- st->imm_curv.v = v;
-}
-
-static __inline void xform4_vec3(const float *mat, float *vec)
-{
- float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12];
- float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13];
- float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
- vec[3] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
- vec[2] = z;
- vec[1] = y;
- vec[0] = x;
-}
-
-static __inline void xform3_vec3(const float *mat, float *vec)
-{
- float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2];
- float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2];
- vec[2] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2];
- vec[1] = y;
- vec[0] = x;
-}
-
-static void shade(struct g3d_vertex *v)
-{
- int i, r, g, b;
- float color[3];
-
- color[0] = st->ambient[0] * st->mtl.kd[0];
- color[1] = st->ambient[1] * st->mtl.kd[1];
- color[2] = st->ambient[2] * st->mtl.kd[2];
-
- for(i=0; i<MAX_LIGHTS; i++) {
- float ldir[3];
- float ndotl;
-
- if(!(st->opt & (G3D_LIGHT0 << i))) {
- continue;
- }
-
- ldir[0] = st->lt[i].x;
- ldir[1] = st->lt[i].y;
- ldir[2] = st->lt[i].z;
-
- if(st->lt[i].type != LT_DIR) {
- ldir[0] -= v->x;
- ldir[1] -= v->y;
- ldir[2] -= v->z;
- NORMALIZE(ldir);
- }
-
- if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
- ndotl = 0.0f;
- }
-
- color[0] += st->mtl.kd[0] * st->lt[i].r * ndotl;
- color[1] += st->mtl.kd[1] * st->lt[i].g * ndotl;
- color[2] += st->mtl.kd[2] * st->lt[i].b * ndotl;
-
- /*
- if(st->opt & G3D_SPECULAR) {
- float ndoth;
- ldir[2] += 1.0f;
- NORMALIZE(ldir);
- if((ndoth = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
- ndoth = 0.0f;
- }
- ndoth = pow(ndoth, st->mtl.shin);
-
- color[0] += st->mtl.ks[0] * st->lt[i].r * ndoth;
- color[1] += st->mtl.ks[1] * st->lt[i].g * ndoth;
- color[2] += st->mtl.ks[2] * st->lt[i].b * ndoth;
- }
- */
- }
-
- r = cround64(color[0] * 255.0);
- g = cround64(color[1] * 255.0);
- b = cround64(color[2] * 255.0);
-
- v->r = r > 255 ? 255 : r;
- v->g = g > 255 ? 255 : g;
- v->b = b > 255 ? 255 : b;
-}
+++ /dev/null
-#ifndef THREEDGFX_H_
-#define THREEDGFX_H_
-
-#include "inttypes.h"
-#include "gfxutil.h"
-
-#define G3D_PIXFMT16
-typedef uint16_t g3d_pixel;
-
-#ifdef G3D_PIXFMT16
-#define G3D_PACK_RGB(r, g, b) PACK_RGB16(r, g, b)
-#define G3D_UNPACK_R(c) UNPACK_R16(c)
-#define G3D_UNPACK_G(c) UNPACK_G16(c)
-#define G3D_UNPACK_B(c) UNPACK_B16(c)
-#endif
-#ifdef G3D_PIXFMT32
-#define G3D_PACK_RGB(r, g, b) PACK_RGB32(r, g, b)
-#define G3D_UNPACK_R(c) UNPACK_R32(c)
-#define G3D_UNPACK_G(c) UNPACK_G32(c)
-#define G3D_UNPACK_B(c) UNPACK_B32(c)
-#endif
-
-
-struct g3d_vertex {
- float x, y, z, w;
- float nx, ny, nz;
- float u, v;
- unsigned char r, g, b, a;
-};
-
-enum {
- G3D_POINTS = 1,
- G3D_LINES = 2,
- G3D_TRIANGLES = 3,
- G3D_QUADS = 4
-};
-
-/* g3d_enable/g3d_disable bits */
-enum {
- G3D_CULL_FACE = 0x000001,
- G3D_DEPTH_TEST = 0x000002, /* XXX not implemented */
- G3D_LIGHTING = 0x000004,
- G3D_LIGHT0 = 0x000008,
- G3D_LIGHT1 = 0x000010,
- G3D_LIGHT2 = 0x000020,
- G3D_LIGHT3 = 0x000040,
- G3D_TEXTURE_2D = 0x000080, /* XXX doesn't affect anything, use g3d_polygon_mode */
- G3D_BLEND = 0x000100,
- G3D_TEXTURE_GEN = 0x000200,
- G3D_CLIP_FRUSTUM = 0x000800,/* when disabled, don't clip against the frustum */
- G3D_CLIP_PLANE0 = 0x001000, /* user-defined 3D clipping planes XXX not impl. */
- G3D_CLIP_PLANE1 = 0x002000,
- G3D_CLIP_PLANE2 = 0x004000,
- G3D_CLIP_PLANE3 = 0x008000,
-
- G3D_TEXTURE_MAT = 0x010000,
- G3D_SPECULAR = 0x020000,
-
- G3D_ALL = 0x7fffffff
-};
-
-/* arg to g3d_front_face */
-enum { G3D_CCW, G3D_CW };
-
-/* arg to g3d_polygon_mode */
-enum {
- G3D_WIRE,
- G3D_FLAT,
- G3D_GOURAUD
-};
-
-/* matrix stacks */
-enum {
- G3D_MODELVIEW,
- G3D_PROJECTION,
- G3D_TEXTURE,
-
- G3D_NUM_MATRICES
-};
-
-int g3d_init(void);
-void g3d_destroy(void);
-
-void g3d_framebuffer(int width, int height, void *pixels);
-void g3d_framebuffer_addr(void *pixels);
-void g3d_viewport(int x, int y, int w, int h);
-
-void g3d_enable(unsigned int opt);
-void g3d_disable(unsigned int opt);
-void g3d_setopt(unsigned int opt, unsigned int mask);
-unsigned int g3d_getopt(unsigned int mask);
-
-void g3d_front_face(unsigned int order);
-void g3d_polygon_mode(int pmode);
-
-void g3d_matrix_mode(int mmode);
-
-void g3d_load_identity(void);
-void g3d_load_matrix(const float *m);
-void g3d_mult_matrix(const float *m);
-void g3d_push_matrix(void);
-void g3d_pop_matrix(void);
-
-void g3d_translate(float x, float y, float z);
-void g3d_rotate(float angle, float x, float y, float z);
-void g3d_scale(float x, float y, float z);
-void g3d_ortho(float left, float right, float bottom, float top, float znear, float zfar);
-void g3d_frustum(float left, float right, float bottom, float top, float znear, float zfar);
-void g3d_perspective(float vfov, float aspect, float znear, float zfar);
-
-/* returns pointer to the *internal* matrix, and if argument m is not null,
- * also copies the internal matrix there. */
-const float *g3d_get_matrix(int which, float *m);
-
-void g3d_light_pos(int idx, float x, float y, float z);
-void g3d_light_dir(int idx, float x, float y, float z);
-void g3d_light_color(int idx, float r, float g, float b);
-
-void g3d_light_ambient(float r, float g, float b);
-
-void g3d_mtl_diffuse(float r, float g, float b);
-void g3d_mtl_specular(float r, float g, float b);
-void g3d_mtl_shininess(float shin);
-
-void g3d_set_texture(int xsz, int ysz, void *pixels);
-
-void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size);
-void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
- const uint16_t *iarr, int iarr_size);
-
-void g3d_begin(int prim);
-void g3d_end(void);
-void g3d_vertex(float x, float y, float z);
-void g3d_normal(float x, float y, float z);
-void g3d_color3b(unsigned char r, unsigned char g, unsigned char b);
-void g3d_color4b(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
-void g3d_color3f(float r, float g, float b);
-void g3d_color4f(float r, float g, float b, float a);
-void g3d_texcoord(float u, float v);
-
-#endif /* THREEDGFX_H_ */
--- /dev/null
+#ifndef BUILD_OPENGL
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+#include "3dgfx.h"
+#include "gfxutil.h"
+#include "polyfill.h"
+#include "polyclip.h"
+#include "inttypes.h"
+#include "demo.h"
+#include "util.h"
+
+#define STACK_SIZE 8
+typedef float g3d_matrix[16];
+
+#define MAX_LIGHTS 4
+
+#define IMM_VBUF_SIZE 256
+
+#define NORMALIZE(v) \
+ do { \
+ float len = sqrt((v)[0] * (v)[0] + (v)[1] * (v)[1] + (v)[2] * (v)[2]); \
+ if(len != 0.0) { \
+ float s = 1.0 / len; \
+ (v)[0] *= s; \
+ (v)[1] *= s; \
+ (v)[2] *= s; \
+ } \
+ } while(0)
+
+enum {LT_POS, LT_DIR};
+struct light {
+ int type;
+ float x, y, z;
+ float r, g, b;
+};
+
+struct material {
+ float kd[3];
+ float ks[3];
+ float shin;
+};
+
+struct g3d_state {
+ unsigned int opt;
+ int frontface;
+ int polymode;
+
+ g3d_matrix mat[G3D_NUM_MATRICES][STACK_SIZE];
+ int mtop[G3D_NUM_MATRICES];
+ int mmode;
+
+ g3d_matrix norm_mat;
+
+ float ambient[3];
+ struct light lt[MAX_LIGHTS];
+ struct material mtl;
+
+ int width, height;
+ g3d_pixel *pixels;
+
+ int vport[4];
+
+ /* immediate mode */
+ int imm_prim;
+ int imm_numv, imm_pcount;
+ struct g3d_vertex imm_curv;
+ struct g3d_vertex imm_vbuf[IMM_VBUF_SIZE];
+};
+
+static void imm_flush(void);
+static __inline void xform4_vec3(const float *mat, float *vec);
+static __inline void xform3_vec3(const float *mat, float *vec);
+static void shade(struct g3d_vertex *v);
+
+static struct g3d_state *st;
+static const float idmat[] = {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+};
+
+int g3d_init(void)
+{
+ if(!(st = malloc(sizeof *st))) {
+ fprintf(stderr, "failed to allocate G3D context\n");
+ return -1;
+ }
+ g3d_reset();
+
+ return 0;
+}
+
+void g3d_destroy(void)
+{
+ free(st);
+}
+
+void g3d_reset(void)
+{
+ int i;
+
+ memset(st, 0, sizeof *st);
+
+ st->opt = G3D_CLIP_FRUSTUM;
+ st->polymode = POLYFILL_FLAT;
+
+ for(i=0; i<G3D_NUM_MATRICES; i++) {
+ g3d_matrix_mode(i);
+ g3d_load_identity();
+ }
+
+ for(i=0; i<MAX_LIGHTS; i++) {
+ g3d_light_color(i, 1, 1, 1);
+ }
+ g3d_light_ambient(0.1, 0.1, 0.1);
+
+ g3d_mtl_diffuse(1, 1, 1);
+}
+
+void g3d_framebuffer(int width, int height, void *pixels)
+{
+ static int prev_height;
+
+ if(height > prev_height) {
+ polyfill_fbheight(height);
+ }
+
+ st->width = width;
+ st->height = height;
+ st->pixels = pixels;
+
+ pfill_fb.pixels = pixels;
+ pfill_fb.width = width;
+ pfill_fb.height = height;
+
+ g3d_viewport(0, 0, width, height);
+}
+
+/* set the framebuffer pointer, without resetting the size */
+void g3d_framebuffer_addr(void *pixels)
+{
+ st->pixels = pixels;
+ pfill_fb.pixels = pixels;
+}
+
+void g3d_viewport(int x, int y, int w, int h)
+{
+ st->vport[0] = x;
+ st->vport[1] = y;
+ st->vport[2] = w;
+ st->vport[3] = h;
+}
+
+void g3d_enable(unsigned int opt)
+{
+ st->opt |= opt;
+}
+
+void g3d_disable(unsigned int opt)
+{
+ st->opt &= ~opt;
+}
+
+void g3d_setopt(unsigned int opt, unsigned int mask)
+{
+ st->opt = (st->opt & ~mask) | (opt & mask);
+}
+
+unsigned int g3d_getopt(unsigned int mask)
+{
+ return st->opt & mask;
+}
+
+void g3d_front_face(unsigned int order)
+{
+ st->frontface = order;
+}
+
+void g3d_polygon_mode(int pmode)
+{
+ st->polymode = pmode;
+}
+
+int g3d_get_polygon_mode(void)
+{
+ return st->polymode;
+}
+
+void g3d_matrix_mode(int mmode)
+{
+ st->mmode = mmode;
+}
+
+void g3d_load_identity(void)
+{
+ int top = st->mtop[st->mmode];
+ memcpy(st->mat[st->mmode][top], idmat, 16 * sizeof(float));
+}
+
+void g3d_load_matrix(const float *m)
+{
+ int top = st->mtop[st->mmode];
+ memcpy(st->mat[st->mmode][top], m, 16 * sizeof(float));
+}
+
+#define M(i,j) (((i) << 2) + (j))
+void g3d_mult_matrix(const float *m2)
+{
+ int i, j, top = st->mtop[st->mmode];
+ float m1[16];
+ float *dest = st->mat[st->mmode][top];
+
+ memcpy(m1, dest, sizeof m1);
+
+ for(i=0; i<4; i++) {
+ for(j=0; j<4; j++) {
+ *dest++ = m1[M(0,j)] * m2[M(i,0)] +
+ m1[M(1,j)] * m2[M(i,1)] +
+ m1[M(2,j)] * m2[M(i,2)] +
+ m1[M(3,j)] * m2[M(i,3)];
+ }
+ }
+}
+
+void g3d_push_matrix(void)
+{
+ int top = st->mtop[st->mmode];
+ if(top >= G3D_NUM_MATRICES) {
+ fprintf(stderr, "g3d_push_matrix overflow\n");
+ return;
+ }
+ memcpy(st->mat[st->mmode][top + 1], st->mat[st->mmode][top], 16 * sizeof(float));
+ st->mtop[st->mmode] = top + 1;
+}
+
+void g3d_pop_matrix(void)
+{
+ if(st->mtop[st->mmode] <= 0) {
+ fprintf(stderr, "g3d_pop_matrix underflow\n");
+ return;
+ }
+ --st->mtop[st->mmode];
+}
+
+void g3d_translate(float x, float y, float z)
+{
+ float m[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1};
+ m[12] = x;
+ m[13] = y;
+ m[14] = z;
+ g3d_mult_matrix(m);
+}
+
+void g3d_rotate(float deg, float x, float y, float z)
+{
+ float m[16] = {0};
+
+ float angle = M_PI * deg / 180.0f;
+ float sina = sin(angle);
+ float cosa = cos(angle);
+ float one_minus_cosa = 1.0f - cosa;
+ float nxsq = x * x;
+ float nysq = y * y;
+ float nzsq = z * z;
+
+ m[0] = nxsq + (1.0f - nxsq) * cosa;
+ m[4] = x * y * one_minus_cosa - z * sina;
+ m[8] = x * z * one_minus_cosa + y * sina;
+ m[1] = x * y * one_minus_cosa + z * sina;
+ m[5] = nysq + (1.0 - nysq) * cosa;
+ m[9] = y * z * one_minus_cosa - x * sina;
+ m[2] = x * z * one_minus_cosa - y * sina;
+ m[6] = y * z * one_minus_cosa + x * sina;
+ m[10] = nzsq + (1.0 - nzsq) * cosa;
+ m[15] = 1.0f;
+
+ g3d_mult_matrix(m);
+}
+
+void g3d_scale(float x, float y, float z)
+{
+ float m[16] = {0};
+ m[0] = x;
+ m[5] = y;
+ m[10] = z;
+ m[15] = 1.0f;
+ g3d_mult_matrix(m);
+}
+
+void g3d_ortho(float left, float right, float bottom, float top, float znear, float zfar)
+{
+ float m[16] = {0};
+
+ float dx = right - left;
+ float dy = top - bottom;
+ float dz = zfar - znear;
+
+ m[0] = 2.0 / dx;
+ m[5] = 2.0 / dy;
+ m[10] = -2.0 / dz;
+ m[12] = -(right + left) / dx;
+ m[13] = -(top + bottom) / dy;
+ m[14] = -(zfar + znear) / dz;
+ m[15] = 1.0f;
+
+ g3d_mult_matrix(m);
+}
+
+void g3d_frustum(float left, float right, float bottom, float top, float nr, float fr)
+{
+ float m[16] = {0};
+
+ float dx = right - left;
+ float dy = top - bottom;
+ float dz = fr - nr;
+
+ float a = (right + left) / dx;
+ float b = (top + bottom) / dy;
+ float c = -(fr + nr) / dz;
+ float d = -2.0 * fr * nr / dz;
+
+ m[0] = 2.0 * nr / dx;
+ m[5] = 2.0 * nr / dy;
+ m[8] = a;
+ m[9] = b;
+ m[10] = c;
+ m[11] = -1.0f;
+ m[14] = d;
+
+ g3d_mult_matrix(m);
+}
+
+void g3d_perspective(float vfov_deg, float aspect, float znear, float zfar)
+{
+ float m[16] = {0};
+
+ float vfov = M_PI * vfov_deg / 180.0f;
+ float s = 1.0f / tan(vfov * 0.5f);
+ float range = znear - zfar;
+
+ m[0] = s / aspect;
+ m[5] = s;
+ m[10] = (znear + zfar) / range;
+ m[11] = -1.0f;
+ m[14] = 2.0f * znear * zfar / range;
+
+ g3d_mult_matrix(m);
+}
+
+const float *g3d_get_matrix(int which, float *m)
+{
+ int top = st->mtop[which];
+
+ if(m) {
+ memcpy(m, st->mat[which][top], 16 * sizeof(float));
+ }
+ return st->mat[which][top];
+}
+
+void g3d_light_pos(int idx, float x, float y, float z)
+{
+ int mvtop = st->mtop[G3D_MODELVIEW];
+
+ st->lt[idx].type = LT_POS;
+ st->lt[idx].x = x;
+ st->lt[idx].y = y;
+ st->lt[idx].z = z;
+
+ xform4_vec3(st->mat[G3D_MODELVIEW][mvtop], &st->lt[idx].x);
+}
+
+void g3d_light_dir(int idx, float x, float y, float z)
+{
+ int mvtop = st->mtop[G3D_MODELVIEW];
+
+ st->lt[idx].type = LT_DIR;
+ st->lt[idx].x = x;
+ st->lt[idx].y = y;
+ st->lt[idx].z = z;
+
+ /* calc the normal matrix */
+ memcpy(st->norm_mat, st->mat[G3D_MODELVIEW][mvtop], 16 * sizeof(float));
+ st->norm_mat[12] = st->norm_mat[13] = st->norm_mat[14] = 0.0f;
+
+ xform4_vec3(st->norm_mat, &st->lt[idx].x);
+
+ NORMALIZE(&st->lt[idx].x);
+}
+
+void g3d_light_color(int idx, float r, float g, float b)
+{
+ st->lt[idx].r = r;
+ st->lt[idx].g = g;
+ st->lt[idx].b = b;
+}
+
+void g3d_light_ambient(float r, float g, float b)
+{
+ st->ambient[0] = r;
+ st->ambient[1] = g;
+ st->ambient[2] = b;
+}
+
+void g3d_mtl_diffuse(float r, float g, float b)
+{
+ st->mtl.kd[0] = r;
+ st->mtl.kd[1] = g;
+ st->mtl.kd[2] = b;
+}
+
+void g3d_mtl_specular(float r, float g, float b)
+{
+ st->mtl.ks[0] = r;
+ st->mtl.ks[1] = g;
+ st->mtl.ks[2] = b;
+}
+
+void g3d_mtl_shininess(float shin)
+{
+ st->mtl.shin = shin;
+}
+
+static INLINE int calc_shift(unsigned int x)
+{
+ int res = -1;
+ while(x) {
+ x >>= 1;
+ ++res;
+ }
+ return res;
+}
+
+static INLINE int calc_mask(unsigned int x)
+{
+ return x - 1;
+}
+
+void g3d_set_texture(int xsz, int ysz, void *pixels)
+{
+ pfill_tex.pixels = pixels;
+ pfill_tex.width = xsz;
+ pfill_tex.height = ysz;
+
+ pfill_tex.xshift = calc_shift(xsz);
+ pfill_tex.yshift = calc_shift(ysz);
+ pfill_tex.xmask = calc_mask(xsz);
+ pfill_tex.ymask = calc_mask(ysz);
+}
+
+void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size)
+{
+ g3d_draw_indexed(prim, varr, varr_size, 0, 0);
+}
+
+void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
+ const uint16_t *iarr, int iarr_size)
+{
+ int i, j, vnum, nfaces, fill_mode;
+ struct pvertex pv[16];
+ struct g3d_vertex v[16];
+ int mvtop = st->mtop[G3D_MODELVIEW];
+ int ptop = st->mtop[G3D_PROJECTION];
+ struct g3d_vertex *tmpv;
+
+ tmpv = alloca(prim * 6 * sizeof *tmpv);
+
+ /* calc the normal matrix */
+ memcpy(st->norm_mat, st->mat[G3D_MODELVIEW][mvtop], 16 * sizeof(float));
+ st->norm_mat[12] = st->norm_mat[13] = st->norm_mat[14] = 0.0f;
+
+ nfaces = (iarr ? iarr_size : varr_size) / prim;
+
+ for(j=0; j<nfaces; j++) {
+ vnum = prim; /* reset vnum for each iteration */
+
+ for(i=0; i<vnum; i++) {
+ v[i] = iarr ? varr[*iarr++] : *varr++;
+
+ xform4_vec3(st->mat[G3D_MODELVIEW][mvtop], &v[i].x);
+ xform3_vec3(st->norm_mat, &v[i].nx);
+
+ if(st->opt & G3D_LIGHTING) {
+ shade(v + i);
+ }
+ if(st->opt & G3D_TEXTURE_GEN) {
+ v[i].u = v[i].nx * 0.5 + 0.5;
+ v[i].v = 0.5 - v[i].ny * 0.5;
+ }
+ if(st->opt & G3D_TEXTURE_MAT) {
+ float *mat = st->mat[G3D_TEXTURE][st->mtop[G3D_TEXTURE]];
+ float x = mat[0] * v[i].u + mat[4] * v[i].v + mat[12];
+ float y = mat[1] * v[i].u + mat[5] * v[i].v + mat[13];
+ float w = mat[3] * v[i].u + mat[7] * v[i].v + mat[15];
+ v[i].u = x / w;
+ v[i].v = y / w;
+ }
+ xform4_vec3(st->mat[G3D_PROJECTION][ptop], &v[i].x);
+ }
+
+ /* clipping */
+ if(st->opt & G3D_CLIP_FRUSTUM) {
+ for(i=0; i<6; i++) {
+ memcpy(tmpv, v, vnum * sizeof *v);
+
+ if(clip_frustum(v, &vnum, tmpv, vnum, i) < 0) {
+ /* polygon completely outside of view volume. discard */
+ vnum = 0;
+ break;
+ }
+ }
+
+ if(!vnum) continue;
+ }
+
+ for(i=0; i<vnum; i++) {
+ if(v[i].w != 0.0f) {
+ v[i].x /= v[i].w;
+ v[i].y /= v[i].w;
+ /*v[i].z /= v[i].w;*/
+ }
+
+ /* viewport transformation */
+ v[i].x = (v[i].x * 0.5f + 0.5f) * (float)st->vport[2] + st->vport[0];
+ v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->vport[3] + st->vport[1];
+
+ /* convert pos to 24.8 fixed point */
+ pv[i].x = cround64(v[i].x * 256.0f);
+ pv[i].y = cround64(v[i].y * 256.0f);
+ /* convert tex coords to 16.16 fixed point */
+ pv[i].u = cround64(v[i].u * 65536.0f);
+ pv[i].v = cround64(v[i].v * 65536.0f);
+ /* pass the color through as is */
+ pv[i].r = v[i].r;
+ pv[i].g = v[i].g;
+ pv[i].b = v[i].b;
+ pv[i].a = v[i].a;
+ }
+
+ /* backface culling */
+ if(vnum > 2 && st->opt & G3D_CULL_FACE) {
+ int32_t ax = pv[1].x - pv[0].x;
+ int32_t ay = pv[1].y - pv[0].y;
+ int32_t bx = pv[2].x - pv[0].x;
+ int32_t by = pv[2].y - pv[0].y;
+ int32_t cross_z = (ax >> 4) * (by >> 4) - (ay >> 4) * (bx >> 4);
+ int sign = (cross_z >> 31) & 1;
+
+ if(!(sign ^ st->frontface)) {
+ continue; /* back-facing */
+ }
+ }
+
+ switch(vnum) {
+ case 1:
+ if(st->opt & (G3D_ALPHA_BLEND | G3D_ADD_BLEND)) {
+ int r, g, b, inv_alpha;
+ g3d_pixel *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
+ if(st->opt & G3D_ALPHA_BLEND) {
+ inv_alpha = 255 - pv[0].a;
+ r = ((int)pv[0].r * pv[0].a + G3D_UNPACK_R(*dest) * inv_alpha) >> 8;
+ g = ((int)pv[0].g * pv[0].a + G3D_UNPACK_G(*dest) * inv_alpha) >> 8;
+ b = ((int)pv[0].b * pv[0].a + G3D_UNPACK_B(*dest) * inv_alpha) >> 8;
+ } else {
+ r = (int)pv[0].r + G3D_UNPACK_R(*dest);
+ g = (int)pv[0].g + G3D_UNPACK_G(*dest);
+ b = (int)pv[0].b + G3D_UNPACK_B(*dest);
+ if(r > 255) r = 255;
+ if(g > 255) g = 255;
+ if(b > 255) b = 255;
+ }
+ *dest++ = G3D_PACK_RGB(r, g, b);
+ } else {
+ g3d_pixel *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8);
+ *dest = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
+ }
+ break;
+
+ case 2:
+ {
+ g3d_pixel col = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
+ draw_line(pv[0].x >> 8, pv[0].y >> 8, pv[1].x >> 8, pv[1].y >> 8, col);
+ }
+ break;
+
+ default:
+ fill_mode = st->polymode;
+ if(st->opt & G3D_TEXTURE_2D) {
+ fill_mode |= POLYFILL_TEX_BIT;
+ }
+ if(st->opt & G3D_ALPHA_BLEND) {
+ fill_mode |= POLYFILL_ALPHA_BIT;
+ } else if(st->opt & G3D_ADD_BLEND) {
+ fill_mode |= POLYFILL_ADD_BIT;
+ }
+ polyfill(fill_mode, pv, vnum);
+ }
+ }
+}
+
+void g3d_begin(int prim)
+{
+ st->imm_prim = prim;
+ st->imm_pcount = prim;
+ st->imm_numv = 0;
+}
+
+void g3d_end(void)
+{
+ imm_flush();
+}
+
+static void imm_flush(void)
+{
+ int numv = st->imm_numv;
+ st->imm_numv = 0;
+ g3d_draw_indexed(st->imm_prim, st->imm_vbuf, numv, 0, 0);
+}
+
+void g3d_vertex(float x, float y, float z)
+{
+ struct g3d_vertex *vptr = st->imm_vbuf + st->imm_numv++;
+ *vptr = st->imm_curv;
+ vptr->x = x;
+ vptr->y = y;
+ vptr->z = z;
+ vptr->w = 1.0f;
+
+ if(!--st->imm_pcount) {
+ if(st->imm_numv >= IMM_VBUF_SIZE - st->imm_prim) {
+ imm_flush();
+ }
+ st->imm_pcount = st->imm_prim;
+ }
+}
+
+void g3d_normal(float x, float y, float z)
+{
+ st->imm_curv.nx = x;
+ st->imm_curv.ny = y;
+ st->imm_curv.nz = z;
+}
+
+#define CLAMP(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+void g3d_color3b(unsigned char r, unsigned char g, unsigned char b)
+{
+ st->imm_curv.r = MIN(r, 255);
+ st->imm_curv.g = MIN(g, 255);
+ st->imm_curv.b = MIN(b, 255);
+ st->imm_curv.a = 255;
+}
+
+void g3d_color4b(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ st->imm_curv.r = MIN(r, 255);
+ st->imm_curv.g = MIN(g, 255);
+ st->imm_curv.b = MIN(b, 255);
+ st->imm_curv.a = MIN(a, 255);
+}
+
+void g3d_color3f(float r, float g, float b)
+{
+ int ir = r * 255.0f;
+ int ig = g * 255.0f;
+ int ib = b * 255.0f;
+ st->imm_curv.r = CLAMP(ir, 0, 255);
+ st->imm_curv.g = CLAMP(ig, 0, 255);
+ st->imm_curv.b = CLAMP(ib, 0, 255);
+ st->imm_curv.a = 255;
+}
+
+void g3d_color4f(float r, float g, float b, float a)
+{
+ int ir = r * 255.0f;
+ int ig = g * 255.0f;
+ int ib = b * 255.0f;
+ int ia = a * 255.0f;
+ st->imm_curv.r = CLAMP(ir, 0, 255);
+ st->imm_curv.g = CLAMP(ig, 0, 255);
+ st->imm_curv.b = CLAMP(ib, 0, 255);
+ st->imm_curv.a = CLAMP(ia, 0, 255);
+}
+
+void g3d_texcoord(float u, float v)
+{
+ st->imm_curv.u = u;
+ st->imm_curv.v = v;
+}
+
+static __inline void xform4_vec3(const float *mat, float *vec)
+{
+ float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12];
+ float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13];
+ float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14];
+ vec[3] = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15];
+ vec[2] = z;
+ vec[1] = y;
+ vec[0] = x;
+}
+
+static __inline void xform3_vec3(const float *mat, float *vec)
+{
+ float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2];
+ float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2];
+ vec[2] = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2];
+ vec[1] = y;
+ vec[0] = x;
+}
+
+static void shade(struct g3d_vertex *v)
+{
+ int i, r, g, b;
+ float color[3];
+
+ color[0] = st->ambient[0] * st->mtl.kd[0];
+ color[1] = st->ambient[1] * st->mtl.kd[1];
+ color[2] = st->ambient[2] * st->mtl.kd[2];
+
+ for(i=0; i<MAX_LIGHTS; i++) {
+ float ldir[3];
+ float ndotl;
+
+ if(!(st->opt & (G3D_LIGHT0 << i))) {
+ continue;
+ }
+
+ ldir[0] = st->lt[i].x;
+ ldir[1] = st->lt[i].y;
+ ldir[2] = st->lt[i].z;
+
+ if(st->lt[i].type != LT_DIR) {
+ ldir[0] -= v->x;
+ ldir[1] -= v->y;
+ ldir[2] -= v->z;
+ NORMALIZE(ldir);
+ }
+
+ if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
+ ndotl = 0.0f;
+ }
+
+ color[0] += st->mtl.kd[0] * st->lt[i].r * ndotl;
+ color[1] += st->mtl.kd[1] * st->lt[i].g * ndotl;
+ color[2] += st->mtl.kd[2] * st->lt[i].b * ndotl;
+
+ /*
+ if(st->opt & G3D_SPECULAR) {
+ float ndoth;
+ ldir[2] += 1.0f;
+ NORMALIZE(ldir);
+ if((ndoth = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) {
+ ndoth = 0.0f;
+ }
+ ndoth = pow(ndoth, st->mtl.shin);
+
+ color[0] += st->mtl.ks[0] * st->lt[i].r * ndoth;
+ color[1] += st->mtl.ks[1] * st->lt[i].g * ndoth;
+ color[2] += st->mtl.ks[2] * st->lt[i].b * ndoth;
+ }
+ */
+ }
+
+ r = cround64(color[0] * 255.0);
+ g = cround64(color[1] * 255.0);
+ b = cround64(color[2] * 255.0);
+
+ v->r = r > 255 ? 255 : r;
+ v->g = g > 255 ? 255 : g;
+ v->b = b > 255 ? 255 : b;
+}
+
+#endif /* !def BUILD_OPENGL */
--- /dev/null
+#ifndef THREEDGFX_H_
+#define THREEDGFX_H_
+
+#include "inttypes.h"
+#include "gfxutil.h"
+
+#define G3D_PIXFMT16
+typedef uint16_t g3d_pixel;
+
+#ifdef G3D_PIXFMT16
+#define G3D_PACK_RGB(r, g, b) PACK_RGB16(r, g, b)
+#define G3D_UNPACK_R(c) UNPACK_R16(c)
+#define G3D_UNPACK_G(c) UNPACK_G16(c)
+#define G3D_UNPACK_B(c) UNPACK_B16(c)
+#endif
+#ifdef G3D_PIXFMT32
+#define G3D_PACK_RGB(r, g, b) PACK_RGB32(r, g, b)
+#define G3D_UNPACK_R(c) UNPACK_R32(c)
+#define G3D_UNPACK_G(c) UNPACK_G32(c)
+#define G3D_UNPACK_B(c) UNPACK_B32(c)
+#endif
+
+
+struct g3d_vertex {
+ float x, y, z, w;
+ float nx, ny, nz;
+ float u, v;
+ unsigned char r, g, b, a;
+};
+
+enum {
+ G3D_POINTS = 1,
+ G3D_LINES = 2,
+ G3D_TRIANGLES = 3,
+ G3D_QUADS = 4
+};
+
+/* g3d_enable/g3d_disable bits */
+enum {
+ G3D_CULL_FACE = 0x000001,
+ G3D_DEPTH_TEST = 0x000002, /* XXX not implemented */
+ G3D_LIGHTING = 0x000004,
+ G3D_LIGHT0 = 0x000008,
+ G3D_LIGHT1 = 0x000010,
+ G3D_LIGHT2 = 0x000020,
+ G3D_LIGHT3 = 0x000040,
+ G3D_TEXTURE_2D = 0x000080,
+ G3D_ALPHA_BLEND = 0x000100,
+ G3D_TEXTURE_GEN = 0x000200,
+ G3D_CLIP_FRUSTUM = 0x000800,/* when disabled, don't clip against the frustum */
+ G3D_CLIP_PLANE0 = 0x001000, /* user-defined 3D clipping planes XXX not impl. */
+ G3D_CLIP_PLANE1 = 0x002000,
+ G3D_CLIP_PLANE2 = 0x004000,
+ G3D_CLIP_PLANE3 = 0x008000,
+
+ G3D_TEXTURE_MAT = 0x010000,
+ G3D_SPECULAR = 0x020000,
+
+ G3D_ADD_BLEND = 0x040000,
+
+ G3D_ALL = 0x7fffffff
+};
+
+/* arg to g3d_front_face */
+enum { G3D_CCW, G3D_CW };
+
+/* arg to g3d_polygon_mode */
+enum {
+ G3D_WIRE,
+ G3D_FLAT,
+ G3D_GOURAUD
+};
+
+/* matrix stacks */
+enum {
+ G3D_MODELVIEW,
+ G3D_PROJECTION,
+ G3D_TEXTURE,
+
+ G3D_NUM_MATRICES
+};
+
+int g3d_init(void);
+void g3d_destroy(void);
+void g3d_reset(void);
+
+void g3d_framebuffer(int width, int height, void *pixels);
+void g3d_framebuffer_addr(void *pixels);
+void g3d_viewport(int x, int y, int w, int h);
+
+void g3d_enable(unsigned int opt);
+void g3d_disable(unsigned int opt);
+void g3d_setopt(unsigned int opt, unsigned int mask);
+unsigned int g3d_getopt(unsigned int mask);
+
+void g3d_front_face(unsigned int order);
+void g3d_polygon_mode(int pmode);
+int g3d_get_polygon_mode(void);
+
+void g3d_matrix_mode(int mmode);
+
+void g3d_load_identity(void);
+void g3d_load_matrix(const float *m);
+void g3d_mult_matrix(const float *m);
+void g3d_push_matrix(void);
+void g3d_pop_matrix(void);
+
+void g3d_translate(float x, float y, float z);
+void g3d_rotate(float angle, float x, float y, float z);
+void g3d_scale(float x, float y, float z);
+void g3d_ortho(float left, float right, float bottom, float top, float znear, float zfar);
+void g3d_frustum(float left, float right, float bottom, float top, float znear, float zfar);
+void g3d_perspective(float vfov, float aspect, float znear, float zfar);
+
+/* returns pointer to the *internal* matrix, and if argument m is not null,
+ * also copies the internal matrix there. */
+const float *g3d_get_matrix(int which, float *m);
+
+void g3d_light_pos(int idx, float x, float y, float z);
+void g3d_light_dir(int idx, float x, float y, float z);
+void g3d_light_color(int idx, float r, float g, float b);
+
+void g3d_light_ambient(float r, float g, float b);
+
+void g3d_mtl_diffuse(float r, float g, float b);
+void g3d_mtl_specular(float r, float g, float b);
+void g3d_mtl_shininess(float shin);
+
+void g3d_set_texture(int xsz, int ysz, void *pixels);
+
+void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size);
+void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
+ const uint16_t *iarr, int iarr_size);
+
+void g3d_begin(int prim);
+void g3d_end(void);
+void g3d_vertex(float x, float y, float z);
+void g3d_normal(float x, float y, float z);
+void g3d_color3b(unsigned char r, unsigned char g, unsigned char b);
+void g3d_color4b(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+void g3d_color3f(float r, float g, float b);
+void g3d_color4f(float r, float g, float b, float a);
+void g3d_texcoord(float u, float v);
+
+#endif /* THREEDGFX_H_ */
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "mesh.h"
+#include "3dgfx.h"
+
+void free_mesh(struct g3d_mesh *mesh)
+{
+ destroy_mesh(mesh);
+ free(mesh);
+}
+
+void destroy_mesh(struct g3d_mesh *mesh)
+{
+ free(mesh->varr);
+ free(mesh->iarr);
+}
+
+int copy_mesh(struct g3d_mesh *dest, struct g3d_mesh *src)
+{
+ dest->prim = src->prim;
+ if(src->varr) {
+ if(!(dest->varr = malloc(src->vcount * sizeof *src->varr))) {
+ return -1;
+ }
+ memcpy(dest->varr, src->varr, src->vcount * sizeof *src->varr);
+ }
+ dest->vcount = src->vcount;
+ if(src->iarr) {
+ if(!(dest->iarr = malloc(src->icount * sizeof *src->iarr))) {
+ free(dest->varr);
+ dest->varr = 0;
+ return -1;
+ }
+ memcpy(dest->iarr, src->iarr, src->icount * sizeof *src->iarr);
+ }
+ dest->icount = src->icount;
+ return 0;
+}
+
+static struct {
+ int prim;
+ struct g3d_vertex *varr;
+ const float *xform;
+} zsort_cls;
+
+static int zsort_cmp(const void *aptr, const void *bptr)
+{
+ int i;
+ float za = 0.0f;
+ float zb = 0.0f;
+ const float *m = zsort_cls.xform;
+ const struct g3d_vertex *va = (const struct g3d_vertex*)aptr;
+ const struct g3d_vertex *vb = (const struct g3d_vertex*)bptr;
+
+ for(i=0; i<zsort_cls.prim; i++) {
+ za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
+ zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
+ ++va;
+ ++vb;
+ }
+
+ za -= zb;
+ return *(int*)&za;
+}
+
+static int zsort_indexed_cmp(const void *aptr, const void *bptr)
+{
+ int i;
+ float za = 0.0f;
+ float zb = 0.0f;
+ const uint16_t *a = (const uint16_t*)aptr;
+ const uint16_t *b = (const uint16_t*)bptr;
+
+ const float *m = zsort_cls.xform;
+
+ for(i=0; i<zsort_cls.prim; i++) {
+ const struct g3d_vertex *va = zsort_cls.varr + a[i];
+ const struct g3d_vertex *vb = zsort_cls.varr + b[i];
+
+ za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
+ zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
+ }
+
+ za -= zb;
+ return *(int*)&za;
+}
+
+
+void zsort_mesh(struct g3d_mesh *m)
+{
+ zsort_cls.varr = m->varr;
+ zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
+ zsort_cls.prim = m->prim;
+
+ if(m->iarr) {
+ int nfaces = m->icount / m->prim;
+ qsort(m->iarr, nfaces, m->prim * sizeof *m->iarr, zsort_indexed_cmp);
+ } else {
+ int nfaces = m->vcount / m->prim;
+ qsort(m->varr, nfaces, m->prim * sizeof *m->varr, zsort_cmp);
+ }
+}
+
+
+void draw_mesh(struct g3d_mesh *mesh)
+{
+ if(mesh->iarr) {
+ g3d_draw_indexed(mesh->prim, mesh->varr, mesh->vcount, mesh->iarr, mesh->icount);
+ } else {
+ g3d_draw(mesh->prim, mesh->varr, mesh->vcount);
+ }
+}
+
+void apply_mesh_xform(struct g3d_mesh *mesh, const float *xform)
+{
+ int i;
+ struct g3d_vertex *v = mesh->varr;
+
+ for(i=0; i<mesh->vcount; i++) {
+ float x = xform[0] * v->x + xform[4] * v->y + xform[8] * v->z + xform[12];
+ float y = xform[1] * v->x + xform[5] * v->y + xform[9] * v->z + xform[13];
+ v->z = xform[2] * v->x + xform[6] * v->y + xform[10] * v->z + xform[14];
+ v->x = x;
+ v->y = y;
+ x = xform[0] * v->nx + xform[4] * v->ny + xform[8] * v->nz;
+ y = xform[1] * v->nx + xform[5] * v->ny + xform[9] * v->nz;
+ v->nz = xform[2] * v->nx + xform[6] * v->ny + xform[10] * v->nz;
+ v->nx = x;
+ v->ny = y;
+ ++v;
+ }
+}
+
+int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb)
+{
+ int i, new_vcount, new_icount;
+ void *tmp;
+ uint16_t *iptr;
+
+ if(ma->prim != mb->prim) {
+ fprintf(stderr, "append_mesh failed, primitive mismatch\n");
+ return -1;
+ }
+
+ if(ma->iarr || mb->iarr) {
+ if(!ma->iarr) {
+ if(indexify_mesh(ma) == -1) {
+ return -1;
+ }
+ } else if(!mb->iarr) {
+ if(indexify_mesh(mb) == -1) {
+ return -1;
+ }
+ }
+
+ new_icount = ma->icount + mb->icount;
+ if(!(iptr = realloc(ma->iarr, new_icount * sizeof *iptr))) {
+ fprintf(stderr, "append_mesh: failed to allocate combined index buffer (%d indices)\n", new_icount);
+ return -1;
+ }
+ ma->iarr = iptr;
+
+ iptr += ma->icount;
+ for(i=0; i<mb->icount; i++) {
+ *iptr++ = mb->iarr[i] + ma->vcount;
+ }
+ ma->icount = new_icount;
+ }
+
+ new_vcount = ma->vcount + mb->vcount;
+ if(!(tmp = realloc(ma->varr, new_vcount * sizeof *ma->varr))) {
+ fprintf(stderr, "append_mesh: failed to allocate combined vertex buffer (%d verts)\n", new_vcount);
+ return -1;
+ }
+ ma->varr = tmp;
+ memcpy(ma->varr + ma->vcount, mb->varr, mb->vcount * sizeof *ma->varr);
+ ma->vcount = new_vcount;
+ return 0;
+}
+
+#define FEQ(a, b) ((a) - (b) < 1e-5 && (b) - (a) < 1e-5)
+static int cmp_vertex(struct g3d_vertex *a, struct g3d_vertex *b)
+{
+ if(!FEQ(a->x, b->x) || !FEQ(a->y, b->y) || !FEQ(a->z, b->z) || !FEQ(a->w, b->w))
+ return -1;
+ if(!FEQ(a->nx, b->nx) || !FEQ(a->ny, b->ny) || !FEQ(a->nz, b->nz))
+ return -1;
+ if(!FEQ(a->u, b->u) || !FEQ(a->v, b->v))
+ return -1;
+ if(a->r != b->r || a->g != b->g || a->b != b->b || a->a != b->a)
+ return -1;
+ return 0;
+}
+
+static int find_existing(struct g3d_vertex *v, struct g3d_vertex *varr, int vcount)
+{
+ int i;
+ for(i=0; i<vcount; i++) {
+ if(cmp_vertex(v, varr++) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int indexify_mesh(struct g3d_mesh *mesh)
+{
+ int i, j, nfaces, max_icount, idx;
+ int out_vcount = 0;
+ struct g3d_vertex *vin, *vout;
+ uint16_t *iout;
+
+ if(mesh->iarr) {
+ fprintf(stderr, "indexify_mesh failed: already indexed\n");
+ return -1;
+ }
+
+ nfaces = mesh->vcount / mesh->prim;
+ max_icount = mesh->vcount;
+
+ if(!(mesh->iarr = malloc(max_icount * sizeof *mesh->iarr))) {
+ fprintf(stderr, "indexify_mesh failed to allocate index buffer of %d indices\n", max_icount);
+ return -1;
+ }
+
+ vin = vout = mesh->varr;
+ iout = mesh->iarr;
+
+ for(i=0; i<nfaces; i++) {
+ for(j=0; j<mesh->prim; j++) {
+ if((idx = find_existing(vin, mesh->varr, out_vcount)) >= 0) {
+ *iout++ = idx;
+ } else {
+ *iout++ = out_vcount++;
+ if(vin != vout) {
+ *vout++ = *vin;
+ }
+ }
+ ++vin;
+ }
+ }
+
+ /* XXX also shrink buffers? I'll just leave them to max size for now */
+ return 0;
+}
+
+void normalize_mesh_normals(struct g3d_mesh *mesh)
+{
+ int i;
+ struct g3d_vertex *v = mesh->varr;
+
+ for(i=0; i<mesh->vcount; i++) {
+ float mag = sqrt(v->nx * v->nx + v->ny * v->ny + v->nz * v->nz);
+ float s = (mag == 0.0f) ? 1.0f : 1.0f / mag;
+ v->nx *= s;
+ v->ny *= s;
+ v->nz *= s;
+ ++v;
+ }
+}
+
+
+void calc_mesh_centroid(struct g3d_mesh *mesh, float *cent)
+{
+ int i;
+ float s = 1.0f / (float)mesh->vcount;
+ cent[0] = cent[1] = cent[2] = 0.0f;
+
+ for(i=0; i<mesh->vcount; i++) {
+ cent[0] += mesh->varr[i].x;
+ cent[1] += mesh->varr[i].y;
+ cent[2] += mesh->varr[i].z;
+ }
+ cent[0] *= s;
+ cent[1] *= s;
+ cent[2] *= s;
+}
+
+static void sphvec(float *res, float theta, float phi, float rad)
+{
+ theta = -theta;
+ res[0] = sin(theta) * sin(phi);
+ res[1] = cos(phi);
+ res[2] = cos(theta) * sin(phi);
+}
+
+int gen_sphere_mesh(struct g3d_mesh *mesh, float rad, int usub, int vsub)
+{
+ int i, j;
+ int nfaces, uverts, vverts;
+ struct g3d_vertex *vptr;
+ uint16_t *iptr;
+
+ mesh->prim = G3D_QUADS;
+
+ if(usub < 4) usub = 4;
+ if(vsub < 2) vsub = 2;
+
+ uverts = usub + 1;
+ vverts = vsub + 1;
+
+ mesh->vcount = uverts * vverts;
+ nfaces = usub * vsub;
+ mesh->icount = nfaces * 4;
+
+ if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
+ fprintf(stderr, "gen_sphere_mesh: failed to allocate vertex buffer (%d vertices)\n", mesh->vcount);
+ return -1;
+ }
+ if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
+ fprintf(stderr, "gen_sphere_mesh: failed to allocate index buffer (%d indices)\n", mesh->icount);
+ return -1;
+ }
+ vptr = mesh->varr;
+ iptr = mesh->iarr;
+
+ for(i=0; i<uverts; i++) {
+ float u = (float)i / (float)(uverts - 1);
+ float theta = u * 2.0 * M_PI;
+
+ for(j=0; j<vverts; j++) {
+ float v = (float)j / (float)(vverts - 1);
+ float phi = v * M_PI;
+ int chess = (i & 1) == (j & 1);
+
+ sphvec(&vptr->x, theta, phi, rad);
+ vptr->w = 1.0f;
+
+ vptr->nx = vptr->x / rad;
+ vptr->ny = vptr->y / rad;
+ vptr->nz = vptr->z / rad;
+ vptr->u = u;
+ vptr->v = v;
+ vptr->r = chess ? 255 : 64;
+ vptr->g = 128;
+ vptr->b = chess ? 64 : 255;
+ ++vptr;
+
+ if(i < usub && j < vsub) {
+ int idx = i * vverts + j;
+ *iptr++ = idx;
+ *iptr++ = idx + 1;
+ *iptr++ = idx + vverts + 1;
+ *iptr++ = idx + vverts;
+ }
+ }
+ }
+ return 0;
+}
+
+int gen_plane_mesh(struct g3d_mesh *m, float width, float height, int usub, int vsub)
+{
+ int i, j;
+ int nfaces, nverts, nidx, uverts, vverts;
+ float x, y, u, v, du, dv;
+ struct g3d_vertex *vptr;
+ uint16_t *iptr;
+
+ if(usub < 1) usub = 1;
+ if(vsub < 1) vsub = 1;
+
+ nfaces = usub * vsub;
+ uverts = usub + 1;
+ vverts = vsub + 1;
+ du = (float)width / (float)usub;
+ dv = (float)height / (float)vsub;
+
+ nverts = uverts * vverts;
+ nidx = nfaces * 4;
+
+ if(!(m->varr = malloc(nverts * sizeof *m->varr))) {
+ fprintf(stderr, "gen_plane_mesh: failed to allocate vertex buffer (%d vertices)\n", nverts);
+ return -1;
+ }
+ if(!(m->iarr = malloc(nidx * sizeof *m->iarr))) {
+ fprintf(stderr, "gen_plane_mesh: failed to allocate index buffer (%d indices)\n", nidx);
+ free(m->varr);
+ m->varr = 0;
+ return -1;
+ }
+
+ m->prim = G3D_QUADS;
+ m->vcount = nverts;
+ m->icount = nidx;
+
+ vptr = m->varr;
+ iptr = m->iarr;
+
+ v = 0.0f;
+ for(i=0; i<vverts; i++) {
+ y = (v - 0.5) * height;
+ u = 0.0f;
+
+ for(j=0; j<uverts; j++) {
+ x = (u - 0.5) * width;
+
+ vptr->x = x;
+ vptr->y = y;
+ vptr->z = 0.0f;
+ vptr->w = 1.0f;
+ vptr->nx = 0.0f;
+ vptr->ny = 0.0f;
+ vptr->nz = 1.0f;
+ vptr->u = u;
+ vptr->v = v;
+ vptr->r = vptr->g = vptr->b = vptr->a = 255;
+ ++vptr;
+
+ u += du;
+ }
+ v += dv;
+ }
+
+ for(i=0; i<vsub; i++) {
+ for(j=0; j<usub; j++) {
+ int idx = i * uverts + j;
+ *iptr++ = idx;
+ *iptr++ = idx + 1;
+ *iptr++ = idx + uverts + 1;
+ *iptr++ = idx + uverts;
+ }
+ }
+ return 0;
+}
+
+int gen_cube_mesh(struct g3d_mesh *mesh, float sz, int sub)
+{
+ int i;
+ float offs;
+ struct g3d_mesh *m;
+ struct g3d_mesh tmpmesh;
+ static float rotface[][4] = {
+ {0, 0, 1, 0},
+ {90, 0, 1, 0},
+ {180, 0, 1, 0},
+ {270, 0, 1, 0},
+ {90, 1, 0, 0},
+ {-90, 1, 0, 0}
+ };
+
+ offs = sz;
+ sz = fabs(sz);
+
+ g3d_matrix_mode(G3D_MODELVIEW);
+ g3d_push_matrix();
+
+ for(i=0; i<6; i++) {
+ m = i > 0 ? &tmpmesh : mesh;
+ if(gen_plane_mesh(m, sz, sz, sub, sub) == -1)
+ return -1;
+ g3d_load_identity();
+ g3d_rotate(rotface[i][0], rotface[i][1], rotface[i][2], rotface[i][3]);
+ g3d_translate(0, 0, offs / 2.0f);
+ apply_mesh_xform(m, g3d_get_matrix(G3D_MODELVIEW, 0));
+ if(i > 0) {
+ if(append_mesh(mesh, m) == -1) {
+ return -1;
+ }
+ }
+ }
+
+ g3d_pop_matrix();
+ return 0;
+}
+
+static void torusvec(float *res, float theta, float phi, float mr, float rr)
+{
+ float rx, ry, rz;
+ theta = -theta;
+
+ rx = -cos(phi) * rr + mr;
+ ry = sin(phi) * rr;
+ rz = 0.0f;
+
+ res[0] = rx * sin(theta) + rz * cos(theta);
+ res[1] = ry;
+ res[2] = -rx * cos(theta) + rz * sin(theta);
+}
+
+int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, int vsub)
+{
+ int i, j;
+ int nfaces, uverts, vverts;
+ struct g3d_vertex *vptr;
+ uint16_t *iptr;
+
+ mesh->prim = G3D_QUADS;
+
+ if(usub < 4) usub = 4;
+ if(vsub < 2) vsub = 2;
+
+ uverts = usub + 1;
+ vverts = vsub + 1;
+
+ mesh->vcount = uverts * vverts;
+ nfaces = usub * vsub;
+ mesh->icount = nfaces * 4;
+
+ printf("generating torus with %d faces (%d vertices)\n", nfaces, mesh->vcount);
+
+ if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
+ return -1;
+ }
+ if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
+ return -1;
+ }
+ vptr = mesh->varr;
+ iptr = mesh->iarr;
+
+ for(i=0; i<uverts; i++) {
+ float u = (float)i / (float)(uverts - 1);
+ float theta = u * 2.0 * M_PI;
+ float rcent[3];
+
+ torusvec(rcent, theta, 0, rad, 0);
+
+ for(j=0; j<vverts; j++) {
+ float v = (float)j / (float)(vverts - 1);
+ float phi = v * 2.0 * M_PI;
+ int chess = (i & 1) == (j & 1);
+
+ torusvec(&vptr->x, theta, phi, rad, ringrad);
+ vptr->w = 1.0f;
+
+ vptr->nx = (vptr->x - rcent[0]) / ringrad;
+ vptr->ny = (vptr->y - rcent[1]) / ringrad;
+ vptr->nz = (vptr->z - rcent[2]) / ringrad;
+ vptr->u = u;
+ vptr->v = v;
+ vptr->r = chess ? 255 : 64;
+ vptr->g = 128;
+ vptr->b = chess ? 64 : 255;
+ ++vptr;
+
+ if(i < usub && j < vsub) {
+ int idx = i * vverts + j;
+ *iptr++ = idx;
+ *iptr++ = idx + 1;
+ *iptr++ = idx + vverts + 1;
+ *iptr++ = idx + vverts;
+ }
+ }
+ }
+ return 0;
+}
+
--- /dev/null
+#ifndef MESH_H_
+#define MESH_H_
+
+#include "inttypes.h"
+
+struct g3d_mesh {
+ int prim;
+ struct g3d_vertex *varr;
+ uint16_t *iarr;
+ int vcount, icount;
+};
+
+void free_mesh(struct g3d_mesh *mesh);
+void destroy_mesh(struct g3d_mesh *mesh);
+
+int copy_mesh(struct g3d_mesh *dest, struct g3d_mesh *src);
+
+int load_mesh(struct g3d_mesh *mesh, const char *fname);
+int save_mesh(struct g3d_mesh *mesh, const char *fname);
+
+void zsort_mesh(struct g3d_mesh *mesh);
+void draw_mesh(struct g3d_mesh *mesh);
+
+void apply_mesh_xform(struct g3d_mesh *mesh, const float *xform);
+int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb);
+int indexify_mesh(struct g3d_mesh *mesh);
+
+void normalize_mesh_normals(struct g3d_mesh *mesh);
+
+void calc_mesh_centroid(struct g3d_mesh *mesh, float *cent);
+
+int gen_sphere_mesh(struct g3d_mesh *mesh, float rad, int usub, int vsub);
+int gen_plane_mesh(struct g3d_mesh *mesh, float width, float height, int usub, int vsub);
+int gen_cube_mesh(struct g3d_mesh *mesh, float sz, int sub);
+int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, int vsub);
+
+#endif /* MESH_H_ */
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+#include "mesh.h"
+#include "dynarr.h"
+#include "rbtree.h"
+#include "3dgfx.h"
+#include "util.h"
+
+typedef struct { float x, y; } vec2_t;
+typedef struct { float x, y, z; } vec3_t;
+typedef struct { float x, y, z, w; } vec4_t;
+
+
+struct vertex_pos_color {
+ float x, y, z;
+ float r, g, b, a;
+};
+
+struct facevertex {
+ int vidx, tidx, nidx;
+};
+
+static char *clean_line(char *s);
+static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int numt, int numn);
+static int cmp_facevert(const void *ap, const void *bp);
+static void free_rbnode_key(struct rbnode *n, void *cls);
+
+/* merge of different indices per attribute happens during face processing.
+ *
+ * A triplet of (vertex index/texcoord index/normal index) is used as the key
+ * to search in a balanced binary search tree for vertex buffer index assigned
+ * to the same triplet if it has been encountered before. That index is
+ * appended to the index buffer.
+ *
+ * If a particular triplet has not been encountered before, a new g3d_vertex is
+ * appended to the vertex buffer. The index of this new vertex is appended to
+ * the index buffer, and also inserted into the tree for future searches.
+ */
+int load_mesh(struct g3d_mesh *mesh, const char *fname)
+{
+ int i, line_num = 0, result = -1;
+ int found_quad = 0;
+ FILE *fp = 0;
+ char buf[256];
+ struct vertex_pos_color *varr = 0;
+ vec3_t *narr = 0;
+ vec2_t *tarr = 0;
+ struct rbtree *rbtree = 0;
+
+ if(!(fp = fopen(fname, "rb"))) {
+ fprintf(stderr, "load_mesh: failed to open file: %s\n", fname);
+ goto err;
+ }
+
+ if(!(rbtree = rb_create(cmp_facevert))) {
+ fprintf(stderr, "load_mesh: failed to create facevertex binary search tree\n");
+ goto err;
+ }
+ rb_set_delete_func(rbtree, free_rbnode_key, 0);
+
+ if(!(mesh->varr = dynarr_alloc(0, sizeof *mesh->varr)) ||
+ !(mesh->iarr = dynarr_alloc(0, sizeof *mesh->iarr))) {
+ fprintf(stderr, "load_mesh: failed to allocate resizable mesh arrays\n");
+ goto err;
+ }
+ if(!(varr = dynarr_alloc(0, sizeof *varr)) ||
+ !(narr = dynarr_alloc(0, sizeof *narr)) ||
+ !(tarr = dynarr_alloc(0, sizeof *tarr))) {
+ fprintf(stderr, "load_mesh: failed to allocate resizable vertex array\n");
+ goto err;
+ }
+
+ while(fgets(buf, sizeof buf, fp)) {
+ char *line = clean_line(buf);
+ ++line_num;
+
+ if(!*line) continue;
+
+ switch(line[0]) {
+ case 'v':
+ if(isspace(line[1])) {
+ /* vertex */
+ struct vertex_pos_color v;
+ int num;
+
+ num = sscanf(line + 2, "%f %f %f %f %f %f %f", &v.x, &v.y, &v.z, &v.r, &v.g, &v.b, &v.a);
+ if(num < 3) {
+ fprintf(stderr, "%s:%d: invalid vertex definition: \"%s\"\n", fname, line_num, line);
+ goto err;
+ }
+ switch(num) {
+ case 3:
+ v.r = 1.0f;
+ case 4:
+ v.g = 1.0f;
+ case 5:
+ v.b = 1.0f;
+ case 6:
+ v.a = 1.0f;
+ }
+ if(!(varr = dynarr_push(varr, &v))) {
+ fprintf(stderr, "load_mesh: failed to resize vertex buffer\n");
+ goto err;
+ }
+
+ } else if(line[1] == 't' && isspace(line[2])) {
+ /* texcoord */
+ vec2_t tc;
+ if(sscanf(line + 3, "%f %f", &tc.x, &tc.y) != 2) {
+ fprintf(stderr, "%s:%d: invalid texcoord definition: \"%s\"\n", fname, line_num, line);
+ goto err;
+ }
+ tc.y = 1.0f - tc.y;
+ if(!(tarr = dynarr_push(tarr, &tc))) {
+ fprintf(stderr, "load_mesh: failed to resize texcoord buffer\n");
+ goto err;
+ }
+
+ } else if(line[1] == 'n' && isspace(line[2])) {
+ /* normal */
+ vec3_t norm;
+ if(sscanf(line + 3, "%f %f %f", &norm.x, &norm.y, &norm.z) != 3) {
+ fprintf(stderr, "%s:%d: invalid normal definition: \"%s\"\n", fname, line_num, line);
+ goto err;
+ }
+ if(!(narr = dynarr_push(narr, &norm))) {
+ fprintf(stderr, "load_mesh: failed to resize normal buffer\n");
+ goto err;
+ }
+ }
+ break;
+
+ case 'f':
+ if(isspace(line[1])) {
+ /* face */
+ char *ptr = line + 2;
+ struct facevertex fv;
+ struct rbnode *node;
+ int vsz = dynarr_size(varr);
+ int tsz = dynarr_size(tarr);
+ int nsz = dynarr_size(narr);
+
+ for(i=0; i<4; i++) {
+ if(!(ptr = parse_face_vert(ptr, &fv, vsz, tsz, nsz))) {
+ if(i < 3 || found_quad) {
+ fprintf(stderr, "%s:%d: invalid face definition: \"%s\"\n", fname, line_num, line);
+ goto err;
+ } else {
+ break;
+ }
+ }
+
+ if((node = rb_find(rbtree, &fv))) {
+ uint16_t idx = (int)(intptr_t)node->data;
+ if(!(mesh->iarr = dynarr_push(mesh->iarr, &idx))) {
+ fprintf(stderr, "load_mesh: failed to resize index array\n");
+ goto err;
+ }
+ } else {
+ uint16_t newidx = dynarr_size(mesh->varr);
+ struct g3d_vertex v;
+ struct facevertex *newfv;
+
+ v.x = varr[fv.vidx].x;
+ v.y = varr[fv.vidx].y;
+ v.z = varr[fv.vidx].z;
+ v.w = 1.0f;
+ v.r = cround64(varr[fv.vidx].r * 255.0);
+ v.g = cround64(varr[fv.vidx].g * 255.0);
+ v.b = cround64(varr[fv.vidx].b * 255.0);
+ v.a = cround64(varr[fv.vidx].a * 255.0);
+ if(fv.tidx >= 0) {
+ v.u = tarr[fv.tidx].x;
+ v.v = tarr[fv.tidx].y;
+ } else {
+ v.u = v.x;
+ v.v = v.y;
+ }
+ if(fv.nidx >= 0) {
+ v.nx = narr[fv.nidx].x;
+ v.ny = narr[fv.nidx].y;
+ v.nz = narr[fv.nidx].z;
+ } else {
+ v.nx = v.ny = 0.0f;
+ v.nz = 1.0f;
+ }
+
+ if(!(mesh->varr = dynarr_push(mesh->varr, &v))) {
+ fprintf(stderr, "load_mesh: failed to resize combined vertex array\n");
+ goto err;
+ }
+ if(!(mesh->iarr = dynarr_push(mesh->iarr, &newidx))) {
+ fprintf(stderr, "load_mesh: failed to resize index array\n");
+ goto err;
+ }
+
+ if((newfv = malloc(sizeof *newfv))) {
+ *newfv = fv;
+ }
+ if(!newfv || rb_insert(rbtree, newfv, (void*)(intptr_t)newidx) == -1) {
+ fprintf(stderr, "load_mesh: failed to insert facevertex to the binary search tree\n");
+ goto err;
+ }
+ }
+ }
+ if(i > 3) found_quad = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ mesh->prim = found_quad ? G3D_QUADS : G3D_TRIANGLES;
+ mesh->vcount = dynarr_size(mesh->varr);
+ mesh->icount = dynarr_size(mesh->iarr);
+ mesh->varr = dynarr_finalize(mesh->varr);
+ mesh->iarr = dynarr_finalize(mesh->iarr);
+ result = 0; /* success */
+
+ printf("loaded %s mesh: %s: %d vertices, %d faces\n", found_quad ? "quad" : "triangle",
+ fname, mesh->vcount, mesh->icount / mesh->prim);
+
+err:
+ if(fp) fclose(fp);
+ dynarr_free(varr);
+ dynarr_free(narr);
+ dynarr_free(tarr);
+ if(result == -1) {
+ dynarr_free(mesh->varr);
+ dynarr_free(mesh->iarr);
+ }
+ rb_free(rbtree);
+ return result;
+}
+
+int save_mesh(struct g3d_mesh *mesh, const char *fname)
+{
+ int i, fvcount;
+ FILE *fp;
+
+ if(!(fp = fopen(fname, "wb"))) {
+ fprintf(stderr, "save_mesh: failed to open %s for writing\n", fname);
+ return -1;
+ }
+ fprintf(fp, "# Wavefront OBJ file shoved in your FACE by Mindlapse. Deal with it\n");
+
+ for(i=0; i<mesh->vcount; i++) {
+ struct g3d_vertex *v = mesh->varr + i;
+ fprintf(fp, "v %f %f %f %f %f %f %f\n", v->x, v->y, v->z, v->r / 255.0f, v->g / 255.0f,
+ v->b / 255.0f, v->a / 255.0f);
+ }
+ for(i=0; i<mesh->vcount; i++) {
+ fprintf(fp, "vn %f %f %f\n", mesh->varr[i].nx, mesh->varr[i].ny, mesh->varr[i].nz);
+ }
+ for(i=0; i<mesh->vcount; i++) {
+ fprintf(fp, "vt %f %f\n", mesh->varr[i].u, mesh->varr[i].v);
+ }
+
+ fvcount = mesh->prim;
+ for(i=0; i<mesh->icount; i++) {
+ int idx = mesh->iarr[i] + 1;
+
+ if(fvcount == mesh->prim) {
+ fprintf(fp, "\nf");
+ fvcount = 0;
+ }
+ fprintf(fp, " %d/%d/%d", idx, idx, idx);
+ ++fvcount;
+ }
+ fprintf(fp, "\n");
+
+ fclose(fp);
+ return 0;
+}
+
+static char *clean_line(char *s)
+{
+ char *end;
+
+ while(*s && isspace(*s)) ++s;
+ if(!*s) return 0;
+
+ end = s;
+ while(*end && *end != '#') ++end;
+ *end = 0;
+
+ while(end > s && isspace(*end)) --end;
+ *end = 0;
+
+ return s;
+}
+
+static char *parse_idx(char *ptr, int *idx, int arrsz)
+{
+ char *endp;
+ int val = strtol(ptr, &endp, 10);
+ if(endp == ptr) return 0;
+
+ if(val < 0) { /* convert negative indices */
+ *idx = arrsz + val;
+ } else {
+ *idx = val - 1; /* indices in obj are 1-based */
+ }
+ return endp;
+}
+
+/* possible face-vertex definitions:
+ * 1. vertex
+ * 2. vertex/texcoord
+ * 3. vertex//normal
+ * 4. vertex/texcoord/normal
+ */
+static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int numt, int numn)
+{
+ if(!(ptr = parse_idx(ptr, &fv->vidx, numv)))
+ return 0;
+ if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0;
+
+ if(*++ptr == '/') { /* no texcoord */
+ fv->tidx = -1;
+ ++ptr;
+ } else {
+ if(!(ptr = parse_idx(ptr, &fv->tidx, numt)))
+ return 0;
+ if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0;
+ ++ptr;
+ }
+
+ if(!(ptr = parse_idx(ptr, &fv->nidx, numn)))
+ return 0;
+ return (!*ptr || isspace(*ptr)) ? ptr : 0;
+}
+
+static int cmp_facevert(const void *ap, const void *bp)
+{
+ const struct facevertex *a = ap;
+ const struct facevertex *b = bp;
+
+ if(a->vidx == b->vidx) {
+ if(a->tidx == b->tidx) {
+ return a->nidx - b->nidx;
+ }
+ return a->tidx - b->tidx;
+ }
+ return a->vidx - b->vidx;
+}
+
+static void free_rbnode_key(struct rbnode *n, void *cls)
+{
+ free(n->key);
+}
--- /dev/null
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+#include "polyclip.h"
+
+struct ray {
+ float origin[3];
+ float dir[3];
+};
+
+static int clip_edge(struct g3d_vertex *poly, int *vnumptr,
+ const struct g3d_vertex *v0, const struct g3d_vertex *v1,
+ const struct cplane *plane);
+static int check_clip_edge(const struct g3d_vertex *v0,
+ const struct g3d_vertex *v1, const struct cplane *plane);
+static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr,
+ const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane);
+static float distance_signed(float *pos, const struct cplane *plane);
+static int intersect(const struct ray *ray, const struct cplane *plane, float *t);
+static int inside_frustum_plane(const struct g3d_vertex *v, int fplane);
+
+
+int clip_poly(struct g3d_vertex *vout, int *voutnum,
+ const struct g3d_vertex *vin, int vnum, struct cplane *plane)
+{
+ int i, nextidx, res;
+ int edges_clipped = 0;
+
+ *voutnum = 0;
+
+ for(i=0; i<vnum; i++) {
+ nextidx = i + 1;
+ if(nextidx >= vnum) nextidx = 0;
+ res = clip_edge(vout, voutnum, vin + i, vin + nextidx, plane);
+ if(res == 0) {
+ ++edges_clipped;
+ }
+ }
+
+ if(*voutnum <= 0) {
+ assert(edges_clipped == 0);
+ return -1;
+ }
+
+ return edges_clipped > 0 ? 0 : 1;
+}
+
+int check_clip_poly(const struct g3d_vertex *v, int vnum, struct cplane *plane)
+{
+ int i, nextidx, res;
+ int edges_clipped = 0;
+
+ for(i=0; i<vnum; i++) {
+ nextidx = i + 1;
+ if(nextidx >= vnum) nextidx = 0;
+ res = check_clip_edge(v + i, v + nextidx, plane);
+ if(res == 0) {
+ ++edges_clipped;
+ }
+ }
+ return edges_clipped ? 0 : res;
+}
+
+int clip_frustum(struct g3d_vertex *vout, int *voutnum,
+ const struct g3d_vertex *vin, int vnum, int fplane)
+{
+ int i, nextidx, res;
+ int edges_clipped = 0;
+
+ if(vnum == 1) {
+ /* special case: point clipping */
+ return inside_frustum_plane(vin, fplane) ? 1 : -1;
+ }
+
+ *voutnum = 0;
+
+ for(i=0; i<vnum; i++) {
+ nextidx = i + 1;
+ if(nextidx >= vnum) nextidx = 0;
+ res = clip_edge_frustum(vout, voutnum, vin + i, vin + nextidx, fplane);
+ if(res == 0) {
+ ++edges_clipped;
+ }
+ }
+
+ if(*voutnum <= 0) {
+ assert(edges_clipped == 0);
+ return -1;
+ }
+
+ return edges_clipped > 0 ? 0 : 1;
+}
+
+#define LERP_VATTR(res, v0, v1, t) \
+ do { \
+ (res)->nx = (v0)->nx + ((v1)->nx - (v0)->nx) * (t); \
+ (res)->ny = (v0)->ny + ((v1)->ny - (v0)->ny) * (t); \
+ (res)->nz = (v0)->nz + ((v1)->nz - (v0)->nz) * (t); \
+ (res)->u = (v0)->u + ((v1)->u - (v0)->u) * (t); \
+ (res)->v = (v0)->v + ((v1)->v - (v0)->v) * (t); \
+ (res)->r = (v0)->r + ((v1)->r - (v0)->r) * (t); \
+ (res)->g = (v0)->g + ((v1)->g - (v0)->g) * (t); \
+ (res)->b = (v0)->b + ((v1)->b - (v0)->b) * (t); \
+ } while(0)
+
+
+/* returns:
+ * 1 -> both inside
+ * 0 -> straddling and clipped
+ * -1 -> both outside
+ *
+ * also returns the size of the polygon through vnumptr
+ */
+static int clip_edge(struct g3d_vertex *poly, int *vnumptr,
+ const struct g3d_vertex *v0, const struct g3d_vertex *v1,
+ const struct cplane *plane)
+{
+ float pos0[3], pos1[3];
+ float d0, d1, t;
+ struct ray ray;
+ int i, vnum = *vnumptr;
+
+ pos0[0] = v0->x; pos0[1] = v0->y; pos0[2] = v0->z;
+ pos1[0] = v1->x; pos1[1] = v1->y; pos1[2] = v1->z;
+
+ d0 = distance_signed(pos0, plane);
+ d1 = distance_signed(pos1, plane);
+
+ for(i=0; i<3; i++) {
+ ray.origin[i] = pos0[i];
+ ray.dir[i] = pos1[i] - pos0[i];
+ }
+
+ if(d0 >= 0.0) {
+ /* start inside */
+ if(d1 >= 0.0) {
+ /* all inside */
+ poly[vnum++] = *v1; /* append v1 */
+ *vnumptr = vnum;
+ return 1;
+ } else {
+ /* going out */
+ struct g3d_vertex *vptr = poly + vnum;
+
+ intersect(&ray, plane, &t);
+
+ vptr->x = ray.origin[0] + ray.dir[0] * t;
+ vptr->y = ray.origin[1] + ray.dir[1] * t;
+ vptr->z = ray.origin[2] + ray.dir[2] * t;
+ vptr->w = 1.0f;
+
+ LERP_VATTR(vptr, v0, v1, t);
+ vnum++; /* append new vertex on the intersection point */
+ }
+ } else {
+ /* start outside */
+ if(d1 >= 0) {
+ /* going in */
+ struct g3d_vertex *vptr = poly + vnum;
+
+ intersect(&ray, plane, &t);
+
+ vptr->x = ray.origin[0] + ray.dir[0] * t;
+ vptr->y = ray.origin[1] + ray.dir[1] * t;
+ vptr->z = ray.origin[2] + ray.dir[2] * t;
+ vptr->w = 1.0f;
+
+ LERP_VATTR(vptr, v0, v1, t);
+ vnum++; /* append new vertex on the intersection point */
+
+ /* then append v1 ... */
+ poly[vnum++] = *v1;
+ } else {
+ /* all outside */
+ return -1;
+ }
+ }
+
+ *vnumptr = vnum;
+ return 0;
+}
+
+/* same as above, but only checks for clipping and classifies the edge */
+static int check_clip_edge(const struct g3d_vertex *v0,
+ const struct g3d_vertex *v1, const struct cplane *plane)
+{
+ float pos0[3], pos1[3];
+ float d0, d1;
+
+ pos0[0] = v0->x; pos0[1] = v0->y; pos0[2] = v0->z;
+ pos1[0] = v1->x; pos1[1] = v1->y; pos1[2] = v1->z;
+
+ d0 = distance_signed(pos0, plane);
+ d1 = distance_signed(pos1, plane);
+
+ if(d0 > 0.0f && d1 > 0.0f) {
+ return 1;
+ }
+ if(d0 < 0.0f && d1 < 0.0f) {
+ return -1;
+ }
+ return 0;
+}
+
+static float distance_signed(float *pos, const struct cplane *plane)
+{
+ float dx = pos[0] - plane->x;
+ float dy = pos[1] - plane->y;
+ float dz = pos[2] - plane->z;
+ return dx * plane->nx + dy * plane->ny + dz * plane->nz;
+}
+
+static int intersect(const struct ray *ray, const struct cplane *plane, float *t)
+{
+ float orig_pt_dir[3];
+
+ float ndotdir = plane->nx * ray->dir[0] + plane->ny * ray->dir[1] + plane->nz * ray->dir[2];
+ if(fabs(ndotdir) < 1e-6) {
+ *t = 0.0f;
+ return 0;
+ }
+
+ orig_pt_dir[0] = plane->x - ray->origin[0];
+ orig_pt_dir[1] = plane->y - ray->origin[1];
+ orig_pt_dir[2] = plane->z - ray->origin[2];
+
+ *t = (plane->nx * orig_pt_dir[0] + plane->ny * orig_pt_dir[1] + plane->nz * orig_pt_dir[2]) / ndotdir;
+ return 1;
+}
+
+/* homogeneous frustum clipper helpers */
+
+static int inside_frustum_plane(const struct g3d_vertex *v, int fplane)
+{
+ switch(fplane) {
+ case CLIP_LEFT:
+ return v->x >= -v->w;
+ case CLIP_RIGHT:
+ return v->x <= v->w;
+ case CLIP_BOTTOM:
+ return v->y >= -v->w;
+ case CLIP_TOP:
+ return v->y <= v->w;
+ case CLIP_NEAR:
+ return v->z >= -v->w;
+ case CLIP_FAR:
+ return v->z <= v->w;
+ }
+ assert(0);
+ return 0;
+}
+
+static float intersect_frustum(const struct g3d_vertex *a, const struct g3d_vertex *b, int fplane)
+{
+ switch(fplane) {
+ case CLIP_LEFT:
+ return (-a->w - a->x) / (b->x - a->x + b->w - a->w);
+ case CLIP_RIGHT:
+ return (a->w - a->x) / (b->x - a->x - b->w + a->w);
+ case CLIP_BOTTOM:
+ return (-a->w - a->y) / (b->y - a->y + b->w - a->w);
+ case CLIP_TOP:
+ return (a->w - a->y) / (b->y - a->y - b->w + a->w);
+ case CLIP_NEAR:
+ return (-a->w - a->z) / (b->z - a->z + b->w - a->w);
+ case CLIP_FAR:
+ return (a->w - a->z) / (b->z - a->z - b->w + a->w);
+ }
+
+ assert(0);
+ return 0;
+}
+
+static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr,
+ const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane)
+{
+ int vnum = *vnumptr;
+ int in0, in1;
+ float t;
+
+ in0 = inside_frustum_plane(v0, fplane);
+ in1 = inside_frustum_plane(v1, fplane);
+
+ if(in0) {
+ /* start inside */
+ if(in1) {
+ /* all inside */
+ poly[vnum++] = *v1; /* append v1 */
+ *vnumptr = vnum;
+ return 1;
+ } else {
+ /* going out */
+ struct g3d_vertex *vptr = poly + vnum;
+
+ t = intersect_frustum(v0, v1, fplane);
+
+ vptr->x = v0->x + (v1->x - v0->x) * t;
+ vptr->y = v0->y + (v1->y - v0->y) * t;
+ vptr->z = v0->z + (v1->z - v0->z) * t;
+ vptr->w = v0->w + (v1->w - v0->w) * t;
+
+ LERP_VATTR(vptr, v0, v1, t);
+ ++vnum; /* append new vertex on the intersection point */
+ }
+ } else {
+ /* start outside */
+ if(in1) {
+ /* going in */
+ struct g3d_vertex *vptr = poly + vnum;
+
+ t = intersect_frustum(v0, v1, fplane);
+
+ vptr->x = v0->x + (v1->x - v0->x) * t;
+ vptr->y = v0->y + (v1->y - v0->y) * t;
+ vptr->z = v0->z + (v1->z - v0->z) * t;
+ vptr->w = v0->w + (v1->w - v0->w) * t;
+
+ LERP_VATTR(vptr, v0, v1, t);
+ ++vnum; /* append new vertex on the intersection point */
+
+ /* then append v1 ... */
+ poly[vnum++] = *v1;
+ } else {
+ /* all outside */
+ return -1;
+ }
+ }
+
+ *vnumptr = vnum;
+ return 0;
+}
--- /dev/null
+#ifndef POLYCLIP_H_
+#define POLYCLIP_H_
+
+#include "3dgfx.h"
+
+struct cplane {
+ float x, y, z;
+ float nx, ny, nz;
+};
+
+enum {
+ CLIP_LEFT, CLIP_RIGHT,
+ CLIP_BOTTOM, CLIP_TOP,
+ CLIP_NEAR, CLIP_FAR
+};
+
+/* Generic polygon clipper
+ * returns:
+ * 1 -> fully inside, not clipped
+ * 0 -> straddling the plane and clipped
+ * -1 -> fully outside, not clipped
+ * in all cases, vertices are copied to vout, and the vertex count is written
+ * to wherever voutnum is pointing
+ */
+int clip_poly(struct g3d_vertex *vout, int *voutnum,
+ const struct g3d_vertex *vin, int vnum, struct cplane *plane);
+
+/* only checks if the polygon would be clipped by the plane, and classifies it
+ * as inside/outside/straddling, without actually producing a clipped polygon.
+ * return values are the same as clip_poly.
+ */
+int check_clip_poly(const struct g3d_vertex *v, int vnum, struct cplane *plane);
+
+/* Special-case frustum clipper (might be slightly faster) */
+int clip_frustum(struct g3d_vertex *vout, int *voutnum,
+ const struct g3d_vertex *vin, int vnum, int fplane);
+
+#endif /* POLYCLIP_H_ */
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#if defined(__WATCOMC__) || defined(_WIN32) || defined(__DJGPP__)
+#include <malloc.h>
+#else
+#include <alloca.h>
+#endif
+#include "polyfill.h"
+#include "gfxutil.h"
+
+#define FILL_POLY_BITS 0x03
+
+/* mode bits: 00-wire 01-flat 10-gouraud 11-reserved
+ * bit 2: texture
+ * bit 3-4: blend mode: 00-none 01-alpha 10-additive 11-reserved
+ */
+void (*fillfunc[])(struct pvertex*, int) = {
+ polyfill_wire,
+ polyfill_flat,
+ polyfill_gouraud,
+ 0,
+ polyfill_tex_wire,
+ polyfill_tex_flat,
+ polyfill_tex_gouraud,
+ 0,
+ polyfill_alpha_wire,
+ polyfill_alpha_flat,
+ polyfill_alpha_gouraud,
+ 0,
+ polyfill_alpha_tex_wire,
+ polyfill_alpha_tex_flat,
+ polyfill_alpha_tex_gouraud,
+ 0,
+ polyfill_add_wire,
+ polyfill_add_flat,
+ polyfill_add_gouraud,
+ 0,
+ polyfill_add_tex_wire,
+ polyfill_add_tex_flat,
+ polyfill_add_tex_gouraud,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+struct pimage pfill_fb, pfill_tex;
+
+#define EDGEPAD 8
+static struct pvertex *edgebuf, *left, *right;
+static int edgebuf_size;
+static int fbheight;
+
+/*
+#define CHECKEDGE(x) \
+ do { \
+ assert(x >= 0); \
+ assert(x < fbheight); \
+ } while(0)
+*/
+#define CHECKEDGE(x)
+
+
+void polyfill_fbheight(int height)
+{
+ void *tmp;
+ int newsz = (height * 2 + EDGEPAD * 3) * sizeof *edgebuf;
+
+ if(newsz > edgebuf_size) {
+ free(edgebuf);
+ if(!(edgebuf = malloc(newsz))) {
+ fprintf(stderr, "failed to allocate edge table buffer (%d bytes)\n", newsz);
+ abort();
+ }
+ edgebuf_size = newsz;
+
+ left = edgebuf + EDGEPAD;
+ right = edgebuf + height + EDGEPAD * 2;
+
+#ifndef NDEBUG
+ memset(edgebuf, 0xaa, EDGEPAD * sizeof *edgebuf);
+ memset(edgebuf + height + EDGEPAD, 0xaa, EDGEPAD * sizeof *edgebuf);
+ memset(edgebuf + height * 2 + EDGEPAD * 2, 0xaa, EDGEPAD * sizeof *edgebuf);
+#endif
+ }
+
+ fbheight = height;
+}
+
+void polyfill(int mode, struct pvertex *verts, int nverts)
+{
+#ifndef NDEBUG
+ if(!fillfunc[mode]) {
+ fprintf(stderr, "polyfill mode %d not implemented\n", mode);
+ abort();
+ }
+#endif
+
+ fillfunc[mode](verts, nverts);
+}
+
+void polyfill_wire(struct pvertex *verts, int nverts)
+{
+ int i, x0, y0, x1, y1;
+ struct pvertex *v = verts;
+ unsigned short color = ((v->r << 8) & 0xf800) |
+ ((v->g << 3) & 0x7e0) | ((v->b >> 3) & 0x1f);
+
+ for(i=0; i<nverts - 1; i++) {
+ x0 = v->x >> 8;
+ y0 = v->y >> 8;
+ ++v;
+ x1 = v->x >> 8;
+ y1 = v->y >> 8;
+ if(clip_line(&x0, &y0, &x1, &y1, 0, 0, pfill_fb.width, pfill_fb.height)) {
+ draw_line(x0, y0, x1, y1, color);
+ }
+ }
+ x0 = verts[0].x >> 8;
+ y0 = verts[0].y >> 8;
+ if(clip_line(&x1, &y1, &x0, &y0, 0, 0, pfill_fb.width, pfill_fb.height)) {
+ draw_line(x1, y1, x0, y0, color);
+ }
+}
+
+void polyfill_tex_wire(struct pvertex *verts, int nverts)
+{
+ polyfill_wire(verts, nverts); /* TODO */
+}
+
+void polyfill_alpha_wire(struct pvertex *verts, int nverts)
+{
+ polyfill_wire(verts, nverts); /* TODO */
+}
+
+void polyfill_alpha_tex_wire(struct pvertex *verts, int nverts)
+{
+ polyfill_wire(verts, nverts); /* TODO */
+}
+
+void polyfill_add_wire(struct pvertex *verts, int nverts)
+{
+ polyfill_wire(verts, nverts); /* TODO */
+}
+
+void polyfill_add_tex_wire(struct pvertex *verts, int nverts)
+{
+ polyfill_wire(verts, nverts); /* TODO */
+}
+
+#define NEXTIDX(x) (((x) - 1 + nverts) % nverts)
+#define PREVIDX(x) (((x) + 1) % nverts)
+
+/* XXX
+ * When HIGH_QUALITY is defined, the rasterizer calculates slopes for attribute
+ * interpolation on each scanline separately; otherwise the slope for each
+ * attribute would be calculated once for the whole polygon, which is faster,
+ * but produces some slight quantization artifacts, due to the limited precision
+ * of fixed-point calculations.
+ */
+#define HIGH_QUALITY
+
+/* extra bits of precision to use when interpolating colors.
+ * try tweaking this if you notice strange quantization artifacts.
+ */
+#define COLOR_SHIFT 12
+
+
+#define POLYFILL polyfill_flat
+#define SCANEDGE scanedge_flat
+#undef GOURAUD
+#undef TEXMAP
+#undef BLEND_ALPHA
+#undef BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_gouraud
+#define SCANEDGE scanedge_gouraud
+#define GOURAUD
+#undef TEXMAP
+#undef BLEND_ALPHA
+#undef BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_tex_flat
+#define SCANEDGE scanedge_tex_flat
+#undef GOURAUD
+#define TEXMAP
+#undef BLEND_ALPHA
+#undef BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_tex_gouraud
+#define SCANEDGE scanedge_tex_gouraud
+#define GOURAUD
+#define TEXMAP
+#undef BLEND_ALPHA
+#undef BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_alpha_flat
+#define SCANEDGE scanedge_alpha_flat
+#undef GOURAUD
+#undef TEXMAP
+#define BLEND_ALPHA
+#undef BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_alpha_gouraud
+#define SCANEDGE scanedge_alpha_gouraud
+#define GOURAUD
+#undef TEXMAP
+#define BLEND_ALPHA
+#undef BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_alpha_tex_flat
+#define SCANEDGE scanedge_alpha_tex_flat
+#undef GOURAUD
+#define TEXMAP
+#define BLEND_ALPHA
+#undef BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_alpha_tex_gouraud
+#define SCANEDGE scanedge_alpha_tex_gouraud
+#define GOURAUD
+#define TEXMAP
+#define BLEND_ALPHA
+#undef BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_add_flat
+#define SCANEDGE scanedge_add_flat
+#undef GOURAUD
+#undef TEXMAP
+#undef BLEND_ALPHA
+#define BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_add_gouraud
+#define SCANEDGE scanedge_add_gouraud
+#define GOURAUD
+#undef TEXMAP
+#undef BLEND_ALPHA
+#define BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_add_tex_flat
+#define SCANEDGE scanedge_add_tex_flat
+#undef GOURAUD
+#define TEXMAP
+#undef BLEND_ALPHA
+#define BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_add_tex_gouraud
+#define SCANEDGE scanedge_add_tex_gouraud
+#define GOURAUD
+#define TEXMAP
+#undef BLEND_ALPHA
+#define BLEND_ADD
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
--- /dev/null
+#ifndef POLYFILL_H_
+#define POLYFILL_H_
+
+#include "inttypes.h"
+#include "3dgfx.h"
+
+#define POLYFILL_MODE_MASK 0x03
+#define POLYFILL_TEX_BIT 0x04
+#define POLYFILL_ALPHA_BIT 0x08
+#define POLYFILL_ADD_BIT 0x10
+
+enum {
+ POLYFILL_WIRE = 0,
+ POLYFILL_FLAT,
+ POLYFILL_GOURAUD,
+
+ POLYFILL_TEX_WIRE = 4,
+ POLYFILL_TEX_FLAT,
+ POLYFILL_TEX_GOURAUD,
+
+ POLYFILL_ALPHA_WIRE = 8,
+ POLYFILL_ALPHA_FLAT,
+ POLYFILL_ALPHA_GOURAUD,
+
+ POLYFILL_ALPHA_TEX_WIRE = 12,
+ POLYFILL_ALPHA_TEX_FLAT,
+ POLYFILL_ALPHA_TEX_GOURAUD,
+
+ POLYFILL_ADD_WIRE = 16,
+ POLYFILL_ADD_FLAT,
+ POLYFILL_ADD_GOURAUD,
+
+ POLYFILL_ADD_TEX_WIRE = 20,
+ POLYFILL_ADD_TEX_FLAT,
+ POLYFILL_ADD_TEX_GOURAUD
+};
+
+/* projected vertices for the rasterizer */
+struct pvertex {
+ int32_t x, y; /* 24.8 fixed point */
+ int32_t u, v; /* 16.16 fixed point */
+ int32_t r, g, b, a; /* int 0-255 */
+};
+
+struct pimage {
+ g3d_pixel *pixels;
+ int width, height;
+
+ int xshift, yshift;
+ unsigned int xmask, ymask;
+};
+
+extern struct pimage pfill_fb;
+extern struct pimage pfill_tex;
+
+void polyfill_fbheight(int height);
+
+void polyfill(int mode, struct pvertex *verts, int nverts);
+
+void polyfill_wire(struct pvertex *verts, int nverts);
+void polyfill_flat(struct pvertex *verts, int nverts);
+void polyfill_gouraud(struct pvertex *verts, int nverts);
+void polyfill_tex_wire(struct pvertex *verts, int nverts);
+void polyfill_tex_flat(struct pvertex *verts, int nverts);
+void polyfill_tex_gouraud(struct pvertex *verts, int nverts);
+void polyfill_alpha_wire(struct pvertex *verts, int nverts);
+void polyfill_alpha_flat(struct pvertex *verts, int nverts);
+void polyfill_alpha_gouraud(struct pvertex *verts, int nverts);
+void polyfill_alpha_tex_wire(struct pvertex *verts, int nverts);
+void polyfill_alpha_tex_flat(struct pvertex *verts, int nverts);
+void polyfill_alpha_tex_gouraud(struct pvertex *verts, int nverts);
+void polyfill_add_wire(struct pvertex *verts, int nverts);
+void polyfill_add_flat(struct pvertex *verts, int nverts);
+void polyfill_add_gouraud(struct pvertex *verts, int nverts);
+void polyfill_add_tex_wire(struct pvertex *verts, int nverts);
+void polyfill_add_tex_flat(struct pvertex *verts, int nverts);
+void polyfill_add_tex_gouraud(struct pvertex *verts, int nverts);
+
+#endif /* POLYFILL_H_ */
--- /dev/null
+static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge)
+{
+ int i;
+ int32_t x, dx, dy, slope;
+#ifdef GOURAUD
+ int r, g, b, dr, dg, db;
+ int32_t rslope, gslope, bslope;
+#ifdef BLEND_ALPHA
+ int32_t a, da, aslope;
+#endif
+#endif /* GOURAUD */
+#ifdef TEXMAP
+ int32_t u, v, du, dv, uslope, vslope;
+#endif
+ int32_t start_idx, end_idx;
+
+ if(v0->y > v1->y) {
+ struct pvertex *tmp = v0;
+ v0 = v1;
+ v1 = tmp;
+ }
+
+ x = v0->x;
+ dy = v1->y - v0->y;
+ dx = v1->x - v0->x;
+ slope = (dx << 8) / dy;
+#ifdef GOURAUD
+ r = (v0->r << COLOR_SHIFT);
+ g = (v0->g << COLOR_SHIFT);
+ b = (v0->b << COLOR_SHIFT);
+ dr = (v1->r << COLOR_SHIFT) - r;
+ dg = (v1->g << COLOR_SHIFT) - g;
+ db = (v1->b << COLOR_SHIFT) - b;
+ rslope = (dr << 8) / dy;
+ gslope = (dg << 8) / dy;
+ bslope = (db << 8) / dy;
+#ifdef BLEND_ALPHA
+ a = (v0->a << COLOR_SHIFT);
+ da = (v1->a << COLOR_SHIFT) - a;
+ aslope = (da << 8) / dy;
+#endif /* BLEND_ALPHA */
+#endif /* GOURAUD */
+#ifdef TEXMAP
+ u = v0->u;
+ v = v0->v;
+ du = v1->u - v0->u;
+ dv = v1->v - v0->v;
+ uslope = (du << 8) / dy;
+ vslope = (dv << 8) / dy;
+#endif
+
+ start_idx = v0->y >> 8;
+ end_idx = v1->y >> 8;
+
+ for(i=start_idx; i<end_idx; i++) {
+ CHECKEDGE(i);
+ edge[i].x = x;
+ x += slope;
+#ifdef GOURAUD
+ /* we'll store the color in the edge tables with COLOR_SHIFT extra bits of precision */
+ CHECKEDGE(i);
+ edge[i].r = r;
+ edge[i].g = g;
+ edge[i].b = b;
+ r += rslope;
+ g += gslope;
+ b += bslope;
+#ifdef BLEND_ALPHA
+ CHECKEDGE(i);
+ edge[i].a = a;
+ a += aslope;
+#endif
+#endif /* GOURAUD */
+#ifdef TEXMAP
+ CHECKEDGE(i);
+ edge[i].u = u;
+ edge[i].v = v;
+ u += uslope;
+ v += vslope;
+#endif
+ }
+
+ return (uint32_t)start_idx | ((uint32_t)(end_idx - 1) << 16);
+}
+
+void POLYFILL(struct pvertex *pv, int nverts)
+{
+ int i, winding;
+ int topidx = 0, botidx = 0, sltop = pfill_fb.height, slbot = 0;
+ g3d_pixel color;
+ /* the following variables are used for interpolating horizontally accros scanlines */
+#if defined(GOURAUD) || defined(TEXMAP)
+ int mid;
+ int32_t dx, tmp;
+#else
+ /* flat version, just pack the color now */
+ color = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
+#endif
+#ifdef GOURAUD
+ int32_t r, g, b, dr, dg, db, rslope, gslope, bslope;
+#ifdef BLEND_ALPHA
+ int32_t a, da, aslope;
+#endif
+#endif
+#ifdef TEXMAP
+ int32_t u, v, du, dv, uslope, vslope;
+#endif
+
+ for(i=1; i<nverts; i++) {
+ if(pv[i].y < pv[topidx].y) topidx = i;
+ if(pv[i].y > pv[botidx].y) botidx = i;
+ }
+
+ winding = 0;
+ for(i=0; i<nverts; i++) {
+ int next = NEXTIDX(i);
+ winding += ((pv[next].x - pv[i].x) >> 4) * ((pv[next].y + pv[i].y) >> 4);
+ }
+
+ for(i=0; i<nverts; i++) {
+ int next = NEXTIDX(i);
+ int32_t y0 = pv[i].y;
+ int32_t y1 = pv[next].y;
+
+ if((y0 >> 8) == (y1 >> 8)) {
+ /*if(y0 > y1) {*/
+ int i0, i1;
+ int idx = y0 >> 8;
+ if(pv[i].x < pv[next].x) {
+ i0 = i;
+ i1 = next;
+ } else {
+ i0 = next;
+ i1 = i;
+ }
+ CHECKEDGE(idx);
+ left[idx].x = pv[i0].x;
+ right[idx].x = pv[i1].x;
+#ifdef GOURAUD
+ left[idx].r = pv[i0].r << COLOR_SHIFT;
+ left[idx].g = pv[i0].g << COLOR_SHIFT;
+ left[idx].b = pv[i0].b << COLOR_SHIFT;
+ right[idx].r = pv[i1].r << COLOR_SHIFT;
+ right[idx].g = pv[i1].g << COLOR_SHIFT;
+ right[idx].b = pv[i1].b << COLOR_SHIFT;
+#ifdef BLEND_ALPHA
+ left[idx].a = pv[i0].a << COLOR_SHIFT;
+ right[idx].a = pv[i1].a << COLOR_SHIFT;
+#endif /* BLEND_ALPHA */
+#endif
+#ifdef TEXMAP
+ left[idx].u = pv[i0].u;
+ left[idx].v = pv[i0].v;
+ right[idx].u = pv[i1].u;
+ right[idx].v = pv[i1].v;
+#endif
+ CHECKEDGE(idx);
+ if(idx > slbot) slbot = idx;
+ if(idx < sltop) sltop = idx;
+ /*}*/
+ } else {
+ struct pvertex *edge;
+ uint32_t res, tmp;
+
+ if(winding < 0) {
+ /* clockwise */
+ edge = y0 > y1 ? left : right;
+ } else {
+ /* counter-clockwise */
+ edge = y0 > y1 ? right : left;
+ }
+ res = SCANEDGE(pv + i, pv + next, edge);
+ tmp = (res >> 16) & 0xffff;
+ if(tmp > slbot) slbot = tmp;
+ if((tmp = res & 0xffff) < sltop) {
+ sltop = tmp;
+ }
+ }
+ }
+
+ /* calculate the slopes of all attributes across the largest span out
+ * of the three: middle, top, or bottom.
+ */
+#ifndef HIGH_QUALITY
+#if defined(GOURAUD) || defined(TEXMAP)
+ mid = (sltop + slbot) >> 1;
+ CHECKEDGE(sltop);
+ CHECKEDGE(slbot);
+ CHECKEDGE(mid);
+ dx = right[mid].x - left[mid].x;
+ if((tmp = right[sltop].x - left[sltop].x) > dx) {
+ dx = tmp;
+ mid = sltop;
+ }
+ if((tmp = right[slbot].x - left[slbot].x) > dx) {
+ dx = tmp;
+ mid = slbot;
+ }
+ if(!dx) dx = 256; /* avoid division by zero */
+#endif
+ CHECKEDGE(idx);
+#ifdef GOURAUD
+ dr = right[mid].r - left[mid].r;
+ dg = right[mid].g - left[mid].g;
+ db = right[mid].b - left[mid].b;
+ rslope = (dr << 8) / dx;
+ gslope = (dg << 8) / dx;
+ bslope = (db << 8) / dx;
+#ifdef BLEND_ALPHA
+ da = right[mid].a - left[mid].a;
+ aslope = (da << 8) / dx;
+#endif /* BLEND_ALPHA */
+#endif
+#ifdef TEXMAP
+ du = right[mid].u - left[mid].u;
+ dv = right[mid].v - left[mid].v;
+ uslope = (du << 8) / dx;
+ vslope = (dv << 8) / dx;
+#endif
+#endif /* !defined(HIGH_QUALITY) */
+
+ /* for each scanline ... */
+ for(i=sltop; i<=slbot; i++) {
+ g3d_pixel *pixptr;
+ int32_t x;
+
+ CHECKEDGE(i);
+ x = left[i].x;
+ pixptr = pfill_fb.pixels + i * pfill_fb.width + (x >> 8);
+
+#ifdef GOURAUD
+ r = left[i].r;
+ g = left[i].g;
+ b = left[i].b;
+#ifdef BLEND_ALPHA
+ a = left[i].a;
+#endif /* BLEND_ALPHA */
+#endif
+#ifdef TEXMAP
+ u = left[i].u;
+ v = left[i].v;
+#endif
+ CHECKEDGE(i);
+
+#if defined(HIGH_QUALITY) && (defined(GOURAUD) || defined(TEXMAP))
+ if(!(dx = right[i].x - left[i].x)) dx = 256;
+
+ CHECKEDGE(i);
+#ifdef GOURAUD
+ dr = right[i].r - left[i].r;
+ dg = right[i].g - left[i].g;
+ db = right[i].b - left[i].b;
+ rslope = (dr << 8) / dx;
+ gslope = (dg << 8) / dx;
+ bslope = (db << 8) / dx;
+#ifdef BLEND_ALPHA
+ da = right[i].a - left[i].a;
+ aslope = (da << 8) / dx;
+#endif /* BLEND_ALPHA */
+#endif /* GOURAUD */
+#ifdef TEXMAP
+ du = right[i].u - left[i].u;
+ dv = right[i].v - left[i].v;
+ uslope = (du << 8) / dx;
+ vslope = (dv << 8) / dx;
+#endif
+#endif /* HIGH_QUALITY */
+ CHECKEDGE(i);
+
+ /* go across the scanline interpolating if necessary */
+ while(x <= right[i].x) {
+#if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND_ALPHA) || defined(BLEND_ADD)
+ int cr, cg, cb;
+#endif
+#if defined(BLEND_ALPHA) || defined(BLEND_ADD)
+ g3d_pixel fbcol;
+#endif
+#ifdef BLEND_ALPHA
+ int alpha, inv_alpha;
+#endif
+#ifdef GOURAUD
+ /* we upped the color precision to while interpolating the
+ * edges, now drop the extra bits before packing
+ */
+ cr = r < 0 ? 0 : (r >> COLOR_SHIFT);
+ cg = g < 0 ? 0 : (g >> COLOR_SHIFT);
+ cb = b < 0 ? 0 : (b >> COLOR_SHIFT);
+ r += rslope;
+ g += gslope;
+ b += bslope;
+#ifdef BLEND_ALPHA
+ a += aslope;
+#else
+ if(cr > 255) cr = 255;
+ if(cg > 255) cg = 255;
+ if(cb > 255) cb = 255;
+#endif /* BLEND_ALPHA */
+#endif /* GOURAUD */
+#ifdef TEXMAP
+ {
+ int tx = (u >> (16 - pfill_tex.xshift)) & pfill_tex.xmask;
+ int ty = (v >> (16 - pfill_tex.yshift)) & pfill_tex.ymask;
+ g3d_pixel texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx];
+#ifdef GOURAUD
+ /* This is not correct, should be /255, but it's much faster
+ * to shift by 8 (/256), and won't make a huge difference
+ */
+ cr = (cr * G3D_UNPACK_R(texel)) >> 8;
+ cg = (cg * G3D_UNPACK_G(texel)) >> 8;
+ cb = (cb * G3D_UNPACK_B(texel)) >> 8;
+#else
+ cr = G3D_UNPACK_R(texel);
+ cg = G3D_UNPACK_G(texel);
+ cb = G3D_UNPACK_B(texel);
+#endif
+ }
+ u += uslope;
+ v += vslope;
+#endif
+
+#if defined(BLEND_ALPHA) || defined(BLEND_ADD)
+#if !defined(GOURAUD) && !defined(TEXMAP)
+ /* flat version: cr,cg,cb are uninitialized so far */
+ cr = pv[0].r;
+ cg = pv[0].g;
+ cb = pv[0].b;
+#endif
+ fbcol = *pixptr;
+
+#ifdef BLEND_ALPHA
+#ifdef GOURAUD
+ alpha = a >> COLOR_SHIFT;
+#else
+ alpha = pv[0].a;
+#endif
+ inv_alpha = 255 - alpha;
+ cr = (cr * alpha + G3D_UNPACK_R(fbcol) * inv_alpha) >> 8;
+ cg = (cg * alpha + G3D_UNPACK_G(fbcol) * inv_alpha) >> 8;
+ cb = (cb * alpha + G3D_UNPACK_B(fbcol) * inv_alpha) >> 8;
+#else /* !BLEND_ALPHA (so BLEND_ADD) */
+ cr += G3D_UNPACK_R(fbcol);
+ cg += G3D_UNPACK_R(fbcol);
+ cb += G3D_UNPACK_R(fbcol);
+#endif
+ if(cr > 255) cr = 255;
+ if(cg > 255) cg = 255;
+ if(cb > 255) cb = 255;
+#endif /* BLEND(ALPHA|ADD) */
+
+#if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND_ALPHA) || defined(BLEND_ADD)
+ color = G3D_PACK_RGB(cr, cg, cb);
+#endif
+
+#ifdef DEBUG_OVERDRAW
+ *pixptr++ += DEBUG_OVERDRAW;
+#else
+ *pixptr++ = color;
+#endif
+ x += 256;
+ }
+ }
+}
+
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "mesh.h"
-#include "3dgfx.h"
-
-void free_mesh(struct g3d_mesh *mesh)
-{
- destroy_mesh(mesh);
- free(mesh);
-}
-
-void destroy_mesh(struct g3d_mesh *mesh)
-{
- free(mesh->varr);
- free(mesh->iarr);
-}
-
-int copy_mesh(struct g3d_mesh *dest, struct g3d_mesh *src)
-{
- dest->prim = src->prim;
- if(src->varr) {
- if(!(dest->varr = malloc(src->vcount * sizeof *src->varr))) {
- return -1;
- }
- memcpy(dest->varr, src->varr, src->vcount * sizeof *src->varr);
- }
- dest->vcount = src->vcount;
- if(src->iarr) {
- if(!(dest->iarr = malloc(src->icount * sizeof *src->iarr))) {
- free(dest->varr);
- dest->varr = 0;
- return -1;
- }
- memcpy(dest->iarr, src->iarr, src->icount * sizeof *src->iarr);
- }
- dest->icount = src->icount;
- return 0;
-}
-
-static struct {
- int prim;
- struct g3d_vertex *varr;
- const float *xform;
-} zsort_cls;
-
-static int zsort_cmp(const void *aptr, const void *bptr)
-{
- int i;
- float za = 0.0f;
- float zb = 0.0f;
- const float *m = zsort_cls.xform;
- const struct g3d_vertex *va = (const struct g3d_vertex*)aptr;
- const struct g3d_vertex *vb = (const struct g3d_vertex*)bptr;
-
- for(i=0; i<zsort_cls.prim; i++) {
- za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
- zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
- ++va;
- ++vb;
- }
- return za - zb;
-}
-
-static int zsort_indexed_cmp(const void *aptr, const void *bptr)
-{
- int i;
- float za = 0.0f;
- float zb = 0.0f;
- const uint16_t *a = (const uint16_t*)aptr;
- const uint16_t *b = (const uint16_t*)bptr;
-
- const float *m = zsort_cls.xform;
-
- for(i=0; i<zsort_cls.prim; i++) {
- const struct g3d_vertex *va = zsort_cls.varr + a[i];
- const struct g3d_vertex *vb = zsort_cls.varr + b[i];
-
- za += m[2] * va->x + m[6] * va->y + m[10] * va->z + m[14];
- zb += m[2] * vb->x + m[6] * vb->y + m[10] * vb->z + m[14];
- }
- return za - zb;
-}
-
-
-void zsort_mesh(struct g3d_mesh *m)
-{
- zsort_cls.varr = m->varr;
- zsort_cls.xform = g3d_get_matrix(G3D_MODELVIEW, 0);
- zsort_cls.prim = m->prim;
-
- if(m->iarr) {
- int nfaces = m->icount / m->prim;
- qsort(m->iarr, nfaces, m->prim * sizeof *m->iarr, zsort_indexed_cmp);
- } else {
- int nfaces = m->vcount / m->prim;
- qsort(m->varr, nfaces, m->prim * sizeof *m->varr, zsort_cmp);
- }
-}
-
-
-void draw_mesh(struct g3d_mesh *mesh)
-{
- if(mesh->iarr) {
- g3d_draw_indexed(mesh->prim, mesh->varr, mesh->vcount, mesh->iarr, mesh->icount);
- } else {
- g3d_draw(mesh->prim, mesh->varr, mesh->vcount);
- }
-}
-
-void apply_mesh_xform(struct g3d_mesh *mesh, const float *xform)
-{
- int i;
- struct g3d_vertex *v = mesh->varr;
-
- for(i=0; i<mesh->vcount; i++) {
- float x = xform[0] * v->x + xform[4] * v->y + xform[8] * v->z + xform[12];
- float y = xform[1] * v->x + xform[5] * v->y + xform[9] * v->z + xform[13];
- v->z = xform[2] * v->x + xform[6] * v->y + xform[10] * v->z + xform[14];
- v->x = x;
- v->y = y;
- x = xform[0] * v->nx + xform[4] * v->ny + xform[8] * v->nz;
- y = xform[1] * v->nx + xform[5] * v->ny + xform[9] * v->nz;
- v->nz = xform[2] * v->nx + xform[6] * v->ny + xform[10] * v->nz;
- v->nx = x;
- v->ny = y;
- ++v;
- }
-}
-
-int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb)
-{
- int i, new_vcount, new_icount;
- void *tmp;
- uint16_t *iptr;
-
- if(ma->prim != mb->prim) {
- fprintf(stderr, "append_mesh failed, primitive mismatch\n");
- return -1;
- }
-
- if(ma->iarr || mb->iarr) {
- if(!ma->iarr) {
- if(indexify_mesh(ma) == -1) {
- return -1;
- }
- } else if(!mb->iarr) {
- if(indexify_mesh(mb) == -1) {
- return -1;
- }
- }
-
- new_icount = ma->icount + mb->icount;
- if(!(iptr = realloc(ma->iarr, new_icount * sizeof *iptr))) {
- fprintf(stderr, "append_mesh: failed to allocate combined index buffer (%d indices)\n", new_icount);
- return -1;
- }
- ma->iarr = iptr;
-
- iptr += ma->icount;
- for(i=0; i<mb->icount; i++) {
- *iptr++ = mb->iarr[i] + ma->vcount;
- }
- ma->icount = new_icount;
- }
-
- new_vcount = ma->vcount + mb->vcount;
- if(!(tmp = realloc(ma->varr, new_vcount * sizeof *ma->varr))) {
- fprintf(stderr, "append_mesh: failed to allocate combined vertex buffer (%d verts)\n", new_vcount);
- return -1;
- }
- ma->varr = tmp;
- memcpy(ma->varr + ma->vcount, mb->varr, mb->vcount * sizeof *ma->varr);
- ma->vcount = new_vcount;
- return 0;
-}
-
-#define FEQ(a, b) ((a) - (b) < 1e-5 && (b) - (a) < 1e-5)
-static int cmp_vertex(struct g3d_vertex *a, struct g3d_vertex *b)
-{
- if(!FEQ(a->x, b->x) || !FEQ(a->y, b->y) || !FEQ(a->z, b->z) || !FEQ(a->w, b->w))
- return -1;
- if(!FEQ(a->nx, b->nx) || !FEQ(a->ny, b->ny) || !FEQ(a->nz, b->nz))
- return -1;
- if(!FEQ(a->u, b->u) || !FEQ(a->v, b->v))
- return -1;
- if(a->r != b->r || a->g != b->g || a->b != b->b || a->a != b->a)
- return -1;
- return 0;
-}
-
-static int find_existing(struct g3d_vertex *v, struct g3d_vertex *varr, int vcount)
-{
- int i;
- for(i=0; i<vcount; i++) {
- if(cmp_vertex(v, varr++) == 0) {
- return i;
- }
- }
- return -1;
-}
-
-int indexify_mesh(struct g3d_mesh *mesh)
-{
- int i, j, nfaces, max_icount, idx;
- int out_vcount = 0;
- struct g3d_vertex *vin, *vout;
- uint16_t *iout;
-
- if(mesh->iarr) {
- fprintf(stderr, "indexify_mesh failed: already indexed\n");
- return -1;
- }
-
- nfaces = mesh->vcount / mesh->prim;
- max_icount = mesh->vcount;
-
- if(!(mesh->iarr = malloc(max_icount * sizeof *mesh->iarr))) {
- fprintf(stderr, "indexify_mesh failed to allocate index buffer of %d indices\n", max_icount);
- return -1;
- }
-
- vin = vout = mesh->varr;
- iout = mesh->iarr;
-
- for(i=0; i<nfaces; i++) {
- for(j=0; j<mesh->prim; j++) {
- if((idx = find_existing(vin, mesh->varr, out_vcount)) >= 0) {
- *iout++ = idx;
- } else {
- *iout++ = out_vcount++;
- if(vin != vout) {
- *vout++ = *vin;
- }
- }
- ++vin;
- }
- }
-
- /* XXX also shrink buffers? I'll just leave them to max size for now */
- return 0;
-}
-
-void normalize_mesh_normals(struct g3d_mesh *mesh)
-{
- int i;
- struct g3d_vertex *v = mesh->varr;
-
- for(i=0; i<mesh->vcount; i++) {
- float mag = sqrt(v->nx * v->nx + v->ny * v->ny + v->nz * v->nz);
- float s = (mag == 0.0f) ? 1.0f : 1.0f / mag;
- v->nx *= s;
- v->ny *= s;
- v->nz *= s;
- ++v;
- }
-}
-
-
-static void sphvec(float *res, float theta, float phi, float rad)
-{
- theta = -theta;
- res[0] = sin(theta) * sin(phi);
- res[1] = cos(phi);
- res[2] = cos(theta) * sin(phi);
-}
-
-int gen_sphere_mesh(struct g3d_mesh *mesh, float rad, int usub, int vsub)
-{
- int i, j;
- int nfaces, uverts, vverts;
- struct g3d_vertex *vptr;
- uint16_t *iptr;
-
- mesh->prim = G3D_QUADS;
-
- if(usub < 4) usub = 4;
- if(vsub < 2) vsub = 2;
-
- uverts = usub + 1;
- vverts = vsub + 1;
-
- mesh->vcount = uverts * vverts;
- nfaces = usub * vsub;
- mesh->icount = nfaces * 4;
-
- if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
- fprintf(stderr, "gen_sphere_mesh: failed to allocate vertex buffer (%d vertices)\n", mesh->vcount);
- return -1;
- }
- if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
- fprintf(stderr, "gen_sphere_mesh: failed to allocate index buffer (%d indices)\n", mesh->icount);
- return -1;
- }
- vptr = mesh->varr;
- iptr = mesh->iarr;
-
- for(i=0; i<uverts; i++) {
- float u = (float)i / (float)(uverts - 1);
- float theta = u * 2.0 * M_PI;
-
- for(j=0; j<vverts; j++) {
- float v = (float)j / (float)(vverts - 1);
- float phi = v * M_PI;
- int chess = (i & 1) == (j & 1);
-
- sphvec(&vptr->x, theta, phi, rad);
- vptr->w = 1.0f;
-
- vptr->nx = vptr->x / rad;
- vptr->ny = vptr->y / rad;
- vptr->nz = vptr->z / rad;
- vptr->u = u;
- vptr->v = v;
- vptr->r = chess ? 255 : 64;
- vptr->g = 128;
- vptr->b = chess ? 64 : 255;
- ++vptr;
-
- if(i < usub && j < vsub) {
- int idx = i * vverts + j;
- *iptr++ = idx;
- *iptr++ = idx + 1;
- *iptr++ = idx + vverts + 1;
- *iptr++ = idx + vverts;
- }
- }
- }
- return 0;
-}
-
-int gen_plane_mesh(struct g3d_mesh *m, float width, float height, int usub, int vsub)
-{
- int i, j;
- int nfaces, nverts, nidx, uverts, vverts;
- float x, y, u, v, du, dv;
- struct g3d_vertex *vptr;
- uint16_t *iptr;
-
- if(usub < 1) usub = 1;
- if(vsub < 1) vsub = 1;
-
- nfaces = usub * vsub;
- uverts = usub + 1;
- vverts = vsub + 1;
- du = (float)width / (float)usub;
- dv = (float)height / (float)vsub;
-
- nverts = uverts * vverts;
- nidx = nfaces * 4;
-
- if(!(m->varr = malloc(nverts * sizeof *m->varr))) {
- fprintf(stderr, "gen_plane_mesh: failed to allocate vertex buffer (%d vertices)\n", nverts);
- return -1;
- }
- if(!(m->iarr = malloc(nidx * sizeof *m->iarr))) {
- fprintf(stderr, "gen_plane_mesh: failed to allocate index buffer (%d indices)\n", nidx);
- free(m->varr);
- m->varr = 0;
- return -1;
- }
-
- m->prim = G3D_QUADS;
- m->vcount = nverts;
- m->icount = nidx;
-
- vptr = m->varr;
- iptr = m->iarr;
-
- v = 0.0f;
- for(i=0; i<vverts; i++) {
- y = (v - 0.5) * height;
- u = 0.0f;
-
- for(j=0; j<uverts; j++) {
- x = (u - 0.5) * width;
-
- vptr->x = x;
- vptr->y = y;
- vptr->z = 0.0f;
- vptr->w = 1.0f;
- vptr->nx = 0.0f;
- vptr->ny = 0.0f;
- vptr->nz = 1.0f;
- vptr->u = u;
- vptr->v = v;
- vptr->r = vptr->g = vptr->b = vptr->a = 255;
- ++vptr;
-
- u += du;
- }
- v += dv;
- }
-
- for(i=0; i<vsub; i++) {
- for(j=0; j<usub; j++) {
- int idx = i * uverts + j;
- *iptr++ = idx;
- *iptr++ = idx + 1;
- *iptr++ = idx + uverts + 1;
- *iptr++ = idx + uverts;
- }
- }
- return 0;
-}
-
-int gen_cube_mesh(struct g3d_mesh *mesh, float sz, int sub)
-{
- int i;
- struct g3d_mesh *m;
- struct g3d_mesh tmpmesh;
- static float rotface[][4] = {
- {0, 0, 1, 0},
- {90, 0, 1, 0},
- {180, 0, 1, 0},
- {270, 0, 1, 0},
- {90, 1, 0, 0},
- {-90, 1, 0, 0}
- };
-
- g3d_matrix_mode(G3D_MODELVIEW);
- g3d_push_matrix();
-
- for(i=0; i<6; i++) {
- m = i > 0 ? &tmpmesh : mesh;
- if(gen_plane_mesh(m, sz, sz, sub, sub) == -1)
- return -1;
- g3d_load_identity();
- g3d_rotate(rotface[i][0], rotface[i][1], rotface[i][2], rotface[i][3]);
- g3d_translate(0, 0, sz / 2.0f);
- apply_mesh_xform(m, g3d_get_matrix(G3D_MODELVIEW, 0));
- if(i > 0) {
- if(append_mesh(mesh, m) == -1) {
- return -1;
- }
- }
- }
-
- g3d_pop_matrix();
- return 0;
-}
-
-static void torusvec(float *res, float theta, float phi, float mr, float rr)
-{
- float rx, ry, rz;
- theta = -theta;
-
- rx = -cos(phi) * rr + mr;
- ry = sin(phi) * rr;
- rz = 0.0f;
-
- res[0] = rx * sin(theta) + rz * cos(theta);
- res[1] = ry;
- res[2] = -rx * cos(theta) + rz * sin(theta);
-}
-
-int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, int vsub)
-{
- int i, j;
- int nfaces, uverts, vverts;
- struct g3d_vertex *vptr;
- uint16_t *iptr;
-
- mesh->prim = G3D_QUADS;
-
- if(usub < 4) usub = 4;
- if(vsub < 2) vsub = 2;
-
- uverts = usub + 1;
- vverts = vsub + 1;
-
- mesh->vcount = uverts * vverts;
- nfaces = usub * vsub;
- mesh->icount = nfaces * 4;
-
- printf("generating torus with %d faces (%d vertices)\n", nfaces, mesh->vcount);
-
- if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) {
- return -1;
- }
- if(!(mesh->iarr = malloc(mesh->icount * sizeof *mesh->iarr))) {
- return -1;
- }
- vptr = mesh->varr;
- iptr = mesh->iarr;
-
- for(i=0; i<uverts; i++) {
- float u = (float)i / (float)(uverts - 1);
- float theta = u * 2.0 * M_PI;
- float rcent[3];
-
- torusvec(rcent, theta, 0, rad, 0);
-
- for(j=0; j<vverts; j++) {
- float v = (float)j / (float)(vverts - 1);
- float phi = v * 2.0 * M_PI;
- int chess = (i & 1) == (j & 1);
-
- torusvec(&vptr->x, theta, phi, rad, ringrad);
- vptr->w = 1.0f;
-
- vptr->nx = (vptr->x - rcent[0]) / ringrad;
- vptr->ny = (vptr->y - rcent[1]) / ringrad;
- vptr->nz = (vptr->z - rcent[2]) / ringrad;
- vptr->u = u;
- vptr->v = v;
- vptr->r = chess ? 255 : 64;
- vptr->g = 128;
- vptr->b = chess ? 64 : 255;
- ++vptr;
-
- if(i < usub && j < vsub) {
- int idx = i * vverts + j;
- *iptr++ = idx;
- *iptr++ = idx + 1;
- *iptr++ = idx + vverts + 1;
- *iptr++ = idx + vverts;
- }
- }
- }
- return 0;
-}
-
+++ /dev/null
-#ifndef MESH_H_
-#define MESH_H_
-
-#include "inttypes.h"
-
-struct g3d_mesh {
- int prim;
- struct g3d_vertex *varr;
- uint16_t *iarr;
- int vcount, icount;
-};
-
-void free_mesh(struct g3d_mesh *mesh);
-void destroy_mesh(struct g3d_mesh *mesh);
-
-int copy_mesh(struct g3d_mesh *dest, struct g3d_mesh *src);
-
-int load_mesh(struct g3d_mesh *mesh, const char *fname);
-int save_mesh(struct g3d_mesh *mesh, const char *fname);
-
-void zsort_mesh(struct g3d_mesh *mesh);
-void draw_mesh(struct g3d_mesh *mesh);
-
-void apply_mesh_xform(struct g3d_mesh *mesh, const float *xform);
-int append_mesh(struct g3d_mesh *ma, struct g3d_mesh *mb);
-int indexify_mesh(struct g3d_mesh *mesh);
-
-void normalize_mesh_normals(struct g3d_mesh *mesh);
-
-int gen_sphere_mesh(struct g3d_mesh *mesh, float rad, int usub, int vsub);
-int gen_plane_mesh(struct g3d_mesh *mesh, float width, float height, int usub, int vsub);
-int gen_cube_mesh(struct g3d_mesh *mesh, float sz, int sub);
-int gen_torus_mesh(struct g3d_mesh *mesh, float rad, float ringrad, int usub, int vsub);
-
-#endif /* MESH_H_ */
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <assert.h>
-#include "mesh.h"
-#include "dynarr.h"
-#include "rbtree.h"
-#include "vmath.h"
-#include "3dgfx.h"
-#include "util.h"
-
-struct vertex_pos_color {
- float x, y, z;
- float r, g, b, a;
-};
-
-struct facevertex {
- int vidx, tidx, nidx;
-};
-
-static char *clean_line(char *s);
-static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int numt, int numn);
-static int cmp_facevert(const void *ap, const void *bp);
-static void free_rbnode_key(struct rbnode *n, void *cls);
-
-/* merge of different indices per attribute happens during face processing.
- *
- * A triplet of (vertex index/texcoord index/normal index) is used as the key
- * to search in a balanced binary search tree for vertex buffer index assigned
- * to the same triplet if it has been encountered before. That index is
- * appended to the index buffer.
- *
- * If a particular triplet has not been encountered before, a new g3d_vertex is
- * appended to the vertex buffer. The index of this new vertex is appended to
- * the index buffer, and also inserted into the tree for future searches.
- */
-int load_mesh(struct g3d_mesh *mesh, const char *fname)
-{
- int i, line_num = 0, result = -1;
- int found_quad = 0;
- FILE *fp = 0;
- char buf[256];
- struct vertex_pos_color *varr = 0;
- vec3_t *narr = 0;
- vec2_t *tarr = 0;
- struct rbtree *rbtree = 0;
-
- if(!(fp = fopen(fname, "rb"))) {
- fprintf(stderr, "load_mesh: failed to open file: %s\n", fname);
- goto err;
- }
-
- if(!(rbtree = rb_create(cmp_facevert))) {
- fprintf(stderr, "load_mesh: failed to create facevertex binary search tree\n");
- goto err;
- }
- rb_set_delete_func(rbtree, free_rbnode_key, 0);
-
- if(!(mesh->varr = dynarr_alloc(0, sizeof *mesh->varr)) ||
- !(mesh->iarr = dynarr_alloc(0, sizeof *mesh->iarr))) {
- fprintf(stderr, "load_mesh: failed to allocate resizable mesh arrays\n");
- goto err;
- }
- if(!(varr = dynarr_alloc(0, sizeof *varr)) ||
- !(narr = dynarr_alloc(0, sizeof *narr)) ||
- !(tarr = dynarr_alloc(0, sizeof *tarr))) {
- fprintf(stderr, "load_mesh: failed to allocate resizable vertex array\n");
- goto err;
- }
-
- while(fgets(buf, sizeof buf, fp)) {
- char *line = clean_line(buf);
- ++line_num;
-
- if(!*line) continue;
-
- switch(line[0]) {
- case 'v':
- if(isspace(line[1])) {
- /* vertex */
- struct vertex_pos_color v;
- int num;
-
- num = sscanf(line + 2, "%f %f %f %f %f %f %f", &v.x, &v.y, &v.z, &v.r, &v.g, &v.b, &v.a);
- if(num < 3) {
- fprintf(stderr, "%s:%d: invalid vertex definition: \"%s\"\n", fname, line_num, line);
- goto err;
- }
- switch(num) {
- case 3:
- v.r = 1.0f;
- case 4:
- v.g = 1.0f;
- case 5:
- v.b = 1.0f;
- case 6:
- v.a = 1.0f;
- }
- if(!(varr = dynarr_push(varr, &v))) {
- fprintf(stderr, "load_mesh: failed to resize vertex buffer\n");
- goto err;
- }
-
- } else if(line[1] == 't' && isspace(line[2])) {
- /* texcoord */
- vec2_t tc;
- if(sscanf(line + 3, "%f %f", &tc.x, &tc.y) != 2) {
- fprintf(stderr, "%s:%d: invalid texcoord definition: \"%s\"\n", fname, line_num, line);
- goto err;
- }
- if(!(tarr = dynarr_push(tarr, &tc))) {
- fprintf(stderr, "load_mesh: failed to resize texcoord buffer\n");
- goto err;
- }
-
- } else if(line[1] == 'n' && isspace(line[2])) {
- /* normal */
- vec3_t norm;
- if(sscanf(line + 3, "%f %f %f", &norm.x, &norm.y, &norm.z) != 3) {
- fprintf(stderr, "%s:%d: invalid normal definition: \"%s\"\n", fname, line_num, line);
- goto err;
- }
- if(!(narr = dynarr_push(narr, &norm))) {
- fprintf(stderr, "load_mesh: failed to resize normal buffer\n");
- goto err;
- }
- }
- break;
-
- case 'f':
- if(isspace(line[1])) {
- /* face */
- char *ptr = line + 2;
- struct facevertex fv;
- struct rbnode *node;
- int vsz = dynarr_size(varr);
- int tsz = dynarr_size(tarr);
- int nsz = dynarr_size(narr);
-
- for(i=0; i<4; i++) {
- if(!(ptr = parse_face_vert(ptr, &fv, vsz, tsz, nsz))) {
- if(i < 3 || found_quad) {
- fprintf(stderr, "%s:%d: invalid face definition: \"%s\"\n", fname, line_num, line);
- goto err;
- } else {
- break;
- }
- }
-
- if((node = rb_find(rbtree, &fv))) {
- uint16_t idx = (int)(intptr_t)node->data;
- if(!(mesh->iarr = dynarr_push(mesh->iarr, &idx))) {
- fprintf(stderr, "load_mesh: failed to resize index array\n");
- goto err;
- }
- } else {
- uint16_t newidx = dynarr_size(mesh->varr);
- struct g3d_vertex v;
- struct facevertex *newfv;
-
- v.x = varr[fv.vidx].x;
- v.y = varr[fv.vidx].y;
- v.z = varr[fv.vidx].z;
- v.w = 1.0f;
- v.r = cround64(varr[fv.vidx].r * 255.0);
- v.g = cround64(varr[fv.vidx].g * 255.0);
- v.b = cround64(varr[fv.vidx].b * 255.0);
- v.a = cround64(varr[fv.vidx].a * 255.0);
- if(fv.tidx >= 0) {
- v.u = tarr[fv.tidx].x;
- v.v = tarr[fv.tidx].y;
- } else {
- v.u = v.x;
- v.v = v.y;
- }
- if(fv.nidx >= 0) {
- v.nx = narr[fv.nidx].x;
- v.ny = narr[fv.nidx].y;
- v.nz = narr[fv.nidx].z;
- } else {
- v.nx = v.ny = 0.0f;
- v.nz = 1.0f;
- }
-
- if(!(mesh->varr = dynarr_push(mesh->varr, &v))) {
- fprintf(stderr, "load_mesh: failed to resize combined vertex array\n");
- goto err;
- }
- if(!(mesh->iarr = dynarr_push(mesh->iarr, &newidx))) {
- fprintf(stderr, "load_mesh: failed to resize index array\n");
- goto err;
- }
-
- if((newfv = malloc(sizeof *newfv))) {
- *newfv = fv;
- }
- if(!newfv || rb_insert(rbtree, newfv, (void*)(intptr_t)newidx) == -1) {
- fprintf(stderr, "load_mesh: failed to insert facevertex to the binary search tree\n");
- goto err;
- }
- }
- }
- if(i > 3) found_quad = 1;
- }
- break;
-
- default:
- break;
- }
- }
-
- mesh->prim = found_quad ? G3D_QUADS : G3D_TRIANGLES;
- mesh->vcount = dynarr_size(mesh->varr);
- mesh->icount = dynarr_size(mesh->iarr);
- mesh->varr = dynarr_finalize(mesh->varr);
- mesh->iarr = dynarr_finalize(mesh->iarr);
- result = 0; /* success */
-
- printf("loaded %s mesh: %s: %d vertices, %d faces\n", found_quad ? "quad" : "triangle",
- fname, mesh->vcount, mesh->icount / mesh->prim);
-
-err:
- if(fp) fclose(fp);
- dynarr_free(varr);
- dynarr_free(narr);
- dynarr_free(tarr);
- if(result == -1) {
- dynarr_free(mesh->varr);
- dynarr_free(mesh->iarr);
- }
- rb_free(rbtree);
- return result;
-}
-
-int save_mesh(struct g3d_mesh *mesh, const char *fname)
-{
- int i, fvcount;
- FILE *fp;
-
- if(!(fp = fopen(fname, "wb"))) {
- fprintf(stderr, "save_mesh: failed to open %s for writing\n", fname);
- return -1;
- }
- fprintf(fp, "# Wavefront OBJ file shoved in your FACE by Mindlapse. Deal with it\n");
-
- for(i=0; i<mesh->vcount; i++) {
- struct g3d_vertex *v = mesh->varr + i;
- fprintf(fp, "v %f %f %f %f %f %f %f\n", v->x, v->y, v->z, v->r / 255.0f, v->g / 255.0f,
- v->b / 255.0f, v->a / 255.0f);
- }
- for(i=0; i<mesh->vcount; i++) {
- fprintf(fp, "vn %f %f %f\n", mesh->varr[i].nx, mesh->varr[i].ny, mesh->varr[i].nz);
- }
- for(i=0; i<mesh->vcount; i++) {
- fprintf(fp, "vt %f %f\n", mesh->varr[i].u, mesh->varr[i].v);
- }
-
- fvcount = mesh->prim;
- for(i=0; i<mesh->icount; i++) {
- int idx = mesh->iarr[i] + 1;
-
- if(fvcount == mesh->prim) {
- fprintf(fp, "\nf");
- fvcount = 0;
- }
- fprintf(fp, " %d/%d/%d", idx, idx, idx);
- ++fvcount;
- }
- fprintf(fp, "\n");
-
- fclose(fp);
- return 0;
-}
-
-static char *clean_line(char *s)
-{
- char *end;
-
- while(*s && isspace(*s)) ++s;
- if(!*s) return 0;
-
- end = s;
- while(*end && *end != '#') ++end;
- *end = 0;
-
- while(end > s && isspace(*end)) --end;
- *end = 0;
-
- return s;
-}
-
-static char *parse_idx(char *ptr, int *idx, int arrsz)
-{
- char *endp;
- int val = strtol(ptr, &endp, 10);
- if(endp == ptr) return 0;
-
- if(val < 0) { /* convert negative indices */
- *idx = arrsz + val;
- } else {
- *idx = val - 1; /* indices in obj are 1-based */
- }
- return endp;
-}
-
-/* possible face-vertex definitions:
- * 1. vertex
- * 2. vertex/texcoord
- * 3. vertex//normal
- * 4. vertex/texcoord/normal
- */
-static char *parse_face_vert(char *ptr, struct facevertex *fv, int numv, int numt, int numn)
-{
- if(!(ptr = parse_idx(ptr, &fv->vidx, numv)))
- return 0;
- if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0;
-
- if(*++ptr == '/') { /* no texcoord */
- fv->tidx = -1;
- ++ptr;
- } else {
- if(!(ptr = parse_idx(ptr, &fv->tidx, numt)))
- return 0;
- if(*ptr != '/') return (!*ptr || isspace(*ptr)) ? ptr : 0;
- ++ptr;
- }
-
- if(!(ptr = parse_idx(ptr, &fv->nidx, numn)))
- return 0;
- return (!*ptr || isspace(*ptr)) ? ptr : 0;
-}
-
-static int cmp_facevert(const void *ap, const void *bp)
-{
- const struct facevertex *a = ap;
- const struct facevertex *b = bp;
-
- if(a->vidx == b->vidx) {
- if(a->tidx == b->tidx) {
- return a->nidx - b->nidx;
- }
- return a->tidx - b->tidx;
- }
- return a->vidx - b->vidx;
-}
-
-static void free_rbnode_key(struct rbnode *n, void *cls)
-{
- free(n->key);
-}
+++ /dev/null
-#include <stdio.h>
-#include <math.h>
-#include <assert.h>
-#include "polyclip.h"
-
-struct ray {
- float origin[3];
- float dir[3];
-};
-
-static int clip_edge(struct g3d_vertex *poly, int *vnumptr,
- const struct g3d_vertex *v0, const struct g3d_vertex *v1,
- const struct cplane *plane);
-static int check_clip_edge(const struct g3d_vertex *v0,
- const struct g3d_vertex *v1, const struct cplane *plane);
-static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr,
- const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane);
-static float distance_signed(float *pos, const struct cplane *plane);
-static int intersect(const struct ray *ray, const struct cplane *plane, float *t);
-static int inside_frustum_plane(const struct g3d_vertex *v, int fplane);
-
-
-int clip_poly(struct g3d_vertex *vout, int *voutnum,
- const struct g3d_vertex *vin, int vnum, struct cplane *plane)
-{
- int i, nextidx, res;
- int edges_clipped = 0;
-
- *voutnum = 0;
-
- for(i=0; i<vnum; i++) {
- nextidx = i + 1;
- if(nextidx >= vnum) nextidx = 0;
- res = clip_edge(vout, voutnum, vin + i, vin + nextidx, plane);
- if(res == 0) {
- ++edges_clipped;
- }
- }
-
- if(*voutnum <= 0) {
- assert(edges_clipped == 0);
- return -1;
- }
-
- return edges_clipped > 0 ? 0 : 1;
-}
-
-int check_clip_poly(const struct g3d_vertex *v, int vnum, struct cplane *plane)
-{
- int i, nextidx, res;
- int edges_clipped = 0;
-
- for(i=0; i<vnum; i++) {
- nextidx = i + 1;
- if(nextidx >= vnum) nextidx = 0;
- res = check_clip_edge(v + i, v + nextidx, plane);
- if(res == 0) {
- ++edges_clipped;
- }
- }
- return edges_clipped ? 0 : res;
-}
-
-int clip_frustum(struct g3d_vertex *vout, int *voutnum,
- const struct g3d_vertex *vin, int vnum, int fplane)
-{
- int i, nextidx, res;
- int edges_clipped = 0;
-
- if(vnum == 1) {
- /* special case: point clipping */
- return inside_frustum_plane(vin, fplane) ? 1 : -1;
- }
-
- *voutnum = 0;
-
- for(i=0; i<vnum; i++) {
- nextidx = i + 1;
- if(nextidx >= vnum) nextidx = 0;
- res = clip_edge_frustum(vout, voutnum, vin + i, vin + nextidx, fplane);
- if(res == 0) {
- ++edges_clipped;
- }
- }
-
- if(*voutnum <= 0) {
- assert(edges_clipped == 0);
- return -1;
- }
-
- return edges_clipped > 0 ? 0 : 1;
-}
-
-#define LERP_VATTR(res, v0, v1, t) \
- do { \
- (res)->nx = (v0)->nx + ((v1)->nx - (v0)->nx) * (t); \
- (res)->ny = (v0)->ny + ((v1)->ny - (v0)->ny) * (t); \
- (res)->nz = (v0)->nz + ((v1)->nz - (v0)->nz) * (t); \
- (res)->u = (v0)->u + ((v1)->u - (v0)->u) * (t); \
- (res)->v = (v0)->v + ((v1)->v - (v0)->v) * (t); \
- (res)->r = (v0)->r + ((v1)->r - (v0)->r) * (t); \
- (res)->g = (v0)->g + ((v1)->g - (v0)->g) * (t); \
- (res)->b = (v0)->b + ((v1)->b - (v0)->b) * (t); \
- } while(0)
-
-
-/* returns:
- * 1 -> both inside
- * 0 -> straddling and clipped
- * -1 -> both outside
- *
- * also returns the size of the polygon through vnumptr
- */
-static int clip_edge(struct g3d_vertex *poly, int *vnumptr,
- const struct g3d_vertex *v0, const struct g3d_vertex *v1,
- const struct cplane *plane)
-{
- float pos0[3], pos1[3];
- float d0, d1, t;
- struct ray ray;
- int i, vnum = *vnumptr;
-
- pos0[0] = v0->x; pos0[1] = v0->y; pos0[2] = v0->z;
- pos1[0] = v1->x; pos1[1] = v1->y; pos1[2] = v1->z;
-
- d0 = distance_signed(pos0, plane);
- d1 = distance_signed(pos1, plane);
-
- for(i=0; i<3; i++) {
- ray.origin[i] = pos0[i];
- ray.dir[i] = pos1[i] - pos0[i];
- }
-
- if(d0 >= 0.0) {
- /* start inside */
- if(d1 >= 0.0) {
- /* all inside */
- poly[vnum++] = *v1; /* append v1 */
- *vnumptr = vnum;
- return 1;
- } else {
- /* going out */
- struct g3d_vertex *vptr = poly + vnum;
-
- intersect(&ray, plane, &t);
-
- vptr->x = ray.origin[0] + ray.dir[0] * t;
- vptr->y = ray.origin[1] + ray.dir[1] * t;
- vptr->z = ray.origin[2] + ray.dir[2] * t;
- vptr->w = 1.0f;
-
- LERP_VATTR(vptr, v0, v1, t);
- vnum++; /* append new vertex on the intersection point */
- }
- } else {
- /* start outside */
- if(d1 >= 0) {
- /* going in */
- struct g3d_vertex *vptr = poly + vnum;
-
- intersect(&ray, plane, &t);
-
- vptr->x = ray.origin[0] + ray.dir[0] * t;
- vptr->y = ray.origin[1] + ray.dir[1] * t;
- vptr->z = ray.origin[2] + ray.dir[2] * t;
- vptr->w = 1.0f;
-
- LERP_VATTR(vptr, v0, v1, t);
- vnum++; /* append new vertex on the intersection point */
-
- /* then append v1 ... */
- poly[vnum++] = *v1;
- } else {
- /* all outside */
- return -1;
- }
- }
-
- *vnumptr = vnum;
- return 0;
-}
-
-/* same as above, but only checks for clipping and classifies the edge */
-static int check_clip_edge(const struct g3d_vertex *v0,
- const struct g3d_vertex *v1, const struct cplane *plane)
-{
- float pos0[3], pos1[3];
- float d0, d1;
-
- pos0[0] = v0->x; pos0[1] = v0->y; pos0[2] = v0->z;
- pos1[0] = v1->x; pos1[1] = v1->y; pos1[2] = v1->z;
-
- d0 = distance_signed(pos0, plane);
- d1 = distance_signed(pos1, plane);
-
- if(d0 > 0.0f && d1 > 0.0f) {
- return 1;
- }
- if(d0 < 0.0f && d1 < 0.0f) {
- return -1;
- }
- return 0;
-}
-
-static float distance_signed(float *pos, const struct cplane *plane)
-{
- float dx = pos[0] - plane->x;
- float dy = pos[1] - plane->y;
- float dz = pos[2] - plane->z;
- return dx * plane->nx + dy * plane->ny + dz * plane->nz;
-}
-
-static int intersect(const struct ray *ray, const struct cplane *plane, float *t)
-{
- float orig_pt_dir[3];
-
- float ndotdir = plane->nx * ray->dir[0] + plane->ny * ray->dir[1] + plane->nz * ray->dir[2];
- if(fabs(ndotdir) < 1e-6) {
- *t = 0.0f;
- return 0;
- }
-
- orig_pt_dir[0] = plane->x - ray->origin[0];
- orig_pt_dir[1] = plane->y - ray->origin[1];
- orig_pt_dir[2] = plane->z - ray->origin[2];
-
- *t = (plane->nx * orig_pt_dir[0] + plane->ny * orig_pt_dir[1] + plane->nz * orig_pt_dir[2]) / ndotdir;
- return 1;
-}
-
-/* homogeneous frustum clipper helpers */
-
-static int inside_frustum_plane(const struct g3d_vertex *v, int fplane)
-{
- switch(fplane) {
- case CLIP_LEFT:
- return v->x >= -v->w;
- case CLIP_RIGHT:
- return v->x <= v->w;
- case CLIP_BOTTOM:
- return v->y >= -v->w;
- case CLIP_TOP:
- return v->y <= v->w;
- case CLIP_NEAR:
- return v->z >= -v->w;
- case CLIP_FAR:
- return v->z <= v->w;
- }
- assert(0);
- return 0;
-}
-
-static float intersect_frustum(const struct g3d_vertex *a, const struct g3d_vertex *b, int fplane)
-{
- switch(fplane) {
- case CLIP_LEFT:
- return (-a->w - a->x) / (b->x - a->x + b->w - a->w);
- case CLIP_RIGHT:
- return (a->w - a->x) / (b->x - a->x - b->w + a->w);
- case CLIP_BOTTOM:
- return (-a->w - a->y) / (b->y - a->y + b->w - a->w);
- case CLIP_TOP:
- return (a->w - a->y) / (b->y - a->y - b->w + a->w);
- case CLIP_NEAR:
- return (-a->w - a->z) / (b->z - a->z + b->w - a->w);
- case CLIP_FAR:
- return (a->w - a->z) / (b->z - a->z - b->w + a->w);
- }
-
- assert(0);
- return 0;
-}
-
-static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr,
- const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane)
-{
- int vnum = *vnumptr;
- int in0, in1;
- float t;
-
- in0 = inside_frustum_plane(v0, fplane);
- in1 = inside_frustum_plane(v1, fplane);
-
- if(in0) {
- /* start inside */
- if(in1) {
- /* all inside */
- poly[vnum++] = *v1; /* append v1 */
- *vnumptr = vnum;
- return 1;
- } else {
- /* going out */
- struct g3d_vertex *vptr = poly + vnum;
-
- t = intersect_frustum(v0, v1, fplane);
-
- vptr->x = v0->x + (v1->x - v0->x) * t;
- vptr->y = v0->y + (v1->y - v0->y) * t;
- vptr->z = v0->z + (v1->z - v0->z) * t;
- vptr->w = v0->w + (v1->w - v0->w) * t;
-
- LERP_VATTR(vptr, v0, v1, t);
- ++vnum; /* append new vertex on the intersection point */
- }
- } else {
- /* start outside */
- if(in1) {
- /* going in */
- struct g3d_vertex *vptr = poly + vnum;
-
- t = intersect_frustum(v0, v1, fplane);
-
- vptr->x = v0->x + (v1->x - v0->x) * t;
- vptr->y = v0->y + (v1->y - v0->y) * t;
- vptr->z = v0->z + (v1->z - v0->z) * t;
- vptr->w = v0->w + (v1->w - v0->w) * t;
-
- LERP_VATTR(vptr, v0, v1, t);
- ++vnum; /* append new vertex on the intersection point */
-
- /* then append v1 ... */
- poly[vnum++] = *v1;
- } else {
- /* all outside */
- return -1;
- }
- }
-
- *vnumptr = vnum;
- return 0;
-}
+++ /dev/null
-#ifndef POLYCLIP_H_
-#define POLYCLIP_H_
-
-#include "3dgfx.h"
-
-struct cplane {
- float x, y, z;
- float nx, ny, nz;
-};
-
-enum {
- CLIP_LEFT, CLIP_RIGHT,
- CLIP_BOTTOM, CLIP_TOP,
- CLIP_NEAR, CLIP_FAR
-};
-
-/* Generic polygon clipper
- * returns:
- * 1 -> fully inside, not clipped
- * 0 -> straddling the plane and clipped
- * -1 -> fully outside, not clipped
- * in all cases, vertices are copied to vout, and the vertex count is written
- * to wherever voutnum is pointing
- */
-int clip_poly(struct g3d_vertex *vout, int *voutnum,
- const struct g3d_vertex *vin, int vnum, struct cplane *plane);
-
-/* only checks if the polygon would be clipped by the plane, and classifies it
- * as inside/outside/straddling, without actually producing a clipped polygon.
- * return values are the same as clip_poly.
- */
-int check_clip_poly(const struct g3d_vertex *v, int vnum, struct cplane *plane);
-
-/* Special-case frustum clipper (might be slightly faster) */
-int clip_frustum(struct g3d_vertex *vout, int *voutnum,
- const struct g3d_vertex *vin, int vnum, int fplane);
-
-#endif /* POLYCLIP_H_ */
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__)
-#include <malloc.h>
-#else
-#include <alloca.h>
-#endif
-#include "polyfill.h"
-#include "gfxutil.h"
-
-#define FILL_POLY_BITS 0x03
-
-/* mode bits: 00-wire 01-flat 10-gouraud 11-reserved
- * bit 2: texture
- * bit 3: blend
- */
-void (*fillfunc[])(struct pvertex*, int) = {
- polyfill_wire,
- polyfill_flat,
- polyfill_gouraud,
- 0,
- polyfill_tex_wire,
- polyfill_tex_flat,
- polyfill_tex_gouraud,
- 0,
- polyfill_blend_wire,
- polyfill_blend_flat,
- polyfill_blend_gouraud,
- 0,
- polyfill_blend_tex_wire,
- polyfill_blend_tex_flat,
- polyfill_blend_tex_gouraud,
- 0
-};
-
-struct pimage pfill_fb, pfill_tex;
-
-void polyfill(int mode, struct pvertex *verts, int nverts)
-{
-#ifndef NDEBUG
- if(!fillfunc[mode]) {
- fprintf(stderr, "polyfill mode %d not implemented\n", mode);
- abort();
- }
-#endif
-
- fillfunc[mode](verts, nverts);
-}
-
-void polyfill_wire(struct pvertex *verts, int nverts)
-{
- int i, x0, y0, x1, y1;
- struct pvertex *v = verts;
- unsigned short color = ((v->r << 8) & 0xf800) |
- ((v->g << 3) & 0x7e0) | ((v->b >> 3) & 0x1f);
-
- for(i=0; i<nverts - 1; i++) {
- x0 = v->x >> 8;
- y0 = v->y >> 8;
- ++v;
- x1 = v->x >> 8;
- y1 = v->y >> 8;
- if(clip_line(&x0, &y0, &x1, &y1, 0, 0, pfill_fb.width, pfill_fb.height)) {
- draw_line(x0, y0, x1, y1, color);
- }
- }
- x0 = verts[0].x >> 8;
- y0 = verts[0].y >> 8;
- if(clip_line(&x1, &y1, &x0, &y0, 0, 0, pfill_fb.width, pfill_fb.height)) {
- draw_line(x1, y1, x0, y0, color);
- }
-}
-
-void polyfill_tex_wire(struct pvertex *verts, int nverts)
-{
- polyfill_wire(verts, nverts); /* TODO */
-}
-
-void polyfill_blend_wire(struct pvertex *verts, int nverts)
-{
- polyfill_wire(verts, nverts); /* TODO */
-}
-
-void polyfill_blend_tex_wire(struct pvertex *verts, int nverts)
-{
- polyfill_wire(verts, nverts); /* TODO */
-}
-
-#define NEXTIDX(x) (((x) - 1 + nverts) % nverts)
-#define PREVIDX(x) (((x) + 1) % nverts)
-
-/* XXX
- * When HIGH_QUALITY is defined, the rasterizer calculates slopes for attribute
- * interpolation on each scanline separately; otherwise the slope for each
- * attribute would be calculated once for the whole polygon, which is faster,
- * but produces some slight quantization artifacts, due to the limited precision
- * of fixed-point calculations.
- */
-#define HIGH_QUALITY
-
-/* extra bits of precision to use when interpolating colors.
- * try tweaking this if you notice strange quantization artifacts.
- */
-#define COLOR_SHIFT 12
-
-
-#define POLYFILL polyfill_flat
-#define SCANEDGE scanedge_flat
-#undef GOURAUD
-#undef TEXMAP
-#undef BLEND
-#include "polytmpl.h"
-#undef POLYFILL
-#undef SCANEDGE
-
-#define POLYFILL polyfill_gouraud
-#define SCANEDGE scanedge_gouraud
-#define GOURAUD
-#undef TEXMAP
-#undef BLEND
-#include "polytmpl.h"
-#undef POLYFILL
-#undef SCANEDGE
-
-#define POLYFILL polyfill_tex_flat
-#define SCANEDGE scanedge_tex_flat
-#undef GOURAUD
-#define TEXMAP
-#undef BLEND
-#include "polytmpl.h"
-#undef POLYFILL
-#undef SCANEDGE
-
-#define POLYFILL polyfill_tex_gouraud
-#define SCANEDGE scanedge_tex_gouraud
-#define GOURAUD
-#define TEXMAP
-#undef BLEND
-#include "polytmpl.h"
-#undef POLYFILL
-#undef SCANEDGE
-
-#define POLYFILL polyfill_blend_flat
-#define SCANEDGE scanedge_blend_flat
-#undef GOURAUD
-#undef TEXMAP
-#define BLEND
-#include "polytmpl.h"
-#undef POLYFILL
-#undef SCANEDGE
-
-#define POLYFILL polyfill_blend_gouraud
-#define SCANEDGE scanedge_blend_gouraud
-#define GOURAUD
-#undef TEXMAP
-#define BLEND
-#include "polytmpl.h"
-#undef POLYFILL
-#undef SCANEDGE
-
-#define POLYFILL polyfill_blend_tex_flat
-#define SCANEDGE scanedge_blend_tex_flat
-#undef GOURAUD
-#define TEXMAP
-#define BLEND
-#include "polytmpl.h"
-#undef POLYFILL
-#undef SCANEDGE
-
-#define POLYFILL polyfill_blend_tex_gouraud
-#define SCANEDGE scanedge_blend_tex_gouraud
-#define GOURAUD
-#define TEXMAP
-#define BLEND
-#include "polytmpl.h"
-#undef POLYFILL
-#undef SCANEDGE
+++ /dev/null
-#ifndef POLYFILL_H_
-#define POLYFILL_H_
-
-#include "inttypes.h"
-#include "3dgfx.h"
-
-#define POLYFILL_MODE_MASK 0x03
-#define POLYFILL_TEX_BIT 0x04
-#define POLYFILL_BLEND_BIT 0x08
-
-enum {
- POLYFILL_WIRE = 0,
- POLYFILL_FLAT,
- POLYFILL_GOURAUD,
-
- POLYFILL_TEX_WIRE = 4,
- POLYFILL_TEX_FLAT,
- POLYFILL_TEX_GOURAUD,
-
- POLYFILL_BLEND_WIRE = 8,
- POLYFILL_BLEND_FLAT,
- POLYFILL_BLEND_GOURAUD,
-
- POLYFILL_BLEND_TEX_WIRE = 12,
- POLYFILL_BLEND_TEX_FLAT,
- POLYFILL_BLEND_TEX_GOURAUD
-};
-
-/* projected vertices for the rasterizer */
-struct pvertex {
- int32_t x, y; /* 24.8 fixed point */
- int32_t u, v; /* 16.16 fixed point */
- int32_t r, g, b, a; /* int 0-255 */
-};
-
-struct pimage {
- g3d_pixel *pixels;
- int width, height;
-
- int xshift, yshift;
- unsigned int xmask, ymask;
-};
-
-extern struct pimage pfill_fb;
-extern struct pimage pfill_tex;
-
-void polyfill(int mode, struct pvertex *verts, int nverts);
-
-void polyfill_wire(struct pvertex *verts, int nverts);
-void polyfill_flat(struct pvertex *verts, int nverts);
-void polyfill_gouraud(struct pvertex *verts, int nverts);
-void polyfill_tex_wire(struct pvertex *verts, int nverts);
-void polyfill_tex_flat(struct pvertex *verts, int nverts);
-void polyfill_tex_gouraud(struct pvertex *verts, int nverts);
-void polyfill_blend_wire(struct pvertex *verts, int nverts);
-void polyfill_blend_flat(struct pvertex *verts, int nverts);
-void polyfill_blend_gouraud(struct pvertex *verts, int nverts);
-void polyfill_blend_tex_wire(struct pvertex *verts, int nverts);
-void polyfill_blend_tex_flat(struct pvertex *verts, int nverts);
-void polyfill_blend_tex_gouraud(struct pvertex *verts, int nverts);
-
-#endif /* POLYFILL_H_ */
+++ /dev/null
-static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge)
-{
- int i;
- int32_t x, dx, dy, slope;
-#ifdef GOURAUD
- int r, g, b, dr, dg, db;
- int32_t rslope, gslope, bslope;
-#ifdef BLEND
- int32_t a, da, aslope;
-#endif
-#endif /* GOURAUD */
-#ifdef TEXMAP
- int32_t u, v, du, dv, uslope, vslope;
-#endif
- int32_t start_idx, end_idx;
-
- if(v0->y > v1->y) {
- struct pvertex *tmp = v0;
- v0 = v1;
- v1 = tmp;
- }
-
- x = v0->x;
- dy = v1->y - v0->y;
- dx = v1->x - v0->x;
- slope = (dx << 8) / dy;
-#ifdef GOURAUD
- r = (v0->r << COLOR_SHIFT);
- g = (v0->g << COLOR_SHIFT);
- b = (v0->b << COLOR_SHIFT);
- dr = (v1->r << COLOR_SHIFT) - r;
- dg = (v1->g << COLOR_SHIFT) - g;
- db = (v1->b << COLOR_SHIFT) - b;
- rslope = (dr << 8) / dy;
- gslope = (dg << 8) / dy;
- bslope = (db << 8) / dy;
-#ifdef BLEND
- a = (v0->a << COLOR_SHIFT);
- da = (v1->a << COLOR_SHIFT) - a;
- aslope = (da << 8) / dy;
-#endif /* BLEND */
-#endif /* GOURAUD */
-#ifdef TEXMAP
- u = v0->u;
- v = v0->v;
- du = v1->u - v0->u;
- dv = v1->v - v0->v;
- uslope = (du << 8) / dy;
- vslope = (dv << 8) / dy;
-#endif
-
- start_idx = v0->y >> 8;
- end_idx = v1->y >> 8;
-
- for(i=start_idx; i<end_idx; i++) {
- edge[i].x = x;
- x += slope;
-#ifdef GOURAUD
- /* we'll store the color in the edge tables with COLOR_SHIFT extra bits of precision */
- edge[i].r = r;
- edge[i].g = g;
- edge[i].b = b;
- r += rslope;
- g += gslope;
- b += bslope;
-#ifdef BLEND
- edge[i].a = a;
- a += aslope;
-#endif
-#endif /* GOURAUD */
-#ifdef TEXMAP
- edge[i].u = u;
- edge[i].v = v;
- u += uslope;
- v += vslope;
-#endif
- }
-
- return (uint32_t)start_idx | ((uint32_t)(end_idx - 1) << 16);
-}
-
-void POLYFILL(struct pvertex *pv, int nverts)
-{
- int i, winding;
- int topidx = 0, botidx = 0, sltop = pfill_fb.height, slbot = 0;
- struct pvertex *left, *right;
- g3d_pixel color;
- /* the following variables are used for interpolating horizontally accros scanlines */
-#if defined(GOURAUD) || defined(TEXMAP)
- int mid;
- int32_t dx, tmp;
-#else
- /* flat version, just pack the color now */
- color = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
-#endif
-#ifdef GOURAUD
- int32_t r, g, b, dr, dg, db, rslope, gslope, bslope;
-#ifdef BLEND
- int32_t a, da, aslope;
-#endif
-#endif
-#ifdef TEXMAP
- int32_t u, v, du, dv, uslope, vslope;
-#endif
-
- for(i=1; i<nverts; i++) {
- if(pv[i].y < pv[topidx].y) topidx = i;
- if(pv[i].y > pv[botidx].y) botidx = i;
- }
-
- winding = 0;
- for(i=0; i<nverts; i++) {
- int next = NEXTIDX(i);
- winding += ((pv[next].x - pv[i].x) >> 4) * ((pv[next].y + pv[i].y) >> 4);
- }
-
- /* +1 to avoid crashing due to off-by-one rounding errors in the rasterization */
- left = alloca((pfill_fb.height + 1) * sizeof *left);
- right = alloca((pfill_fb.height + 1) * sizeof *right);
-
- for(i=0; i<nverts; i++) {
- int next = NEXTIDX(i);
- int32_t y0 = pv[i].y;
- int32_t y1 = pv[next].y;
-
- if((y0 >> 8) == (y1 >> 8)) {
- /*if(y0 > y1) {*/
- int i0, i1;
- int idx = y0 >> 8;
- if(pv[i].x < pv[next].x) {
- i0 = i;
- i1 = next;
- } else {
- i0 = next;
- i1 = i;
- }
- left[idx].x = pv[i0].x;
- right[idx].x = pv[i1].x;
-#ifdef GOURAUD
- left[idx].r = pv[i0].r << COLOR_SHIFT;
- left[idx].g = pv[i0].g << COLOR_SHIFT;
- left[idx].b = pv[i0].b << COLOR_SHIFT;
- right[idx].r = pv[i1].r << COLOR_SHIFT;
- right[idx].g = pv[i1].g << COLOR_SHIFT;
- right[idx].b = pv[i1].b << COLOR_SHIFT;
-#ifdef BLEND
- left[idx].a = pv[i0].a << COLOR_SHIFT;
- right[idx].a = pv[i1].a << COLOR_SHIFT;
-#endif /* BLEND */
-#endif
-#ifdef TEXMAP
- left[idx].u = pv[i0].u;
- left[idx].v = pv[i0].v;
- right[idx].u = pv[i1].u;
- right[idx].v = pv[i1].v;
-#endif
- if(idx > slbot) slbot = idx;
- if(idx < sltop) sltop = idx;
- /*}*/
- } else {
- struct pvertex *edge;
- uint32_t res, tmp;
-
- if(winding < 0) {
- /* clockwise */
- edge = y0 > y1 ? left : right;
- } else {
- /* counter-clockwise */
- edge = y0 > y1 ? right : left;
- }
- res = SCANEDGE(pv + i, pv + next, edge);
- tmp = (res >> 16) & 0xffff;
- if(tmp > slbot) slbot = tmp;
- if((tmp = res & 0xffff) < sltop) {
- sltop = tmp;
- }
- }
- }
-
- /* calculate the slopes of all attributes across the largest span out
- * of the three: middle, top, or bottom.
- */
-#ifndef HIGH_QUALITY
-#if defined(GOURAUD) || defined(TEXMAP)
- mid = (sltop + slbot) >> 1;
- dx = right[mid].x - left[mid].x;
- if((tmp = right[sltop].x - left[sltop].x) > dx) {
- dx = tmp;
- mid = sltop;
- }
- if((tmp = right[slbot].x - left[slbot].x) > dx) {
- dx = tmp;
- mid = slbot;
- }
- if(!dx) dx = 256; /* avoid division by zero */
-#endif
-#ifdef GOURAUD
- dr = right[mid].r - left[mid].r;
- dg = right[mid].g - left[mid].g;
- db = right[mid].b - left[mid].b;
- rslope = (dr << 8) / dx;
- gslope = (dg << 8) / dx;
- bslope = (db << 8) / dx;
-#ifdef BLEND
- da = right[mid].a - left[mid].a;
- aslope = (da << 8) / dx;
-#endif /* BLEND */
-#endif
-#ifdef TEXMAP
- du = right[mid].u - left[mid].u;
- dv = right[mid].v - left[mid].v;
- uslope = (du << 8) / dx;
- vslope = (dv << 8) / dx;
-#endif
-#endif /* !defined(HIGH_QUALITY) */
-
- /* for each scanline ... */
- for(i=sltop; i<=slbot; i++) {
- g3d_pixel *pixptr;
- int32_t x;
-
- x = left[i].x;
- pixptr = pfill_fb.pixels + i * pfill_fb.width + (x >> 8);
-
-#ifdef GOURAUD
- r = left[i].r;
- g = left[i].g;
- b = left[i].b;
-#ifdef BLEND
- a = left[i].a;
-#endif /* BLEND */
-#endif
-#ifdef TEXMAP
- u = left[i].u;
- v = left[i].v;
-#endif
-
-#if defined(HIGH_QUALITY) && (defined(GOURAUD) || defined(TEXMAP))
- if(!(dx = right[i].x - left[i].x)) dx = 256;
-
-#ifdef GOURAUD
- dr = right[i].r - left[i].r;
- dg = right[i].g - left[i].g;
- db = right[i].b - left[i].b;
- rslope = (dr << 8) / dx;
- gslope = (dg << 8) / dx;
- bslope = (db << 8) / dx;
-#ifdef BLEND
- da = right[i].a - left[i].a;
- aslope = (da << 8) / dx;
-#endif /* BLEND */
-#endif /* GOURAUD */
-#ifdef TEXMAP
- du = right[i].u - left[i].u;
- dv = right[i].v - left[i].v;
- uslope = (du << 8) / dx;
- vslope = (dv << 8) / dx;
-#endif
-#endif /* HIGH_QUALITY */
-
- /* go across the scanline interpolating if necessary */
- while(x <= right[i].x) {
-#if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND)
- int cr, cg, cb;
-#endif
-#ifdef BLEND
- g3d_pixel fbcol;
- int alpha, inv_alpha;
-#endif
-#ifdef GOURAUD
- /* we upped the color precision to while interpolating the
- * edges, now drop the extra bits before packing
- */
- cr = r < 0 ? 0 : (r >> COLOR_SHIFT);
- cg = g < 0 ? 0 : (g >> COLOR_SHIFT);
- cb = b < 0 ? 0 : (b >> COLOR_SHIFT);
- r += rslope;
- g += gslope;
- b += bslope;
-#ifdef BLEND
- a += aslope;
-#else
- if(cr > 255) cr = 255;
- if(cg > 255) cg = 255;
- if(cb > 255) cb = 255;
-#endif /* BLEND */
-#endif /* GOURAUD */
-#ifdef TEXMAP
- {
- int tx = (u >> (16 - pfill_tex.xshift)) & pfill_tex.xmask;
- int ty = (v >> (16 - pfill_tex.yshift)) & pfill_tex.ymask;
- g3d_pixel texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx];
-#ifdef GOURAUD
- /* This is not correct, should be /255, but it's much faster
- * to shift by 8 (/256), and won't make a huge difference
- */
- cr = (cr * G3D_UNPACK_R(texel)) >> 8;
- cg = (cg * G3D_UNPACK_G(texel)) >> 8;
- cb = (cb * G3D_UNPACK_B(texel)) >> 8;
-#else
- cr = G3D_UNPACK_R(texel);
- cg = G3D_UNPACK_G(texel);
- cb = G3D_UNPACK_B(texel);
-#endif
- }
- u += uslope;
- v += vslope;
-#endif
-
-#ifdef BLEND
-#if !defined(GOURAUD) && !defined(TEXMAP)
- /* flat version: cr,cg,cb are uninitialized so far */
- cr = pv[0].r;
- cg = pv[0].g;
- cb = pv[0].b;
-#endif
-#ifdef GOURAUD
- alpha = a >> COLOR_SHIFT;
-#else
- alpha = pv[0].a;
-#endif
- fbcol = *pixptr;
- inv_alpha = 255 - alpha;
- cr = (cr * alpha + G3D_UNPACK_R(fbcol) * inv_alpha) >> 8;
- cg = (cg * alpha + G3D_UNPACK_G(fbcol) * inv_alpha) >> 8;
- cb = (cb * alpha + G3D_UNPACK_B(fbcol) * inv_alpha) >> 8;
- if(cr > 255) cr = 255;
- if(cg > 255) cg = 255;
- if(cb > 255) cb = 255;
-#endif /* BLEND */
-
-#if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND)
- color = G3D_PACK_RGB(cr, cg, cb);
-#endif
-
-#ifdef DEBUG_OVERDRAW
- *pixptr++ += DEBUG_OVERDRAW;
-#else
- *pixptr++ = color;
-#endif
- x += 256;
- }
- }
-}
-
static struct screen *cur, *prev, *next;
static long trans_start, trans_dur;
+const char *dbg_curscr_name;
+int dbg_curscr_name_len, dbg_curscr_name_pos;
+
int scr_init(void)
{
int i, idx = 0;
void (*keypress)(int key);
};
-const char *dbg_curscr_name;
-int dbg_curscr_name_len, dbg_curscr_name_pos;
+extern const char *dbg_curscr_name;
+extern int dbg_curscr_name_len, dbg_curscr_name_pos;
int scr_init(void);
void scr_shutdown(void);