From: John Tsiombikas Date: Mon, 16 May 2022 05:02:27 +0000 (+0300) Subject: removed clang-format and clang_complete files from the repo X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=commitdiff_plain;h=HEAD;hp=6c97c0ce46b475901a38393602887912a44a473b removed clang-format and clang_complete files from the repo --- diff --git a/.clang_complete b/.clang_complete deleted file mode 100644 index e2c26a4..0000000 --- a/.clang_complete +++ /dev/null @@ -1,4 +0,0 @@ --x c --Isrc --Isrc/dos --Isrc/dos/stl diff --git a/.gitignore b/.gitignore index e86dd42..ac97839 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ Release *sdf demo *.zip +*.ZIP data *.a *.dll diff --git a/GNUmakefile b/GNUmakefile index 8b0f6fb..767026f 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -8,15 +8,15 @@ bin = demo asmsrc += cspr/dbgfont.asm cspr/confont.asm bindata = data/loading.img -inc = -I/usr/local/include -Isrc -Isrc/3dgfx -Isrc/scr -Isrc/glut -Ilibs \ +inc = -I/usr/local/include -Isrc -Isrc/3dgfx -Isrc/scr -Isrc/utils -Isrc/glut -Ilibs \ -Ilibs/imago/src -Ilibs/mikmod/include def = -DMINIGLUT_USE_LIBC -DMIKMOD_STATIC -warn = -pedantic -Wall -Wno-unused-variable -Wno-unused-function +warn = -pedantic -Wall -Wno-unused-variable -Wno-unused-function -Wno-address #opt = -O3 -ffast-math dbg = -g -CFLAGS = $(arch) $(warn) -MMD $(opt) -fno-strict-aliasing $(dbg) $(inc) -LDFLAGS = $(arch) -Llibs/imago -Llibs/mikmod -limago -lmikmod \ +CFLAGS = $(arch) $(warn) -MMD $(opt) -fno-pie -fno-strict-aliasing $(dbg) $(inc) +LDFLAGS = $(arch) -no-pie -Llibs/imago -Llibs/mikmod -limago -lmikmod \ $(sndlib_$(sys)) -lm cpu ?= $(shell uname -m | sed 's/i.86/i386/') @@ -27,7 +27,7 @@ endif sys ?= $(shell uname -s | sed 's/MINGW.*/mingw/; s/IRIX.*/IRIX/') ifeq ($(sys), mingw) - obj = $(src:.c=.w32.o) + obj = $(src:.c=.w32.o) $(asmsrc:.asm=.w32.o) bin = demo_win32.exe @@ -52,6 +52,9 @@ $(bin): $(obj) imago mikmod %.o: %.asm nasm -f elf -o $@ $< +%.w32.o: %.asm + nasm -f coff -o $@ $< + %.w32.o: %.c $(CC) -o $@ $(CFLAGS) -c $< diff --git a/Makefile b/Makefile index 562b0d6..1f6ab07 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,21 @@ !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 src/dos/mouse.obj + src/dos/vbe.obj src/dos/vga.obj src/dos/watdpmi.obj src/dos/mouse.obj & + src/dos/pci.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 src/data.obj + src/image.obj src/ts_text.obj src/util.obj src/util_s.obj src/cpuid.obj & + src/cpuid_s.obj src/darray.obj src/data.obj src/rlebmap.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 + src/scr/tunnel.obj src/scr/cybersun.obj src/scr/raytrace.obj & + src/scr/rt.obj src/scr/minifx.obj csprobj = cspr/dbgfont.obj cspr/confont.obj incpath = -Isrc -Isrc/dos -Isrc/3dgfx -Ilibs -Ilibs/imago/src -Ilibs/anim/src & @@ -22,18 +25,21 @@ libpath = libpath libs/imago libpath libs/anim libpath libs/midas 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 src\dos\mouse.obj + src\dos\vbe.obj src\dos\vga.obj src\dos\watdpmi.obj src\dos\mouse.obj & + src\dos\pci.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 src\data.obj + src\image.obj src\ts_text.obj src\util.obj src\util_s.obj src\cpuid.obj & + src\cpuid_s.obj src\darray.obj src\data.obj src\rlebmap.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 + src\scr\tunnel.obj src\scr\cybersun.obj src\scr\raytrace.obj & + src\scr\rt.obj src\scr\minifx.obj csprobj = cspr\dbgfont.obj cspr\confont.obj incpath = -Isrc -Isrc\dos -Isrc\3dgfx -Ilibs -Ilibs\imago\src -Ilibs\anim\src & diff --git a/Makefile.dj b/Makefile.dj index e249553..59d4042 100644 --- a/Makefile.dj +++ b/Makefile.dj @@ -1,7 +1,8 @@ -src = $(wildcard src/*.c) $(wildcard src/scr/*.c) $(wildcard src/dos/*.c) +src = $(wildcard src/*.c) $(wildcard src/3dgfx/*.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) +dep = $(src:.c=.d) bin = demo.exe asmsrc += cspr/dbgfont.asm cspr/confont.asm @@ -14,22 +15,24 @@ else TOOLPREFIX = i586-pc-msdosdjgpp- endif -inc = -Isrc -Isrc/scr -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/anim/src +inc = -Isrc -Isrc/3dgfx -Isrc/scr -Isrc/dos -Ilibs \ + -Ilibs/imago/src -Ilibs/anim/src -Ilibs/midas opt = -O3 -ffast-math -fno-strict-aliasing warn = -pedantic -Wall -Wno-unused-function -Wno-unused-variable ifdef RELEASE dbg = -g - def = -DNDEBUG -DNO_MUSIC + def = -DNDEBUG -DNO_SOUND else - def = -DNO_MUSIC + def = -DNO_SOUND endif #prof = -pg CC = $(TOOLPREFIX)gcc AR = $(TOOLPREFIX)ar -CFLAGS = $(warn) -march=pentium $(dbg) $(opt) $(prof) $(inc) $(def) +CFLAGS = -march=pentium $(warn) -MMD $(dbg) $(opt) $(prof) $(inc) $(def) LDFLAGS = libs/imago/imago.dja libs/anim/anim.dja +#libs/midas/libmidas.a ifneq ($(hostsys), dos) .PHONY: all @@ -44,29 +47,23 @@ $(bin): $(obj) imago anim 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 + $(MAKE) -C libs/imago -f Makefile.dj .PHONY: anim anim: - $(MAKE) -C libs/anim -f Makefile + $(MAKE) -C libs/anim -f Makefile.dj .PHONY: cleanlibs cleanlibs: - $(MAKE) -C libs/imago -f Makefile clean - $(MAKE) -C libs/anim -f Makefile clean + $(MAKE) -C libs/imago clean -f Makefile.dj + $(MAKE) -C libs/anim clean -f Makefile.dj .PHONY: clean .PHONY: cleandep @@ -74,12 +71,14 @@ cleanlibs: ifeq ($(hostsys), dos) clean: del src\*.odj + del src\3dgfx\*.odj del src\dos\*.odj del $(bin) cleandep: - del src\*.dep - del src\dos\*.dep + del src\*.d + del src\3dgfx\*.d + del src\dos\*.d else clean: rm -f $(obj) $(bin) diff --git a/README.md b/README.md index b3a41a1..6d34b63 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,49 @@ -Unnamed Mindlapse DOS demo for Pentium 133 ------------------------------------------- -The demo requires VESA Bios Extensions (VBE) 2.0. If your graphics card doesn't -support VBE 2.0 or greater, then make sure to load the `univbe` TSR first. +Unnamed Mindlapse DOS demo for Pentium-era PCs +---------------------------------------------- +The demo uses VBE 320x240 16bpp. Some VBE implementations do not expose +double-scan video modes (240 lines), but can be made to work with a third-party +VBE TSR like `univbe` or `s3vbe`. Linear framebuffer (VBE 2.0) support is +recommended, but not necessary. The demo will fallback to VBE 1.2 banked modes +if LFB modes are not available. Source structure ---------------- - src/ cross-platform demo framework and miscellaneous utility code - src/scr/ demo screens (parts) and effects support code - src/dos/ DOS platform code + - src/glut/ GLUT platform code (windows/UNIX version) - src/sdl/ SDL 1.x platform code (windows/UNIX version) - libs/cgmath/ math library, header-file only - libs/imago/ image loading library (includes libpng, zlib, libjpeg) - libs/anim/ keyframe animation library +Coding style conventions +------------------------ +Very few style issues are mandated: + + - All filenames should be lowercase unless convention says otherwise + (`Makefile`, `README`, etc). + - All filenames under `src/` and of any tools necessary to build from MS-DOS + will have to use maximum 8.3 characters. + - Source code should be C89-compliant. Any compiler-specific features beyond + that will have to be ifdefed. + - Use tabs for indentation, where each tab is equivalent to 4 spaces. + +Everything else is left to the discretion of each individual, but also if +you're editing an existing file, try to match the style of the surrounding code. + +Some general style suggestions, which will not be enforced: + + - Don't use overly long names, abbreviate wherever it makes sense. + - Don't cast the return value of malloc. `void*` are converted implicitly, and + the cast hides forgetting to include `stdlib.h`. + - Preferably use lowercase with underscores for everything. + - Preferably use the K&R brace style if possible. + +This section will be expanded as necessary. + Building on DOS with Watcom --------------------------- -NOTE: Don't. Watcom produces significantly worse code than GCC, and at the -moment watcom-compiled version of the demo crashes on 3D scenes for some reason -which I need to investigate at some point. Suspect either inline assembly with -missing "modify" part, or more likely some FPU optimization which fucks up the -clipper. - Make sure you have Watcom or OpenWatcom installed, and the appropriate env-vars set (the watcom installer automatically adds them to autoexec.bat by default). @@ -147,3 +170,71 @@ defined in `cdpmi.h`: #define virt_to_phys(v) ((v) + __djgpp_base_address) #define phys_to_virt(p) ((p) - __djgpp_base_address) + +Notes about moving code to/from a DOS computer +---------------------------------------------- +The easiest way to move code back and forth to a DOS computer, is to connect it +to the local network. For this you need a DOS packet driver for your NIC, which +thankfully most NIC vendors seem to provide, and a number of useful network +utilities which come with their own TCP/IP stack (mTCP and WATTCP). The +following are recommended: + + - mTCP: http://www.brutman.com/mTCP + - WATTCP: http://www.watt-32.net + - ssh2dos: http://sshdos.sourceforge.net + - rsync: http://www.2net.co.uk/rsync.html + +Here's an example batch file I'm using to set up the network: + + @echo off + c:\net\rtspkt\rtspkt 0x61 + set MTCPCFG=c:\net\mtcp\mtcp.cfg + set WATT_ROOT=c:\net\watt + set WATTCP.CFG=c:\net\watt\bin + set ETC=c:\net\watt\bin + set PATH=%PATH%;c:\net\mtcp;c:\net\watt\bin + +The rtspkt program is the packet driver for my realtek NIC, and I'm instructing +it to use interrupt 61h. The rest are environment variables needed by mTCP and +WATTCP. If you run out of environment space you might need to increase it with +`SHELL=C:\DOS\COMMAND.COM /e:1024 /p` in `config.sys`, or just put all binaries +in a single place instead of adding multiple directories to the `PATH`. + +### mTCP configuration +The `mtcp.cfg` file configures the mTCP TCP/IP stack. Go through the file, which +comes with mTCP, and make any necessary changes. For instance I've set +`packetint 0x61` to match the packet driver interrupt, and I'm using static IP +assignments, so I've set it up like this: + + ipaddr 192.168.0.21 + netmask 255.255.0.0 + gateway 192.168.1.1 + nameserver 1.1.1.1 + +### WATTCP configuration +The `wattcp.cfg` file is in the wattcp bin directory, and includes similar +configuration options: + + my_ip = 192.168.0.21 + hostname = "retrop1" + netmask = 255.255.0.0 + nameserver = 1.1.1.1 + gateway = 192.168.1.1 + domain.suffix = localdomain + pkt.vector = 0x61 + hosts = $(ETC)\hosts + +### Server-side configuration +The `pull.bat` file in the demo repo uses rsync to get the source code from the +git repo on my main GNU/Linux computer. To avoid having to type passwords all +the time, I've configures rsyncd to allow access to the demo directory in the +`/etc/rsyncd.conf` file: + + [dosdemo] + path = /home/nuclear/code/demoscene/dosdemo + comment = DOS demo project + +Since the DOS rsync utility is unfortunately read-only, the `push.bat` relies on +ssh2dos instead, which does require a password. The sshd on the server might +need to be configured to allow older encryption algorithms, depending on your +current setup. diff --git a/libs/imago/src/conv.c b/libs/imago/src/conv.c index 756469c..94fb87f 100644 --- a/libs/imago/src/conv.c +++ b/libs/imago/src/conv.c @@ -17,7 +17,7 @@ along with this program. If not, see . */ #include #include "imago2.h" -#include "types.h" +#include "inttypes.h" /* pixel-format conversions are sub-optimal at the moment to avoid * writing a lot of code. optimize at some point ? diff --git a/libs/imago/src/filetga.c b/libs/imago/src/filetga.c index 2192ff4..97504ca 100644 --- a/libs/imago/src/filetga.c +++ b/libs/imago/src/filetga.c @@ -20,7 +20,7 @@ along with this program. If not, see . #include #include -#include "types.h" +#include "inttypes.h" #include "imago2.h" #include "ftmodule.h" diff --git a/libs/imago/src/inttypes.h b/libs/imago/src/inttypes.h new file mode 100644 index 0000000..cbcc4d0 --- /dev/null +++ b/libs/imago/src/inttypes.h @@ -0,0 +1,57 @@ +/* +colcycle - color cycling image viewer +Copyright (C) 2016 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef INT_TYPES_H_ +#define INT_TYPES_H_ + +#if defined(__DOS__) || defined(__MSDOS__) +typedef char int8_t; +typedef short int16_t; +typedef long int32_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned long uint32_t; + +typedef unsigned long intptr_t; +#else + +#ifdef _MSC_VER +typedef __int8 int8_t; +typedef __int16 int16_t; +typedef __int32 int32_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; + +#ifdef _WIN64 +typedef __int64 intptr_t; +#else +typedef __int32 intptr_t; +#endif +#else /* not msvc */ + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199900 +#include +#else +#include +#endif + +#endif /* end !msvc */ +#endif /* end !dos */ + +#endif /* INT_TYPES_H_ */ diff --git a/libs/imago/src/types.h b/libs/imago/src/types.h deleted file mode 100644 index d06e5c0..0000000 --- a/libs/imago/src/types.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -colcycle - color cycling image viewer -Copyright (C) 2016 John Tsiombikas - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ -#ifndef INT_TYPES_H_ -#define INT_TYPES_H_ - -#if defined(__DOS__) || defined(__MSDOS__) -typedef char int8_t; -typedef short int16_t; -typedef long int32_t; - -typedef unsigned char uint8_t; -typedef unsigned short uint16_t; -typedef unsigned long uint32_t; - -typedef unsigned long intptr_t; -#else - -#ifdef _MSC_VER -typedef __int8 int8_t; -typedef __int16 int16_t; -typedef __int32 int32_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; - -#ifdef _WIN64 -typedef __int64 intptr_t; -#else -typedef __int32 intptr_t; -#endif -#else /* not msvc */ - -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199900 -#include -#else -#include -#endif - -#endif /* end !msvc */ -#endif /* end !dos */ - -#endif /* INT_TYPES_H_ */ diff --git a/libs/mikmod/GNUmakefile b/libs/mikmod/GNUmakefile index 9f472ff..7fcc00e 100644 --- a/libs/mikmod/GNUmakefile +++ b/libs/mikmod/GNUmakefile @@ -10,7 +10,7 @@ alib = libmikmod.a def = -DHAVE_CONFIG_H -DMIKMOD_BUILD inc = -I. -Iinclude warn = -pedantic -Wall -Wno-unused-variable -Wno-unused-function -CFLAGS = -m32 $(warn) -g $(def) $(inc) `pkg-config --cflags sdl` +CFLAGS = -m32 $(warn) -g $(def) $(inc) $(alib): $(obj) $(AR) rcs $@ $(obj) diff --git a/pull.bat b/pull.bat index 96498c0..a099a39 100644 --- a/pull.bat +++ b/pull.bat @@ -1,4 +1,30 @@ -ssh2dos -g -i c:\prog\ssh2dos\doskey -S -B nuclear 192.168.0.4 cd code/demoscene/dosdemo && git archive -o dd.zip master -scp2dos -r -g -i c:\prog\ssh2dos\doskey nuclear@192.168.0.4:code/demoscene/dosdemo/dd.zip . -unzip32 -o dd.zip -del dd.zip +mkdir src +rsync -v 192.168.0.4::dosdemo/Makefile Makefile +rsync -v 192.168.0.4::dosdemo/src/*.c src +rsync -v 192.168.0.4::dosdemo/src/*.h src +rsync -v 192.168.0.4::dosdemo/src/*.asm src +mkdir src\dos +rsync -v 192.168.0.4::dosdemo/src/dos/*.c src/dos +rsync -v 192.168.0.4::dosdemo/src/dos/*.h src/dos +rsync -v 192.168.0.4::dosdemo/src/dos/*.asm src/dos +mkdir src\glut +rsync -v 192.168.0.4::dosdemo/src/glut/*.c src/glut +rsync -v 192.168.0.4::dosdemo/src/glut/*.h src/glut +mkdir src\sdl +rsync -v 192.168.0.4::dosdemo/src/sdl/*.c src/sdl +mkdir src\scr +rsync -v 192.168.0.4::dosdemo/src/scr/*.c src/scr +rsync -v 192.168.0.4::dosdemo/src/scr/*.h src/scr +mkdir src\3dgfx +rsync -v 192.168.0.4::dosdemo/src/3dgfx/*.c src/3dgfx +rsync -v 192.168.0.4::dosdemo/src/3dgfx/*.h src/3dgfx + +mkdir tools +mkdir tools\csprite +rsync -v 192.168.0.4::dosdemo/tools/csprite/Makefile tools/csprite/Makefile +rsync -v 192.168.0.4::dosdemo/tools/csprite/src/*.c tools/csprite/src +rsync -v 192.168.0.4::dosdemo/tools/csprite/src/*.h tools/csprite/src + +mkdir tools\img2bin +rsync -v 192.168.0.4::dosdemo/tools/img2bin/Makefile tools/img2bin/Makefile +rsync -v 192.168.0.4::dosdemo/tools/img2bin/*.c tools/img2bin diff --git a/push.bat b/push.bat new file mode 100644 index 0000000..f541c4d --- /dev/null +++ b/push.bat @@ -0,0 +1,3 @@ +del ddsrc.zip +zip -r ddsrc.zip . -i *.c -i *.h -i *.asm -i *.s -i *.S -i *.inl -i *akefile* -i *.bat -i packsrc -i unpsrc -x *.swp -x libs/* +scp2dos -g ddsrc.zip nuclear@192.168.0.4:code/demoscene/dosdemo diff --git a/src/3dgfx/3dgfx.c b/src/3dgfx/3dgfx.c index ef569e6..dcd28c6 100644 --- a/src/3dgfx/3dgfx.c +++ b/src/3dgfx/3dgfx.c @@ -503,6 +503,8 @@ void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size) g3d_draw_indexed(prim, varr, varr_size, 0, 0); } +#define NEED_NORMALS (st->opt & (G3D_LIGHTING | G3D_TEXTURE_GEN)) + void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, const uint16_t *iarr, int iarr_size) { @@ -516,8 +518,10 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, 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; + if(NEED_NORMALS) { + 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; @@ -528,14 +532,16 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, 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(NEED_NORMALS) { + 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]]; diff --git a/src/3dgfx/mesh.c b/src/3dgfx/mesh.c index b8bb9c1..c40b491 100644 --- a/src/3dgfx/mesh.c +++ b/src/3dgfx/mesh.c @@ -364,8 +364,8 @@ int gen_plane_mesh(struct g3d_mesh *m, float width, float height, int usub, int nfaces = usub * vsub; uverts = usub + 1; vverts = vsub + 1; - du = (float)width / (float)usub; - dv = (float)height / (float)vsub; + du = 1.0f / (float)usub; + dv = 1.0f / (float)vsub; nverts = uverts * vverts; nidx = nfaces * 4; diff --git a/src/3dgfx/mesh.h b/src/3dgfx/mesh.h index 5357cb0..e02cf55 100644 --- a/src/3dgfx/mesh.h +++ b/src/3dgfx/mesh.h @@ -10,6 +10,8 @@ struct g3d_mesh { int vcount, icount; }; +int init_mesh(struct g3d_mesh *mesh, int prim, int num_verts, int num_idx); + void free_mesh(struct g3d_mesh *mesh); void destroy_mesh(struct g3d_mesh *mesh); diff --git a/src/3dgfx/polytmpl.h b/src/3dgfx/polytmpl.h index 167d5e1..f601623 100644 --- a/src/3dgfx/polytmpl.h +++ b/src/3dgfx/polytmpl.h @@ -101,9 +101,6 @@ void POLYFILL(struct pvertex *pv, int nverts) #if defined(GOURAUD) || defined(TEXMAP) || defined(ZBUF) 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; @@ -118,6 +115,11 @@ void POLYFILL(struct pvertex *pv, int nverts) int32_t z, dz, zslope; #endif +#if !defined(GOURAUD) && !defined(TEXMAP) + /* flat version, just pack the color now */ + color = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b); +#endif + for(i=1; i pv[botidx].y) botidx = i; diff --git a/src/bsptree.c b/src/bsptree.c index f286ac7..d6417b9 100644 --- a/src/bsptree.c +++ b/src/bsptree.c @@ -6,8 +6,12 @@ #if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__) #include #else +#ifdef WIN32 +#include +#else #include #endif +#endif #include "bsptree.h" #include "dynarr.h" #include "inttypes.h" @@ -248,7 +252,9 @@ static int choose_poly(struct bsppoly *polyarr, int num_polys) struct cplane *plane = &polyarr[i].plane; int num_splits = 0; +#ifdef USE_OPENMP #pragma omp parallel for reduction(+:num_splits) +#endif for(j=0; j +#include +#include "cpuid.h" + +static const char *cpuname(struct cpuid_info *cpu); +static const char *cpuvendor(struct cpuid_info *cpu); + +struct cpuid_info cpuid; + +void print_cpuid(struct cpuid_info *cpu) +{ + int i, col, len; + char buf[64]; + static const char *featstr[32] = { + "fpu", "vme", "dbgext", "pse", "tsc", "msr", "pae", "mce", + "cx8", "apic", "?", "sep", "mtrr", "pge", "mca", "cmov", + "pat", "pse36", "psn", "clf", "?", "dtes", "acpi", "mmx", + "fxsr", "sse", "sse2", "ss", "htt", "tm1", "ia64", "pbe"}; + static const char *feat2str[32] = { + "sse3", "pclmul", "dtes64", "monitor", "ds-cpl", "vmx", "smx", "est", + "tm2", "ssse3", "cid", "sdbg", "fma", "cx16", "etprd", "pdcm", + "?", "pcid", "dca", "sse41", "sse42", "x2apic", "movbe", "popcnt", + "?", "aes", "xsave", "osxsave", "avx", "f16c", "rdrand", "?"}; + + printf("CPU: %s - %s\n", cpuvendor(cpu), cpuname(cpu)); + printf("features:\n "); + col = 3; + for(i=0; i<32; i++) { + if(cpu->feat & (1 << i)) { + len = strlen(featstr[i]) + 1; + if(col + len >= 80) { + fputs("\n ", stdout); + col = 3; + } + col += printf(" %s", featstr[i]); + } + } + for(i=0; i<32; i++) { + if(cpu->feat2 & (1 << i)) { + len = strlen(feat2str[i]) + 1; + if(col + len >= 80) { + fputs("\n ", stdout); + col = 3; + } + col += printf(" %s", feat2str[i]); + } + } + putchar('\n'); +} + +static const char *fam4_models[16] = { + "486 DX 25/33", "486 DX 50", "486 SX", "486 DX/2", "486 SL", "486 SX/2", + 0, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB" +}; +static const char *fam5_models[16] = { + "Pentium 60/66", "Pentium 60/66", "Pentium 75-200", "OverDrive", "Pentium MMX", + 0, 0, "Mobile Pentium 75-200", "Mobile Pentium MMX", "Quark" +}; +static const char *fam6_models[16] = { + "Pentium Pro", "Pentium Pro", 0, "Pentium 2", "Pentium 2", "Pentium 2", + "Mobile Pentium 2", "Pentium 3", "Pentium 3", 0, "Pentium 3", "Pentium 3" +}; + + +static const char *cpuname(struct cpuid_info *cpu) +{ + int model, family; + char *rd, *wr; + + if(*cpu->brandstr) { + /* unwank the string */ + rd = wr = cpu->brandstr; + while(*rd) { + if(rd[0] == '(' && rd[1] == 'T' && rd[2] == 'M' && rd[3] == ')') + rd += 4; + else if(rd[0] == '(' && rd[1] == 'R' && rd[2] == ')') + rd += 3; + if(rd != wr) *wr = *rd; + wr++; + rd++; + } + return cpu->brandstr; + } + + if(CPUID_EXTMODEL(cpu->id)) { + /* processors new enough to have an extended model, should also provide + * a brand string. If we end up here, we don't know what it is + */ + return "unknown"; + } + + model = CPUID_MODEL(cpu->id); + family = CPUID_FAMILY(cpu->id) | (CPUID_EXTFAMILY(cpu->id) << 4); + + switch(family) { + case 3: return "386"; + case 4: return fam4_models[model] ? fam4_models[model] : "486"; + case 5: return fam5_models[model] ? fam5_models[model] : "Pentium"; + case 6: return fam6_models[model] ? fam6_models[model] : "unknown"; + case 15: return "Pentium 4"; + default: + break; + } + return "unknown"; +} + +static const char *cpuvendor(struct cpuid_info *cpu) +{ + static char other[16]; + static const struct { const char *wank, *vendor; } unwanktab[] = { + {"GenuineIntel", "intel"}, + {"AuthenticAMD", "AMD"}, + {"AMDisbetter!", "AMD"}, + {"CentaurHauls", "IDT"}, + {"CyrixInstead", "Cyrix"}, + {"TransmetaCPU", "Transmeta"}, + {"GenuineTMx86", "Transmeta"}, + {"Geode by NSC", "NatSemi"}, + {"NexGenDriven", "NexGen"}, + {"RiseRiseRise", "Rise"}, + {"SiS SiS SiS ", "SiS"}, + {"UMC UMC UMC ", "UMC"}, + {"VIA VIA VIA ", "VIA"}, + {"Vortex86 SoC", "DM&P"}, + {" Shanghai ", "Zhaoxin"}, + {"HygonGenuine", "Hygon"}, + {"E2K MACHINE", "MCST Elbrus"}, + {"MiSTer A0486", "ao486"}, + {"bhyve bhyve ", "bhyve"}, + {" KVMKVMKVM ", "KVM"}, + {"TCGTCGTCGTCG", "qemu"}, + {"Microsoft Hv", "MS Hyper-V"}, + {" lrpepyh vr", "Parallels"}, + {"VMwareVMware", "VMware"}, + {"XenVMMXenVMM", "Xen"}, + {"ACRNACRNACRN", "ACRN"}, + {" QNXQVMBSQG ", "QNX Hypervisor"}, + {0, 0} + }; + + int i; + for(i=0; unwanktab[i].wank; i++) { + if(memcmp(cpu->vendor, unwanktab[i].wank, 12) == 0) { + return unwanktab[i].vendor; + } + } + + memcpy(other, cpu->vendor, 12); + other[12] = 0; + return other; +} diff --git a/src/cpuid.h b/src/cpuid.h new file mode 100644 index 0000000..5566f69 --- /dev/null +++ b/src/cpuid.h @@ -0,0 +1,96 @@ +#ifndef CPUID_H_ +#define CPUID_H_ + +#include "inttypes.h" + +struct cpuid_info { + uint32_t maxidx; /* 0: eax */ + char vendor[12]; /* 0: ebx, edx, ecx */ + uint32_t id; /* 1: eax */ + uint32_t rsvd0; /* 1: ebx */ + uint32_t feat; /* 1: edx */ + uint32_t feat2; /* 1: ecx */ + + char brandstr[48]; /* 80000002h-80000004h */ +}; + +extern struct cpuid_info cpuid; + +#define CPU_HAVE_MMX (cpuid.feat & CPUID_FEAT_MMX) +#define CPU_HAVE_MTRR (cpuid.feat & CPUID_FEAT_MTRR) + +#define CPUID_STEPPING(id) ((id) & 0xf) +#define CPUID_MODEL(id) (((id) >> 4) & 0xf) +#define CPUID_FAMILY(id) (((id) >> 8) & 0xf) +#define CPUID_EXTMODEL(id) (((id) >> 16) & 0xf) +#define CPUID_EXTFAMILY(id) (((id) >> 20) & 0xff) + +#define CPUID_FEAT_FPU 0x00000001 +#define CPUID_FEAT_VME 0x00000002 +#define CPUID_FEAT_DBGEXT 0x00000004 +#define CPUID_FEAT_PSE 0x00000008 +#define CPUID_FEAT_TSC 0x00000010 +#define CPUID_FEAT_MSR 0x00000020 +#define CPUID_FEAT_PAE 0x00000040 +#define CPUID_FEAT_MCE 0x00000080 +#define CPUID_FEAT_CX8 0x00000100 +#define CPUID_FEAT_APIC 0x00000200 + +#define CPUID_FEAT_SEP 0x00000800 +#define CPUID_FEAT_MTRR 0x00001000 +#define CPUID_FEAT_PGE 0x00002000 +#define CPUID_FEAT_MCA 0x00004000 +#define CPUID_FEAT_CMOV 0x00008000 +#define CPUID_FEAT_PAT 0x00010000 +#define CPUID_FEAT_PSE36 0x00020000 +#define CPUID_FEAT_PSN 0x00040000 +#define CPUID_FEAT_CLF 0x00080000 + +#define CPUID_FEAT_DTES 0x00200000 +#define CPUID_FEAT_ACPI 0x00400000 +#define CPUID_FEAT_MMX 0x00800000 +#define CPUID_FEAT_FXSR 0x01000000 +#define CPUID_FEAT_SSE 0x02000000 +#define CPUID_FEAT_SSE2 0x04000000 +#define CPUID_FEAT_SS 0x08000000 +#define CPUID_FEAT_HTT 0x10000000 +#define CPUID_FEAT_TM1 0x20000000 +#define CPUID_FEAT_IA64 0x40000000 +#define CPUID_FEAT_PBE 0x80000000 + +#define CPUID_FEAT2_SSE3 0x00000001 +#define CPUID_FEAT2_PCLMUL 0x00000002 +#define CPUID_FEAT2_DTES64 0x00000004 +#define CPUID_FEAT2_MONITOR 0x00000008 +#define CPUID_FEAT2_DS_CPL 0x00000010 +#define CPUID_FEAT2_VMX 0x00000020 +#define CPUID_FEAT2_SMX 0x00000040 +#define CPUID_FEAT2_EST 0x00000080 +#define CPUID_FEAT2_TM2 0x00000100 +#define CPUID_FEAT2_SSSE3 0x00000200 +#define CPUID_FEAT2_CID 0x00000400 +#define CPUID_FEAT2_SDBG 0x00000800 +#define CPUID_FEAT2_FMA 0x00001000 +#define CPUID_FEAT2_CX16 0x00002000 +#define CPUID_FEAT2_ETPRD 0x00004000 +#define CPUID_FEAT2_PDCM 0x00008000 + +#define CPUID_FEAT2_PCID 0x00020000 +#define CPUID_FEAT2_DCA 0x00040000 +#define CPUID_FEAT2_SSE41 0x00080000 +#define CPUID_FEAT2_SSE42 0x00100000 +#define CPUID_FEAT2_X2APIC 0x00200000 +#define CPUID_FEAT2_MOVBE 0x00400000 +#define CPUID_FEAT2_POPCNT 0x00800000 + +#define CPUID_FEAT2_AES 0x02000000 +#define CPUID_FEAT2_XSAVE 0x04000000 +#define CPUID_FEAT2_OSXSAVE 0x08000000 +#define CPUID_FEAT2_AVX 0x10000000 +#define CPUID_FEAT2_F16C 0x20000000 +#define CPUID_FEAT2_RDRAND 0x40000000 + +int read_cpuid(struct cpuid_info *info); +void print_cpuid(struct cpuid_info *info); + +#endif /* CPUID_H_ */ diff --git a/src/cpuid_s.asm b/src/cpuid_s.asm new file mode 100644 index 0000000..b936168 --- /dev/null +++ b/src/cpuid_s.asm @@ -0,0 +1,132 @@ + section .text + bits 32 +; foo_ are watcom functions, _foo are djgpp functions + +F_ID equ 0x200000 + + global read_cpuid + global _read_cpuid + global read_cpuid_ +read_cpuid_: + push eax + call check_cpuid + pop eax + jnc read_cpuid_nocheck + mov eax, -1 + ret + +_read_cpuid: +read_cpuid: + call check_cpuid + mov eax, [esp + 4] + jnc read_cpuid_nocheck + mov eax, -1 + ret + + ; determine if cpuid is available. avail: cf=0, not avail: cf=1 +check_cpuid: + pushf + pop eax + mov edx, eax ; keep a copy of the original eflags in edx + xor eax, F_ID + push eax + popf + pushf + pop eax + clc + cmp eax, edx + jnz .noerr + stc +.noerr: ret + + ; enter with the cpuid_info structure pointer in eax +read_cpuid_nocheck: + push ebp + mov ebp, esp + push ebx + push edi + push esi + push eax ; save the original struct pointer + sub esp, 8 + mov edi, eax ; struct pointer -> edi + + ; clear struct + cld + push edi + mov ecx, (32+48)/4 + xor eax, eax + rep stosd + pop edi + + xor eax, eax + mov [esp], eax ; current index + cpuid + + mov [edi], eax ; maxidx + ; clamp to the size of our cpuid_info structure + cmp eax, 1 + jbe .skipclamp + mov eax, 1 +.skipclamp: + mov [esp + 4], eax ; maximum index + + mov [edi + 4], ebx ; vendor name + mov [edi + 8], edx + mov [edi + 12], ecx + add edi, 16 + +.loop: mov eax, [esp] + inc eax + cmp eax, [esp + 4] + ja .loopend + mov [esp], eax + cpuid + mov [edi], eax + mov [edi + 4], ebx + mov [edi + 8], edx + mov [edi + 12], ecx + add edi, 16 + jmp .loop +.loopend: + ; try to retrieve the brand string (avail on P4 or newer) + mov eax, 80000000h + cpuid + test eax, 80000000h + jz .done ; no extended cpuid functions + cmp eax, 80000004h + jb .done ; no brand string available + + ; brand string available + mov esi, esp ; save esp to esi + mov esp, [esp + 8] ; esp <- original struct pointer + add esp, 32+48 ; offset to end of brandstr + mov eax, 80000004h + cpuid + push edx + push ecx + push ebx + push eax + mov eax, 80000003h + cpuid + push edx + push ecx + push ebx + push eax + mov eax, 80000002h + cpuid + push edx + push ecx + push ebx + push eax + mov esp, esi ; done restore esp + +.done: add esp, 8 + pop eax + pop esi + pop edi + pop ebx + pop ebp + xor eax, eax + ret + +; vi:ft=nasm: diff --git a/src/darray.c b/src/darray.c new file mode 100644 index 0000000..66c0715 --- /dev/null +++ b/src/darray.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include "darray.h" +#include "util.h" + + +/* The array descriptor keeps auxilliary information needed to manipulate + * the dynamic array. It's allocated adjacent to the array buffer. + */ +struct arrdesc { + int nelem, szelem; + int max_elem; + int bufsz; /* not including the descriptor */ +}; + +#define DESC(x) ((struct arrdesc*)((char*)(x) - sizeof(struct arrdesc))) + +void *darr_alloc(int elem, int szelem) +{ + struct arrdesc *desc; + + desc = malloc_nf(elem * szelem + sizeof *desc); + desc->nelem = desc->max_elem = elem; + desc->szelem = szelem; + desc->bufsz = elem * szelem; + return (char*)desc + sizeof *desc; +} + +void darr_free(void *da) +{ + if(da) { + free(DESC(da)); + } +} + +void *darr_resize_impl(void *da, int elem) +{ + int newsz; + struct arrdesc *desc; + + if(!da) return 0; + desc = DESC(da); + + newsz = desc->szelem * elem; + desc = realloc_nf(desc, newsz + sizeof *desc); + + desc->nelem = desc->max_elem = elem; + desc->bufsz = newsz; + return (char*)desc + sizeof *desc; +} + +int darr_empty(void *da) +{ + return DESC(da)->nelem ? 0 : 1; +} + +int darr_size(void *da) +{ + return DESC(da)->nelem; +} + + +void *darr_clear_impl(void *da) +{ + return darr_resize_impl(da, 0); +} + +/* stack semantics */ +void *darr_push_impl(void *da, void *item) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(nelem >= desc->max_elem) { + /* need to resize */ + int newsz = desc->max_elem ? desc->max_elem * 2 : 1; + + da = darr_resize_impl(da, newsz); + desc = DESC(da); + desc->nelem = nelem; + } + + if(item) { + memcpy((char*)da + desc->nelem * desc->szelem, item, desc->szelem); + } + desc->nelem++; + return da; +} + +void *darr_pop_impl(void *da) +{ + struct arrdesc *desc; + int nelem; + + desc = DESC(da); + nelem = desc->nelem; + + if(!nelem) return da; + + if(nelem <= desc->max_elem / 3) { + /* reclaim space */ + int newsz = desc->max_elem / 2; + + da = darr_resize_impl(da, newsz); + desc = DESC(da); + desc->nelem = nelem; + } + desc->nelem--; + + return da; +} + +void *darr_finalize(void *da) +{ + struct arrdesc *desc = DESC(da); + memmove(desc, da, desc->bufsz); + return desc; +} diff --git a/src/darray.h b/src/darray.h new file mode 100644 index 0000000..b9a7051 --- /dev/null +++ b/src/darray.h @@ -0,0 +1,48 @@ +#ifndef DYNAMIC_ARRAY_H_ +#define DYNAMIC_ARRAY_H_ + +void *darr_alloc(int elem, int szelem); +void darr_free(void *da); +void *darr_resize_impl(void *da, int elem); +#define darr_resize(da, elem) do { (da) = darr_resize_impl(da, elem); } while(0) + +int darr_empty(void *da); +int darr_size(void *da); + +void *darr_clear_impl(void *da); +#define darr_clear(da) do { (da) = darr_clear_impl(da); } while(0) + +/* stack semantics */ +void *darr_push_impl(void *da, void *item); +#define darr_push(da, item) do { (da) = darr_push_impl(da, item); } while(0) +void *darr_pop_impl(void *da); +#define darr_pop(da) do { (da) = darr_pop_impl(da); } while(0) + +/* Finalize the array. No more resizing is possible after this call. + * Use free() instead of dynarr_free() to deallocate a finalized array. + * Returns pointer to the finalized array. + * Complexity: O(n) + */ +void *darr_finalize(void *da); + +/* utility macros to push characters to a string. assumes and maintains + * the invariant that the last element is always a zero + */ +#define darr_strpush(da, c) \ + do { \ + char cnull = 0, ch = (char)(c); \ + (da) = dynarr_pop_impl(da); \ + (da) = dynarr_push_impl((da), &ch); \ + (da) = dynarr_push_impl((da), &cnull); \ + } while(0) + +#define darr_strpop(da) \ + do { \ + char cnull = 0; \ + (da) = dynarr_pop_impl(da); \ + (da) = dynarr_pop_impl(da); \ + (da) = dynarr_push_impl((da), &cnull); \ + } while(0) + + +#endif /* DYNAMIC_ARRAY_H_ */ diff --git a/src/demo.c b/src/demo.c index f9d4900..2479c42 100644 --- a/src/demo.c +++ b/src/demo.c @@ -17,7 +17,7 @@ #define MOUSE_TIMEOUT 1200 #define GUARD_XPAD 0 -#define GUARD_YPAD 32 +#define GUARD_YPAD 64 int fb_width, fb_height, fb_bpp, fb_scan_size; float fb_aspect; @@ -42,10 +42,21 @@ static int con_active; extern uint16_t loading_pixels[]; /* data.asm */ - int demo_init(int argc, char **argv) { - struct screen *scr; + if(demo_init1(argc, argv) == -1) { + return -1; + } + if(demo_init2() == -1) { + return -1; + } + return 0; +} + +static struct screen *scr; + +int demo_init1(int argc, char **argv) +{ char *env; if(load_config("demo.cfg") == -1) { @@ -57,13 +68,11 @@ int demo_init(int argc, char **argv) if(parse_args(argc, argv) == -1) { return -1; } + return 0; +} - /* reuse the loading image as our back buffer. - * adjust fb_pixels to leave 4 pixels guard band top/bottom. We have enough - * space since the loading image is 8 pixels taller. - */ - fb_pixels = loading_pixels + 320 * 4; - +int demo_init2(void) +{ con_init(); initFpsFonts(); @@ -81,6 +90,7 @@ int demo_init(int argc, char **argv) if(scr_init() == -1) { return -1; } + if(opt.start_scr) { scr = scr_lookup(opt.start_scr); } else { diff --git a/src/demo.h b/src/demo.h index de0654b..af4870f 100644 --- a/src/demo.h +++ b/src/demo.h @@ -54,6 +54,8 @@ enum { extern float sball_matrix[16]; int demo_init(int argc, char **argv); +int demo_init1(int argc, char **argv); +int demo_init2(void); void demo_cleanup(void); int demo_resizefb(int width, int height, int bpp); @@ -66,6 +68,7 @@ void demo_keyboard(int key, int press); /* defined in main_*.c */ void demo_quit(void); +void demo_abort(void); unsigned long get_msec(void); void set_palette(int idx, int r, int g, int b); diff --git a/src/dos/audos.c b/src/dos/audos.c index 74376c6..2e6f376 100644 --- a/src/dos/audos.c +++ b/src/dos/audos.c @@ -1,5 +1,6 @@ -#ifndef NO_SOUND #include + +#ifndef NO_SOUND #include #include #include diff --git a/src/dos/cdpmi.h b/src/dos/cdpmi.h index 71138b6..e8a6950 100644 --- a/src/dos/cdpmi.h +++ b/src/dos/cdpmi.h @@ -29,6 +29,17 @@ struct dpmi_regs { } PACKED; #pragma pack (pop) +enum { + FLAGS_CF = 0x000001, + FLAGS_PF = 0x000004, + FLAGS_ZF = 0x000040, + FLAGS_SF = 0x000080, + FLAGS_IF = 0x000020, + FLAGS_DF = 0x000040, + FLAGS_VM = 0x020000, + FLAGS_ID = 0x200000, +}; + uint16_t dpmi_alloc(unsigned int par, uint16_t *sel); void dpmi_free(uint16_t sel); void dpmi_int(int inum, struct dpmi_regs *regs); diff --git a/src/dos/dosutil.h b/src/dos/dosutil.h new file mode 100644 index 0000000..4e4c8c3 --- /dev/null +++ b/src/dos/dosutil.h @@ -0,0 +1,19 @@ +#ifndef DOSUTIL_H_ +#define DOSUTIL_H_ + +#include +#include + +#ifdef __DJGPP__ +#include + +#define outp(p, v) outportb(p, v) +#define outpw(p, v) outportw(p, v) +#define outpd(p, v) outportl(p, v) + +#define inp(p) inportb(p) +#define inpw(p) inportw(p) +#define inpd(p) inportl(p) +#endif + +#endif /* DOSUTIL_H_ */ diff --git a/src/dos/gfx.c b/src/dos/gfx.c index 48b5c20..2f67bad 100644 --- a/src/dos/gfx.c +++ b/src/dos/gfx.c @@ -1,12 +1,20 @@ #include #include #include +#include #include "demo.h" #include "cdpmi.h" #include "gfx.h" #include "vbe.h" #include "vga.h" #include "util.h" +#include "cpuid.h" + +#ifdef __DJGPP__ +#define VMEM_PTR ((void*)(0xa0000 + __djgpp_conventional_base)) +#else +#define VMEM_PTR ((void*)0xa0000) +#endif #define SAME_BPP(a, b) \ ((a) == (b) || ((a) == 16 && (b) == 15) || ((a) == 15 && (b) == 16) || \ @@ -18,6 +26,10 @@ static void blit_frame_lfb(void *pixels, int vsync); static void blit_frame_banked(void *pixels, int vsync); static uint32_t calc_mask(int sz, int pos); +static void enable_wrcomb(uint32_t addr, int len); +static const char *mtrr_type_name(int type); +static void print_mtrr(void); + static struct video_mode *vmodes; static int num_vmodes; @@ -85,17 +97,13 @@ int init_video(void) vmptr->rmask = calc_mask(minf.rsize, minf.rpos); vmptr->gmask = calc_mask(minf.gsize, minf.gpos); vmptr->bmask = calc_mask(minf.bsize, minf.bpos); - vmptr->bpp = vmptr->rbits + vmptr->gbits + vmptr->bbits; + /*vmptr->bpp = vmptr->rbits + vmptr->gbits + vmptr->bbits;*/ } if(minf.attr & VBE_ATTR_LFB) { vmptr->fb_addr = minf.fb_addr; - } else { - vmptr->bank_size = (uint32_t)minf.bank_size * 1024; - if(!vmptr->bank_size) { - vmptr->bank_size = 65536; - } } vmptr->max_pages = minf.num_img_pages; + vmptr->win_gran = minf.win_gran; printf("%04x: ", vbe.modes[i]); vbe_print_mode_info(stdout, &minf); @@ -184,7 +192,7 @@ void *set_video_mode(int idx, int nbuf) } /* unmap previous video memory mapping, if there was one (switching modes) */ - if(vpgaddr[0] && vpgaddr[0] != (void*)0xa0000) { + if(vpgaddr[0] && vpgaddr[0] != VMEM_PTR) { dpmi_munmap(vpgaddr[0]); vpgaddr[0] = vpgaddr[1] = 0; } @@ -192,12 +200,19 @@ void *set_video_mode(int idx, int nbuf) curmode = vm; if(nbuf < 1) nbuf = 1; if(nbuf > 2) nbuf = 2; - pgcount = nbuf > vm->max_pages ? vm->max_pages : nbuf; + pgcount = nbuf > vm->max_pages + 1 ? vm->max_pages + 1 : nbuf; pgsize = vm->ysz * vm->pitch; fbsize = pgcount * pgsize; + if(vm->bpp > 8) { + printf("rgb mask: %x %x %x\n", (unsigned int)vm->rmask, + (unsigned int)vm->gmask, (unsigned int)vm->bmask); + printf("rgb shift: %d %d %d\n", vm->rshift, vm->gshift, vm->bshift); + } printf("pgcount: %d, pgsize: %d, fbsize: %d\n", pgcount, pgsize, fbsize); - printf("phys addr: %p\n", (void*)vm->fb_addr); + if(vm->fb_addr) { + printf("phys addr: %p\n", (void*)vm->fb_addr); + } fflush(stdout); if(vm->fb_addr) { @@ -221,11 +236,48 @@ void *set_video_mode(int idx, int nbuf) blit_frame = blit_frame_lfb; + /* only attempt to set up write combining if the CPU we're running on + * supports memory type range registers, and we're running on ring 0 + */ + if(CPU_HAVE_MTRR) { + int cpl = get_cpl(); + if(cpl > 0) { + fprintf(stderr, "Can't set framebuffer range to write-combining, running in ring %d\n", cpl); + } else { + uint32_t len = (uint32_t)vbe.vmem_blk << 16; + + /* if vmem_blk is 0 or if the reported size is absurd (more than + * 256mb), just use the framebuffer size for this mode to setup the + * mtrr + */ + if(!len || len > 0x10000000) { + printf("reported vmem too large or overflowed, using fbsize for wrcomb setup\n"); + len = fbsize; + } + print_mtrr(); + enable_wrcomb(vm->fb_addr, len); + } + } + } else { - vpgaddr[0] = (void*)0xa0000; + vpgaddr[0] = VMEM_PTR; vpgaddr[1] = 0; blit_frame = blit_frame_banked; + + /* calculate window granularity shift */ + vm->win_gran_shift = 0; + vm->win_64k_step = 1; + if(vm->win_gran > 0 && vm->win_gran < 64) { + int gran = vm->win_gran; + while(gran < 64) { + vm->win_gran_shift++; + gran <<= 1; + } + vm->win_64k_step = 1 << vm->win_gran_shift; + } + + printf("granularity: %dk (step: %d)\n", vm->win_gran, vm->win_64k_step); } /* allocate main memory framebuffer */ @@ -236,13 +288,14 @@ void *set_video_mode(int idx, int nbuf) return 0; } + fflush(stdout); return vpgaddr[0]; } int set_text_mode(void) { /* unmap previous video memory mapping, if there was one (switching modes) */ - if(vpgaddr[0] && vpgaddr[0] != (void*)0xa0000) { + if(vpgaddr[0] && vpgaddr[0] != VMEM_PTR) { dpmi_munmap(vpgaddr[0]); vpgaddr[0] = vpgaddr[1] = 0; } @@ -277,8 +330,7 @@ static void blit_frame_lfb(void *pixels, int vsync) static void blit_frame_banked(void *pixels, int vsync) { - int i, sz, offs; - unsigned int pending; + int sz, offs, pending; unsigned char *pptr = pixels; demo_post_draw(pixels); @@ -289,23 +341,168 @@ static void blit_frame_banked(void *pixels, int vsync) offs = 0; pending = pgsize; while(pending > 0) { - sz = pending > curmode->bank_size ? curmode->bank_size : pending; - //memcpy64((void*)0xa0000, pptr, sz >> 3); - memcpy((void*)0xa0000, pptr, sz); + sz = pending > 65536 ? 65536 : pending; + /*memcpy64(VMEM_PTR, pptr, sz >> 3);*/ + memcpy(VMEM_PTR, pptr, sz); pptr += sz; pending -= sz; - vbe_setwin(0, ++offs); + offs += curmode->win_64k_step; + vbe_setwin(0, offs); } - vbe_setwin(0, 0); } static uint32_t calc_mask(int sz, int pos) { - int i; uint32_t mask = 0; while(sz-- > 0) { mask = (mask << 1) | 1; } return mask << pos; } + +#define MSR_MTRRCAP 0xfe +#define MSR_MTRRDEFTYPE 0x2ff +#define MSR_MTRRBASE(x) (0x200 | ((x) << 1)) +#define MSR_MTRRMASK(x) (0x201 | ((x) << 1)) +#define MTRRDEF_EN 0x800 +#define MTRRCAP_HAVE_WC 0x400 +#define MTRRMASK_VALID 0x800 + +#define MTRR_WC 1 + +static int get_page_memtype(uint32_t addr, int num_ranges) +{ + int i; + uint32_t rlow, rhigh; + uint32_t base, mask; + + for(i=0; i 0) { + if(get_page_memtype(addr, num_ranges) != MTRR_WC) { + return 0; + } + addr += 4096; + len -= 4096; + } + return 1; +} + +static int alloc_mtrr(int num_ranges) +{ + int i; + uint32_t rlow, rhigh; + + for(i=0; i> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + mask = ~mask & 0xfffff000; + + printf(" ... mask: %08x\n", (unsigned int)mask); + + _disable(); + get_msr(MSR_MTRRDEFTYPE, &def, &rhigh); + set_msr(MSR_MTRRDEFTYPE, def & ~MTRRDEF_EN, rhigh); + + set_msr(MSR_MTRRBASE(mtrr), addr | MTRR_WC, 0); + set_msr(MSR_MTRRMASK(mtrr), mask | MTRRMASK_VALID, 0); + + set_msr(MSR_MTRRDEFTYPE, def | MTRRDEF_EN, 0); + _enable(); +} + +static const char *mtrr_names[] = { "N/A", "W C", "N/A", "N/A", "W T", "W P", "W B" }; + +static const char *mtrr_type_name(int type) +{ + if(type < 0 || type >= sizeof mtrr_names / sizeof *mtrr_names) { + return mtrr_names[0]; + } + return mtrr_names[type]; +} + +static void print_mtrr(void) +{ + int i, num_ranges; + uint32_t rlow, rhigh, base, mask; + + get_msr(MSR_MTRRCAP, &rlow, &rhigh); + num_ranges = rlow & 0xff; + + for(i=0; i #include "keyb.h" #include "scancode.h" #include "inttypes.h" +#include "dosutil.h" #define KB_INTR 0x9 #define KB_PORT 0x60 @@ -55,9 +56,6 @@ static void (INTERRUPT *prev_handler)(); #define DONE_INIT prev_intr.pm_offset static _go32_dpmi_seginfo intr, prev_intr; - -#define outp(p, v) outportb(p, v) -#define inp(p) inportb(p) #endif static void INTERRUPT kbintr(); diff --git a/src/dos/logger.c b/src/dos/logger.c index 70489ad..1976770 100644 --- a/src/dos/logger.c +++ b/src/dos/logger.c @@ -5,17 +5,64 @@ #include #include "logger.h" +static int logfd = -1, orig_fd1 = -1; + int init_logger(const char *fname) { - int fd; - if((fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { + if(logfd != -1) return -1; + + if((logfd = open(fname, O_CREAT | O_WRONLY | O_TRUNC, 0644)) == -1) { fprintf(stderr, "init_logger: failed to open %s: %s\n", fname, strerror(errno)); return -1; } + orig_fd1 = dup(1); close(1); close(2); - dup(fd); - dup(fd); + dup(logfd); + dup(logfd); + return 0; +} + +void stop_logger(void) +{ + if(logfd >= 0) { + close(logfd); + logfd = -1; + } + if(orig_fd1 >= 0) { + close(1); + close(2); + dup(orig_fd1); + dup(orig_fd1); + orig_fd1 = -1; + } +} + +int print_tail(const char *fname) +{ + FILE *fp; + char buf[64]; + long lineoffs[16]; + int wr, rd, c; + + if(!(fp = fopen(fname, "r"))) { + return -1; + } + wr = rd = 0; + lineoffs[wr++] = 0; + while(fgets(buf, sizeof buf, fp)) { + lineoffs[wr] = ftell(fp); + wr = (wr + 1) & 0xf; + if(wr == rd) { + rd = (rd + 1) & 0xf; + } + } + + fseek(fp, lineoffs[rd], SEEK_SET); + while((c = fgetc(fp)) != -1) { + fputc(c, stdout); + } + fclose(fp); return 0; } diff --git a/src/dos/logger.h b/src/dos/logger.h index 9ef9a85..56f6be7 100644 --- a/src/dos/logger.h +++ b/src/dos/logger.h @@ -6,6 +6,9 @@ extern "C" { #endif int init_logger(const char *fname); +void stop_logger(void); + +int print_tail(const char *fname); #ifdef __cplusplus } diff --git a/src/dos/main.c b/src/dos/main.c index 566d47e..7f67e85 100644 --- a/src/dos/main.c +++ b/src/dos/main.c @@ -8,8 +8,10 @@ #include "logger.h" #include "cdpmi.h" #include "audio.h" +#include "mouse.h" #include "sball.h" #include "vmath.h" +#include "cpuid.h" static int handle_sball_event(sball_event *ev); static void recalc_sball_matrix(float *xform); @@ -40,6 +42,16 @@ int main(int argc, char **argv) init_logger("demo.log"); +#ifdef __WATCOMC__ + printf("watcom build\n"); +#elif defined(__DJGPP__) + printf("djgpp build\n"); +#endif + + if(read_cpuid(&cpuid) == 0) { + print_cpuid(&cpuid); + } + /* au_init needs to be called early, before init_timer, and also before * we enter graphics mode, to use the midas configuration tool if necessary */ @@ -50,6 +62,10 @@ int main(int argc, char **argv) init_timer(100); kb_init(32); + if(init_pci() != -1) { + /* TODO detect and initialize S3 virge */ + } + if(init_video() == -1) { return 1; } @@ -119,6 +135,15 @@ void demo_quit(void) quit = 1; } +void demo_abort(void) +{ + set_text_mode(); + stop_logger(); + printf("demo_abort called. see demo.log for details. Last lines:\n\n"); + print_tail("demo.log"); + abort(); +} + #define TX(ev) ((ev)->motion.motion[0]) #define TY(ev) ((ev)->motion.motion[1]) #define TZ(ev) ((ev)->motion.motion[2]) diff --git a/src/dos/pci.c b/src/dos/pci.c new file mode 100644 index 0000000..19a2e4d --- /dev/null +++ b/src/dos/pci.c @@ -0,0 +1,421 @@ +/* +S3 Virge driver hack +Copyright (C) 2021 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include +#include +#include +#include "dosutil.h" +#include "inttypes.h" +#include "pci.h" +#include "cdpmi.h" + +#define CONFIG_ADDR_PORT 0xcf8 +#define CONFIG_DATA_PORT 0xcfc + +#define ADDR_ENABLE 0x80000000 +#define ADDR_BUSID(x) (((uint32_t)(x) & 0xff) << 16) +#define ADDR_DEVID(x) (((uint32_t)(x) & 0x1f) << 11) +#define ADDR_FUNC(x) (((uint32_t)(x) & 3) << 8) + +/* signature returned in edx by the PCI BIOS present function: FOURCC "PCI " */ +#define PCI_SIG 0x20494350 + +#define TYPE_MULTIFUNC 0x80 + + +static struct pci_device *pcidev; +static int num_pcidevs, max_pcidevs; + + +static int enum_bus(int busid); +static int enum_dev(int busid, int dev); +static int read_dev_info(struct pci_config_data *res, int bus, int dev, int func); +static void print_dev_info(struct pci_config_data *info, int bus, int dev, int func); + +static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg); +static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg); +static const char *class_str(int cc); +static const char *subclass_str(int cc, int sub); + +static uint32_t (*cfg_read32)(int, int, int, int); + +static void clear_devices(void); +static void add_device(struct pci_device *dev); + +int init_pci(void) +{ + int i, count = 0; + struct dpmi_regs regs = {0}; + + clear_devices(); + + regs.eax = 0xb101; + dpmi_int(0x1a, ®s); + + /* PCI BIOS present if CF=0, AH=0, and EDX has the "PCI " sig FOURCC */ + if((regs.flags & FLAGS_CF) || (regs.eax & 0xff00) || regs.edx != PCI_SIG) { + fprintf(stderr, "No PCI BIOS present\n"); + return -1; + } + + printf("PCI BIOS v%x.%x found\n", (regs.ebx & 0xff00) >> 8, regs.ebx & 0xff); + if(regs.eax & 1) { + cfg_read32 = cfg_read32_m1; + } else { + if(!(regs.eax & 2)) { + fprintf(stderr, "Failed to find supported PCI mess mechanism\n"); + return -1; + } + printf("PCI mess mechanism #1 unsupported, falling back to mechanism #2\n"); + cfg_read32 = cfg_read32_m2; + } + + for(i=0; i<256; i++) { + count += enum_bus(i); + } + printf("found %d PCI devices\n\n", count); + return 0; +} + +static int enum_bus(int busid) +{ + int i, count = 0; + + for(i=0; i<32; i++) { + count += enum_dev(busid, i); + } + + return count; +} + +static int enum_dev(int busid, int devid) +{ + int i, count; + struct pci_device dev; + + dev.bus = busid; + dev.dev = devid; + dev.func = 0; + + /* vendor id ffff is invalid */ + if((cfg_read32(busid, devid, 0, 0) & 0xffff) == 0xffff) { + return 0; + } + if(read_dev_info(&dev.cfg, busid, devid, 0) == -1) { + return 0; + } + print_dev_info(&dev.cfg, busid, devid, 0); + add_device(&dev); + + count = 1; + + if(dev.cfg.hdr_type & TYPE_MULTIFUNC) { + for(i=1; i<8; i++) { + if(read_dev_info(&dev.cfg, busid, devid, i) == -1) { + continue; + } + print_dev_info(&dev.cfg, busid, devid, i); + dev.func = i; + add_device(&dev); + count++; + } + } + return count; +} + +static int read_dev_info(struct pci_config_data *res, int bus, int dev, int func) +{ + int i; + uint32_t *ptr = (uint32_t*)res; + + *ptr++ = cfg_read32(bus, dev, func, 0); + if(res->vendor == 0xffff) { + return -1; + } + + for(i=1; i<16; i++) { + *ptr++ = cfg_read32(bus, dev, func, i * 4); + } + return 0; +} + +static void print_dev_info(struct pci_config_data *info, int bus, int dev, int func) +{ + printf("- (%d:%d,%d) Device %04x:%04x: ", bus, dev, func, info->vendor, info->device); + printf("\"%s\" (%d) - %s-func\n", class_str(info->class), info->class, + info->hdr_type & TYPE_MULTIFUNC ? "multi" : "single"); + printf(" subclass: \"%s\" (%d), iface: %d\n", subclass_str(info->class, info->subclass), + info->subclass, info->iface); +} + +static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg) +{ + uint32_t addr = ADDR_ENABLE | ADDR_BUSID(bus) | ADDR_DEVID(dev) | + ADDR_FUNC(func) | reg; + + outpd(CONFIG_ADDR_PORT, addr); + return inpd(CONFIG_DATA_PORT); +} + +static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg) +{ + fprintf(stderr, "BUG: PCI mess mechanism #2 not implemented yet!"); + demo_abort(); + return 0; +} + +static const char *class_names[] = { + "unknown", + "mass storage controller", + "network controller", + "display controller", + "multimedia device", + "memory controller", + "bridge device", + "simple communication controller", + "base system peripheral", + "input device", + "docking station", + "processor", + "serial bus controller", + "wireless controller", + "intelligent I/O controller", + "satellite communication controller", + "encryption/decryption controller", + "data acquisition & signal processing controller" +}; + +static const char *class_mass_names[] = { + "SCSI bus controller", + "IDE controller", + "floppy disk controller", + "IPI bus controller", + "RAID controller" +}; + +static const char *class_net_names[] = { + "ethernet controller", + "token ring controller", + "FDDI controller", + "ATM controller", + "ISDN controller" +}; + +static const char *class_disp_names[] = { + "VGA-compatible controller", + "XGA controller", + "3D controller" +}; + +static const char *class_mm_names[] = { + "video device", + "audio device", + "telephony device" +}; + +static const char *class_bridge_names[] = { + "host bridge", + "ISA bridge", + "EISA bridge", + "MCA bridge", + "PCI-to-PCI bridge", + "Subtractive decode PCI-to-PCI bridge", + "PCMCIA bridge", + "NuBus bridge", + "CardBus bridge", + "RACEway bridge" +}; + +static const char *class_comm_names[] = { + "serial controller", + "parallel/IEEE1284", + "multiport serial controller", + "modem" +}; + +static const char *class_base_names[] = { + "interrupt controller", + "DMA controller", + "timer", + "RTC", + "PCI hot-plug controller" +}; + +static const char *class_input_names[] = { + "keyboard controller", + "digitizer", + "mouse controller", + "scanner controller", + "gameport controller" +}; + +static const char *class_ser_names[] = { + "firewire", + "ACCESS.bus", + "SSA", + "USB", + "Fibre Channel", + "SMBus" +}; + +static const char *class_sat_names[] = { + "TV", + "audio", + "voice", + "data" +}; + + +static const char *class_str(int cc) +{ + if(cc == 0xff) { + return "other"; + } + if(cc >= 0x12) { + return "unknown"; + } + return class_names[cc]; +} + +static const char *subclass_str(int cc, int sub) +{ + if(sub == 0x80) return "other"; + + switch(cc) { + case 0: + if(sub == 1) return "VGA-compatible device"; + return "unknown"; + + case 1: + if(sub > 4) return "unknown"; + return class_mass_names[sub]; + + case 2: + if(sub > 4) return "unknown"; + return class_net_names[sub]; + + case 3: + if(sub > 2) return "unknown"; + return class_disp_names[sub]; + + case 4: + if(sub > 2) return "unknown"; + return class_mm_names[sub]; + + case 5: + if(sub == 0) return "RAM"; + if(sub == 1) return "flash"; + return "unknown"; + + case 6: + if(sub > 8) return "unknown"; + return class_bridge_names[sub]; + + case 7: + if(sub > 3) return "unknown"; + return class_comm_names[sub]; + + case 8: + if(sub > 4) return "unknown"; + return class_base_names[sub]; + + case 9: + if(sub > 4) return "unknown"; + return class_input_names[sub]; + + case 10: + if(sub == 0) return "generic docking station"; + return "unknown"; + + case 11: + switch(sub) { + case 0: return "386"; + case 1: return "486"; + case 2: return "pentium"; + case 0x10: return "alpha"; + case 0x20: return "powerpc"; + case 0x30: return "mips"; + case 0x40: return "co-processor"; + default: + break; + } + return "unknown"; + + case 12: + if(sub > 5) return "unknown"; + return class_ser_names[sub]; + + case 13: + if(sub == 0) return "irda controller"; + if(sub == 1) return "IR controller"; + if(sub == 0x10) return "RF controller"; + return "unknonw"; + + case 15: + if(sub > 4) return "unknown"; + return class_sat_names[sub]; + + case 16: + if(sub == 0) return "network & computing crypto"; + if(sub == 1) return "entertainment crypto"; + return "unknown"; + + case 17: + if(sub == 0) return "DPIO module"; + return "unknown"; + + default: + break; + } + return "unknown"; +} + +static void clear_devices(void) +{ + free(pcidev); + pcidev = 0; + num_pcidevs = max_pcidevs = 0; +} + +static void add_device(struct pci_device *dev) +{ + if(num_pcidevs >= max_pcidevs) { + void *newarr; + int newsz = max_pcidevs ? max_pcidevs << 1 : 8; + + if(!(newarr = realloc(pcidev, newsz * sizeof *pcidev))) { + fprintf(stderr, "failed to resize PCI device array (%d)\n", newsz); + return; + } + pcidev = newarr; + max_pcidevs = newsz; + } + + pcidev[num_pcidevs++] = *dev; +} + +struct pci_device *find_pci_dev(uint16_t vendorid, uint16_t devid) +{ + int i; + for(i=0; i + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef PCI_H_ +#define PCI_H_ + +#include "inttypes.h" +#include "util.h" + +#pragma pack (push, 1) +struct pci_config_data { + uint16_t vendor, device; + uint16_t cmd, status; + uint8_t rev, iface, subclass, class; + uint8_t cacheline_size; + uint8_t latency_timer; + uint8_t hdr_type; + uint8_t bist; + uint32_t base_addr[6]; + uint32_t cardbus_cis; + uint16_t subsys_vendor; + uint16_t subsys; + uint32_t rom_addr; + uint32_t reserved1, reserved2; + uint8_t intr_line, intr_pin; + uint8_t min_grant, max_latency; +} PACKED; +#pragma pop (push) + +struct pci_device { + int bus, dev, func; + struct pci_config_data cfg; +}; + +int init_pci(void); + +struct pci_device *find_pci_dev(uint16_t vendorid, uint16_t devid); + +#endif /* PCI_H_ */ diff --git a/src/dos/sball.c b/src/dos/sball.c index 7eb1fd9..6261f1b 100644 --- a/src/dos/sball.c +++ b/src/dos/sball.c @@ -16,6 +16,7 @@ #include "sball.h" #include "inttypes.h" +#include "dosutil.h" struct motion { int x, y, z; @@ -142,9 +143,6 @@ static void (INTERRUPT *prev_recv_intr)(void); #define INTERRUPT static _go32_dpmi_seginfo intr, prev_intr; - -#define outp(port, val) outportb(port, val) -#define inp(port) inportb(port) #endif static void INTERRUPT recv_intr(void); diff --git a/src/dos/timer.c b/src/dos/timer.c index 2440bd5..5492f0b 100644 --- a/src/dos/timer.c +++ b/src/dos/timer.c @@ -22,6 +22,7 @@ #include "pit8254.h" #include "inttypes.h" #include "util.h" +#include "dosutil.h" #define PIT_TIMER_INTR 8 #define DOS_TIMER_INTR 0x1c @@ -45,8 +46,6 @@ static void (INTERRUPT *prev_timer_intr)(); #define INTERRUPT static _go32_dpmi_seginfo intr, prev_intr; - -#define outp(p, v) outportb(p, v) #endif static void INTERRUPT timer_irq(); diff --git a/src/dos/vbe.c b/src/dos/vbe.c index 05a5883..cb37ca1 100644 --- a/src/dos/vbe.c +++ b/src/dos/vbe.c @@ -207,7 +207,7 @@ void vbe_print_mode_info(FILE *fp, struct vbe_mode_info *minf) if(minf->attr & VBE_ATTR_LFB) { fprintf(fp, " lfb@%lx", (unsigned long)minf->fb_addr); } else { - fprintf(fp, " %xkb/bank", (unsigned int)minf->bank_size); + fprintf(fp, " (%dk gran)", (int)minf->win_gran); } fprintf(fp, " ["); diff --git a/src/dos/vga.c b/src/dos/vga.c index c829684..f2f8142 100644 --- a/src/dos/vga.c +++ b/src/dos/vga.c @@ -1,5 +1,11 @@ +#include #include "vga.h" +#include "vgaregs.h" #include "cdpmi.h" +#include "dosutil.h" + +static void crtc_write(int reg, unsigned char val); +static unsigned char crtc_read(int reg); int vga_setmode(int mode) { @@ -9,3 +15,57 @@ int vga_setmode(int mode) dpmi_int(0x10, ®s); return 0; } + +static unsigned short crtc_modex_regs[] = { + 0x0d06, /* vertical total */ + 0x3e07, /* vcount overflow bit */ + 0x4109, /* double-scan */ + 0xea10, /* vsync start */ + 0xac11, /* vsync end & protect */ + 0xdf12, /* vertical visible */ + 0x0014, /* no dword mode */ + 0xe715, /* vblank start */ + 0x0616, /* vblank end */ + 0xe317, /* byte mode */ + 0 +}; + +int vga_setmodex(void) +{ + int i; + unsigned char val; + + vga_setmode(0x13); + + /* disable chain-4 (C4=0, O/E=1 (sequential), EM=1 (extmem), A/G=0 (gfx) */ + outpw(VGA_SC_ADDR_PORT, VGA_SC_MEMMODE_REG | 0x0600); + /* pull reset low */ + outpw(VGA_SC_ADDR_PORT, VGA_SC_RESET_REG | 0x0100); + /* 25mhz dot clock, 60hz scan */ + outp(VGA_MISC_PORT, VGA_MISC_480 | VGA_MISC_PG1 | VGA_MISC_CLK25 | + VGA_MISC_CPUEN | VGA_MISC_COLOR); + /* return reset high */ + outpw(VGA_SC_ADDR_PORT, VGA_SC_RESET_REG | 0x0300); + + /* disable CRTC write-protect */ + crtc_write(CRTC_VRETEND_REG, crtc_read(CRTC_VRETEND_REG) & ~CRTC_VRETEND_PR); + /* change CRTC registers */ + for(i=0; crtc_modex_regs[i]; i++) { + outpw(VGA_CRTC_PORT, crtc_modex_regs[i]); + } + + vga_planemask(0xf); + memset(VGA_FBADDR, 3, 320 * 240 / 4); + return 0; +} + +static void crtc_write(int reg, unsigned char val) +{ + outpw(VGA_CRTC_ADDR_PORT, reg | ((unsigned int)val << 8)); +} + +static unsigned char crtc_read(int reg) +{ + outp(VGA_CRTC_ADDR_PORT, reg); + return inp(VGA_CRTC_DATA_PORT); +} diff --git a/src/dos/vga.h b/src/dos/vga.h index c6d7070..99738eb 100644 --- a/src/dos/vga.h +++ b/src/dos/vga.h @@ -2,8 +2,17 @@ #define VGA_H_ #include "inttypes.h" +#include "dosutil.h" +#include "cdpmi.h" +#include "vgaregs.h" + +#define VGA_FBADDR ((void*)phys_to_virt(0xa0000)) int vga_setmode(int mode); +int vga_setmodex(void); + +#define vga_planemask(mask) \ + outpw(VGA_SC_ADDR_PORT, VGA_SC_MAPMASK_REG | ((unsigned short)(mask) << 8)) #ifdef __WATCOMC__ void vga_setpal(int16_t idx, uint8_t r, uint8_t g, uint8_t b); diff --git a/src/dos/vgaregs.h b/src/dos/vgaregs.h new file mode 100644 index 0000000..15c4090 --- /dev/null +++ b/src/dos/vgaregs.h @@ -0,0 +1,85 @@ +#ifndef VGAREGS_H_ +#define VGAREGS_H_ + +/* ---- VGA registers ---- */ +#define VGA_AC_PORT 0x3c0 +#define VGA_AC_RD_PORT 0x3c1 +#define VGA_SC_ADDR_PORT 0x3c4 +#define VGA_SC_DATA_PORT 0x3c5 +#define VGA_GC_ADDR_PORT 0x3ce +#define VGA_GC_DATA_PORT 0x3cf +#define VGA_CRTC_PORT 0x3d4 +#define VGA_CRTC_ADDR_PORT 0x3d4 +#define VGA_CRTC_DATA_PORT 0x3d5 +#define VGA_STAT0_PORT 0x3c2 +#define VGA_STAT1_PORT 0x3da +#define VGA_MISC_PORT 0x3c2 +#define VGA_MISC_RD_PORT 0x3cc + +/* attribute controller registers */ +#define VGA_AC_EN 0x20 +#define VGA_AC_MODE_REG 0x10 + +/* sequence controller registers */ +#define VGA_SC_RESET_REG 0x00 +#define VGA_SC_CLOCK_REG 0x01 +#define VGA_SC_MAPMASK_REG 0x02 +#define VGA_SC_MEMMODE_REG 0x04 + +/* graphics controller registers */ +#define VGA_GC_SR_REG 0x00 +#define VGA_GC_SREN_REG 0x01 +#define VGA_GC_ROT_REG 0x03 +#define VGA_GC_MODE_REG 0x05 +#define VGA_GC_MASK_REG 0x08 + +/* attribute controller mode register (10h) bits */ +#define VGA_AC_MODE_GFX 0x01 +#define VGA_AC_MODE_MONO 0x02 +#define VGA_AC_MODE_LGE 0x04 +#define VGA_AC_MODE_BLINK 0x08 +#define VGA_AC_MODE_PIXPAN 0x20 +#define VGA_AC_MODE_8BIT 0x40 + +/* misc register bits */ +#define VGA_MISC_COLOR 0x01 +#define VGA_MISC_CPUEN 0x02 +#define VGA_MISC_CLK25 0 +#define VGA_MISC_CLK28 0x04 +#define VGA_MISC_PG1 0x20 +#define VGA_MISC_400 0 +#define VGA_MISC_350 0x40 +#define VGA_MISC_480 0xc0 + + +/* CRTC registers */ +#define CRTC_HTOTAL_REG 0x00 +#define CRTC_HEND_REG 0x01 +#define CRTC_HBLSTART_REG 0x02 +#define CRTC_HBLEND_REG 0x03 +#define CRTC_HRETSTART_REG 0x04 +#define CRTC_HRETEND_REG 0x05 +#define CRTC_VTOTAL_REG 0x06 +#define CRTC_OVF_REG 0x07 +#define CRTC_PRESET_REG 0x08 +#define CRTC_MAXSCAN_REG 0x09 +#define CRTC_CURSTART_REG 0x0a +#define CRTC_CUREND_REG 0x0b +#define CRTC_STARTH_REG 0x0c +#define CRTC_STARTL_REG 0x0d +#define CRTC_CURH_REG 0x0e +#define CRTC_CURL_REG 0x0f +#define CRTC_VRETSTART_REG 0x10 +#define CRTC_VRETEND_REG 0x11 +#define CRTC_VEND_REG 0x12 +#define CRTC_OFFSET_REG 0x13 +#define CRTC_UL_REG 0x14 +#define CRTC_VBLSTART_REG 0x15 +#define CRTC_VBLEND_REG 0x16 +#define CRTC_MODE_REG 0x17 +#define CRTC_LCMP_REG 0x18 + +/* CRTC register bits */ +#define CRTC_VRETEND_PR 0x80 + +#endif /* VGAREGS_H_ */ diff --git a/src/glut/audio.c b/src/glut/audio.c index c776d3b..6a7b96c 100644 --- a/src/glut/audio.c +++ b/src/glut/audio.c @@ -9,6 +9,7 @@ #endif #include "mikmod.h" #include "audio.h" +#include "cfgopt.h" #ifdef _WIN32 #include @@ -37,6 +38,8 @@ int au_init(void) curmod = 0; vol_master = vol_mus = vol_sfx = 255; + if(!opt.music) return 0; + #if defined(__linux__) MikMod_RegisterDriver(&drv_alsa); #elif defined(__FreeBSD__) @@ -63,7 +66,7 @@ int au_init(void) { #ifdef _WIN32 HANDLE thr; - if((thr = CreateThread(0, 0, update, 0, 0, 0))) { + if((thr = CreateThread(0, 0, upd_thread, 0, 0, 0))) { CloseHandle(thr); } #else @@ -78,8 +81,10 @@ int au_init(void) void au_shutdown(void) { - curmod = 0; - MikMod_Exit(); + if(opt.music) { + curmod = 0; + MikMod_Exit(); + } } struct au_module *au_load_module(const char *fname) @@ -169,7 +174,7 @@ void au_update(void) } #ifdef _WIN32 -static DWORD WINAPI upd_thread(void *cls); +static DWORD WINAPI upd_thread(void *cls) #else static void *update(void *cls) #endif diff --git a/src/glut/main.c b/src/glut/main.c index abe25cc..a552832 100644 --- a/src/glut/main.c +++ b/src/glut/main.c @@ -11,6 +11,7 @@ #include "cfgopt.h" #include "cgmath/cgmath.h" #include "util.h" +#include "cpuid.h" static void display(void); static void idle(void); @@ -101,6 +102,9 @@ int main(int argc, char **argv) glEnable(GL_TEXTURE_2D); glEnable(GL_CULL_FACE); + if(read_cpuid(&cpuid) == 0) { + print_cpuid(&cpuid); + } if(!set_video_mode(match_video_mode(FB_WIDTH, FB_HEIGHT, FB_BPP), 1)) { return 1; @@ -118,21 +122,26 @@ int main(int argc, char **argv) wgl_swap_interval_ext = wglGetProcAddress("wglSwapIntervalEXT"); #endif - reshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); - if(au_init() == -1) { return 1; } time_msec = 0; - if(demo_init(argc, argv) == -1) { + if(demo_init1(argc, argv) == -1) { return 1; } - atexit(demo_cleanup); if(opt.fullscreen) { set_fullscreen(opt.fullscreen); + reshape(glutGet(GLUT_SCREEN_WIDTH), glutGet(GLUT_SCREEN_HEIGHT)); + } else { + reshape(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); } + if(demo_init2() == -1) { + return 1; + } + atexit(demo_cleanup); + reset_timer(); glutMainLoop(); @@ -144,6 +153,11 @@ void demo_quit(void) exit(0); } +void demo_abort(void) +{ + abort(); +} + struct video_mode *video_modes(void) { return vmodes; diff --git a/src/glut/w32_dirent.c b/src/glut/w32_dirent.c deleted file mode 100644 index d399023..0000000 --- a/src/glut/w32_dirent.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * dirent.c - * This file has no copyright assigned and is placed in the Public Domain. - * This file is a part of the mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within the package. - * - * Derived from DIRLIB.C by Matt J. Weinstein - * This note appears in the DIRLIB.H - * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 - * - * Updated by Jeremy Bettis - * Significantly revised and rewinddir, seekdir and telldir added by Colin - * Peters - * - */ -#ifdef _MSC_VER - -#include -#include -#include -#include -#include -#include "w32_dirent.h" - -#define WIN32_LEAN_AND_MEAN -#include /* for GetFileAttributes */ - -#define SUFFIX "*" -#define SLASH "\\" - -/* - * opendir - * - * Returns a pointer to a DIR structure appropriately filled in to begin - * searching a directory. - */ -DIR * opendir (const char *szPath) -{ - DIR *nd; - unsigned int rc; - char szFullPath[MAX_PATH]; - - errno = 0; - - if (!szPath) - { - errno = EFAULT; - return (DIR *) 0; - } - - if (szPath[0] == ('\0')) - { - errno = ENOTDIR; - return (DIR *) 0; - } - - /* Attempt to determine if the given path really is a directory. */ - rc = GetFileAttributes (szPath); - if (rc == (unsigned int)-1) - { - /* call GetLastError for more error info */ - errno = ENOENT; - return (DIR *) 0; - } - if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) - { - /* Error, entry exists but not a directory. */ - errno = ENOTDIR; - return (DIR *) 0; - } - - /* Make an absolute pathname. */ - _fullpath (szFullPath, szPath, MAX_PATH); - - /* Allocate enough space to store DIR structure and the complete - * directory path given. */ - nd = (DIR *) malloc (sizeof (DIR) + (strlen (szFullPath) - + strlen (SLASH) - + strlen (SUFFIX) + 1) - * sizeof (char)); - - if (!nd) - { - /* Error, out of memory. */ - errno = ENOMEM; - return (DIR *) 0; - } - - /* Create the search expression. */ - strcpy (nd->dd_name, szFullPath); - - /* Add on a slash if the path does not end with one. */ - if (nd->dd_name[0] != ('\0') - && strrchr (nd->dd_name, ('/')) != nd->dd_name - + strlen (nd->dd_name) - 1 - && strrchr (nd->dd_name, ('\\')) != nd->dd_name - + strlen (nd->dd_name) - 1) - { - strcat (nd->dd_name, SLASH); - } - - /* Add on the search pattern */ - strcat (nd->dd_name, SUFFIX); - - /* Initialize handle to -1 so that a premature closedir doesn't try - * to call _findclose on it. */ - nd->dd_handle = -1; - - /* Initialize the status. */ - nd->dd_stat = 0; - - /* Initialize the dirent structure. ino and reclen are invalid under - * Win32, and name simply points at the appropriate part of the - * findfirst structure. */ - nd->dd_dir.d_ino = 0; - nd->dd_dir.d_reclen = 0; - nd->dd_dir.d_namlen = 0; - memset (nd->dd_dir.d_name, 0, FILENAME_MAX); - - return nd; -} - - -/* - * readdir - * - * Return a pointer to a dirent structure filled with the information on the - * next entry in the directory. - */ -struct dirent * -readdir (DIR * dirp) -{ - errno = 0; - - /* Check for valid DIR struct. */ - if (!dirp) - { - errno = EFAULT; - return (struct dirent *) 0; - } - - if (dirp->dd_stat < 0) - { - /* We have already returned all files in the directory - * (or the structure has an invalid dd_stat). */ - return (struct dirent *) 0; - } - else if (dirp->dd_stat == 0) - { - /* We haven't started the search yet. */ - /* Start the search */ - dirp->dd_handle = (long)_findfirst (dirp->dd_name, &(dirp->dd_dta)); - - if (dirp->dd_handle == -1) - { - /* Whoops! Seems there are no files in that - * directory. */ - dirp->dd_stat = -1; - } - else - { - dirp->dd_stat = 1; - } - } - else - { - /* Get the next search entry. */ - if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) - { - /* We are off the end or otherwise error. - _findnext sets errno to ENOENT if no more file - Undo this. */ - DWORD winerr = GetLastError (); - if (winerr == ERROR_NO_MORE_FILES) - errno = 0; - _findclose (dirp->dd_handle); - dirp->dd_handle = -1; - dirp->dd_stat = -1; - } - else - { - /* Update the status to indicate the correct - * number. */ - dirp->dd_stat++; - } - } - - if (dirp->dd_stat > 0) - { - /* Successfully got an entry. Everything about the file is - * already appropriately filled in except the length of the - * file name. */ - dirp->dd_dir.d_namlen = (unsigned short)strlen (dirp->dd_dta.name); - strcpy (dirp->dd_dir.d_name, dirp->dd_dta.name); - return &dirp->dd_dir; - } - - return (struct dirent *) 0; -} - - -/* - * closedir - * - * Frees up resources allocated by opendir. - */ -int -closedir (DIR * dirp) -{ - int rc; - - errno = 0; - rc = 0; - - if (!dirp) - { - errno = EFAULT; - return -1; - } - - if (dirp->dd_handle != -1) - { - rc = _findclose (dirp->dd_handle); - } - - /* Delete the dir structure. */ - free (dirp); - - return rc; -} - -/* - * rewinddir - * - * Return to the beginning of the directory "stream". We simply call findclose - * and then reset things like an opendir. - */ -void -rewinddir (DIR * dirp) -{ - errno = 0; - - if (!dirp) - { - errno = EFAULT; - return; - } - - if (dirp->dd_handle != -1) - { - _findclose (dirp->dd_handle); - } - - dirp->dd_handle = -1; - dirp->dd_stat = 0; -} - -/* - * telldir - * - * Returns the "position" in the "directory stream" which can be used with - * seekdir to go back to an old entry. We simply return the value in stat. - */ -long -telldir (DIR * dirp) -{ - errno = 0; - - if (!dirp) - { - errno = EFAULT; - return -1; - } - return dirp->dd_stat; -} - -/* - * seekdir - * - * Seek to an entry previously returned by telldir. We rewind the directory - * and call readdir repeatedly until either dd_stat is the position number - * or -1 (off the end). This is not perfect, in that the directory may - * have changed while we weren't looking. But that is probably the case with - * any such system. - */ -void -seekdir (DIR * dirp, long lPos) -{ - errno = 0; - - if (!dirp) - { - errno = EFAULT; - return; - } - - if (lPos < -1) - { - /* Seeking to an invalid position. */ - errno = EINVAL; - return; - } - else if (lPos == -1) - { - /* Seek past end. */ - if (dirp->dd_handle != -1) - { - _findclose (dirp->dd_handle); - } - dirp->dd_handle = -1; - dirp->dd_stat = -1; - } - else - { - /* Rewind and read forward to the appropriate index. */ - rewinddir (dirp); - - while ((dirp->dd_stat < lPos) && readdir (dirp)) - ; - } -} - -#else - -int _utk_w32_dirent_c_shut_up_stupid_compiler_warning; - -#endif /* WIN32 */ diff --git a/src/glut/w32_dirent.h b/src/glut/w32_dirent.h deleted file mode 100644 index 5b256bc..0000000 --- a/src/glut/w32_dirent.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * DIRENT.H (formerly DIRLIB.H) - * This file has no copyright assigned and is placed in the Public Domain. - * This file is a part of the mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within the package. - * - */ -#ifndef W32_DIRENT_H_ -#define W32_DIRENT_H_ - -#include -#include - -#ifndef RC_INVOKED - -#ifdef __cplusplus -extern "C" { -#endif - -struct dirent -{ - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - char d_name[FILENAME_MAX]; /* File name. */ -}; - -/* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - * dd_stat field is now int (was short in older versions). - */ -typedef struct -{ - /* disk transfer area for this dir */ - struct _finddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; -} DIR; - -DIR* __cdecl opendir (const char*); -struct dirent* __cdecl readdir (DIR*); -int __cdecl closedir (DIR*); -void __cdecl rewinddir (DIR*); -long __cdecl telldir (DIR*); -void __cdecl seekdir (DIR*, long); - - -/* wide char versions */ - -struct _wdirent -{ - long d_ino; /* Always zero. */ - unsigned short d_reclen; /* Always zero. */ - unsigned short d_namlen; /* Length of name in d_name. */ - wchar_t d_name[FILENAME_MAX]; /* File name. */ -}; - -/* - * This is an internal data structure. Good programmers will not use it - * except as an argument to one of the functions below. - */ -typedef struct -{ - /* disk transfer area for this dir */ - struct _wfinddata_t dd_dta; - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct _wdirent dd_dir; - - /* _findnext handle */ - long dd_handle; - - /* - * Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - wchar_t dd_name[1]; -} _WDIR; - - - -_WDIR* __cdecl _wopendir (const wchar_t*); -struct _wdirent* __cdecl _wreaddir (_WDIR*); -int __cdecl _wclosedir (_WDIR*); -void __cdecl _wrewinddir (_WDIR*); -long __cdecl _wtelldir (_WDIR*); -void __cdecl _wseekdir (_WDIR*, long); - - -#ifdef __cplusplus -} -#endif - -#endif /* Not RC_INVOKED */ - -#endif /* Not _DIRENT_H_ */ diff --git a/src/glut/w32dir.c b/src/glut/w32dir.c new file mode 100644 index 0000000..fc4541e --- /dev/null +++ b/src/glut/w32dir.c @@ -0,0 +1,327 @@ +/* + * dirent.c + * This file has no copyright assigned and is placed in the Public Domain. + * This file is a part of the mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within the package. + * + * Derived from DIRLIB.C by Matt J. Weinstein + * This note appears in the DIRLIB.H + * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 + * + * Updated by Jeremy Bettis + * Significantly revised and rewinddir, seekdir and telldir added by Colin + * Peters + * + */ +#ifdef _MSC_VER + +#include +#include +#include +#include +#include +#include "w32dir.h" + +#define WIN32_LEAN_AND_MEAN +#include /* for GetFileAttributes */ + +#define SUFFIX "*" +#define SLASH "\\" + +/* + * opendir + * + * Returns a pointer to a DIR structure appropriately filled in to begin + * searching a directory. + */ +DIR * opendir (const char *szPath) +{ + DIR *nd; + unsigned int rc; + char szFullPath[MAX_PATH]; + + errno = 0; + + if (!szPath) + { + errno = EFAULT; + return (DIR *) 0; + } + + if (szPath[0] == ('\0')) + { + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Attempt to determine if the given path really is a directory. */ + rc = GetFileAttributes (szPath); + if (rc == (unsigned int)-1) + { + /* call GetLastError for more error info */ + errno = ENOENT; + return (DIR *) 0; + } + if (!(rc & FILE_ATTRIBUTE_DIRECTORY)) + { + /* Error, entry exists but not a directory. */ + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Make an absolute pathname. */ + _fullpath (szFullPath, szPath, MAX_PATH); + + /* Allocate enough space to store DIR structure and the complete + * directory path given. */ + nd = (DIR *) malloc (sizeof (DIR) + (strlen (szFullPath) + + strlen (SLASH) + + strlen (SUFFIX) + 1) + * sizeof (char)); + + if (!nd) + { + /* Error, out of memory. */ + errno = ENOMEM; + return (DIR *) 0; + } + + /* Create the search expression. */ + strcpy (nd->dd_name, szFullPath); + + /* Add on a slash if the path does not end with one. */ + if (nd->dd_name[0] != ('\0') + && strrchr (nd->dd_name, ('/')) != nd->dd_name + + strlen (nd->dd_name) - 1 + && strrchr (nd->dd_name, ('\\')) != nd->dd_name + + strlen (nd->dd_name) - 1) + { + strcat (nd->dd_name, SLASH); + } + + /* Add on the search pattern */ + strcat (nd->dd_name, SUFFIX); + + /* Initialize handle to -1 so that a premature closedir doesn't try + * to call _findclose on it. */ + nd->dd_handle = -1; + + /* Initialize the status. */ + nd->dd_stat = 0; + + /* Initialize the dirent structure. ino and reclen are invalid under + * Win32, and name simply points at the appropriate part of the + * findfirst structure. */ + nd->dd_dir.d_ino = 0; + nd->dd_dir.d_reclen = 0; + nd->dd_dir.d_namlen = 0; + memset (nd->dd_dir.d_name, 0, FILENAME_MAX); + + return nd; +} + + +/* + * readdir + * + * Return a pointer to a dirent structure filled with the information on the + * next entry in the directory. + */ +struct dirent * +readdir (DIR * dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if (!dirp) + { + errno = EFAULT; + return (struct dirent *) 0; + } + + if (dirp->dd_stat < 0) + { + /* We have already returned all files in the directory + * (or the structure has an invalid dd_stat). */ + return (struct dirent *) 0; + } + else if (dirp->dd_stat == 0) + { + /* We haven't started the search yet. */ + /* Start the search */ + dirp->dd_handle = (long)_findfirst (dirp->dd_name, &(dirp->dd_dta)); + + if (dirp->dd_handle == -1) + { + /* Whoops! Seems there are no files in that + * directory. */ + dirp->dd_stat = -1; + } + else + { + dirp->dd_stat = 1; + } + } + else + { + /* Get the next search entry. */ + if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) + { + /* We are off the end or otherwise error. + _findnext sets errno to ENOENT if no more file + Undo this. */ + DWORD winerr = GetLastError (); + if (winerr == ERROR_NO_MORE_FILES) + errno = 0; + _findclose (dirp->dd_handle); + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Update the status to indicate the correct + * number. */ + dirp->dd_stat++; + } + } + + if (dirp->dd_stat > 0) + { + /* Successfully got an entry. Everything about the file is + * already appropriately filled in except the length of the + * file name. */ + dirp->dd_dir.d_namlen = (unsigned short)strlen (dirp->dd_dta.name); + strcpy (dirp->dd_dir.d_name, dirp->dd_dta.name); + return &dirp->dd_dir; + } + + return (struct dirent *) 0; +} + + +/* + * closedir + * + * Frees up resources allocated by opendir. + */ +int +closedir (DIR * dirp) +{ + int rc; + + errno = 0; + rc = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + + if (dirp->dd_handle != -1) + { + rc = _findclose (dirp->dd_handle); + } + + /* Delete the dir structure. */ + free (dirp); + + return rc; +} + +/* + * rewinddir + * + * Return to the beginning of the directory "stream". We simply call findclose + * and then reset things like an opendir. + */ +void +rewinddir (DIR * dirp) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return; + } + + if (dirp->dd_handle != -1) + { + _findclose (dirp->dd_handle); + } + + dirp->dd_handle = -1; + dirp->dd_stat = 0; +} + +/* + * telldir + * + * Returns the "position" in the "directory stream" which can be used with + * seekdir to go back to an old entry. We simply return the value in stat. + */ +long +telldir (DIR * dirp) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + return dirp->dd_stat; +} + +/* + * seekdir + * + * Seek to an entry previously returned by telldir. We rewind the directory + * and call readdir repeatedly until either dd_stat is the position number + * or -1 (off the end). This is not perfect, in that the directory may + * have changed while we weren't looking. But that is probably the case with + * any such system. + */ +void +seekdir (DIR * dirp, long lPos) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return; + } + + if (lPos < -1) + { + /* Seeking to an invalid position. */ + errno = EINVAL; + return; + } + else if (lPos == -1) + { + /* Seek past end. */ + if (dirp->dd_handle != -1) + { + _findclose (dirp->dd_handle); + } + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Rewind and read forward to the appropriate index. */ + rewinddir (dirp); + + while ((dirp->dd_stat < lPos) && readdir (dirp)) + ; + } +} + +#else + +int _utk_w32_dirent_c_shut_up_stupid_compiler_warning; + +#endif /* WIN32 */ diff --git a/src/glut/w32dir.h b/src/glut/w32dir.h new file mode 100644 index 0000000..5b256bc --- /dev/null +++ b/src/glut/w32dir.h @@ -0,0 +1,121 @@ +/* + * DIRENT.H (formerly DIRLIB.H) + * This file has no copyright assigned and is placed in the Public Domain. + * This file is a part of the mingw-runtime package. + * No warranty is given; refer to the file DISCLAIMER within the package. + * + */ +#ifndef W32_DIRENT_H_ +#define W32_DIRENT_H_ + +#include +#include + +#ifndef RC_INVOKED + +#ifdef __cplusplus +extern "C" { +#endif + +struct dirent +{ + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + char d_name[FILENAME_MAX]; /* File name. */ +}; + +/* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + * dd_stat field is now int (was short in older versions). + */ +typedef struct +{ + /* disk transfer area for this dir */ + struct _finddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct dirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + char dd_name[1]; +} DIR; + +DIR* __cdecl opendir (const char*); +struct dirent* __cdecl readdir (DIR*); +int __cdecl closedir (DIR*); +void __cdecl rewinddir (DIR*); +long __cdecl telldir (DIR*); +void __cdecl seekdir (DIR*, long); + + +/* wide char versions */ + +struct _wdirent +{ + long d_ino; /* Always zero. */ + unsigned short d_reclen; /* Always zero. */ + unsigned short d_namlen; /* Length of name in d_name. */ + wchar_t d_name[FILENAME_MAX]; /* File name. */ +}; + +/* + * This is an internal data structure. Good programmers will not use it + * except as an argument to one of the functions below. + */ +typedef struct +{ + /* disk transfer area for this dir */ + struct _wfinddata_t dd_dta; + + /* dirent struct to return from dir (NOTE: this makes this thread + * safe as long as only one thread uses a particular DIR struct at + * a time) */ + struct _wdirent dd_dir; + + /* _findnext handle */ + long dd_handle; + + /* + * Status of search: + * 0 = not started yet (next entry to read is first entry) + * -1 = off the end + * positive = 0 based index of next entry + */ + int dd_stat; + + /* given path for dir with search pattern (struct is extended) */ + wchar_t dd_name[1]; +} _WDIR; + + + +_WDIR* __cdecl _wopendir (const wchar_t*); +struct _wdirent* __cdecl _wreaddir (_WDIR*); +int __cdecl _wclosedir (_WDIR*); +void __cdecl _wrewinddir (_WDIR*); +long __cdecl _wtelldir (_WDIR*); +void __cdecl _wseekdir (_WDIR*, long); + + +#ifdef __cplusplus +} +#endif + +#endif /* Not RC_INVOKED */ + +#endif /* Not _DIRENT_H_ */ diff --git a/src/noise.c b/src/noise.c index 4401e5a..63bfa82 100644 --- a/src/noise.c +++ b/src/noise.c @@ -186,12 +186,12 @@ float noise3(float x, float y, float z) c = lerp(a, b, sy); /* interpolate along the bottom slice of the cell */ - u = dotgrad3(grad3[b00 + bz0], rx0, ry0, rz1); - v = dotgrad3(grad3[b10 + bz0], rx1, ry0, rz1); + u = dotgrad3(grad3[b00 + bz1], rx0, ry0, rz1); + v = dotgrad3(grad3[b10 + bz1], rx1, ry0, rz1); a = lerp(u, v, sx); - u = dotgrad3(grad3[b01 + bz0], rx0, ry1, rz1); - v = dotgrad3(grad3[b11 + bz0], rx1, ry1, rz1); + u = dotgrad3(grad3[b01 + bz1], rx0, ry1, rz1); + v = dotgrad3(grad3[b11 + bz1], rx1, ry1, rz1); b = lerp(u, v, sx); d = lerp(a, b, sy); @@ -298,12 +298,12 @@ float pnoise3(float x, float y, float z, int per_x, int per_y, int per_z) c = lerp(a, b, sy); /* interpolate along the bottom slice of the cell */ - u = dotgrad3(grad3[b00 + bz0], rx0, ry0, rz1); - v = dotgrad3(grad3[b10 + bz0], rx1, ry0, rz1); + u = dotgrad3(grad3[b00 + bz1], rx0, ry0, rz1); + v = dotgrad3(grad3[b10 + bz1], rx1, ry0, rz1); a = lerp(u, v, sx); - u = dotgrad3(grad3[b01 + bz0], rx0, ry1, rz1); - v = dotgrad3(grad3[b11 + bz0], rx1, ry1, rz1); + u = dotgrad3(grad3[b01 + bz1], rx0, ry1, rz1); + v = dotgrad3(grad3[b11 + bz1], rx1, ry1, rz1); b = lerp(u, v, sx); d = lerp(a, b, sy); diff --git a/src/rlebmap.c b/src/rlebmap.c new file mode 100644 index 0000000..de5e168 --- /dev/null +++ b/src/rlebmap.c @@ -0,0 +1,309 @@ +#include +#include +#include "rlebmap.h" + +/* Number of numbers per scanline. Each streak has 2 numbers (start, length) */ +#define RLE_ELEMENTS_PER_SCANLINE RLE_STREAKS_PER_SCANLINE * 2 + +/* Two RLE_TYPE elements per streak (= start,length) */ +#define RLE_BYTES_PER_SCANLINE RLE_ELEMENTS_PER_SCANLINE * sizeof(RLE_TYPE) + +/* RLE_TYPE count required for storing an RLE of w,h */ +static int rleWorstCaseElementCount(int w, int h) { + /* Allocate an extra worst case for one scanline, which is w/2 streaks = w + * (start,length) elements */ + return h * RLE_ELEMENTS_PER_SCANLINE + w; +} + +/* Byte count of the 'scans' buffer */ +static int rleScansByteCount(RleBitmap *rle) { + return rleWorstCaseElementCount(rle->w, rle->h) * sizeof(RLE_TYPE); +} + +RleBitmap *rleCreate(unsigned int w, unsigned int h) { + RleBitmap *ret = malloc(sizeof(RleBitmap)); + ret->w = w; + ret->h = h; + + /* Allocate scans */ + ret->scans = calloc(rleWorstCaseElementCount(w, h), sizeof(RLE_TYPE)); + + return ret; +} + +void rleDestroy(RleBitmap *b) { + if (!b) + return; + free(b->scans); + free(b); +} + +void rleClear(RleBitmap *rle) { memset(rle->scans, 0, rleScansByteCount(rle)); } + +RleBitmap *rleEncode(RleBitmap *rle, unsigned char *pixels, unsigned int pixelsW, + unsigned int pixelsH) { + int x = 0; + int y = 0; + int streakActive = 0; + int currentStreakLength = 0; + RLE_TYPE *output = 0; + unsigned char *currentInputPixel = pixels; + + /* https://www.youtube.com/watch?v=RKMR02o1I88&feature=youtu.be&t=55 */ + if (!rle) + rle = rleCreate(pixelsW, pixelsH); + else + rleClear(rle); /* The following code assumes cleared array */ + + for (y = 0; y < pixelsH; y++) { + /* Go to the beginning of the RLE scan */ + output = rle->scans + y * RLE_ELEMENTS_PER_SCANLINE; + + for (x = 0; x < pixelsW; x++) { + if (*currentInputPixel++) { + if (streakActive) { + if (currentStreakLength >= RLE_MAX_STREAK_LENGTH) { + /* Do not allow streaks of more than max length - + * close current streak */ + *output++ = (RLE_TYPE)currentStreakLength; + + /* Begin new streak at current x */ + *output++ = (RLE_TYPE)x; + currentStreakLength = 0; + } + } else { + /* Begin new streak */ + *output++ = (RLE_TYPE)x; + currentStreakLength = 0; + streakActive = 1; + } + currentStreakLength++; + } else { + if (streakActive) { + /* Close current streak */ + *output++ = (RLE_TYPE)currentStreakLength; + currentStreakLength = 0; + streakActive = 0; + } + } /* End if (current pixel on) */ + } /* End for (all x) */ + + /* We reached the end of the scan - close any active streak */ + if (streakActive) { + *output++ = (RLE_TYPE)currentStreakLength; + } + streakActive = 0; + currentStreakLength = 0; + } /* End for (all scans */ + + return rle; +} + +void rleDistributeStreaks(RleBitmap *rle) { + int scanline = 0; + int halfW = rle->w >> 1; + RLE_TYPE *ptr = 0; + RLE_TYPE tmp = 0; + +#define LAST_STREAK RLE_STREAKS_PER_SCANLINE + + ptr = rle->scans; + for (scanline = 0; scanline < rle->h; scanline++) { + if (ptr[0] >= halfW) { + /* Exchange first with last streak */ + tmp = ptr[0]; + ptr[0] = ptr[LAST_STREAK * 2 - 2]; + ptr[LAST_STREAK * 2 - 2] = tmp; + tmp = ptr[1]; + ptr[1] = ptr[LAST_STREAK * 2 - 1]; + ptr[LAST_STREAK * 2 - 1] = tmp; + } + + ptr += 8; + } +} + +void rleBlit(RleBitmap *rle, unsigned short *dst, int dstW, int dstH, int dstStride, int blitX, + int blitY) { + int scanline = 0; + int streakPos = 0; + int streakLength = 0; + int streak = 0; + RLE_TYPE *input = rle->scans; + unsigned short *output; + unsigned int *output32; + + dst += blitX + blitY * dstStride; + + for (scanline = blitY; scanline < blitY + rle->h; scanline++) { + if (scanline < 0 || scanline >= dstH) + continue; + for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) { + streakPos = (int)*input++; + streakLength = (int)*input++; + + if ((streakPos + blitX) <= 0) + continue; + + output = dst + streakPos; + + /* Check if we need to write the first pixel as 16bit */ + if (streakLength % 2) { + *output++ = RLE_FILL_COLOR; + } + + /* Then, write 2 pixels at a time */ + streakLength >>= 1; + output32 = (unsigned int *)output; + while (streakLength--) { + *output32++ = RLE_FILL_COLOR_32; + } + } + + dst += dstStride; + } +} + +/* This is madness. We could at least check that we are not interpolating from 0 -> something + * (length). This could remove the need for 'distributeScans' */ +void interpolateScan(RLE_TYPE *output, RLE_TYPE *a, RLE_TYPE *b, float t) { + static int div = 1 << 23; + int ti, i; + + t += 1.0f; + ti = (*((unsigned int *)&t)) & 0x7FFFFF; + + for (i = 0; i < RLE_ELEMENTS_PER_SCANLINE; i++) { + if (*a == 0) { + *output++ = *b++; + a++; + } else { + if (*b == 0) { + *output++ = *a++; + b++; + } else { + *output++ = ((*b++ * ti) + (*a++ * (div - ti))) >> 23; + } + } + } +} + +void rleBlitScale(RleBitmap *rle, unsigned short *dst, int dstW, int dstH, int dstStride, int blitX, + int blitY, float scaleX, float scaleY) { + int scanline = 0; + int streakPos = 0; + int streakLength = 0; + int streak = 0; + unsigned short *output; + unsigned int *output32; + unsigned char *input; + int scanlineCounter = 0; + int scaleXFixed; + static unsigned char scan[512]; + + /*int blitW = (int)(rle->w * scaleX + 0.5f);*/ + int blitH = (int)(rle->h * scaleY + 0.5f); + + /* From this point on, scaleY will be inverted */ + scaleY = 1.0f / scaleY; + + scaleXFixed = (int)(scaleX * (float)(1 << RLE_FIXED_BITS) + 0.5f); + + dst += blitX + blitY * dstStride; + + for (scanline = blitY; scanline < blitY + blitH; scanline++) { + float normalScan = scanlineCounter * scaleY; /* ScaleY is inverted */ + unsigned char *scan0 = rle->scans + RLE_BYTES_PER_SCANLINE * (int)normalScan; + unsigned char *scan1 = scan0 + RLE_BYTES_PER_SCANLINE; + normalScan -= (int)normalScan; + interpolateScan(scan, scan0, scan1, normalScan); + input = scan; + scanlineCounter++; + + if (scanline < 0 || scanline >= dstH) + continue; + for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) { + streakPos = (*input++ * scaleXFixed) >> RLE_FIXED_BITS; + streakLength = (*input++ * scaleXFixed) >> RLE_FIXED_BITS; + + if ((streakPos + blitX) <= 0) + continue; + + output = dst + streakPos; + + /* Check if we need to write the first pixel as 16bit */ + if (streakLength % 2) { + *output++ = RLE_FILL_COLOR; + } + + /* Then, write 2 pixels at a time */ + streakLength >>= 1; + output32 = (unsigned int *)output; + while (streakLength--) { + *output32++ = RLE_FILL_COLOR_32; + } + } + + dst += dstStride; + } +} + +void rleBlitScaleInv(RleBitmap *rle, unsigned short *dst, int dstW, int dstH, int dstStride, + int blitX, int blitY, float scaleX, float scaleY) { + int scanline = 0; + int streakPos = 0; + int streakLength = 0; + int streak = 0; + unsigned short *output; + unsigned int *output32; + unsigned char *input; + int scanlineCounter = 0; + int scaleXFixed; + static unsigned char scan[512]; + + /*int blitW = (int)(rle->w * scaleX + 0.5f);*/ + int blitH = (int)(rle->h * scaleY + 0.5f); + + /* From this point on, scaleY will be inverted */ + scaleY = 1.0f / scaleY; + + scaleXFixed = (int)(scaleX * (float)(1 << RLE_FIXED_BITS) + 0.5f); + + dst += blitX + blitY * dstStride; + + for (scanline = blitY; scanline > blitY - blitH; scanline--) { + float normalScan = scanlineCounter * scaleY; /* ScaleY is inverted */ + unsigned char *scan0 = rle->scans + RLE_BYTES_PER_SCANLINE * (int)normalScan; + unsigned char *scan1 = scan0 + RLE_BYTES_PER_SCANLINE; + normalScan -= (int)normalScan; + interpolateScan(scan, scan0, scan1, normalScan); + input = scan; + scanlineCounter++; + + if (scanline < 0 || scanline >= dstH) + continue; + for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) { + streakPos = (*input++ * scaleXFixed) >> RLE_FIXED_BITS; + streakLength = (*input++ * scaleXFixed) >> RLE_FIXED_BITS; + + if ((streakPos + blitX) <= 0) + continue; + + output = dst + streakPos; + + /* Check if we need to write the first pixel as 16bit */ + if (streakLength % 2) { + *output++ = RLE_FILL_COLOR; + } + + /* Then, write 2 pixels at a time */ + streakLength >>= 1; + output32 = (unsigned int *)output; + while (streakLength--) { + *output32++ = RLE_FILL_COLOR_32; + } + } + + dst -= dstStride; + } +} diff --git a/src/rlebmap.h b/src/rlebmap.h new file mode 100644 index 0000000..3f36b16 --- /dev/null +++ b/src/rlebmap.h @@ -0,0 +1,66 @@ +#ifndef __RLE_BITMAP_H__ +#define __RLE_BITMAP_H__ + +/* Limit streak count per scanline so we can directly jump to specific scanline + */ +#define RLE_STREAKS_PER_SCANLINE 4 + +/* Streaks will not exceed this many pixels. This allows us to optimize with a + * padded framebuffer. If a streak start position happens to lie within + * framebuffer, we will blit it without checking for out of bounds */ +#define RLE_MAX_STREAK_LENGTH 32 + +/* Using the following type for storing start and for storing length in (start, + * length) pairs. */ +#define RLE_TYPE unsigned char + +/* For now, keep a static fill color. We can change this. Not that much about + * speed, but let's keep function definitions more compact. */ +#define RLE_FILL_COLOR 0 + +/* Two entries of RLE_FILL_COLOR (16 bits) packed one after the other. */ +#define RLE_FILL_COLOR_32 ((RLE_FILL_COLOR << 16) | RLE_FILL_COLOR) + +/* For fixed-point arithmetic. Used for scaling. */ +#define RLE_FIXED_BITS 16 + +/* This is a bitmap (image in 1bpp), encoded as streaks of consecutive pixels. + */ +typedef struct { + unsigned int w, h; + + /* Each scan is RLE_BYTES_PER_SCANLINE long and contains pairs of + * (start, length). */ + RLE_TYPE *scans; +} RleBitmap; + +/* Constructor */ +RleBitmap *rleCreate(unsigned int w, unsigned int h); + +/* Destructor */ +void rleDestroy(RleBitmap *rle); + +/* Clears 'rle' to "all transparent" */ +void rleClear(RleBitmap *rle); + +/* Encode 'pixels' into 'rle' and also return it. Pixels are either 0 or 1. This + * will create an RleBitmap of 'h' scanlines. */ +RleBitmap *rleEncode(RleBitmap *rle, unsigned char *pixels, unsigned int pixelsW, + unsigned int pixelsH); + +/* Rearranges the streaks to make it less frequent that they produce garbege when interpolated */ +void rleDistributeStreaks(RleBitmap *rle); + +/* Blits without scaling */ +void rleBlit(RleBitmap *rle, unsigned short *dst, int dstW, int dstH, int dstStride, int blitX, + int blitY); + +/* Scaled blit */ +void rleBlitScale(RleBitmap *rle, unsigned short *dst, int dstW, int dstH, int dstStride, int blitX, + int blitY, float scaleX, float scaleY); + +/* Inverted blit (upside down) */ +void rleBlitScaleInv(RleBitmap *rle, unsigned short *dst, int dstW, int dstH, int dstStride, + int blitX, int blitY, float scaleX, float scaleY); + +#endif // __RLE_BITMAP_H__ diff --git a/src/sball.h b/src/sball.h index e12b12c..e26d336 100644 --- a/src/sball.h +++ b/src/sball.h @@ -1,36 +1,36 @@ -#ifndef SBALL_H_ -#define SBALL_H_ - -enum { - SBALL_EV_NONE, - SBALL_EV_MOTION, - SBALL_EV_BUTTON -}; - -struct sball_event_motion { - int type; - int motion[6]; -}; - -struct sball_event_button { - int type; - int id; - int pressed; - unsigned int state; -}; - -typedef union sball_event { - int type; - struct sball_event_motion motion; - struct sball_event_button button; -} sball_event; - -int sball_init(void); -void sball_shutdown(void); - -int sball_getdev(void); - -int sball_pending(void); -int sball_getevent(sball_event *ev); - -#endif /* SBALL_H_ */ +#ifndef SBALL_H_ +#define SBALL_H_ + +enum { + SBALL_EV_NONE, + SBALL_EV_MOTION, + SBALL_EV_BUTTON +}; + +struct sball_event_motion { + int type; + int motion[6]; +}; + +struct sball_event_button { + int type; + int id; + int pressed; + unsigned int state; +}; + +typedef union sball_event { + int type; + struct sball_event_motion motion; + struct sball_event_button button; +} sball_event; + +int sball_init(void); +void sball_shutdown(void); + +int sball_getdev(void); + +int sball_pending(void); +int sball_getevent(sball_event *ev); + +#endif /* SBALL_H_ */ diff --git a/src/scr/cybersun.c b/src/scr/cybersun.c new file mode 100644 index 0000000..fde29ab --- /dev/null +++ b/src/scr/cybersun.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include "demo.h" +#include "3dgfx.h" +#include "screen.h" +#include "gfxutil.h" +#include "mesh.h" +#include "image.h" +#include "util.h" +#include "cgmath/cgmath.h" + +#define TM_RIPPLE_START 1.0f +#define TM_RIPPLE_TRANS_LEN 3.0f + +#define VFOV 50.0f +#define HFOV (VFOV * 1.333333f) + +static int init(void); +static void destroy(void); +static void start(long trans_time); +static void draw(void); +static void draw_mountains(void); + +static struct screen scr = { + "cybersun", + init, + destroy, + start, + 0, + draw +}; + +static float cam_theta = 0, cam_phi = 0; +static float cam_dist = 0; + +static struct g3d_mesh gmesh; +#define GMESH_GRIDSZ 25 +#define GMESH_SIZE 128 +static struct image gtex; + +#define MOUNTIMG_WIDTH 512 +#define MOUNTIMG_HEIGHT 64 +static struct image mountimg; +static int mountimg_skip[MOUNTIMG_WIDTH]; + +static long part_start; + + +struct screen *cybersun_screen(void) +{ + return &scr; +} + +static int init(void) +{ + int i, j; + + if(gen_plane_mesh(&gmesh, GMESH_SIZE, GMESH_SIZE, GMESH_GRIDSZ, GMESH_GRIDSZ) == -1) { + return -1; + } + for(i=0; iz = sin(x * 0.5 + t) + cos(x * 0.8f) * 0.5f; + vptr->z += cos(y * 0.5 + t); + vptr->z += sin(r + t) * 0.5f; + vptr->z *= r * 0.1f > 1.0f ? 1.0f : r * 0.1f; + vptr->z *= ampl; + vptr++; + } + } +} + +static void draw(void) +{ + int i; + + update(); + + g3d_matrix_mode(G3D_MODELVIEW); + g3d_load_identity(); + g3d_translate(0, -2, -cam_dist); + g3d_rotate(cam_phi, 1, 0, 0); + g3d_rotate(cam_theta, 0, 1, 0); + if(opt.sball) { + g3d_mult_matrix(sball_matrix); + } + + g3d_clear(G3D_COLOR_BUFFER_BIT | G3D_DEPTH_BUFFER_BIT); + draw_mountains(); + + g3d_set_texture(gtex.width, gtex.height, gtex.pixels); + g3d_enable(G3D_TEXTURE_2D); + g3d_enable(G3D_DEPTH_TEST); + + g3d_push_matrix(); + g3d_rotate(-90, 1, 0, 0); + draw_mesh(&gmesh); + g3d_pop_matrix(); + + g3d_disable(G3D_DEPTH_TEST); + g3d_disable(G3D_TEXTURE_2D); + + swap_buffers(fb_pixels); +} + +/* XXX all the sptr calculations assume mountimg.width == 512 */ +static void draw_mountains(void) +{ + int i, j, horizon_y, y; + int32_t x, xstart, xend, dx; + uint16_t *dptr, *sptr; + + /* 24.8 fixed point, 512 width, 90deg arc */ + xstart = cround64(cam_theta * (256.0 * MOUNTIMG_WIDTH / 90.0)); + xend = cround64((cam_theta + HFOV) * (256.0 * MOUNTIMG_WIDTH / 90.0)); + dx = (xend - xstart) / FB_WIDTH; + x = xstart; + + horizon_y = cround64(-cam_phi * (FB_HEIGHT / 45.0)) + FB_HEIGHT / 2; + y = horizon_y - MOUNTIMG_HEIGHT; + + if(y >= FB_HEIGHT) { + /* TODO draw gradient for the sky */ + return; + } + if(horizon_y < 0) { + memset(fb_pixels, 0, FB_WIDTH * FB_HEIGHT * 2); + return; + } + + for(i=0; i> 8) & 0x1ff]; + int vspan = MOUNTIMG_HEIGHT - skip; + + dptr = fb_pixels + (y + skip) * FB_WIDTH + i; + + for(j=0; j +#include #include #include #include -#include -#include -#include "imago2.h" -#include "demo.h" -#include "screen.h" -/* APPROX. 170 FPS Minimum */ +#include "rlebmap.h" -typedef struct { - unsigned int w, h; - unsigned char *scans; -} RLEBitmap; - -static RLEBitmap *rleCreate(unsigned int w, unsigned int h); -static void rleDestroy(RLEBitmap *b); -static void rleBlit(unsigned short *dst, int dstW, int dstH, int dstStride, - RLEBitmap *bitmap, int blitX, int blitY); -static void rleBlitScale(unsigned short *dst, int dstW, int dstH, int dstStride, - RLEBitmap *bitmap, int blitX, int blitY, float scaleX, float scaleY); -static void rleBlitScaleInv(unsigned short *dst, int dstW, int dstH, int dstStride, - RLEBitmap *bitmap, int blitX, int blitY, float scaleX, float scaleY); -static RLEBitmap *rleEncode(RLEBitmap *b, unsigned char *pixels, unsigned int w, unsigned int h); +/* APPROX. 170 FPS Minimum */ static void updatePropeller(float t); #define BG_FILENAME "data/grise.png" #define GROBJ_01_FILENAME "data/grobj_01.png" -#define BB_SIZE 512 /* Let's use a power of 2. Maybe we'll zoom/rotate the effect */ +#define BB_SIZE 512 /* Let's use a power of 2. Maybe we'll zoom/rotate the effect */ /* Every backBuffer scanline is guaranteed to have that many dummy pixels before and after */ #define PIXEL_PADDING 32 @@ -59,8 +46,6 @@ static void processNormal(); static void initScrollTables(); static void updateScrollTables(float dt); - - static unsigned short *background = 0; static int backgroundW = 0; static int backgroundH = 0; @@ -80,42 +65,37 @@ static float nearScrollAmount = 0.0f; static unsigned char miniFXBuffer[1024]; -static RLEBitmap *grobj = 0; -static RLEBitmap *rlePropeller = 0; +static RleBitmap *grobj = 0; +static RleBitmap *rlePropeller = 0; -static struct screen scr = { - "galaxyrise", - init, - destroy, - start, - 0, - draw -}; +static struct screen scr = {"galaxyrise", init, destroy, start, 0, draw}; -struct screen *grise_screen(void) -{ +struct screen *grise_screen(void) { return &scr; } -static int init(void) -{ +static int init(void) { unsigned char *tmpBitmap; int tmpBitmapW, tmpBitmapH; /* Allocate back buffer */ - backBuffer = (unsigned short*) calloc(BB_SIZE * BB_SIZE, sizeof(unsigned short)); + backBuffer = (unsigned short *)calloc(BB_SIZE * BB_SIZE, sizeof(unsigned short)); - /* grise.png contains the background (horizon), baked reflection and normalmap for displacement */ - if (!(background = img_load_pixels(BG_FILENAME, &backgroundW, &backgroundH, IMG_FMT_RGBA32))) { + /* grise.png contains the background (horizon), baked reflection and normalmap for + * displacement */ + if (!(background = + img_load_pixels(BG_FILENAME, &backgroundW, &backgroundH, IMG_FMT_RGBA32))) { fprintf(stderr, "failed to load image " BG_FILENAME "\n"); return -1; } /* Convert to 16bpp */ - convert32To16((unsigned int*)background, background, backgroundW * NORMALMAP_SCANLINE); /* Normalmap will keep its 32 bit color */ + convert32To16((unsigned int *)background, background, + backgroundW * NORMALMAP_SCANLINE); /* Normalmap will keep its 32 bit color */ /* Load reflected objects */ - if (!(tmpBitmap = img_load_pixels(GROBJ_01_FILENAME, &tmpBitmapW, &tmpBitmapH, IMG_FMT_GREY8))) { + if (!(tmpBitmap = + img_load_pixels(GROBJ_01_FILENAME, &tmpBitmapW, &tmpBitmapH, IMG_FMT_GREY8))) { fprintf(stderr, "failed to load image " GROBJ_01_FILENAME "\n"); return -1; } @@ -131,8 +111,7 @@ static int init(void) return 0; } -static void destroy(void) -{ +static void destroy(void) { free(backBuffer); backBuffer = 0; @@ -141,14 +120,9 @@ static void destroy(void) rleDestroy(grobj); } -static void start(long trans_time) -{ - lastFrameTime = time_msec; -} - +static void start(long trans_time) { lastFrameTime = time_msec; } -static void draw(void) -{ +static void draw(void) { int scroll = MIN_SCROLL + (MAX_SCROLL - MIN_SCROLL) * mouse_x / FB_WIDTH; unsigned short *dst = backBuffer + PIXEL_PADDING; unsigned short *src = background + scroll; @@ -188,7 +162,9 @@ static void draw(void) } /* Blit reflections first, to be displaced */ - for (i = 0; i < 5; i++) rleBlitScaleInv(backBuffer + PIXEL_PADDING, FB_WIDTH, FB_HEIGHT, BB_SIZE, rlePropeller, 134 + (i-3) * 60, 200, 1.0f, 1.8f); + for (i = 0; i < 5; i++) + rleBlitScaleInv(rlePropeller, backBuffer + PIXEL_PADDING, FB_WIDTH, FB_HEIGHT, + BB_SIZE, 134 + (i - 3) * 60, 200, 1.0f, 1.8f); /* Perform displacement */ dst = backBuffer + HORIZON_HEIGHT * BB_SIZE + PIXEL_PADDING; @@ -202,9 +178,11 @@ static void draw(void) for (i = 0; i < FB_WIDTH; i++) { /* Try to immitate modulo without the division */ - if (i == md) accum += md; + if (i == md) + accum += md; scrolledIndex = i - accum + sc; - if (scrolledIndex >= md) scrolledIndex -= md; + if (scrolledIndex >= md) + scrolledIndex -= md; /* Displace */ d = dispScanline[scrolledIndex]; @@ -216,7 +194,9 @@ static void draw(void) } /* Then after displacement, blit the objects */ - for (i = 0; i < 5; i++) rleBlit(backBuffer + PIXEL_PADDING, FB_WIDTH, FB_HEIGHT, BB_SIZE, rlePropeller, 134 + (i-3) * 60, 100); + for (i = 0; i < 5; i++) + rleBlit(rlePropeller, backBuffer + PIXEL_PADDING, FB_WIDTH, FB_HEIGHT, BB_SIZE, + 134 + (i - 3) * 60, 100); /* Blit effect to framebuffer */ src = backBuffer + PIXEL_PADDING; @@ -235,9 +215,9 @@ static void convert32To16(unsigned int *src32, unsigned short *dst16, unsigned i unsigned int p; while (pixelCount) { p = *src32++; - *dst16++ = ((p << 8) & 0xF800) /* R */ - | ((p >> 5) & 0x07E0) /* G */ - | ((p >> 19) & 0x001F); /* B */ + *dst16++ = ((p << 8) & 0xF800) /* R */ + | ((p >> 5) & 0x07E0) /* G */ + | ((p >> 19) & 0x001F); /* B */ pixelCount--; } } @@ -252,20 +232,22 @@ static void processNormal() { short minDisplacement = 256; unsigned short *dst; short *dst2; - unsigned int *normalmap = (unsigned int*)background; + unsigned int *normalmap = (unsigned int *)background; normalmap += NORMALMAP_SCANLINE * backgroundW; - dst = (unsigned short*)normalmap; - displacementMap = (short*)dst; + dst = (unsigned short *)normalmap; + displacementMap = (short *)dst; dst2 = displacementMap; for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) { - scrollModTable[scanline] = (int) (backgroundW / scrollScaleTable[scanline] + 0.5f); + scrollModTable[scanline] = (int)(backgroundW / scrollScaleTable[scanline] + 0.5f); for (i = 0; i < backgroundW; i++) { x = (int)(i * scrollScaleTable[scanline] + 0.5f); if (x < backgroundW) { *dst = (unsigned short)(normalmap[x] >> 8) & 0xFF; - if ((short)*dst > maxDisplacement) maxDisplacement = (short)(*dst); - if ((short)*dst < minDisplacement) minDisplacement = (short)(*dst); + if ((short)*dst > maxDisplacement) + maxDisplacement = (short)(*dst); + if ((short)*dst < minDisplacement) + minDisplacement = (short)(*dst); } else { *dst = 0; } @@ -282,9 +264,13 @@ static void processNormal() { /* Second pass - subtract half maximum displacement to displace in both directions */ for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) { for (i = 0; i < backgroundW; i++) { - /* Remember that MIN_SCROLL is the padding around the screen, so ti's the maximum displacement we can get (positive & negative) */ - *dst2 = 2 * MAX_DISPLACEMENT * (*dst2 - minDisplacement) / (maxDisplacement - minDisplacement) - MAX_DISPLACEMENT; - *dst2 = (short)((float)*dst2 / scrollScaleTable[scanline] + 0.5f); /* Displacements must also scale with distance*/ + /* Remember that MIN_SCROLL is the padding around the screen, so ti's the + * maximum displacement we can get (positive & negative) */ + *dst2 = 2 * MAX_DISPLACEMENT * (*dst2 - minDisplacement) / + (maxDisplacement - minDisplacement) - + MAX_DISPLACEMENT; + *dst2 = (short)((float)*dst2 / scrollScaleTable[scanline] + + 0.5f); /* Displacements must also scale with distance*/ dst2++; } } @@ -306,12 +292,11 @@ static void initScrollTables() { } } - static void updateScrollTables(float dt) { int i = 0; nearScrollAmount += dt * NEAR_SCROLL_SPEED; - nearScrollAmount = (float) fmod(nearScrollAmount, 512.0f); + nearScrollAmount = (float)fmod(nearScrollAmount, 512.0f); for (i = 0; i < REFLECTION_HEIGHT; i++) { scrollTable[i] = nearScrollAmount / scrollScaleTable[i]; @@ -320,298 +305,9 @@ static void updateScrollTables(float dt) { } /* ------------------------------------------------------------------------------------------------- - * RLE STUFF + * PROPELLER STUFF * ------------------------------------------------------------------------------------------------- */ -/* Limit streak count per scanline so we can directly jump to specific scanline */ -#define RLE_STREAKS_PER_SCANLINE 4 -/* Every streak is encoded by 2 bytes: offset and count of black pixels in the streak */ -#define RLE_BYTES_PER_SCANLINE RLE_STREAKS_PER_SCANLINE * 2 -#define RLE_FILL_COLOR 0 -#define RLE_FILL_COLOR_32 ((RLE_FILL_COLOR << 16) | RLE_FILL_COLOR) - -#define RLE_FIXED_BITS 16 - -static int rleByteCount(int w, int h) { - return h * RLE_BYTES_PER_SCANLINE + w; -} - -static RLEBitmap *rleCreate(unsigned int w, unsigned int h) { - RLEBitmap *ret = (RLEBitmap*)malloc(sizeof(RLEBitmap)); - ret->w = w; - ret->h = h; - - /* Add some padding at the end of the buffer, with the worst case for a scanline (w/2 streaks) */ - ret->scans = (unsigned char*) calloc(rleByteCount(w, h), 1); - - return ret; -} - -static void rleDestroy(RLEBitmap *b) { - if (!b) return; - free(b->scans); - free(b); -} - -static RLEBitmap *rleEncode(RLEBitmap *b, unsigned char *pixels, unsigned int w, unsigned int h) { - int scanline; - int i; - int penActive = 0; - int counter = 0; - int accum = 0; - unsigned char *output; - - /* https://www.youtube.com/watch?v=RKMR02o1I88&feature=youtu.be&t=55 */ - if (!b) b = rleCreate(w, h); - else memset(b->scans, 0, rleByteCount(b->w, b->h)); /* The following code assumes cleared array */ - - for (scanline = 0; scanline < h; scanline++) { - output = b->scans + scanline * RLE_BYTES_PER_SCANLINE; - accum = 0; - for (i = 0; i < w; i++) { - if (*pixels++) { - if (penActive) { - if (counter >= PIXEL_PADDING) { - *output++ = (unsigned char) counter; - counter = 0; - *output++ = (unsigned char)accum; - } - counter++; - accum++; - } else { - *output++ = (unsigned char)accum; - counter = 1; - accum++; - penActive = 1; - } - } else { - if (penActive) { - *output++ = (unsigned char)counter; - counter = 1; - accum++; - penActive = 0; - } else { - counter++; - accum++; - } - } - } - - if (penActive) { - *output++ = (unsigned char)counter; - } - penActive = 0; - counter = 0; - } - - return b; -} - -static void rleDistributeStreaks(RLEBitmap *bitmap) { - int scanline, halfW = bitmap->w >> 1; - unsigned char *ptr, tmp; - - ptr = bitmap->scans; - for (scanline = 0; scanline < bitmap->h; scanline++) { - if (ptr[0] >= halfW) { - tmp = ptr[0]; - ptr[0] = ptr[6]; - ptr[6] = tmp; - tmp = ptr[1]; - ptr[1] = ptr[7]; - ptr[7] = tmp; - } - - ptr += 8; - } -} - -static void rleBlit(unsigned short *dst, int dstW, int dstH, int dstStride, - RLEBitmap *bitmap, int blitX, int blitY) -{ - int scanline = 0; - int streakPos = 0; - int streakLength = 0; - int streak = 0; - unsigned char *input = bitmap->scans; - unsigned short *output; - unsigned int *output32; - - dst += blitX + blitY * dstStride; - - for (scanline = blitY; scanline < blitY + bitmap->h; scanline++) { - if (scanline < 0 || scanline >= dstH) continue; - for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) { - streakPos = *input++; - streakLength = *input++; - - if ((streakPos + blitX) <= 0) continue; - - output = dst + streakPos; - - /* Check if we need to write the first pixel as 16bit */ - if (streakLength % 2) { - *output++ = RLE_FILL_COLOR; - } - - /* Then, write 2 pixels at a time */ - streakLength >>= 1; - output32 = (unsigned int*) output; - while (streakLength--) { - *output32++ = RLE_FILL_COLOR_32; - } - } - - dst += dstStride; - } -} - -static void interpolateScan(unsigned char *output, unsigned char *a, unsigned char *b, float t) { - static int div = 1 << 23; - int ti, i; - - t += 1.0f; - ti = (*((unsigned int*)&t)) & 0x7FFFFF; - - for (i = 0; i < RLE_BYTES_PER_SCANLINE; i++) { - if (*a == 0) { - *output++ = *b++; - a++; - } else { - if (*b == 0) { - *output++ = *a++; - b++; - } else { - *output++ = ((*b++ * ti) + (*a++ * (div - ti))) >> 23; - } - } - } -} - -static void rleBlitScale(unsigned short *dst, int dstW, int dstH, int dstStride, - RLEBitmap *bitmap, int blitX, int blitY, float scaleX, float scaleY) -{ - int scanline = 0; - int streakPos = 0; - int streakLength = 0; - int streak = 0; - unsigned short *output; - unsigned int *output32; - unsigned char *input; - int scanlineCounter = 0; - int scaleXFixed; - static unsigned char scan[512]; - - /*int blitW = (int)(bitmap->w * scaleX + 0.5f);*/ - int blitH = (int)(bitmap->h * scaleY + 0.5f); - - /* From this point on, scaleY will be inverted */ - scaleY = 1.0f / scaleY; - - scaleXFixed = (int)(scaleX * (float)(1 << RLE_FIXED_BITS) + 0.5f); - - dst += blitX + blitY * dstStride; - - for (scanline = blitY; scanline < blitY + blitH; scanline++) { - float normalScan = scanlineCounter * scaleY; /* ScaleY is inverted */ - unsigned char *scan0 = bitmap->scans + RLE_BYTES_PER_SCANLINE * (int)normalScan; - unsigned char *scan1 = scan0 + RLE_BYTES_PER_SCANLINE; - normalScan -= (int)normalScan; - interpolateScan(scan, scan0, scan1, normalScan); - input = scan; - scanlineCounter++; - - if (scanline < 0 || scanline >= dstH) continue; - for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) { - streakPos = (*input++ * scaleXFixed) >> RLE_FIXED_BITS; - streakLength = (*input++ * scaleXFixed) >> RLE_FIXED_BITS; - - if ((streakPos + blitX) <= 0) continue; - - output = dst + streakPos; - - /* Check if we need to write the first pixel as 16bit */ - if (streakLength % 2) { - *output++ = RLE_FILL_COLOR; - } - - /* Then, write 2 pixels at a time */ - streakLength >>= 1; - output32 = (unsigned int*)output; - while (streakLength--) { - *output32++ = RLE_FILL_COLOR_32; - } - } - - dst += dstStride; - } -} - - - -static void rleBlitScaleInv(unsigned short *dst, int dstW, int dstH, int dstStride, - RLEBitmap *bitmap, int blitX, int blitY, float scaleX, float scaleY) -{ - int scanline = 0; - int streakPos = 0; - int streakLength = 0; - int streak = 0; - unsigned short *output; - unsigned int *output32; - unsigned char *input; - int scanlineCounter = 0; - int scaleXFixed; - static unsigned char scan[512]; - - /*int blitW = (int)(bitmap->w * scaleX + 0.5f);*/ - int blitH = (int)(bitmap->h * scaleY + 0.5f); - - /* From this point on, scaleY will be inverted */ - scaleY = 1.0f / scaleY; - - scaleXFixed = (int)(scaleX * (float)(1 << RLE_FIXED_BITS) + 0.5f); - - dst += blitX + blitY * dstStride; - - for (scanline = blitY; scanline > blitY - blitH; scanline--) { - float normalScan = scanlineCounter * scaleY; /* ScaleY is inverted */ - unsigned char *scan0 = bitmap->scans + RLE_BYTES_PER_SCANLINE * (int)normalScan; - unsigned char *scan1 = scan0 + RLE_BYTES_PER_SCANLINE; - normalScan -= (int)normalScan; - interpolateScan(scan, scan0, scan1, normalScan); - input = scan; - scanlineCounter++; - - if (scanline < 0 || scanline >= dstH) continue; - for (streak = 0; streak < RLE_STREAKS_PER_SCANLINE; streak++) { - streakPos = (*input++ * scaleXFixed) >> RLE_FIXED_BITS; - streakLength = (*input++ * scaleXFixed) >> RLE_FIXED_BITS; - - if ((streakPos + blitX) <= 0) continue; - - output = dst + streakPos; - - /* Check if we need to write the first pixel as 16bit */ - if (streakLength % 2) { - *output++ = RLE_FILL_COLOR; - } - - /* Then, write 2 pixels at a time */ - streakLength >>= 1; - output32 = (unsigned int*)output; - while (streakLength--) { - *output32++ = RLE_FILL_COLOR_32; - } - } - - dst -= dstStride; - } -} - -/* ------------------------------------------------------------------------------------------------- -* PROPELLER STUFF -* ------------------------------------------------------------------------------------------------- -*/ #define PROPELLER_CIRCLE_RADIUS 18 #define PROPELLER_CIRCLE_RADIUS_SQ (PROPELLER_CIRCLE_RADIUS * PROPELLER_CIRCLE_RADIUS) @@ -667,17 +363,20 @@ static void updatePropeller(float t) { /* First circle */ cx = propellerState.circleX[0] - i; cy = propellerState.circleY[0] - j; - if (cx*cx + cy*cy < PROPELLER_CIRCLE_RADIUS_SQ) count++; + if (cx * cx + cy * cy < PROPELLER_CIRCLE_RADIUS_SQ) + count++; /* 2nd circle */ cx = propellerState.circleX[1] - i; cy = propellerState.circleY[1] - j; - if (cx*cx + cy*cy < PROPELLER_CIRCLE_RADIUS_SQ) count++; + if (cx * cx + cy * cy < PROPELLER_CIRCLE_RADIUS_SQ) + count++; /* 3rd circle */ cx = propellerState.circleX[2] - i; cy = propellerState.circleY[2] - j; - if (cx*cx + cy*cy < PROPELLER_CIRCLE_RADIUS_SQ) count++; + if (cx * cx + cy * cy < PROPELLER_CIRCLE_RADIUS_SQ) + count++; *dst++ = count >= 2; } diff --git a/src/scr/minifx.c b/src/scr/minifx.c new file mode 100644 index 0000000..84f9c38 --- /dev/null +++ b/src/scr/minifx.c @@ -0,0 +1,169 @@ +#include "demo.h" +#include "imago2.h" +#include "screen.h" +#include +#include +#include +#include +#include + +#include "rlebmap.h" + +/* APPROX. 170 FPS Minimum */ + +static int init(void); +static void destroy(void); +static void start(long trans_time); +static void stop(long trans_time); +static void draw(void); + +static void updatePropeller(float t, RleBitmap *rle); + +static unsigned short *backBuffer; + +static unsigned char miniFXBuffer[1024]; + +static long lastFrameTime = 0; + +static struct screen scr = {"minifx", init, destroy, start, 0, draw}; + +struct screen *minifx_screen(void) { + return &scr; +} + +static int init(void) { + /* Allocate back buffer */ + backBuffer = calloc(FB_WIDTH * FB_HEIGHT, sizeof(unsigned short)); + + return 0; +} + +static void destroy(void) { + free(backBuffer); + backBuffer = 0; +} + +static void start(long trans_time) { lastFrameTime = time_msec; } + +static void draw(void) { + long lastFrameDuration; + int i, stride; + RleBitmap *rle; + int clearColor; + unsigned short clearColor16; + + lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f; + lastFrameTime = time_msec; + + clearColor = 0x888888; + clearColor16 = ((clearColor << 8) & 0xF800) /* R */ + | ((clearColor >> 5) & 0x07E0) /* G */ + | ((clearColor >> 19) & 0x001F); /* B */ + + for (i=0; i= 2; + } + } + + /* Then, encode to rle */ + rleEncode(rle, miniFXBuffer, 32, 32); + + /* Distribute the produced streaks so that they don't produce garbage when interpolated */ + rleDistributeStreaks(rle); +} diff --git a/src/scr/raytrace.c b/src/scr/raytrace.c new file mode 100644 index 0000000..1593d9f --- /dev/null +++ b/src/scr/raytrace.c @@ -0,0 +1,239 @@ +#include +#include +#include "demo.h" +#include "screen.h" +#include "gfxutil.h" +#include "util.h" +#include "cgmath/cgmath.h" +#include "rt.h" + +static int init(void); +static void destroy(void); +static void start(long trans_time); +static void draw(void); + +static struct screen scr = { + "raytrace", + init, + destroy, + start, + 0, + draw +}; + +struct tile { + int x, y; + uint16_t *fbptr; +}; + +#define TILESZ 16 +#define NUM_TILES ((320 / TILESZ) * (240 / TILESZ)) + +static cgm_vec3 raydir[240][320]; +static struct tile tiles[NUM_TILES]; +static struct rtscene scn; + +struct screen *raytrace_screen(void) +{ + return &scr; +} + +static int init(void) +{ + int i, j, k; + float z = 1.0f / tan(cgm_deg_to_rad(25.0f)); + struct tile *tptr = tiles; + + for(i=0; i<240; i++) { + cgm_vec3 *vptr = raydir[i]; + float y = 1.0f - (float)i / 120.0f; + for(j=0; j<320; j++) { + vptr->x = ((float)j / 160.0f - 1.0f) * 1.333333f; + vptr->y = y; + vptr->z = z; + vptr++; + + if(((j & (TILESZ-1)) | (i & (TILESZ-1))) == 0) { + tptr->x = j; + tptr->y = i; + tptr->fbptr = fb_pixels + i * 320 + j; + tptr++; + } + } + } + + rt_init(&scn); + + rt_color(1, 0, 0); + rt_specular(0.8f, 0.8f, 0.8f); + rt_shininess(30.0f); + rt_add_sphere(&scn, 0, 0, 0, 1); /* x,y,z, rad */ + + rt_color(0.4, 0.4, 0.4); + rt_specular(0, 0, 0); + rt_shininess(1); + rt_add_plane(&scn, 0, 1, 0, -1); /* nx,ny,nz, dist */ + + rt_color(1, 1, 1); + rt_add_light(&scn, -8, 15, -10); + return 0; +} + +static void destroy(void) +{ + rt_destroy(&scn); +} + +static void start(long start_time) +{ +} + +static uint16_t INLINE rend_pixel(int x, int y) +{ + int r, g, b; + cgm_ray ray; + cgm_vec3 col; + + ray.dir = raydir[y][x]; + cgm_vcons(&ray.origin, 0, 0, -5); + + if(ray_trace(&ray, &scn, 0, &col)) { + r = cround64(col.x * 255.0f); + g = cround64(col.y * 255.0f); + b = cround64(col.z * 255.0f); + if(r > 255) r = 255; + if(g > 255) g = 255; + if(b > 255) b = 255; + return PACK_RGB16(r, g, b); + } + return 0; +} + +#define CMPMASK 0xe79c +static void rend_tile(uint16_t *fbptr, int x0, int y0, int tsz, int valid) +{ + uint16_t *cptr[4]; + uint16_t cpix[4], tmp; + uint32_t pp0, pp1, pp2, pp3, *fb32; + int i, x1, y1, offs; + + fb32 = (uint32_t*)fbptr; + + if(tsz <= 2) { + switch(valid) { + case 0: + fbptr[1] = fbptr[320] = fbptr[321] = *fbptr; + break; + case 1: + fbptr[0] = fbptr[320] = fbptr[321] = fbptr[1]; + break; + case 2: + fbptr[0] = fbptr[1] = fbptr[321] = fbptr[320]; + break; + case 3: + fbptr[0] = fbptr[1] = fbptr[320] = fbptr[321]; + break; + default: + printf("valid = %d\n", valid); + fbptr[0] = fbptr[1] = fbptr[320] = fbptr[321] = 0xff00; + } + return; + } + + offs = tsz - 1; + x1 = x0 + offs; + y1 = y0 + offs; + + cptr[0] = fbptr; + cptr[1] = fbptr + tsz - 1; + cptr[2] = fbptr + (offs << 8) + (offs << 6); + cptr[3] = cptr[2] + tsz - 1; + + cpix[0] = valid == 0 ? *cptr[0] : rend_pixel(x0, y0); + cpix[1] = valid == 1 ? *cptr[1] : rend_pixel(x1, y0); + cpix[2] = valid == 2 ? *cptr[2] : rend_pixel(x0, y1); + cpix[3] = valid == 3 ? *cptr[3] : rend_pixel(x1, y1); + + tmp = cpix[0] & CMPMASK; + if((cpix[1] & CMPMASK) != tmp) goto subdiv; + if((cpix[2] & CMPMASK) != tmp) goto subdiv; + if((cpix[3] & CMPMASK) != tmp) goto subdiv; + + pp0 = cpix[0] | ((uint32_t)cpix[0] << 16); + pp1 = cpix[1] | ((uint32_t)cpix[1] << 16); + pp2 = cpix[2] | ((uint32_t)cpix[2] << 16); + pp3 = cpix[3] | ((uint32_t)cpix[3] << 16); + + switch(tsz) { + case 2: +#ifdef SUBDBG + pp0 = 0x18ff; +#endif + fb32[0] = fb32[160] = pp0; + break; + case 4: +#ifdef SUBDBG + pp0 = pp1 = pp2 = pp3 = 0x03800380; +#endif + fb32[0] = fb32[160] = pp0; + fb32[1] = fb32[161] = pp1; + fb32[320] = fb32[480] = pp2; + fb32[321] = fb32[481] = pp3; + break; + case 8: +#ifdef SUBDBG + pp1 = pp0 = pp2 = pp3 = 0xe00fe00f; +#endif + fb32[0] = fb32[1] = pp0; fb32[2] = fb32[3] = pp1; + fb32[160] = fb32[161] = pp0; fb32[162] = fb32[163] = pp1; + fb32[320] = fb32[321] = pp0; fb32[322] = fb32[323] = pp1; + fb32[480] = fb32[481] = pp0; fb32[482] = fb32[483] = pp1; + fb32[640] = fb32[641] = pp2; fb32[642] = fb32[643] = pp3; + fb32[800] = fb32[801] = pp2; fb32[802] = fb32[803] = pp3; + fb32[960] = fb32[961] = pp2; fb32[962] = fb32[963] = pp3; + fb32[1120] = fb32[1121] = pp2; fb32[1122] = fb32[1123] = pp3; + break; + + case 16: +#ifdef SUBDBG + pp0 = 0xff00ff00; +#endif + for(i=0; i<4; i++) { + memset16(fbptr, pp0, 16); fbptr += 320; + memset16(fbptr, pp0, 16); fbptr += 320; + memset16(fbptr, pp0, 16); fbptr += 320; + memset16(fbptr, pp0, 16); fbptr += 320; + } + break; + } + return; + +subdiv: + *cptr[0] = cpix[0]; + *cptr[1] = cpix[1]; + *cptr[2] = cpix[2]; + *cptr[3] = cpix[3]; + + tsz >>= 1; + rend_tile(fbptr, x0, y0, tsz, 0); + rend_tile(fbptr + tsz, x0 + tsz, y0, tsz, 1); + fbptr += (tsz << 8) + (tsz << 6); + y0 += tsz; + rend_tile(fbptr, x0, y0, tsz, 2); + rend_tile(fbptr + tsz, x0 + tsz, y0, tsz, 3); +} + +static void draw(void) +{ + int i, j, xbound, ybound; + uint16_t *fbptr; + struct tile *tile; + + tile = tiles; + for(i=0; ifbptr, tile->x, tile->y, TILESZ, -1); + tile++; + } + + swap_buffers(0); +} diff --git a/src/scr/rt.c b/src/scr/rt.c new file mode 100644 index 0000000..13f2dbe --- /dev/null +++ b/src/scr/rt.c @@ -0,0 +1,261 @@ +#include +#include +#include +#include +#include "rt.h" +#include "util.h" +#include "darray.h" + +static cgm_vec3 cur_col, cur_spec; +static float cur_shin; +static struct image *cur_tex; + +void rt_init(struct rtscene *scn) +{ + scn->obj = darr_alloc(0, sizeof *scn->obj); + scn->num_obj = 0; + scn->lt = darr_alloc(0, sizeof *scn->lt); + scn->num_lt = 0; + + cgm_vcons(&cur_col, 1, 1, 1); + cgm_vcons(&cur_spec, 0, 0, 0); + cur_shin = 1; + cur_tex = 0; +} + +void rt_destroy(struct rtscene *scn) +{ + darr_free(scn->obj); + darr_free(scn->lt); + memset(scn, 0, sizeof *scn); +} + + +void rt_color(float r, float g, float b) +{ + cgm_vcons(&cur_col, r, g, b); +} + +void rt_specular(float r, float g, float b) +{ + cgm_vcons(&cur_spec, r, g, b); +} + +void rt_shininess(float s) +{ + cur_shin = s; +} + +static union rtobject *add_object(struct rtscene *scn, enum rt_obj_type type) +{ + union rtobject *obj; + + obj = calloc_nf(1, sizeof *obj); + obj->type = type; + + obj->x.mtl.kd = cur_col; + obj->x.mtl.ks = cur_spec; + obj->x.mtl.shin = cur_shin; + obj->x.mtl.tex = cur_tex; + + darr_push(scn->obj, &obj); + scn->num_obj = darr_size(scn->obj); + return obj; +} + +union rtobject *rt_add_sphere(struct rtscene *scn, float x, float y, float z, float r) +{ + union rtobject *obj = add_object(scn, RT_SPH); + cgm_vcons(&obj->s.p, x, y, z); + obj->s.r = r; + return obj; +} + +union rtobject *rt_add_plane(struct rtscene *scn, float nx, float ny, float nz, float d) +{ + union rtobject *obj = add_object(scn, RT_PLANE); + cgm_vcons(&obj->p.n, nx, ny, nz); + obj->p.d = d; + return obj; +} + +struct rtlight *rt_add_light(struct rtscene *scn, float x, float y, float z) +{ + struct rtlight *lt = calloc_nf(1, sizeof *lt); + + cgm_vcons(<->p, x, y, z); + lt->color = cur_col; + + darr_push(scn->lt, <); + scn->num_lt = darr_size(scn->lt); + return lt; +} + + +/* color is initialized to black */ +static void shade(struct rayhit *hit, struct rtscene *scn, int lvl, cgm_vec3 *color) +{ + int i; + float ndotl, vdotr, spec; + cgm_ray sray; + cgm_vec3 col, rdir; + struct rtlight *lt; + struct rtmaterial *mtl = &hit->obj->x.mtl; + + sray.origin = hit->p; + cgm_vnormalize(&hit->n); + cgm_vnormalize(&hit->ray->dir); + + for(i=0; inum_lt; i++) { + lt = scn->lt[i]; + sray.dir = lt->p; + cgm_vsub(&sray.dir, &sray.origin); + + if(ray_scene(&sray, scn, 1.0f, 0)) continue; + + cgm_vnormalize(&sray.dir); + ndotl = cgm_vdot(&sray.dir, &hit->n); + if(ndotl < 0.0f) ndotl = 0.0f; + + rdir = hit->ray->dir; + cgm_vreflect(&rdir, &hit->n); + vdotr = cgm_vdot(&sray.dir, &rdir); + if(vdotr < 0.0f) vdotr = 0.0f; + spec = pow(vdotr, mtl->shin); + + color->x += (mtl->kd.x * ndotl + mtl->ks.x * spec) * lt->color.x; + color->y += (mtl->kd.y * ndotl + mtl->ks.y * spec) * lt->color.y; + color->z += (mtl->kd.z * ndotl + mtl->ks.z * spec) * lt->color.z; + } +} + +int ray_trace(cgm_ray *ray, struct rtscene *scn, int lvl, cgm_vec3 *color) +{ + struct rayhit hit; + + color->x = color->y = color->z = 0.0f; + if(!ray_scene(ray, scn, FLT_MAX, &hit)) { + return 0; + } + hit.ray = ray; + shade(&hit, scn, lvl, color); + return 1; +} + + +int ray_scene(cgm_ray *ray, struct rtscene *scn, float maxt, struct rayhit *hit) +{ + int i; + + if(hit) { + struct rayhit hit0 = {FLT_MAX}; + + /* find nearest hit */ + for(i=0; inum_obj; i++) { + if(ray_object(ray, scn->obj[i], maxt, hit) && hit->t < hit0.t) { + hit0 = *hit; + } + } + + if(hit0.obj) { + *hit = hit0; + return 1; + } + } else { + /* find any hit */ + for(i=0; inum_obj; i++) { + if(ray_object(ray, scn->obj[i], maxt, 0)) { + return 1; + } + } + } + + return 0; +} + +int ray_object(cgm_ray *ray, union rtobject *obj, float maxt, struct rayhit *hit) +{ + switch(obj->type) { + case RT_SPH: + return ray_sphere(ray, &obj->s, maxt, hit); + case RT_PLANE: + return ray_plane(ray, &obj->p, maxt, hit); + default: + break; + } + return 0; +} + +#define SQ(x) ((x) * (x)) +int ray_sphere(cgm_ray *ray, struct rtsphere *sph, float maxt, struct rayhit *hit) +{ + float a, a2, b, c, d, sqrt_d, t1, t2; + + a = SQ(ray->dir.x) + SQ(ray->dir.y) + SQ(ray->dir.z); + b = 2.0f * ray->dir.x * (ray->origin.x - sph->p.x) + + 2.0f * ray->dir.y * (ray->origin.y - sph->p.y) + + 2.0f * ray->dir.z * (ray->origin.z - sph->p.z); + c = SQ(sph->p.x) + SQ(sph->p.y) + SQ(sph->p.z) + + SQ(ray->origin.x) + SQ(ray->origin.y) + SQ(ray->origin.z) + + 2.0f * (-sph->p.x * ray->origin.x - sph->p.y * ray->origin.y - sph->p.z * ray->origin.z) - + SQ(sph->r); + + if((d = SQ(b) - 4.0f * a * c) < 0.0f) return 0; + + sqrt_d = sqrt(d); + a2 = 2.0f * a; + t1 = (-b + sqrt_d) / a2; + t2 = (-b - sqrt_d) / a2; + + if((t1 < 1e-5f && t2 < 1e-5f) || (t1 > maxt && t2 > maxt)) { + return 0; + } + + if(hit) { + float t; + if(t1 < 1e-5f) { + t = t2; + } else if(t2 < 1e-5f) { + t = t1; + } else { + t = t1 < t2 ? t1 : t2; + } + + hit->t = t; + cgm_raypos(&hit->p, ray, t); + + hit->n.x = hit->p.x - sph->p.x; + hit->n.y = hit->p.y - sph->p.y; + hit->n.z = hit->p.z - sph->p.z; + + hit->obj = (union rtobject*)sph; + } + return 1; +} + +int ray_plane(cgm_ray *ray, struct rtplane *plane, float maxt, struct rayhit *hit) +{ + cgm_vec3 vo; + float t, ndotdir; + + ndotdir = cgm_vdot(&plane->n, &ray->dir); + if(fabs(ndotdir) < 1e-5) { + return 0; + } + + vo.x = plane->n.x * plane->d - ray->origin.x; + vo.y = plane->n.y * plane->d - ray->origin.y; + vo.z = plane->n.z * plane->d - ray->origin.z; + t = cgm_vdot(&plane->n, &vo) / ndotdir; + + if(t < 1e-5 || t > maxt) return 0; + + if(hit) { + hit->t = t; + cgm_raypos(&hit->p, ray, t); + hit->n = plane->n; + + hit->obj = (union rtobject*)plane; + } + return 1; +} diff --git a/src/scr/rt.h b/src/scr/rt.h new file mode 100644 index 0000000..f619a88 --- /dev/null +++ b/src/scr/rt.h @@ -0,0 +1,81 @@ +#ifndef RT_H_ +#define RT_H_ + +#include "image.h" +#include "cgmath/cgmath.h" + +struct rtmaterial { + cgm_vec3 kd, ks; + float shin; + struct image *tex; +}; + +enum rt_obj_type { RT_SPH, RT_PLANE }; + +#define OBJ_COMMON \ + enum rt_obj_type type; \ + struct rtmaterial mtl + +struct rtany { + OBJ_COMMON; +}; + +struct rtsphere { + OBJ_COMMON; + cgm_vec3 p; + float r; +}; + +struct rtplane { + OBJ_COMMON; + cgm_vec3 n; + float d; +}; + +union rtobject { + enum rt_obj_type type; + struct rtany x; + struct rtsphere s; + struct rtplane p; +}; + +struct rtlight { + cgm_vec3 p, color; +}; + +struct rayhit { + float t; + cgm_vec3 p, n; + float u, v; + cgm_ray *ray; + union rtobject *obj; +}; + +struct rtscene { + union rtobject **obj; + int num_obj; + struct rtlight **lt; + int num_lt; +}; + +/* scene management */ +void rt_init(struct rtscene *scn); +void rt_destroy(struct rtscene *scn); + +void rt_color(float r, float g, float b); +void rt_specular(float r, float g, float b); +void rt_shininess(float s); + +union rtobject *rt_add_sphere(struct rtscene *scn, float x, float y, float z, float r); +union rtobject *rt_add_plane(struct rtscene *scn, float nx, float ny, float nz, float d); +struct rtlight *rt_add_light(struct rtscene *scn, float x, float y, float z); + +/* returns 0 for no hit */ +int ray_trace(cgm_ray *ray, struct rtscene *scn, int lvl, cgm_vec3 *color); + +int ray_object(cgm_ray *ray, union rtobject *obj, float maxt, struct rayhit *hit); +int ray_scene(cgm_ray *ray, struct rtscene *scn, float maxt, struct rayhit *hit); +int ray_sphere(cgm_ray *ray, struct rtsphere *sph, float maxt, struct rayhit *hit); +int ray_plane(cgm_ray *ray, struct rtplane *plane, float maxt, struct rayhit *hit); + +#endif /* RT_H_ */ diff --git a/src/scr/thunder.c b/src/scr/thunder.c index 062eb57..3aa3b7e 100644 --- a/src/scr/thunder.c +++ b/src/scr/thunder.c @@ -377,62 +377,62 @@ unsigned char fog(float z) { return (unsigned char)ret; } -void sort(PointSprite *begin, PointSprite *end) { - PointSprite pivotValue; - size_t sz; - PointSprite *left, *right; - int leftCond, rightCond; - PointSprite tmp; - - sz = end - begin; - - if (sz < 2) return; /* already sorted */ - if (sz == 2) { - /* trivial case */ - if (begin[1] < begin[0]) { - tmp = begin[0]; - begin[0] = begin[1]; - begin[1] = tmp; - return; - } - } - - /* minimum 3 elements from now on */ - - /* choose a pivot near the middle, since we frequently sort already sorted arrays */ - pivotValue = begin[sz / 2]; - - left = begin; - right = end - 1; - - while (right > left) { - /* check if left and right elements meet the conditions */ - leftCond = pivotValue >= *left; - rightCond = pivotValue < *right; - - if (!leftCond && !rightCond) { - tmp = *left; - *left = *right; - *right = tmp; - left++; - right--; - } - else if (leftCond && rightCond) { - left++; - right--; - } - else if (leftCond) { - left++; - } - else { - right--; - } - } - - /* recursion */ - sort(begin, left); - sort(left, end); -} +void sort(PointSprite *begin, PointSprite *end) { + PointSprite pivotValue; + size_t sz; + PointSprite *left, *right; + int leftCond, rightCond; + PointSprite tmp; + + sz = end - begin; + + if (sz < 2) return; /* already sorted */ + if (sz == 2) { + /* trivial case */ + if (begin[1] < begin[0]) { + tmp = begin[0]; + begin[0] = begin[1]; + begin[1] = tmp; + return; + } + } + + /* minimum 3 elements from now on */ + + /* choose a pivot near the middle, since we frequently sort already sorted arrays */ + pivotValue = begin[sz / 2]; + + left = begin; + right = end - 1; + + while (right > left) { + /* check if left and right elements meet the conditions */ + leftCond = pivotValue >= *left; + rightCond = pivotValue < *right; + + if (!leftCond && !rightCond) { + tmp = *left; + *left = *right; + *right = tmp; + left++; + right--; + } + else if (leftCond && rightCond) { + left++; + right--; + } + else if (leftCond) { + left++; + } + else { + right--; + } + } + + /* recursion */ + sort(begin, left); + sort(left, end); +} void sortPointSprites() { sort(pointSprites, pointSprites + pointSpriteCount); diff --git a/src/screen.c b/src/screen.c index baf4ec2..190b19f 100644 --- a/src/screen.c +++ b/src/screen.c @@ -25,6 +25,9 @@ struct screen *metaballs_screen(void); struct screen *greets_screen(void); struct screen *infcubes_screen(void); struct screen *hairball_screen(void); +struct screen *cybersun_screen(void); +struct screen *raytrace_screen(void); +struct screen *minifx_screen(void); void start_loadscr(void); void end_loadscr(void); @@ -79,6 +82,16 @@ int scr_init(void) if(!(scr[idx++] = hairball_screen())) { return -1; } + if(!(scr[idx++] = cybersun_screen())) { + return -1; + } + if(!(scr[idx++] = raytrace_screen())) { + return -1; + } + if (!(scr[idx++] = minifx_screen())) { + return -1; + } + num_screens = idx; assert(num_screens <= NUM_SCR); @@ -187,7 +200,7 @@ int scr_change(struct screen *s, long trans_time) /* loading screen */ extern uint16_t loading_pixels[]; static long prev_load_msec; -static long load_delay = 180; +static long load_delay; void start_loadscr(void) { @@ -198,7 +211,9 @@ void start_loadscr(void) } swap_buffers(loading_pixels); - sleep_msec(load_delay * 2); + if(load_delay) { + sleep_msec(load_delay * 2); + } prev_load_msec = get_msec(); } @@ -216,7 +231,9 @@ void end_loadscr(void) blitfb(loading_pixels + SPLAT_Y * 320 + SPLAT_X, loading_pixels + 320 * 240, 32, 72, 32); blit_key(loading_pixels + FING_Y * 320 + FING_LAST_X, 320, loading_pixels + 247 * 320 + 64, FING_W, FING_H, FING_W, 0); swap_buffers(loading_pixels); - sleep_msec(load_delay * 4); + if(load_delay) { + sleep_msec(load_delay * 3); + } } void loadscr(int n, int count) diff --git a/src/sdl/main.c b/src/sdl/main.c index f2487cf..784b208 100644 --- a/src/sdl/main.c +++ b/src/sdl/main.c @@ -9,6 +9,7 @@ #include "cfgopt.h" #include "sball.h" #include "vmath.h" +#include "cpuid.h" static void handle_event(SDL_Event *ev); static void toggle_fullscreen(void); @@ -65,6 +66,10 @@ int main(int argc, char **argv) SDL_WM_SetCaption("dosdemo/SDL", 0); SDL_ShowCursor(0); + if(read_cpuid(&cpuid) == 0) { + print_cpuid(&cpuid); + } + time_msec = 0; if(demo_init(argc, argv) == -1) { /*free(fb_pixels);*/ diff --git a/src/tinyfps.c b/src/tinyfps.c index 41102e6..269c965 100644 --- a/src/tinyfps.c +++ b/src/tinyfps.c @@ -4,9 +4,10 @@ #include "tinyfps.h" #include "demo.h" -/* TinyFPS, just a minimal fraps like font to show FPS during the demo and not just after. - * I'll be using it in my effects for my performance test purposes, just adding it here. - * Maybe it would be nice if initFpsFonts would be called in demo.c once but I avoided touching that code. +/* TinyFPS, just a minimal fraps like font to show FPS during the demo and not + * just after. I'll be using it in my effects for my performance test + * purposes, just adding it here. Maybe it would be nice if initFpsFonts would + * be called in demo.c once but I avoided touching that code. */ /* diff --git a/src/treestor.c b/src/treestor.c index 91adfec..69853c8 100644 --- a/src/treestor.c +++ b/src/treestor.c @@ -4,7 +4,7 @@ #include #include "treestor.h" -#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__) +#if defined(__WATCOMC__) || defined(WIN32) || defined(__DJGPP__) #include #else #include diff --git a/src/util.c b/src/util.c index a91bb95..2a70ec8 100644 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,37 @@ +#include +#include +#include +#include #include "util.h" +#include "demo.h" uint32_t perf_start_count, perf_interval_count; + +void *malloc_nf_impl(size_t sz, const char *file, int line) +{ + void *p; + if(!(p = malloc(sz))) { + fprintf(stderr, "%s:%d failed to allocate %lu bytes\n", file, line, (unsigned long)sz); + demo_abort(); + } + return p; +} + +void *calloc_nf_impl(size_t num, size_t sz, const char *file, int line) +{ + void *p; + if(!(p = calloc(num, sz))) { + fprintf(stderr, "%s:%d failed to allocate %lu bytes\n", file, line, (unsigned long)(num * sz)); + demo_abort(); + } + return p; +} + +void *realloc_nf_impl(void *p, size_t sz, const char *file, int line) +{ + if(!(p = realloc(p, sz))) { + fprintf(stderr, "%s:%d failed to realloc %lu bytes\n", file, line, (unsigned long)sz); + demo_abort(); + } + return p; +} diff --git a/src/util.h b/src/util.h index 8a46036..ec87a4d 100644 --- a/src/util.h +++ b/src/util.h @@ -1,6 +1,7 @@ #ifndef UTIL_H_ #define UTIL_H_ +#include #include "inttypes.h" #ifdef __GNUC__ @@ -110,21 +111,26 @@ void halt(void); #ifdef __GNUC__ #if defined(__i386__) || defined(__x86_64__) -#define memset16(dest, val, count) asm volatile ( \ - "cld\n\t" \ - "test $1, %2\n\t" \ - "jz 0f\n\t" \ - "rep stosw\n\t" \ - "jmp 1f\n\t" \ - "0:\n\t" \ - "shr $1, %2\n\t" \ - "push %%ax\n\t" \ - "shl $16, %%eax\n\t" \ - "pop %%ax\n\t" \ - "rep stosl\n\t" \ - "1:\n\t"\ - :: "D"(dest), "a"((uint16_t)(val)), "c"(count) \ - : "memory") +#define memset16(dest, val, count) \ + do { \ + uint32_t dummy1, dummy2; \ + asm volatile ( \ + "cld\n\t" \ + "test $1, %%ecx\n\t" \ + "jz 0f\n\t" \ + "rep stosw\n\t" \ + "jmp 1f\n\t" \ + "0:\n\t" \ + "shr $1, %%ecx\n\t" \ + "push %%ax\n\t" \ + "shl $16, %%eax\n\t" \ + "pop %%ax\n\t" \ + "rep stosl\n\t" \ + "1:\n\t"\ + : "=D"(dummy1), "=c"(dummy2) \ + : "0"(dest), "a"((uint16_t)(val)), "1"(count) \ + : "flags", "memory"); \ + } while(0) #else static void INLINE memset16(void *dest, uint16_t val, int count) { @@ -168,14 +174,14 @@ static void INLINE memset16(void *dest, uint16_t val, int count) : "%eax", "%ebx", "%ecx", "%edx") #define debug_break() \ - asm volatile ("int $3") + asm volatile("int $3") #define halt() \ asm volatile("hlt") #endif #ifdef _MSC_VER -void __inline memset16(void *dest, uint16_t val, int count) +static void __inline memset16(void *dest, uint16_t val, int count) { __asm { cld @@ -221,6 +227,36 @@ void __inline memset16(void *dest, uint16_t val, int count) do { \ __asm { int 3 } \ } while(0) + +static unsigned int __inline get_cs(void) +{ + unsigned int res; + __asm { + xor eax, eax + mov ax, cs + mov [res], ax + } + return res; +} #endif +unsigned int get_cs(void); +#define get_cpl() ((int)(get_cs() & 3)) + +void get_msr(uint32_t msr, uint32_t *low, uint32_t *high); +void set_msr(uint32_t msr, uint32_t low, uint32_t high); + + +/* Non-failing versions of malloc/calloc/realloc. They never return 0, they call + * demo_abort on failure. Use the macros, don't call the *_impl functions. + */ +#define malloc_nf(sz) malloc_nf_impl(sz, __FILE__, __LINE__) +void *malloc_nf_impl(size_t sz, const char *file, int line); +#define calloc_nf(n, sz) calloc_nf_impl(n, sz, __FILE__, __LINE__) +void *calloc_nf_impl(size_t num, size_t sz, const char *file, int line); +#define realloc_nf(p, sz) realloc_nf_impl(p, sz, __FILE__, __LINE__) +void *realloc_nf_impl(void *p, size_t sz, const char *file, int line); + + + #endif /* UTIL_H_ */ diff --git a/src/util_s.asm b/src/util_s.asm new file mode 100644 index 0000000..65198b5 --- /dev/null +++ b/src/util_s.asm @@ -0,0 +1,63 @@ + section .text + bits 32 +; foo_ are watcom functions, _foo are djgpp functions + + global get_cs + global _get_cs + global get_cs_ +get_cs: +_get_cs: +get_cs_: + xor eax, eax + mov ax, cs + ret + + global get_msr + global _get_msr +get_msr: +_get_msr: + push ebp + mov ebp, esp + push ebx + mov ecx, [ebp + 8] + rdmsr + mov ebx, [ebp + 12] + mov [ebx], eax + mov ebx, [ebp + 16] + mov [ebx], edx + pop ebx + pop ebp + ret + + global get_msr_ +get_msr_: + push ebx + push edx + mov ecx, eax + rdmsr + pop ebx + mov [ebx], eax + pop ebx + mov [ebx], edx + ret + + global set_msr + global _set_msr +set_msr: +_set_msr: + mov ecx, [esp + 4] + mov eax, [esp + 8] + mov edx, [esp + 12] + rdmsr + ret + + global set_msr_ +set_msr_: + mov ecx, eax + mov eax, edx + mov edx, ebx + wrmsr + ret + + +; vi:ft=nasm: diff --git a/tools/csprite/src/main.c b/tools/csprite/src/main.c index a59aa3e..c549b3e 100644 --- a/tools/csprite/src/main.c +++ b/tools/csprite/src/main.c @@ -3,7 +3,11 @@ #include #include #include +#ifdef WIN32 +#include +#else #include +#endif #include "image.h" struct rect { diff --git a/tools/img2bin/Makefile b/tools/img2bin/Makefile index b6e9f4e..0763597 100644 --- a/tools/img2bin/Makefile +++ b/tools/img2bin/Makefile @@ -3,12 +3,18 @@ bin = img2bin root = ../.. -CFLAGS = -pedantic -Wall -g -I$(root)/libs/imago/src -LDFLAGS = -L$(root)/libs/imago -limago -lm +imagodir = $(root)/libs/imago +libimago = $(imagodir)/libimago.a -$(bin): $(obj) +CFLAGS = -pedantic -Wall -g -I$(imagodir)/src +LDFLAGS = -L$(imagodir) -limago -lm + +$(bin): $(obj) $(libimago) $(CC) -o $@ $(obj) $(LDFLAGS) +$(libimago): + $(MAKE) -C $(imagodir) + .PHONY: clean clean: rm -f $(obj) $(bin) diff --git a/tools/scripts/fixmknam b/tools/scripts/fixmknam new file mode 100755 index 0000000..15c6118 --- /dev/null +++ b/tools/scripts/fixmknam @@ -0,0 +1,7 @@ +#!/bin/sh + +for i in `find . -name 'makefile*'`; do + name=`echo $i | sed 's/makefile/Makefile/'` + echo "$i -> $name" + mv $i $name +done diff --git a/tools/scripts/pceminst b/tools/scripts/pceminst index c0e8660..6687f82 100755 --- a/tools/scripts/pceminst +++ b/tools/scripts/pceminst @@ -1,10 +1,10 @@ #!/bin/sh # NOTES: -# assumes a PCem setup with a fat16 image mounted at /pcem_dos. fstab entry: -# /home/nuclear/.pcem/pentium_dos.img /pcem_dos msdos user,noauto,loop,fmask=0113,dmask=0002,gid=6,offset=32256 0 0 +# assumes a PCem setup with a fat16 image mounted at /pcem/pentium. fstab entry: +# /home/nuclear/.pcem/pentium_dos.img /pcem/pentium msdos user,noauto,loop,fmask=0113,dmask=0002,gid=6,offset=32256 0 0 -mntpt=/pcem_dos +mntpt=/pcem/pentium do_umount=false if ! ( mount | grep pcem >/dev/null ); then