backport cont.
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 9 Jun 2020 23:21:15 +0000 (02:21 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 9 Jun 2020 23:21:15 +0000 (02:21 +0300)
31 files changed:
Makefile
Makefile.dj [new file with mode: 0644]
Makefile.wat [deleted file]
libs/anim/Makefile
libs/anim/Makefile.dj [new file with mode: 0644]
libs/anim/Makefile.wat [deleted file]
libs/imago/Makefile
libs/imago/Makefile.dj [new file with mode: 0644]
libs/imago/Makefile.wat [deleted file]
src/3dgfx.c [deleted file]
src/3dgfx.h [deleted file]
src/3dgfx/3dgfx.c [new file with mode: 0644]
src/3dgfx/3dgfx.h [new file with mode: 0644]
src/3dgfx/mesh.c [new file with mode: 0644]
src/3dgfx/mesh.h [new file with mode: 0644]
src/3dgfx/meshload.c [new file with mode: 0644]
src/3dgfx/polyclip.c [new file with mode: 0644]
src/3dgfx/polyclip.h [new file with mode: 0644]
src/3dgfx/polyfill.c [new file with mode: 0644]
src/3dgfx/polyfill.h [new file with mode: 0644]
src/3dgfx/polytmpl.h [new file with mode: 0644]
src/mesh.c [deleted file]
src/mesh.h [deleted file]
src/meshload.c [deleted file]
src/polyclip.c [deleted file]
src/polyclip.h [deleted file]
src/polyfill.c [deleted file]
src/polyfill.h [deleted file]
src/polytmpl.h [deleted file]
src/screen.c
src/screen.h

index e249553..8a2db49 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,97 +1,97 @@
-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
diff --git a/Makefile.dj b/Makefile.dj
new file mode 100644 (file)
index 0000000..e249553
--- /dev/null
@@ -0,0 +1,97 @@
+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)
diff --git a/Makefile.wat b/Makefile.wat
deleted file mode 100644 (file)
index 8268d57..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-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)
index d0e6d59..657e083 100644 (file)
@@ -1,30 +1,27 @@
-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)
diff --git a/libs/anim/Makefile.dj b/libs/anim/Makefile.dj
new file mode 100644 (file)
index 0000000..d0e6d59
--- /dev/null
@@ -0,0 +1,30 @@
+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
diff --git a/libs/anim/Makefile.wat b/libs/anim/Makefile.wat
deleted file mode 100644 (file)
index 657e083..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-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)
index b8b014f..7959d19 100644 (file)
@@ -1,36 +1,50 @@
-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)
diff --git a/libs/imago/Makefile.dj b/libs/imago/Makefile.dj
new file mode 100644 (file)
index 0000000..b8b014f
--- /dev/null
@@ -0,0 +1,36 @@
+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
diff --git a/libs/imago/Makefile.wat b/libs/imago/Makefile.wat
deleted file mode 100644 (file)
index 7959d19..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-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)
diff --git a/src/3dgfx.c b/src/3dgfx.c
deleted file mode 100644 (file)
index b1dea9f..0000000
+++ /dev/null
@@ -1,748 +0,0 @@
-#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;
-}
diff --git a/src/3dgfx.h b/src/3dgfx.h
deleted file mode 100644 (file)
index f6250d5..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-#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_ */
diff --git a/src/3dgfx/3dgfx.c b/src/3dgfx/3dgfx.c
new file mode 100644 (file)
index 0000000..e199a64
--- /dev/null
@@ -0,0 +1,782 @@
+#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 */
diff --git a/src/3dgfx/3dgfx.h b/src/3dgfx/3dgfx.h
new file mode 100644 (file)
index 0000000..e317fab
--- /dev/null
@@ -0,0 +1,145 @@
+#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_ */
diff --git a/src/3dgfx/mesh.c b/src/3dgfx/mesh.c
new file mode 100644 (file)
index 0000000..b8bb9c1
--- /dev/null
@@ -0,0 +1,548 @@
+#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;
+}
+
diff --git a/src/3dgfx/mesh.h b/src/3dgfx/mesh.h
new file mode 100644 (file)
index 0000000..5357cb0
--- /dev/null
@@ -0,0 +1,37 @@
+#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_ */
diff --git a/src/3dgfx/meshload.c b/src/3dgfx/meshload.c
new file mode 100644 (file)
index 0000000..d6e42a4
--- /dev/null
@@ -0,0 +1,355 @@
+#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);
+}
diff --git a/src/3dgfx/polyclip.c b/src/3dgfx/polyclip.c
new file mode 100644 (file)
index 0000000..35e6cd6
--- /dev/null
@@ -0,0 +1,331 @@
+#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;
+}
diff --git a/src/3dgfx/polyclip.h b/src/3dgfx/polyclip.h
new file mode 100644 (file)
index 0000000..adee29d
--- /dev/null
@@ -0,0 +1,38 @@
+#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_ */
diff --git a/src/3dgfx/polyfill.c b/src/3dgfx/polyfill.c
new file mode 100644 (file)
index 0000000..972c218
--- /dev/null
@@ -0,0 +1,286 @@
+#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
diff --git a/src/3dgfx/polyfill.h b/src/3dgfx/polyfill.h
new file mode 100644 (file)
index 0000000..19092f0
--- /dev/null
@@ -0,0 +1,79 @@
+#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_ */
diff --git a/src/3dgfx/polytmpl.h b/src/3dgfx/polytmpl.h
new file mode 100644 (file)
index 0000000..2072e2b
--- /dev/null
@@ -0,0 +1,363 @@
+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;
+               }
+       }
+}
+
diff --git a/src/mesh.c b/src/mesh.c
deleted file mode 100644 (file)
index 0e8d869..0000000
+++ /dev/null
@@ -1,524 +0,0 @@
-#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;
-}
-
diff --git a/src/mesh.h b/src/mesh.h
deleted file mode 100644 (file)
index 410863a..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#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_ */
diff --git a/src/meshload.c b/src/meshload.c
deleted file mode 100644 (file)
index 5abd96e..0000000
+++ /dev/null
@@ -1,350 +0,0 @@
-#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);
-}
diff --git a/src/polyclip.c b/src/polyclip.c
deleted file mode 100644 (file)
index 35e6cd6..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-#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;
-}
diff --git a/src/polyclip.h b/src/polyclip.h
deleted file mode 100644 (file)
index adee29d..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#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_ */
diff --git a/src/polyfill.c b/src/polyfill.c
deleted file mode 100644 (file)
index 3f94e25..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-#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
diff --git a/src/polyfill.h b/src/polyfill.h
deleted file mode 100644 (file)
index 86c7947..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-#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_ */
diff --git a/src/polytmpl.h b/src/polytmpl.h
deleted file mode 100644 (file)
index 0f50b7d..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-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;
-               }
-       }
-}
-
index ea9bb94..5167d96 100644 (file)
@@ -37,6 +37,9 @@ static int num_screens;
 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;
index 85a1f86..325f434 100644 (file)
@@ -15,8 +15,8 @@ struct screen {
        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);