+++ /dev/null
--x c
--Isrc
--Isrc/dos
--Isrc/dos/stl
*sdf
demo
*.zip
+*.ZIP
data
*.a
*.dll
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/')
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
%.o: %.asm
nasm -f elf -o $@ $<
+%.w32.o: %.asm
+ nasm -f coff -o $@ $<
+
%.w32.o: %.c
$(CC) -o $@ $(CFLAGS) -c $<
!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 &
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 &
-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
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
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
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)
-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).
#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.
*/
#include <string.h>
#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 ?
#include <string.h>
#include <stdlib.h>
-#include "types.h"
+#include "inttypes.h"
#include "imago2.h"
#include "ftmodule.h"
--- /dev/null
+/*
+colcycle - color cycling image viewer
+Copyright (C) 2016 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef 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 <stdint.h>
+#else
+#include <sys/types.h>
+#endif
+
+#endif /* end !msvc */
+#endif /* end !dos */
+
+#endif /* INT_TYPES_H_ */
+++ /dev/null
-/*
-colcycle - color cycling image viewer
-Copyright (C) 2016 John Tsiombikas <nuclear@member.fsf.org>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef 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 <stdint.h>
-#else
-#include <inttypes.h>
-#endif
-
-#endif /* end !msvc */
-#endif /* end !dos */
-
-#endif /* INT_TYPES_H_ */
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)
-ssh2dos -g -i c:\prog\ssh2dos\doskey -S -B nuclear 192.168.0.4 cd code/demoscene/dosdemo && git archive -o dd.zip master\r
-scp2dos -r -g -i c:\prog\ssh2dos\doskey nuclear@192.168.0.4:code/demoscene/dosdemo/dd.zip .\r
-unzip32 -o dd.zip\r
-del dd.zip\r
+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
--- /dev/null
+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
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)
{
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;
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]];
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;
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);
#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;
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<nverts; i++) {
if(pv[i].y < pv[topidx].y) topidx = i;
if(pv[i].y > pv[botidx].y) botidx = i;
#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__)
#include <malloc.h>
#else
+#ifdef WIN32
+#include <malloc.h>
+#else
#include <alloca.h>
#endif
+#endif
#include "bsptree.h"
#include "dynarr.h"
#include "inttypes.h"
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<num_polys; j++) {
if(i == j) continue;
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#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;
+}
--- /dev/null
+#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_ */
--- /dev/null
+ 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:
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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;
+}
--- /dev/null
+#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_ */
#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;
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) {
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();
if(scr_init() == -1) {
return -1;
}
+
if(opt.start_scr) {
scr = scr_lookup(opt.start_scr);
} else {
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);
/* 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);
-#ifndef NO_SOUND
#include <stdio.h>
+
+#ifndef NO_SOUND
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
} 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);
--- /dev/null
+#ifndef DOSUTIL_H_
+#define DOSUTIL_H_
+
+#include <dos.h>
+#include <conio.h>
+
+#ifdef __DJGPP__
+#include <pc.h>
+
+#define outp(p, v) outportb(p, v)
+#define outpw(p, v) outportw(p, v)
+#define outpd(p, v) outportl(p, v)
+
+#define inp(p) inportb(p)
+#define inpw(p) inportw(p)
+#define inpd(p) inportl(p)
+#endif
+
+#endif /* DOSUTIL_H_ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <dos.h>
#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) || \
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;
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);
}
/* 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;
}
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) {
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 */
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;
}
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);
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<num_ranges; i++) {
+ get_msr(MSR_MTRRMASK(i), &rlow, &rhigh);
+ if(!(rlow & MTRRMASK_VALID)) {
+ continue;
+ }
+ mask = rlow & 0xfffff000;
+
+ get_msr(MSR_MTRRBASE(i), &rlow, &rhigh);
+ base = rlow & 0xfffff000;
+
+ if((addr & mask) == (base & mask)) {
+ return rlow & 0xff;
+ }
+ }
+
+ get_msr(MSR_MTRRDEFTYPE, &rlow, &rhigh);
+ return rlow & 0xff;
+}
+
+static int check_wrcomb_enabled(uint32_t addr, int len, int num_ranges)
+{
+ while(len > 0) {
+ if(get_page_memtype(addr, num_ranges) != MTRR_WC) {
+ return 0;
+ }
+ addr += 4096;
+ len -= 4096;
+ }
+ return 1;
+}
+
+static int alloc_mtrr(int num_ranges)
+{
+ int i;
+ uint32_t rlow, rhigh;
+
+ for(i=0; i<num_ranges; i++) {
+ get_msr(MSR_MTRRMASK(i), &rlow, &rhigh);
+ if(!(rlow & MTRRMASK_VALID)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static void enable_wrcomb(uint32_t addr, int len)
+{
+ int num_ranges, mtrr;
+ uint32_t rlow, rhigh;
+ uint32_t def, mask;
+
+ if(len <= 0 || (addr | (uint32_t)len) & 0xfff) {
+ fprintf(stderr, "failed to enable write combining, unaligned range: %p/%x\n",
+ (void*)addr, (unsigned int)len);
+ return;
+ }
+
+ get_msr(MSR_MTRRCAP, &rlow, &rhigh);
+ num_ranges = rlow & 0xff;
+
+ printf("enable_wrcomb: addr=%p len=%x\n", (void*)addr, (unsigned int)len);
+
+ if(!(rlow & MTRRCAP_HAVE_WC)) {
+ fprintf(stderr, "failed to enable write combining, processor doesn't support it\n");
+ return;
+ }
+
+ if(check_wrcomb_enabled(addr, len, num_ranges)) {
+ return;
+ }
+
+ if((mtrr = alloc_mtrr(num_ranges)) == -1) {
+ fprintf(stderr, "failed to enable write combining, no free MTRRs\n");
+ return;
+ }
+
+ mask = len - 1;
+ mask |= mask >> 1;
+ mask |= mask >> 2;
+ mask |= mask >> 4;
+ mask |= mask >> 8;
+ mask |= mask >> 16;
+ mask = ~mask & 0xfffff000;
+
+ printf(" ... mask: %08x\n", (unsigned int)mask);
+
+ _disable();
+ get_msr(MSR_MTRRDEFTYPE, &def, &rhigh);
+ set_msr(MSR_MTRRDEFTYPE, def & ~MTRRDEF_EN, rhigh);
+
+ set_msr(MSR_MTRRBASE(mtrr), addr | MTRR_WC, 0);
+ set_msr(MSR_MTRRMASK(mtrr), mask | MTRRMASK_VALID, 0);
+
+ set_msr(MSR_MTRRDEFTYPE, def | MTRRDEF_EN, 0);
+ _enable();
+}
+
+static const char *mtrr_names[] = { "N/A", "W C", "N/A", "N/A", "W T", "W P", "W B" };
+
+static const char *mtrr_type_name(int type)
+{
+ if(type < 0 || type >= sizeof mtrr_names / sizeof *mtrr_names) {
+ return mtrr_names[0];
+ }
+ return mtrr_names[type];
+}
+
+static void print_mtrr(void)
+{
+ int i, num_ranges;
+ uint32_t rlow, rhigh, base, mask;
+
+ get_msr(MSR_MTRRCAP, &rlow, &rhigh);
+ num_ranges = rlow & 0xff;
+
+ for(i=0; i<num_ranges; i++) {
+ get_msr(MSR_MTRRBASE(i), &base, &rhigh);
+ get_msr(MSR_MTRRMASK(i), &mask, &rhigh);
+
+ if(mask & MTRRMASK_VALID) {
+ printf("mtrr%d: base %p, mask %08x type %s\n", i, (void*)(base & 0xfffff000),
+ (unsigned int)(mask & 0xfffff000), mtrr_type_name(base & 0xff));
+ } else {
+ printf("mtrr%d unused (%08x/%08x)\n", i, (unsigned int)base,
+ (unsigned int)mask);
+ }
+ }
+ fflush(stdout);
+}
uint32_t rmask, gmask, bmask;
uint32_t fb_addr;
short max_pages;
- uint32_t bank_size;
+ short win_gran, win_gran_shift, win_64k_step;
};
#ifdef __cplusplus
#include "keyb.h"
#include "scancode.h"
#include "inttypes.h"
+#include "dosutil.h"
#define KB_INTR 0x9
#define KB_PORT 0x60
#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();
#include <fcntl.h>
#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;
}
#endif
int init_logger(const char *fname);
+void stop_logger(void);
+
+int print_tail(const char *fname);
#ifdef __cplusplus
}
#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);
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
*/
init_timer(100);
kb_init(32);
+ if(init_pci() != -1) {
+ /* TODO detect and initialize S3 virge */
+ }
+
if(init_video() == -1) {
return 1;
}
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])
--- /dev/null
+/*
+S3 Virge driver hack
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <conio.h>
+#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<num_pcidevs; i++) {
+ if(pcidev[i].cfg.vendor == vendorid && pcidev[i].cfg.device == devid) {
+ return pcidev + i;
+ }
+ }
+ return 0;
+}
--- /dev/null
+/*
+S3 Virge driver hack
+Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+#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_ */
#include "sball.h"
#include "inttypes.h"
+#include "dosutil.h"
struct motion {
int x, y, z;
#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);
#include "pit8254.h"
#include "inttypes.h"
#include "util.h"
+#include "dosutil.h"
#define PIT_TIMER_INTR 8
#define DOS_TIMER_INTR 0x1c
#define INTERRUPT
static _go32_dpmi_seginfo intr, prev_intr;
-
-#define outp(p, v) outportb(p, v)
#endif
static void INTERRUPT timer_irq();
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, " [");
+#include <string.h>
#include "vga.h"
+#include "vgaregs.h"
#include "cdpmi.h"
+#include "dosutil.h"
+
+static void crtc_write(int reg, unsigned char val);
+static unsigned char crtc_read(int reg);
int vga_setmode(int mode)
{
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);
+}
#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);
--- /dev/null
+#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_ */
#endif
#include "mikmod.h"
#include "audio.h"
+#include "cfgopt.h"
#ifdef _WIN32
#include <windows.h>
curmod = 0;
vol_master = vol_mus = vol_sfx = 255;
+ if(!opt.music) return 0;
+
#if defined(__linux__)
MikMod_RegisterDriver(&drv_alsa);
#elif defined(__FreeBSD__)
{
#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
void au_shutdown(void)
{
- curmod = 0;
- MikMod_Exit();
+ if(opt.music) {
+ curmod = 0;
+ MikMod_Exit();
+ }
}
struct au_module *au_load_module(const char *fname)
}
#ifdef _WIN32
-static DWORD WINAPI upd_thread(void *cls);
+static DWORD WINAPI upd_thread(void *cls)
#else
static void *update(void *cls)
#endif
#include "cfgopt.h"
#include "cgmath/cgmath.h"
#include "util.h"
+#include "cpuid.h"
static void display(void);
static void idle(void);
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;
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();
exit(0);
}
+void demo_abort(void)
+{
+ abort();
+}
+
struct video_mode *video_modes(void)
{
return vmodes;
+++ /dev/null
-/*
- * 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 <jeremy@hksys.com>
- * Significantly revised and rewinddir, seekdir and telldir added by Colin
- * Peters <colin@fu.is.saga-u.ac.jp>
- *
- */
-#ifdef _MSC_VER
-
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <io.h>
-#include <direct.h>
-#include "w32_dirent.h"
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h> /* 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 */
+++ /dev/null
-/*
- * 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 <stdio.h>
-#include <io.h>
-
-#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_ */
--- /dev/null
+/*
+ * 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 <jeremy@hksys.com>
+ * Significantly revised and rewinddir, seekdir and telldir added by Colin
+ * Peters <colin@fu.is.saga-u.ac.jp>
+ *
+ */
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <io.h>
+#include <direct.h>
+#include "w32dir.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h> /* 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 */
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <io.h>
+
+#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_ */
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);
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);
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#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;
+ }
+}
--- /dev/null
+#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__
-#ifndef SBALL_H_\r
-#define SBALL_H_\r
-\r
-enum {\r
- SBALL_EV_NONE,\r
- SBALL_EV_MOTION,\r
- SBALL_EV_BUTTON\r
-};\r
-\r
-struct sball_event_motion {\r
- int type;\r
- int motion[6];\r
-};\r
-\r
-struct sball_event_button {\r
- int type;\r
- int id;\r
- int pressed;\r
- unsigned int state;\r
-};\r
-\r
-typedef union sball_event {\r
- int type;\r
- struct sball_event_motion motion;\r
- struct sball_event_button button;\r
-} sball_event;\r
-\r
-int sball_init(void);\r
-void sball_shutdown(void);\r
-\r
-int sball_getdev(void);\r
-\r
-int sball_pending(void);\r
-int sball_getevent(sball_event *ev);\r
-\r
-#endif /* SBALL_H_ */\r
+#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_ */
--- /dev/null
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+#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; i<gmesh.vcount; i++) {
+ gmesh.varr[i].u *= GMESH_GRIDSZ;
+ gmesh.varr[i].v *= GMESH_GRIDSZ;
+ }
+ if(load_image(>ex, "data/pgrid.png") == -1) {
+ return -1;
+ }
+ if(load_image(&mountimg, "data/cybmount.png") == -1) {
+ return -1;
+ }
+ assert(mountimg.width == MOUNTIMG_WIDTH);
+ assert(mountimg.height == MOUNTIMG_HEIGHT);
+
+ for(i=0; i<MOUNTIMG_WIDTH; i++) {
+ uint16_t *pptr = mountimg.pixels + i;
+ for(j=0; j<MOUNTIMG_HEIGHT; j++) {
+ if(*pptr != 0x7e0) {
+ mountimg_skip[i] = j;
+ break;
+ }
+ pptr += MOUNTIMG_WIDTH;
+ }
+ }
+ destroy_image(&mountimg);
+ mountimg.pixels = 0;
+
+ return 0;
+}
+
+static void destroy(void)
+{
+ destroy_mesh(&gmesh);
+ destroy_image(>ex);
+}
+
+static void start(long trans_time)
+{
+ g3d_matrix_mode(G3D_PROJECTION);
+ g3d_load_identity();
+ g3d_perspective(VFOV, 1.3333333, 0.5, 500.0);
+
+ g3d_enable(G3D_CULL_FACE);
+
+ g3d_clear_color(85, 70, 136);
+
+ part_start = time_msec;
+}
+
+static void update(void)
+{
+ int i, j;
+ float t = (time_msec - part_start) / 1000.0f;
+ struct g3d_vertex *vptr;
+
+ float ampl = cgm_smoothstep(TM_RIPPLE_START, TM_RIPPLE_START + TM_RIPPLE_TRANS_LEN, t);
+
+ mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
+
+ /* update mesh */
+ vptr = gmesh.varr;
+ for(i=0; i<GMESH_GRIDSZ + 1; i++) {
+ for(j=0; j<GMESH_GRIDSZ + 1; j++) {
+ float u = (float)j / GMESH_GRIDSZ - 0.5f;
+ float v = (float)i / GMESH_GRIDSZ - 0.5f;
+ float x = u * 32.0f;
+ float y = v * 32.0f;
+ float r = sqrt(x * x + y * y);
+
+ vptr->z = 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<FB_WIDTH; i++) {
+ int skip = mountimg_skip[(x >> 8) & 0x1ff];
+ int vspan = MOUNTIMG_HEIGHT - skip;
+
+ dptr = fb_pixels + (y + skip) * FB_WIDTH + i;
+
+ for(j=0; j<vspan; j++) {
+ *dptr = 0; /* black mountains */
+ dptr += FB_WIDTH;
+ }
+
+ x += dx;
+ }
+
+ if(horizon_y < FB_HEIGHT) {
+ memset(fb_pixels + horizon_y * FB_WIDTH, 0, (FB_HEIGHT - horizon_y) * FB_WIDTH * 2);
+ }
+}
+#include "demo.h"
+#include "imago2.h"
+#include "screen.h"
+#include <assert.h>
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <math.h>
-#include <assert.h>
-#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
static void initScrollTables();
static void updateScrollTables(float dt);
-
-
static unsigned short *background = 0;
static int backgroundW = 0;
static int backgroundH = 0;
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;
}
return 0;
}
-static void destroy(void)
-{
+static void destroy(void) {
free(backBuffer);
backBuffer = 0;
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;
}
/* 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;
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];
}
/* 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;
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--;
}
}
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;
}
/* 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++;
}
}
}
}
-
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];
}
/* -------------------------------------------------------------------------------------------------
- * 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)
/* 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;
}
--- /dev/null
+#include "demo.h"
+#include "imago2.h"
+#include "screen.h"
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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<FB_WIDTH * FB_HEIGHT; i++) {
+ backBuffer[i] = clearColor16;
+ }
+
+ /* For now create / destroy in each frame. We will manage these later */
+ rle = rleCreate(32, 32);
+
+ updatePropeller(time_msec / 1000.0f, rle);
+ stride = FB_WIDTH;
+ /*
+ rleBlit(rle, backBuffer, FB_WIDTH, FB_HEIGHT, stride,
+ 100, 100);
+ */
+
+ rleBlitScale(rle, backBuffer, FB_WIDTH, FB_HEIGHT, stride, 50,
+ 50, 3.0, 3.0);
+
+ rleDestroy(rle);
+
+ /* Blit effect to framebuffer */
+ memcpy(fb_pixels, backBuffer, FB_WIDTH * FB_HEIGHT * sizeof(unsigned short));
+ swap_buffers(0);
+}
+
+
+#define PROPELLER_CIRCLE_RADIUS 18
+#define PROPELLER_CIRCLE_RADIUS_SQ (PROPELLER_CIRCLE_RADIUS * PROPELLER_CIRCLE_RADIUS)
+
+static struct {
+ int circleX[3];
+ int circleY[3];
+} propellerState;
+
+static void updatePropeller(float t, RleBitmap *rle) {
+
+ int i, j;
+ int cx, cy, count = 0;
+ unsigned char *dst;
+ float x = 0.0f;
+ float y = 18.0f;
+ float nx, ny;
+ float cost, sint;
+ static float sin120 = 0.86602540378f;
+ static float cos120 = -0.5f;
+
+ t *= 0.1; /* Slow-mo to see what happens */
+
+ /* Rotate */
+ sint = sin(t);
+ cost = cos(t);
+ nx = x * cost - y * sint;
+ ny = y * cost + x * sint;
+ x = nx;
+ y = ny;
+ propellerState.circleX[0] = (int)(x + 0.5f) + 16;
+ propellerState.circleY[0] = (int)(y + 0.5f) + 16;
+
+ /* Rotate by 120 degrees, for the second circle */
+ nx = x * cos120 - y * sin120;
+ ny = y * cos120 + x * sin120;
+ x = nx;
+ y = ny;
+ propellerState.circleX[1] = (int)(x + 0.5f) + 16;
+ propellerState.circleY[1] = (int)(y + 0.5f) + 16;
+
+ /* 3rd circle */
+ nx = x * cos120 - y * sin120;
+ ny = y * cos120 + x * sin120;
+ x = nx;
+ y = ny;
+ propellerState.circleX[2] = (int)(x + 0.5f) + 16;
+ propellerState.circleY[2] = (int)(y + 0.5f) + 16;
+
+ /* Write effect to the mini fx buffer*/
+ dst = miniFXBuffer;
+ for (j = 0; j < 32; j++) {
+ for (i = 0; i < 32; i++) {
+ count = 0;
+
+ /* First circle */
+ cx = propellerState.circleX[0] - i;
+ cy = propellerState.circleY[0] - j;
+ 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++;
+
+ /* 3rd circle */
+ cx = propellerState.circleX[2] - i;
+ cy = propellerState.circleY[2] - j;
+ if (cx * cx + cy * cy < PROPELLER_CIRCLE_RADIUS_SQ)
+ count++;
+
+ *dst++ = count >= 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);
+}
--- /dev/null
+#include <stdio.h>
+#include <math.h>
+#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; i<NUM_TILES; i++) {
+ rend_tile(tile->fbptr, tile->x, tile->y, TILESZ, -1);
+ tile++;
+ }
+
+ swap_buffers(0);
+}
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#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; i<scn->num_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; i<scn->num_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; i<scn->num_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;
+}
--- /dev/null
+#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_ */
return (unsigned char)ret;
}
-void sort(PointSprite *begin, PointSprite *end) {\r
- PointSprite pivotValue;\r
- size_t sz;\r
- PointSprite *left, *right;\r
- int leftCond, rightCond;\r
- PointSprite tmp;\r
-\r
- sz = end - begin;\r
-\r
- if (sz < 2) return; /* already sorted */\r
- if (sz == 2) {\r
- /* trivial case */\r
- if (begin[1] < begin[0]) {\r
- tmp = begin[0];\r
- begin[0] = begin[1];\r
- begin[1] = tmp;\r
- return;\r
- }\r
- }\r
-\r
- /* minimum 3 elements from now on */\r
-\r
- /* choose a pivot near the middle, since we frequently sort already sorted arrays */\r
- pivotValue = begin[sz / 2];\r
-\r
- left = begin;\r
- right = end - 1;\r
-\r
- while (right > left) {\r
- /* check if left and right elements meet the conditions */\r
- leftCond = pivotValue >= *left;\r
- rightCond = pivotValue < *right;\r
-\r
- if (!leftCond && !rightCond) {\r
- tmp = *left;\r
- *left = *right;\r
- *right = tmp;\r
- left++;\r
- right--;\r
- }\r
- else if (leftCond && rightCond) {\r
- left++;\r
- right--;\r
- }\r
- else if (leftCond) {\r
- left++;\r
- }\r
- else {\r
- right--;\r
- }\r
- }\r
-\r
- /* recursion */\r
- sort(begin, left);\r
- sort(left, end);\r
-}\r
+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);
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);
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);
/* 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)
{
}
swap_buffers(loading_pixels);
- sleep_msec(load_delay * 2);
+ if(load_delay) {
+ sleep_msec(load_delay * 2);
+ }
prev_load_msec = get_msec();
}
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)
#include "cfgopt.h"
#include "sball.h"
#include "vmath.h"
+#include "cpuid.h"
static void handle_event(SDL_Event *ev);
static void toggle_fullscreen(void);
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);*/
#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.
*/
/*
#include <errno.h>
#include "treestor.h"
-#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__)
+#if defined(__WATCOMC__) || defined(WIN32) || defined(__DJGPP__)
#include <malloc.h>
#else
#include <alloca.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
#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;
+}
#ifndef UTIL_H_
#define UTIL_H_
+#include <stdlib.h>
#include "inttypes.h"
#ifdef __GNUC__
#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)
{
: "%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
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_ */
--- /dev/null
+ 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:
#include <string.h>
#include <stdint.h>
#include <assert.h>
+#ifdef WIN32
+#include <malloc.h>
+#else
#include <alloca.h>
+#endif
#include "image.h"
struct rect {
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)
--- /dev/null
+#!/bin/sh
+
+for i in `find . -name 'makefile*'`; do
+ name=`echo $i | sed 's/makefile/Makefile/'`
+ echo "$i -> $name"
+ mv $i $name
+done
#!/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