reorganized the source code
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 15 Dec 2019 06:43:46 +0000 (08:43 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sun, 15 Dec 2019 06:43:46 +0000 (08:43 +0200)
34 files changed:
GNUmakefile
Makefile
Makefile.dj
README.md
src/bump.c [deleted file]
src/fract.c [deleted file]
src/greets.c [deleted file]
src/grise.c [deleted file]
src/hairball.c [deleted file]
src/infcubes.c [deleted file]
src/metaball.c [deleted file]
src/plasma.c [deleted file]
src/polytest.c [deleted file]
src/scr/bump.c [new file with mode: 0644]
src/scr/fract.c [new file with mode: 0644]
src/scr/greets.c [new file with mode: 0644]
src/scr/grise.c [new file with mode: 0644]
src/scr/hairball.c [new file with mode: 0644]
src/scr/infcubes.c [new file with mode: 0644]
src/scr/metaball.c [new file with mode: 0644]
src/scr/plasma.c [new file with mode: 0644]
src/scr/polytest.c [new file with mode: 0644]
src/scr/smoketxt.c [new file with mode: 0644]
src/scr/smoketxt.h [new file with mode: 0644]
src/scr/thunder.c [new file with mode: 0644]
src/scr/tilemaze.c [new file with mode: 0644]
src/scr/tilemaze.h [new file with mode: 0644]
src/scr/tunnel.c [new file with mode: 0644]
src/smoketxt.c [deleted file]
src/smoketxt.h [deleted file]
src/thunder.c [deleted file]
src/tilemaze.c [deleted file]
src/tilemaze.h [deleted file]
src/tunnel.c [deleted file]

index f64feca..199fc30 100644 (file)
@@ -1,9 +1,9 @@
-src = $(wildcard src/*.c) $(wildcard src/sdl/*.c)
+src = $(wildcard src/*.c) $(wildcard src/scr/*.c) $(wildcard src/sdl/*.c)
 obj = $(src:.c=.o) $(asmsrc:.asm=.o)
 dep = $(obj:.o=.d)
 bin = demo
 
 obj = $(src:.c=.o) $(asmsrc:.asm=.o)
 dep = $(obj:.o=.d)
 bin = demo
 
-inc = -I/usr/local/include -Isrc -Isrc/sdl -Ilibs -Ilibs/imago/src -Ilibs/mikmod/include
+inc = -I/usr/local/include -Isrc -Isrc/scr -Isrc/sdl -Ilibs -Ilibs/imago/src -Ilibs/mikmod/include
 warn = -pedantic -Wall -Wno-unused-variable -Wno-unused-function
 
 CFLAGS = $(warn) -g $(inc) `sdl-config --cflags`
 warn = -pedantic -Wall -Wno-unused-variable -Wno-unused-function
 
 CFLAGS = $(warn) -g $(inc) `sdl-config --cflags`
index 2faa385..1d0d7da 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -37,9 +37,9 @@ $(bin): cflags.occ $(obj) libs/imago/imago.lib
        %write ldflags.lnk $(LDFLAGS)
        $(LD) debug all name $@ system dos4g file { @objects } @ldflags
 
        %write ldflags.lnk $(LDFLAGS)
        $(LD) debug all name $@ system dos4g file { @objects } @ldflags
 
-.c: src;src/dos
-.cc: src;src/dos
-.asm: src;src/dos
+.c: src;src/dos;src/scr
+.cc: src;src/dos;src/scr
+.asm: src;src/dos;src/scr
 
 cflags.occ: Makefile
        %write $@ $(CFLAGS)
 
 cflags.occ: Makefile
        %write $@ $(CFLAGS)
index b95f943..9306382 100644 (file)
@@ -1,5 +1,5 @@
-src = $(wildcard src/*.c) $(wildcard src/dos/*.c)
-asmsrc = $(wildcard src/*.asm) $(wildcard src/dos/*.asm)
+src = $(wildcard src/*.c) $(wildcard src/scr/*.c) $(wildcard src/dos/*.c)
+asmsrc = $(wildcard src/*.asm) $(wildcard src/scr/*.asm) $(wildcard src/dos/*.asm)
 obj = $(src:.c=.cof) $(asmsrc:.asm=.cof)
 dep = $(obj:.cof=.dep)
 bin = demo.exe
 obj = $(src:.c=.cof) $(asmsrc:.asm=.cof)
 dep = $(obj:.cof=.dep)
 bin = demo.exe
@@ -11,7 +11,7 @@ else
        TOOLPREFIX = i586-pc-msdosdjgpp-
 endif
 
        TOOLPREFIX = i586-pc-msdosdjgpp-
 endif
 
-inc = -Isrc -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/anim/src -Ilibs/mikmod/include
+inc = -Isrc -Isrc/scr -Isrc/dos -Ilibs -Ilibs/imago/src -Ilibs/anim/src -Ilibs/mikmod/include
 opt = -O3 -ffast-math -fno-strict-aliasing
 dbg = -g
 warn = -pedantic -Wall -Wno-unused-function -Wno-unused-variable
 opt = -O3 -ffast-math -fno-strict-aliasing
 dbg = -g
 warn = -pedantic -Wall -Wno-unused-function -Wno-unused-variable
index 102090e..ec9721f 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,8 +1,17 @@
 Unnamed Mindlapse DOS demo for Pentium 133
 ------------------------------------------
 The demo requires VESA Bios Extensions (VBE) 2.0. If your graphics card doesn't
 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 run the `univbe` TSR first, or
-the demo will fail to find a usable LFB video mode.
+support VBE 2.0 or greater, then make sure to load the `univbe` TSR first.
+
+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/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
 
 Building on DOS with Watcom
 ---------------------------
 
 Building on DOS with Watcom
 ---------------------------
diff --git a/src/bump.c b/src/bump.c
deleted file mode 100644 (file)
index b82594b..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-// Bump effect (not moving yet of course, I have many ideas on this to commit before it's ready)
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "demo.h"
-#include "screen.h"
-
-static int init(void);
-static void destroy(void);
-static void start(long trans_time);
-static void draw(void);
-
-static struct screen scr = {
-       "bump",
-       init,
-       destroy,
-       start,
-       0,
-       draw
-};
-
-struct point {
-       int x, y;
-};
-
-#define NUM_BIG_LIGHTS 3
-#define BIG_LIGHT_WIDTH 256
-#define BIG_LIGHT_HEIGHT BIG_LIGHT_WIDTH
-
-#define NUM_PARTICLES 64
-#define PARTICLE_LIGHT_WIDTH 32
-#define PARTICLE_LIGHT_HEIGHT 32
-
-
-static unsigned long startingTime;
-
-static unsigned char *heightmap;
-static unsigned short *lightmap;
-static int *bumpOffset;
-
-static unsigned short *bigLight[NUM_BIG_LIGHTS];
-static struct point bigLightPoint[NUM_BIG_LIGHTS];
-
-static unsigned short *particleLight;
-static struct point particlePoint[NUM_PARTICLES];
-
-struct screen *bump_screen(void)
-{
-       return &scr;
-}
-
-static int init(void)
-{
-       int i, j, x, y, c, r, g, b;
-
-       const int numBlurs = 3;
-       const int lightRadius = BIG_LIGHT_WIDTH / 2;
-       const int particleRadius = PARTICLE_LIGHT_WIDTH / 2;
-
-       const int bigLightSize = BIG_LIGHT_WIDTH * BIG_LIGHT_HEIGHT;
-       const int particleLightSize = PARTICLE_LIGHT_WIDTH * PARTICLE_LIGHT_HEIGHT;
-       const int fb_size = fb_width * fb_height;
-
-       // Just some parameters to temporary test the colors of 3 lights
-       // if every light uses it's own channel bits, it's better
-       const float rgbMul[9] = { 1.0f, 0.0f, 0.0f, 
-                                                                 0.0f, 1.0f, 0.0f,
-                                                                 0.0f, 0.0f, 1.0f};
-
-       heightmap = malloc(sizeof(*heightmap) * fb_size);
-       lightmap = malloc(sizeof(*lightmap) * fb_size);
-       bumpOffset = malloc(sizeof(*bumpOffset) * fb_size);
-
-       for (i = 0; i < NUM_BIG_LIGHTS; i++)
-               bigLight[i] = malloc(sizeof(*bigLight[i]) * bigLightSize);
-
-       particleLight = malloc(sizeof(*particleLight) * particleLightSize);
-
-       memset(lightmap, 0, sizeof(*lightmap) * fb_size);
-       memset(bumpOffset, 0, sizeof(*bumpOffset) * fb_size);
-       memset(particlePoint, 0, sizeof(*particlePoint) * NUM_PARTICLES);
-
-       // Create random junk
-       for (i = 0; i < fb_size; i++)
-               heightmap[i] = rand() & 255;
-
-       // Blur to smooth
-       for (j = 0; j < numBlurs; j++)
-               for (i = 0; i < fb_size; i++)
-                       heightmap[i] = (heightmap[abs((i - 1) % fb_size)] + heightmap[abs((i + 1) % fb_size)] + heightmap[abs((i - fb_width) % fb_size)] + heightmap[abs((i + fb_width) % fb_size)]) >> 2;
-
-       // Inclination precalculation
-       i = 0;
-       for (y = 0; y < fb_height; y++)
-       {
-               for (x = 0; x < fb_width; x++)
-               {
-                       const float offsetPower = 0.75f;
-                       int dx, dy, xp, yp;
-
-                       dx = i < fb_size - 1 ? (int)((heightmap[i] - heightmap[i + 1]) * offsetPower) : 0;
-                       dy = i < fb_size - fb_width ? (int)((heightmap[i] - heightmap[i + fb_width]) * offsetPower) : 0;
-
-                       xp = x + dx;
-                       if (xp < 0) xp = 0;
-                       if (xp > fb_width - 1) xp = fb_width - 1;
-
-                       yp = y + dy;
-                       if (yp < 0) yp = 0;
-                       if (yp > fb_height - 1) yp = fb_height - 1;
-
-                       bumpOffset[i++] = yp * fb_width + xp;
-               }
-       }
-
-       // Generate three lights
-       i = 0;
-       for (y = 0; y < BIG_LIGHT_HEIGHT; y++)
-       {
-               int yc = y - (BIG_LIGHT_HEIGHT / 2);
-               for (x = 0; x < BIG_LIGHT_WIDTH; x++)
-               {
-                       int xc = x - (BIG_LIGHT_WIDTH / 2);
-                       float d = (float)sqrt(xc * xc + yc * yc);
-                       float invDist = ((float)lightRadius - (float)sqrt(xc * xc + yc * yc)) / (float)lightRadius;
-                       if (invDist < 0.0f) invDist = 0.0f;
-
-                       c = (int)(invDist * 63);
-                       r = c >> 1;
-                       g = c;
-                       b = c >> 1;
-
-                       for (j = 0; j < NUM_BIG_LIGHTS; j++)
-                       {
-                               bigLight[j][i] = ((int)(r * rgbMul[j * 3]) << 11) | ((int)(g * rgbMul[j * 3 + 1]) << 5) | (int)(b * rgbMul[j * 3 + 2]);
-                       }
-                       i++;
-               }
-       }
-
-       i = 0;
-       for (y = 0; y < PARTICLE_LIGHT_HEIGHT; y++)
-       {
-               int yc = y - (PARTICLE_LIGHT_HEIGHT / 2);
-               for (x = 0; x < PARTICLE_LIGHT_WIDTH; x++)
-               {
-                       int xc = x - (PARTICLE_LIGHT_WIDTH / 2);
-
-                       float invDist = ((float)particleRadius - (float)sqrt(xc * xc + yc * yc)) / (float)particleRadius;
-                       if (invDist < 0.0f) invDist = 0.0f;
-
-                       c = (int)(pow(invDist, 0.75f) * 63);
-                       particleLight[i++] = ((c >> 1) << 11) | (c << 5) | (c >> 1);
-               }
-       }
-
-       return 0;
-}
-
-static void destroy(void)
-{
-}
-
-static void start(long trans_time)
-{
-       startingTime = time_msec;
-}
-
-static void eraseArea(struct point *p, int width, int height)
-{
-       int x, y, dx;
-       unsigned short *dst;
-
-       int x0 = p->x;
-       int y0 = p->y;
-       int x1 = p->x + width;
-       int y1 = p->y + height;
-
-       if (x0 < 0) x0 = 0;
-       if (y0 < 0) y0 = 0;
-       if (x1 > fb_width) x1 = fb_width;
-       if (y1 > fb_height) y1 = fb_height;
-
-       dx = x1 - x0;
-
-       dst = lightmap + y0 * fb_width + x0;
-
-       for (y = y0; y < y1; y++)
-       {
-               for (x = x0; x < x1; x++)
-               {
-                       *dst++ = 0;
-               }
-               dst += fb_width - dx;
-       }
-}
-
-
-static void renderLight(struct point *p, int width, int height, unsigned short *light)
-{
-       int x, y, dx;
-       unsigned short *src, *dst;
-
-       int x0 = p->x;
-       int y0 = p->y;
-       int x1 = p->x + width;
-       int y1 = p->y + height;
-
-       int xl = 0;
-       int yl = 0;
-
-       if (x0 < 0)
-       {
-               xl = -x0;
-               x0 = 0;
-       }
-
-       if (y0 < 0)
-       {
-               yl = -y0;
-               y0 = 0;
-       }
-
-       if (x1 > fb_width) x1 = fb_width;
-       if (y1 > fb_height) y1 = fb_height;
-
-       dx = x1 - x0;
-
-       dst = lightmap + y0 * fb_width + x0;
-       src = light + yl * width + xl;
-
-       for (y = y0; y < y1; y++)
-       {
-               for (x = x0; x < x1; x++)
-               {
-                       *dst++ |= *src++;
-               }
-               dst += fb_width - dx;
-               src += width - dx;
-       }
-}
-
-static void eraseLights()
-{
-       int i;
-       for (i = 0; i < NUM_BIG_LIGHTS; i++)
-               eraseArea(&bigLightPoint[i], BIG_LIGHT_WIDTH, BIG_LIGHT_HEIGHT);
-}
-
-static void renderLights()
-{
-       int i;
-       for (i = 0; i < NUM_BIG_LIGHTS; i++)
-               renderLight(&bigLightPoint[i], BIG_LIGHT_WIDTH, BIG_LIGHT_HEIGHT, bigLight[i]);
-}
-
-static void renderParticles()
-{
-       int i;
-       for (i = 0; i < NUM_PARTICLES; i++)
-               renderLight(&particlePoint[i], PARTICLE_LIGHT_WIDTH, PARTICLE_LIGHT_HEIGHT, particleLight);
-}
-
-static void animateLights()
-{
-       struct point center;
-       float dt = (float)(time_msec - startingTime) / 1000.0f;
-       float tt = 1.0f - sin(dt);
-       float disperse = tt * 64.0f;
-
-       center.x = (fb_width >> 1) - (BIG_LIGHT_WIDTH / 2);
-       center.y = (fb_height >> 1) - (BIG_LIGHT_HEIGHT / 2);
-
-       bigLightPoint[0].x = center.x + sin(1.2f * dt) * (144.0f + disperse);
-       bigLightPoint[0].y = center.y + sin(0.8f * dt) * (148.0f + disperse);
-
-       bigLightPoint[1].x = center.x + sin(1.5f * dt) * (156.0f + disperse);
-       bigLightPoint[1].y = center.y + sin(1.1f * dt) * (92.0f + disperse);
-
-       bigLightPoint[2].x = center.x + sin(2.0f * dt) * (112.0f + disperse);
-       bigLightPoint[2].y = center.y + sin(1.3f * dt) * (136.0f + disperse);
-}
-
-static void renderBump(unsigned short *vram)
-{
-       int i;
-       for (i = 0; i < fb_width * fb_height; i++)
-       {
-               unsigned short c = lightmap[bumpOffset[i]];
-               *vram++ = c;
-       }
-}
-
-static void animateParticles()
-{
-       int i;
-       struct point center;
-       float dt = (float)(time_msec - startingTime) / 2000.0f;
-       float tt = sin(dt);
-
-       center.x = (fb_width >> 1) - (PARTICLE_LIGHT_WIDTH / 2);
-       center.y = (fb_height >> 1) - (PARTICLE_LIGHT_HEIGHT / 2);
-
-       for (i = 0; i < NUM_PARTICLES; i++)
-       {
-               particlePoint[i].x = center.x + (sin(1.2f * (i*i*i + dt)) * 74.0f + sin(0.6f * (i + dt)) * 144.0f) * tt;
-               particlePoint[i].y = center.y + (sin(1.8f * (i + dt)) * 68.0f + sin(0.5f * (i*i + dt)) * 132.0f) * tt;
-       }
-}
-
-static void draw(void)
-{
-       memset(lightmap, 0, fb_width * fb_height * sizeof(*lightmap));
-
-       //eraseLights();
-       animateLights();
-       renderLights();
-
-       animateParticles();
-       renderParticles();
-
-       renderBump((unsigned short*)fb_pixels);
-
-       swap_buffers(0);
-}
diff --git a/src/fract.c b/src/fract.c
deleted file mode 100644 (file)
index 6eeb678..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-#include <string.h>
-#include <limits.h>
-#include "demo.h"
-#include "screen.h"
-#include "gfxutil.h"
-
-struct vec2x {
-       long x, y;
-};
-
-static int init(void);
-static void destroy(void);
-static void draw(void);
-static int julia(long x, long y, long cx, long cy, int max_iter);
-
-static struct screen scr = {
-       "fract",
-       init,
-       destroy,
-       0, 0,
-       draw
-};
-
-/*static long aspect_24x8 = (long)(1.3333333 * 256.0);*/
-static long xscale_24x8 = (long)(1.3333333 * 1.2 * 256.0);
-static long yscale_24x8 = (long)(1.2 * 256.0);
-static int cx, cy;
-static int max_iter = 50;
-
-#define WALK_SIZE      20
-
-struct screen *fract_screen(void)
-{
-       return &scr;
-}
-
-static int init(void)
-{
-       return 0;
-}
-
-static void destroy(void)
-{
-}
-
-static void draw(void)
-{
-       int i, j;
-       unsigned short *pixels = fb_pixels;
-
-       cx = mouse_x;
-       cy = mouse_y;
-
-       for(i=0; i<fb_height; i++) {
-               for(j=0; j<fb_width; j++) {
-                       unsigned char pidx = julia(j, i, cx, cy, max_iter) & 0xff;
-                       *pixels++ = (pidx >> 3) | ((pidx >> 2) << 5) | ((pidx >> 3) << 11);
-               }
-       }
-
-       pixels = fb_pixels;
-       pixels[mouse_y * fb_width + mouse_x] = 0xffe;
-       swap_buffers(0);
-}
-
-static long normalize_coord(long x, long range)
-{
-       /* 2 * x / range - 1*/
-       return (x << 17) / range - 65536;
-}
-
-static int julia(long x, long y, long cx, long cy, int max_iter)
-{
-       int i;
-
-       /* convert to fixed point roughly [-1, 1] */
-       x = (normalize_coord(x, fb_width) >> 8) * xscale_24x8;
-       y = (normalize_coord(y, fb_height) >> 8) * yscale_24x8;
-       cx = (normalize_coord(cx, fb_width) >> 8) * xscale_24x8;
-       cy = (normalize_coord(cy, fb_height) >> 8) * yscale_24x8;
-
-       for(i=0; i<max_iter; i++) {
-               /* z_n = z_{n-1}**2 + c */
-               long px = x >> 8;
-               long py = y >> 8;
-
-               if(px * px + py * py > (4 << 16)) {
-                       break;
-               }
-               x = px * px - py * py + cx;
-               y = (px * py << 1) + cy;
-       }
-
-       return i < max_iter ? (256 * i / max_iter) : 0;
-}
diff --git a/src/greets.c b/src/greets.c
deleted file mode 100644 (file)
index 8b128c6..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include "demo.h"
-#include "3dgfx.h"
-#include "screen.h"
-#include "cfgopt.h"
-#include "imago2.h"
-#include "util.h"
-#include "gfxutil.h"
-#include "timer.h"
-#include "smoketxt.h"
-
-#ifdef MSDOS
-#include "dos/gfx.h"   /* for wait_vsync assembly macro */
-#else
-void wait_vsync(void);
-#endif
-
-#define BLUR_RAD       5
-
-
-static int init(void);
-static void destroy(void);
-static void start(long trans_time);
-static void draw(void);
-
-
-static struct screen scr = {
-       "greets",
-       init,
-       destroy,
-       start, 0,
-       draw
-};
-
-static long start_time;
-
-static struct smktxt *stx;
-
-static uint16_t *cur_smokebuf, *prev_smokebuf;
-static int smokebuf_size;
-#define smokebuf_start (cur_smokebuf < prev_smokebuf ? cur_smokebuf : prev_smokebuf)
-#define swap_smoke_buffers() \
-       do { \
-               uint16_t *tmp = cur_smokebuf; \
-               cur_smokebuf = prev_smokebuf; \
-               prev_smokebuf = tmp; \
-       } while(0)
-
-static float cam_theta, cam_phi = 25;
-static float cam_dist = 3;
-
-struct screen *greets_screen(void)
-{
-       return &scr;
-}
-
-
-static int init(void)
-{
-       if(!(stx = create_smktxt("data/greets1.png", "data/vfield1"))) {
-               return -1;
-       }
-
-       smokebuf_size = fb_width * fb_height * sizeof *cur_smokebuf;
-       if(!(cur_smokebuf = malloc(smokebuf_size * 2))) {
-               perror("failed to allocate smoke framebuffer");
-               return -1;
-       }
-       prev_smokebuf = cur_smokebuf + fb_width * fb_height;
-
-       return 0;
-}
-
-static void destroy(void)
-{
-       free(smokebuf_start);
-       destroy_smktxt(stx);
-}
-
-static void start(long trans_time)
-{
-       g3d_matrix_mode(G3D_PROJECTION);
-       g3d_load_identity();
-       g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
-
-       memset(smokebuf_start, 0, smokebuf_size * 2);
-
-       start_time = time_msec;
-}
-
-static void update(void)
-{
-       static long prev_msec;
-       static int prev_mx, prev_my;
-       static unsigned int prev_bmask;
-
-       long msec = time_msec - start_time;
-       float dt = (msec - prev_msec) / 1000.0f;
-       prev_msec = msec;
-
-       if(mouse_bmask) {
-               if((mouse_bmask ^ prev_bmask) == 0) {
-                       int dx = mouse_x - prev_mx;
-                       int dy = mouse_y - prev_my;
-
-                       if(dx || dy) {
-                               if(mouse_bmask & 1) {
-                                       cam_theta += dx * 1.0;
-                                       cam_phi += dy * 1.0;
-
-                                       if(cam_phi < -90) cam_phi = -90;
-                                       if(cam_phi > 90) cam_phi = 90;
-                               }
-                               if(mouse_bmask & 4) {
-                                       cam_dist += dy * 0.5;
-
-                                       if(cam_dist < 0) cam_dist = 0;
-                               }
-                       }
-               }
-       }
-       prev_mx = mouse_x;
-       prev_my = mouse_y;
-       prev_bmask = mouse_bmask;
-
-       update_smktxt(stx, dt);
-}
-
-static void draw(void)
-{
-       int i, j;
-       uint16_t *dest, *src;
-       unsigned long msec;
-       static unsigned long last_swap;
-
-       update();
-
-       g3d_matrix_mode(G3D_MODELVIEW);
-       g3d_load_identity();
-       g3d_translate(0, 0, -cam_dist);
-       g3d_rotate(cam_phi, 1, 0, 0);
-       g3d_rotate(cam_theta, 0, 1, 0);
-       if(opt.sball) {
-               g3d_mult_matrix(sball_matrix);
-       }
-
-       memcpy(cur_smokebuf, prev_smokebuf, smokebuf_size);
-
-       g3d_framebuffer(fb_width, fb_height, cur_smokebuf);
-       draw_smktxt(stx);
-       g3d_framebuffer(fb_width, fb_height, fb_pixels);
-
-       dest = fb_pixels;
-       src = cur_smokebuf;
-       for(i=0; i<fb_height; i++) {
-               for(j=0; j<fb_width; j++) {
-                       unsigned int alpha = *src++;
-                       *dest++ = PACK_RGB16(alpha, alpha, alpha);
-               }
-       }
-
-       /*perf_start();*/
-       blur_grey_horiz(prev_smokebuf, cur_smokebuf, fb_width, fb_height, BLUR_RAD, 240);
-       /*
-       perf_end();
-       printf("blur perf: %lu\n", (unsigned long)perf_interval_count);
-       */
-       blur_grey_vert(cur_smokebuf, prev_smokebuf, fb_width, fb_height, BLUR_RAD, 240);
-       swap_smoke_buffers();
-
-       msec = get_msec();
-       if(msec - last_swap < 16) {
-               wait_vsync();
-       }
-       if(!opt.vsync) {
-               wait_vsync();
-       }
-       swap_buffers(fb_pixels);
-       last_swap = get_msec();
-}
diff --git a/src/grise.c b/src/grise.c
deleted file mode 100644 (file)
index 94e3850..0000000
+++ /dev/null
@@ -1,691 +0,0 @@
-#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 */
-
-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);
-
-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 */
-
-/* Every backBuffer scanline is guaranteed to have that many dummy pixels before and after */
-#define PIXEL_PADDING 32
-
-/* Make sure this is less than PIXEL_PADDING*/
-#define MAX_DISPLACEMENT 16
-
-#define MIN_SCROLL PIXEL_PADDING
-#define MAX_SCROLL (backgroundW - fb_width - MIN_SCROLL)
-
-#define FAR_SCROLL_SPEED 15.0f
-#define NEAR_SCROLL_SPEED 120.0f
-
-#define HORIZON_HEIGHT 100
-#define REFLECTION_HEIGHT (240 - HORIZON_HEIGHT)
-
-#define NORMALMAP_SCANLINE 372
-
-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 convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount);
-static void processNormal();
-static void initScrollTables();
-static void updateScrollTables(float dt);
-
-
-
-static unsigned short *background = 0;
-static int backgroundW = 0;
-static int backgroundH = 0;
-
-static unsigned int lastFrameTime = 0;
-static float lastFrameDuration = 0.0f;
-
-static short *displacementMap;
-
-static unsigned short *backBuffer;
-
-static float scrollScaleTable[REFLECTION_HEIGHT];
-static float scrollTable[REFLECTION_HEIGHT];
-static int scrollTableRounded[REFLECTION_HEIGHT];
-static int scrollModTable[REFLECTION_HEIGHT];
-static float nearScrollAmount = 0.0f;
-
-static unsigned char miniFXBuffer[1024];
-
-static RLEBitmap *grobj = 0;
-static RLEBitmap *rlePropeller = 0;
-
-static struct screen scr = {
-       "galaxyrise",
-       init,
-       destroy,
-       start,
-       0,
-       draw
-};
-
-struct screen *grise_screen(void)
-{
-       return &scr;
-}
-
-static int init(void)
-{
-       unsigned char *tmpBitmap;
-       int tmpBitmapW, tmpBitmapH;
-
-       /* Allocate back buffer */
-       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))) {
-               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 */
-
-       /* Load reflected objects */
-       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;
-       }
-
-       grobj = rleEncode(0, tmpBitmap, tmpBitmapW, tmpBitmapH);
-
-       img_free_pixels(tmpBitmap);
-
-       initScrollTables();
-
-       processNormal();
-
-       return 0;
-}
-
-static void destroy(void)
-{
-       free(backBuffer);
-       backBuffer = 0;
-
-       img_free_pixels(background);
-
-       rleDestroy(grobj);
-}
-
-static void start(long trans_time)
-{
-       lastFrameTime = time_msec;
-}
-
-
-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;
-       int scanline = 0;
-       int i = 0;
-       short *dispScanline;
-       int d;
-       int accum = 0;
-       int md, sc;
-       int scrolledIndex;
-
-       lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
-       lastFrameTime = time_msec;
-
-       /* Update mini-effects here */
-       updatePropeller(4.0f * time_msec / 1000.0f);
-
-       /* First, render the horizon */
-       for (scanline = 0; scanline < HORIZON_HEIGHT; scanline++) {
-               memcpy(dst, src, fb_width * 2);
-               src += backgroundW;
-               dst += BB_SIZE;
-       }
-
-       /* Create scroll offsets for all scanlines of the normalmap */
-       updateScrollTables(lastFrameDuration);
-
-       /* Render the baked reflection one scanline below its place, so that
-        * the displacement that follows will be done in a cache-friendly way
-        */
-       src -= PIXEL_PADDING; /* We want to also fill the PADDING pixels here */
-       dst = backBuffer + (HORIZON_HEIGHT + 1) * BB_SIZE;
-       for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
-               memcpy(dst, src, (fb_width + PIXEL_PADDING) * 2);
-               src += backgroundW;
-               dst += BB_SIZE;
-       }
-
-       /* 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);
-
-       /* Perform displacement */
-       dst = backBuffer + HORIZON_HEIGHT * BB_SIZE + PIXEL_PADDING;
-       src = dst + BB_SIZE; /* The pixels to be displaced are 1 scanline below */
-       dispScanline = displacementMap;
-       for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
-
-               md = scrollModTable[scanline];
-               sc = scrollTableRounded[scanline];
-               accum = 0;
-
-               for (i = 0; i < fb_width; i++) {
-                       /* Try to immitate modulo without the division */
-                       if (i == md) accum += md;
-                       scrolledIndex = i - accum + sc;
-                       if (scrolledIndex >= md) scrolledIndex -= md;
-
-                       /* Displace */
-                       d = dispScanline[scrolledIndex];
-                       *dst++ = src[i + d];
-               }
-               src += backgroundW;
-               dst += BB_SIZE - fb_width;
-               dispScanline += backgroundW;
-       }
-
-       /* 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);
-
-       /* Blit effect to framebuffer */
-       src = backBuffer + PIXEL_PADDING;
-       dst = fb_pixels;
-       for (scanline = 0; scanline < fb_height; scanline++) {
-               memcpy(dst, src, fb_width * 2);
-               src += BB_SIZE;
-               dst += fb_width;
-       }
-
-       swap_buffers(0);
-}
-
-/* src and dst can be the same */
-static void convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount) {
-       unsigned int p;
-       while (pixelCount) {
-               p = *src32++;
-               *dst16++ =      ((p << 8) & 0xF800)             /* R */
-                       |               ((p >> 5) & 0x07E0)             /* G */
-                       |               ((p >> 19) & 0x001F);   /* B */
-               pixelCount--;
-       }
-}
-
-/* Normal map preprocessing */
-/* Scale normal with depth and unpack R component (horizontal component) */
-static void processNormal() {
-       int scanline;
-       int i;
-       int x;
-       short maxDisplacement = 0;
-       short minDisplacement = 256;
-       unsigned short *dst;
-       short *dst2;
-       unsigned int *normalmap = (unsigned int*)background;
-       normalmap += NORMALMAP_SCANLINE * backgroundW;
-       dst = (unsigned short*)normalmap;
-       displacementMap = (short*)dst;
-       dst2 = displacementMap;
-
-       for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
-               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);
-                       } else {
-                               *dst = 0;
-                       }
-                       dst++;
-               }
-               normalmap += backgroundW;
-       }
-
-       if (maxDisplacement == minDisplacement) {
-               printf("Warning: grise normalmap fucked up\n");
-               return;
-       }
-
-       /* 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*/
-                       dst2++;
-               }
-       }
-}
-
-static float distanceScale(int scanline) {
-       float farScale, t;
-       farScale = (float)NEAR_SCROLL_SPEED / (float)FAR_SCROLL_SPEED;
-       t = (float)scanline / ((float)REFLECTION_HEIGHT - 1);
-       return 1.0f / (1.0f / farScale + (1.0f - 1.0f / farScale) * t);
-}
-
-static void initScrollTables() {
-       int i = 0;
-       for (i = 0; i < REFLECTION_HEIGHT; i++) {
-               scrollScaleTable[i] = distanceScale(i);
-               scrollTable[i] = 0.0f;
-               scrollTableRounded[i] = 0;
-       }
-}
-
-
-static void updateScrollTables(float dt) {
-       int i = 0;
-
-       nearScrollAmount += dt * NEAR_SCROLL_SPEED;
-       nearScrollAmount = (float) fmod(nearScrollAmount, 512.0f);
-
-       for (i = 0; i < REFLECTION_HEIGHT; i++) {
-               scrollTable[i] = nearScrollAmount / scrollScaleTable[i];
-               scrollTableRounded[i] = (int)(scrollTable[i] + 0.5f) % scrollModTable[i];
-       }
-}
-
-/* -------------------------------------------------------------------------------------------------
- *                                   RLE 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)
-
-static struct {
-       int circleX[3];
-       int circleY[3];
-} propellerState;
-
-static void updatePropeller(float t) {
-       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;
-
-       /* 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 */
-       rlePropeller = rleEncode(rlePropeller, miniFXBuffer, 32, 32);
-
-       /* Distribute the produced streaks so that they don't produce garbage when interpolated */
-       rleDistributeStreaks(rlePropeller);
-}
diff --git a/src/hairball.c b/src/hairball.c
deleted file mode 100644 (file)
index 89c45c3..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <float.h>
-#include "demo.h"
-#include "3dgfx.h"
-#include "vmath.h"
-#include "screen.h"
-#include "util.h"
-#include "cfgopt.h"
-#include "mesh.h"
-
-
-#ifdef MSDOS
-#include "dos/gfx.h"   /* for wait_vsync assembly macro */
-#else
-void wait_vsync(void);
-#endif
-
-#define NSPAWNPOS      64
-#define SPAWN_RATE     16.0f
-//#define GRAV         (-6.0f)
-#define GRAV           0.0f
-#define HAIR_LENGTH 20
-
-struct particle {
-       vec3_t pos;
-       vec3_t vel;
-       int r, g, b, a;
-       int life;
-
-       struct particle *next;
-};
-
-struct hairball {
-       vec3_t pos;
-       quat_t rot;
-       float xform[16];
-
-       struct particle *plist[NSPAWNPOS];
-};
-
-static int init(void);
-static void destroy(void);
-static void start(long trans_time);
-static void draw(void);
-static void update_hairball(struct hairball *hb, float dt);
-static void draw_hairball(struct hairball *hb);
-
-static struct particle *palloc(void);
-void pfree(struct particle *p);
-
-
-static struct screen scr = {
-       "hairball",
-       init,
-       destroy,
-       start, 0,
-       draw
-};
-
-static long start_time;
-
-static float cam_theta, cam_phi = 15;
-static float cam_dist = 8;
-
-static vec3_t *spawnpos, *spawndir;
-static struct hairball hball;
-static struct g3d_mesh sphmesh;
-
-struct screen *hairball_screen(void)
-{
-       return &scr;
-}
-
-static int init(void)
-{
-       int i, j, numpt = 0;
-
-       gen_sphere_mesh(&sphmesh, 1.0f, 12, 6);
-
-       hball.xform[0] = hball.xform[5] = hball.xform[10] = hball.xform[15] = 1.0f;
-       hball.rot.w = 1.0f;
-
-       if(!(spawnpos = malloc(NSPAWNPOS * sizeof *spawnpos)) ||
-                       !(spawndir = malloc(NSPAWNPOS * sizeof *spawndir))) {
-               fprintf(stderr, "failed to allocate spawnpos/dir array\n");
-               return -1;
-       }
-
-       while(numpt < NSPAWNPOS) {
-               float best_dist = -1.0f;
-               for(i=0; i<100; i++) {
-                       vec3_t pos = sphrand(1.0f);
-
-                       float mindist = FLT_MAX;
-                       for(j=0; j<numpt; j++) {
-                               float dx = pos.x - spawnpos[i].x;
-                               float dy = pos.y - spawnpos[i].y;
-                               float dz = pos.z - spawnpos[i].z;
-                               float dsq = dx * dx + dy * dy + dz * dz;
-                               if(dsq < mindist) {
-                                       mindist = dsq;
-                               }
-                       }
-
-                       if(mindist > best_dist) {
-                               spawnpos[numpt] = pos;
-                               best_dist = mindist;
-                       }
-               }
-
-               spawndir[numpt] = spawnpos[numpt];
-               ++numpt;
-       }
-
-       return 0;
-}
-
-static void destroy(void)
-{
-}
-
-static void start(long trans_time)
-{
-       g3d_matrix_mode(G3D_PROJECTION);
-       g3d_load_identity();
-       g3d_perspective(50.0, 1.33333, 0.5, 100.0);
-
-       start_time = time_msec;
-}
-
-static void update(void)
-{
-       static float prev_mx, prev_my;
-       static long prev_msec;
-       int mouse_dx, mouse_dy;
-       long msec = time_msec - start_time;
-       float dt = (msec - prev_msec) / 1000.0f;
-       prev_msec = msec;
-
-       mouse_dx = mouse_x - prev_mx;
-       mouse_dy = mouse_y - prev_my;
-       prev_mx = mouse_x;
-       prev_my = mouse_y;
-
-
-       if(opt.sball) {
-               memcpy(hball.xform, sball_matrix, 16 * sizeof(float));
-
-               hball.pos.x = hball.xform[12];
-               hball.pos.y = hball.xform[13];
-               hball.pos.z = hball.xform[14];
-       } else {
-               if(mouse_bmask & MOUSE_BN_MIDDLE) {
-                       hball.pos.x += mouse_dx * 0.05;
-                       hball.pos.y -= mouse_dy * 0.05;
-               }
-
-               quat_to_mat(hball.xform, hball.rot);
-               hball.xform[12] = hball.pos.x;
-               hball.xform[13] = hball.pos.y;
-               hball.xform[14] = hball.pos.z;
-       }
-
-       update_hairball(&hball, dt);
-
-       mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
-}
-
-static void draw(void)
-{
-       unsigned long msec;
-       static unsigned long last_swap;
-
-       update();
-
-       memset(fb_pixels, 0, fb_width * fb_height * 2);
-
-       g3d_matrix_mode(G3D_MODELVIEW);
-       g3d_load_identity();
-       g3d_translate(0, 0, -cam_dist);
-       g3d_rotate(cam_phi, 1, 0, 0);
-       g3d_rotate(cam_theta, 0, 1, 0);
-
-       draw_hairball(&hball);
-
-       msec = get_msec();
-       if(msec - last_swap < 16) {
-               wait_vsync();
-       }
-       if(!opt.vsync) {
-               wait_vsync();
-       }
-       swap_buffers(fb_pixels);
-       last_swap = get_msec();
-}
-
-static void update_hairball(struct hairball *hb, float dt)
-{
-       int i, j, spawn_count;
-       struct particle pdummy, *prev, *p;
-       static float spawn_acc;
-
-       /* update particles */
-       for(i=0; i<NSPAWNPOS; i++) {
-               pdummy.next = hb->plist[i];
-               prev = &pdummy;
-               while(prev && prev->next) {
-                       p = prev->next;
-                       if(--p->life <= 0) {
-                               prev->next = p->next;
-                               pfree(p);
-                               prev = prev->next;
-                               continue;
-                       }
-
-                       p->pos.x += p->vel.x * dt;
-                       p->pos.y += p->vel.y * dt;
-                       p->pos.z += p->vel.z * dt;
-                       p->vel.y += GRAV * dt;
-
-                       p->r = p->g = p->b = (p->life << 8) / HAIR_LENGTH - 1;
-
-                       prev = p;
-               }
-
-               hb->plist[i] = pdummy.next;
-       }
-
-       /* spawn new particles */
-       spawn_acc += dt;
-       if(spawn_acc >= (1.0f / SPAWN_RATE)) {
-               for(i=0; i<NSPAWNPOS; i++) {
-                       struct particle *p = palloc();
-                       float *mat = hb->xform;
-                       vec3_t pos = spawnpos[i];
-                       vec3_t dir = spawndir[i];
-
-                       p->pos.x = mat[0] * pos.x + mat[4] * pos.y + mat[8] * pos.z + mat[12];
-                       p->pos.y = mat[1] * pos.x + mat[5] * pos.y + mat[9] * pos.z + mat[13];
-                       p->pos.z = mat[2] * pos.x + mat[6] * pos.y + mat[10] * pos.z + mat[14];
-
-                       p->vel.x = mat[0] * dir.x + mat[4] * dir.y + mat[8] * dir.z;
-                       p->vel.y = mat[1] * dir.x + mat[5] * dir.y + mat[9] * dir.z;
-                       p->vel.z = mat[2] * dir.x + mat[6] * dir.y + mat[10] * dir.z;
-                       p->life = HAIR_LENGTH;
-
-                       p->next = hb->plist[i];
-                       hb->plist[i] = p;
-               }
-               spawn_acc -= 1.0f / SPAWN_RATE;
-       }
-}
-
-static void draw_hairball(struct hairball *hb)
-{
-       int i, col;
-       struct particle *p;
-       vec3_t prevpos;
-       vec3_t start[NSPAWNPOS];
-
-       for(i=0; i<NSPAWNPOS; i++) {
-               start[i].x = hb->xform[0] * spawnpos[i].x + hb->xform[4] * spawnpos[i].y + hb->xform[8] * spawnpos[i].z + hb->xform[12];
-               start[i].y = hb->xform[1] * spawnpos[i].x + hb->xform[5] * spawnpos[i].y + hb->xform[9] * spawnpos[i].z + hb->xform[13];
-               start[i].z = hb->xform[2] * spawnpos[i].x + hb->xform[6] * spawnpos[i].y + hb->xform[10] * spawnpos[i].z + hb->xform[14];
-       }
-
-       g3d_begin(G3D_LINES);
-       for(i=0; i<NSPAWNPOS; i++) {
-               if(start[i].z >= hb->pos.z) continue;
-               p = hb->plist[i];
-               prevpos = start[i];
-               while(p) {
-                       g3d_color3b(p->r, p->g, p->b);
-                       g3d_vertex(prevpos.x, prevpos.y, prevpos.z);
-                       g3d_vertex(p->pos.x, p->pos.y, p->pos.z);
-                       prevpos = p->pos;
-                       p = p->next;
-               }
-       }
-       g3d_end();
-
-
-       g3d_push_matrix();
-       g3d_mult_matrix(hb->xform);
-       zsort_mesh(&sphmesh);
-       draw_mesh(&sphmesh);
-       g3d_pop_matrix();
-
-       g3d_begin(G3D_LINES);
-       for(i=0; i<NSPAWNPOS; i++) {
-               if(start[i].z < hb->pos.z) continue;
-               p = hb->plist[i];
-               prevpos = start[i];
-               while(p) {
-                       g3d_color3b(p->r, p->g, p->b);
-                       g3d_vertex(prevpos.x, prevpos.y, prevpos.z);
-                       g3d_vertex(p->pos.x, p->pos.y, p->pos.z);
-                       prevpos = p->pos;
-                       p = p->next;
-               }
-       }
-       g3d_end();
-
-}
-
-
-static struct particle *palloc(void)
-{
-       return malloc(sizeof(struct particle));
-}
-
-void pfree(struct particle *p)
-{
-       free(p);
-}
diff --git a/src/infcubes.c b/src/infcubes.c
deleted file mode 100644 (file)
index dd1bd33..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "demo.h"
-#include "3dgfx.h"
-#include "screen.h"
-#include "cfgopt.h"
-#include "polyfill.h"
-#include "imago2.h"
-#include "gfxutil.h"
-#include "mesh.h"
-
-static int init(void);
-static void destroy(void);
-static void start(long trans_time);
-static void draw(void);
-static int gen_phong_tex(struct pimage *img, int xsz, int ysz, float sexp,
-               float offx, float offy, int dr, int dg, int db, int sr, int sg, int sb);
-
-static struct screen scr = {
-       "infcubes",
-       init,
-       destroy,
-       start, 0,
-       draw
-};
-
-static float cam_theta = -29, cam_phi = 35;
-static float cam_dist = 6;
-static struct pimage tex_inner, tex_outer;
-static struct g3d_mesh mesh_cube, mesh_cube2;
-
-struct screen *infcubes_screen(void)
-{
-       return &scr;
-}
-
-#define PHONG_TEX_SZ   128
-
-static int init(void)
-{
-       static const float scalemat[16] = {-6, 0, 0, 0, 0, -6, 0, 0, 0, 0, -6, 0, 0, 0, 0, 1};
-       /*
-       if(!(tex_inner.pixels = img_load_pixels("data/crate.jpg", &tex_inner.width,
-                                       &tex_inner.height, IMG_FMT_RGB24))) {
-               fprintf(stderr, "infcubes: failed to load crate texture\n");
-               return -1;
-       }
-       convimg_rgb24_rgb16(tex_inner.pixels, (unsigned char*)tex_inner.pixels, tex_inner.width, tex_inner.height);
-       */
-       gen_phong_tex(&tex_inner, PHONG_TEX_SZ, PHONG_TEX_SZ, 5.0f, 0, 0, 10, 50, 92, 192, 192, 192);
-
-       if(!(tex_outer.pixels = img_load_pixels("data/refmap1.jpg", &tex_outer.width,
-                                       &tex_outer.height, IMG_FMT_RGB24))) {
-               fprintf(stderr, "infcubes: failed to load outer texture\n");
-               return -1;
-       }
-       convimg_rgb24_rgb16(tex_outer.pixels, (unsigned char*)tex_outer.pixels, tex_outer.width, tex_outer.height);
-       /*gen_phong_tex(&tex_outer, PHONG_TEX_SZ, PHONG_TEX_SZ, 5.0f, 50, 50, 50, 255, 255, 255);*/
-
-       /*
-       if(gen_cube_mesh(&mesh_cube, 1.0f, 3) == -1) {
-               return -1;
-       }
-       */
-       if(load_mesh(&mesh_cube, "data/bevelbox.obj") == -1) {
-               return -1;
-       }
-       if(load_mesh(&mesh_cube2, "data/bevelbox.obj") == -1) {
-               return -1;
-       }
-       apply_mesh_xform(&mesh_cube2, scalemat);
-       normalize_mesh_normals(&mesh_cube2);
-       return 0;
-}
-
-static void destroy(void)
-{
-       img_free_pixels(tex_inner.pixels);
-}
-
-static void start(long trans_time)
-{
-       g3d_matrix_mode(G3D_PROJECTION);
-       g3d_load_identity();
-       g3d_perspective(70.0, 1.3333333, 0.5, 100.0);
-
-       g3d_enable(G3D_CULL_FACE);
-       g3d_disable(G3D_LIGHTING);
-       g3d_enable(G3D_LIGHT0);
-}
-
-static void update(void)
-{
-       mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
-}
-
-static void draw(void)
-{
-       float t = (float)time_msec / 16.0f;
-       update();
-
-       g3d_matrix_mode(G3D_MODELVIEW);
-       g3d_load_identity();
-       g3d_translate(0, 0, -cam_dist);
-       g3d_rotate(cam_phi, 1, 0, 0);
-       g3d_rotate(cam_theta, 0, 1, 0);
-       if(opt.sball) {
-               g3d_mult_matrix(sball_matrix);
-       }
-
-       memset(fb_pixels, 0, fb_width * fb_height * 2);
-
-       g3d_polygon_mode(G3D_FLAT);
-       g3d_enable(G3D_TEXTURE_2D);
-       g3d_enable(G3D_TEXTURE_GEN);
-
-       g3d_push_matrix();
-       g3d_rotate(t, 1, 0, 0);
-       g3d_rotate(t, 0, 1, 0);
-       g3d_set_texture(tex_outer.width, tex_outer.height, tex_outer.pixels);
-       draw_mesh(&mesh_cube2);
-       g3d_pop_matrix();
-
-       g3d_set_texture(tex_inner.width, tex_inner.height, tex_inner.pixels);
-       draw_mesh(&mesh_cube);
-       g3d_disable(G3D_TEXTURE_GEN);
-
-       swap_buffers(fb_pixels);
-}
-
-static int gen_phong_tex(struct pimage *img, int xsz, int ysz, float sexp,
-               float offx, float offy, int dr, int dg, int db, int sr, int sg, int sb)
-{
-       int i, j;
-       float u, v, du, dv;
-       uint16_t *pix;
-
-       if(!(img->pixels = malloc(xsz * ysz * sizeof *pix))) {
-               return -1;
-       }
-       pix = img->pixels;
-
-       du = 2.0f / (float)(xsz - 1);
-       dv = 2.0f / (float)(ysz - 1);
-
-       v = -1.0f - offy;
-       for(i=0; i<ysz; i++) {
-               u = -1.0f - offx;
-               for(j=0; j<xsz; j++) {
-                       float d = sqrt(u * u + v * v);
-                       float val = pow(cos(d * M_PI / 2.0f), sexp);
-                       int ival = abs(val * 255.0f);
-
-                       int r = dr + ival * sr / 256;
-                       int g = dg + ival * sg / 256;
-                       int b = db + ival * sb / 256;
-
-                       if(r > 255) r = 255;
-                       if(g > 255) g = 255;
-                       if(b > 255) b = 255;
-
-                       *pix++ = PACK_RGB16(r, g, b);
-
-                       u += du;
-               }
-               v += dv;
-       }
-
-       img->width = xsz;
-       img->height = ysz;
-       return 0;
-}
diff --git a/src/metaball.c b/src/metaball.c
deleted file mode 100644 (file)
index 9404912..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include "screen.h"
-#include "demo.h"
-#include "3dgfx.h"
-#include "gfxutil.h"
-#include "util.h"
-#include "metasurf.h"
-#include "mesh.h"
-
-struct metaball {
-       float energy;
-       float pos[3];
-};
-
-static int init(void);
-static void destroy(void);
-static void start(long trans_time);
-static void draw(void);
-
-static void calc_voxel_field(void);
-
-static struct screen scr = {
-       "metaballs",
-       init,
-       destroy,
-       start, 0,
-       draw
-};
-
-static float cam_theta, cam_phi = 25;
-static float cam_dist = 10;
-static struct g3d_mesh mmesh;
-
-static struct metasurface *msurf;
-
-#define VOL_SZ 32
-#define VOL_SCALE      10.0f
-#define VOX_DIST       (VOL_SCALE / VOL_SZ)
-#define VOL_HALF_SCALE (VOL_SCALE * 0.5f)
-
-#define NUM_MBALLS     3
-static struct metaball mball[NUM_MBALLS];
-
-static int dbg;
-
-struct screen *metaballs_screen(void)
-{
-       return &scr;
-}
-
-static int init(void)
-{
-       mball[0].energy = 1.2;
-       mball[1].energy = 0.8;
-       mball[2].energy = 1.0;
-
-       if(!(msurf = msurf_create())) {
-               fprintf(stderr, "failed to initialize metasurf\n");
-               return -1;
-       }
-       msurf_set_resolution(msurf, VOL_SZ, VOL_SZ, VOL_SZ);
-       msurf_set_bounds(msurf, -VOL_HALF_SCALE, -VOL_HALF_SCALE, -VOL_HALF_SCALE,
-                       VOL_HALF_SCALE, VOL_HALF_SCALE, VOL_HALF_SCALE);
-       msurf_set_threshold(msurf, 1.7);
-       msurf_set_inside(msurf, MSURF_GREATER);
-
-       mmesh.prim = G3D_TRIANGLES;
-       mmesh.varr = 0;
-       mmesh.iarr = 0;
-       mmesh.vcount = mmesh.icount = 0;
-
-       return 0;
-}
-
-static void destroy(void)
-{
-       msurf_free(msurf);
-}
-
-static void start(long trans_time)
-{
-       g3d_matrix_mode(G3D_PROJECTION);
-       g3d_load_identity();
-       g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
-
-       g3d_enable(G3D_CULL_FACE);
-       g3d_enable(G3D_LIGHTING);
-       g3d_enable(G3D_LIGHT0);
-
-       g3d_polygon_mode(G3D_GOURAUD);
-}
-
-static void update(void)
-{
-       int i, j;
-       float tsec = time_msec / 1000.0f;
-       static float phase[] = {0.0, M_PI / 3.0, M_PI * 0.8};
-       static float speed[] = {0.8, 1.4, 1.0};
-       static float scale[][3] = {{1, 2, 0.8}, {0.5, 1.6, 0.6}, {1.5, 0.7, 0.5}};
-       static float offset[][3] = {{0, 0, 0}, {0.25, 0, 0}, {-0.2, 0.15, 0.2}};
-
-       mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
-
-       for(i=0; i<NUM_MBALLS; i++) {
-               float t = (tsec + phase[i]) * speed[i];
-
-               for(j=0; j<3; j++) {
-                       float x = sin(t + j * M_PI / 2.0);
-                       mball[i].pos[j] = offset[i][j] + x * scale[i][j];
-               }
-       }
-
-       calc_voxel_field();
-       msurf_polygonize(msurf);
-
-       mmesh.vcount = msurf_vertex_count(msurf);
-       mmesh.varr = msurf_vertices(msurf);
-}
-
-static void draw(void)
-{
-       int i, j;
-
-       update();
-
-       memset(fb_pixels, 0, fb_width * fb_height * 2);
-
-       for(i=0; i<120; i++) {
-               for(j=0; j<160; j++) {
-                       fb_pixels[(i + 60) * 320 + (j + 80)] = 0x1e7;
-               }
-       }
-       g3d_viewport(80, 60, 160, 120);
-
-       g3d_matrix_mode(G3D_MODELVIEW);
-       g3d_load_identity();
-       g3d_translate(0, 0, -cam_dist);
-       g3d_rotate(cam_phi, 1, 0, 0);
-       g3d_rotate(cam_theta, 0, 1, 0);
-
-       g3d_light_pos(0, -10, 10, 20);
-
-       zsort_mesh(&mmesh);
-
-       g3d_mtl_diffuse(0.6, 0.6, 0.6);
-
-       draw_mesh(&mmesh);
-
-       g3d_viewport(0, 0, fb_width, fb_height);
-
-       swap_buffers(fb_pixels);
-}
-
-static void calc_voxel_field(void)
-{
-       int i, j, k, b;
-       float *voxptr;
-
-       if(!(voxptr = msurf_voxels(msurf))) {
-               fprintf(stderr, "failed to allocate voxel field\n");
-               abort();
-       }
-
-       for(i=0; i<VOL_SZ; i++) {
-               float z = -VOL_HALF_SCALE + i * VOX_DIST;
-
-               for(j=0; j<VOL_SZ; j++) {
-                       float y = -VOL_HALF_SCALE + j * VOX_DIST;
-
-                       for(k=0; k<VOL_SZ; k++) {
-                               float x = -VOL_HALF_SCALE + k * VOX_DIST;
-
-                               float val = 0.0f;
-                               for(b=0; b<NUM_MBALLS; b++) {
-                                       float dx = mball[b].pos[0] - x;
-                                       float dy = mball[b].pos[1] - y;
-                                       float dz = mball[b].pos[2] - z;
-
-                                       float lensq = dx * dx + dy * dy + dz * dz;
-
-                                       val += lensq == 0.0f ? 1024.0f : mball[b].energy / lensq;
-                               }
-
-                               *voxptr++ = val;
-                       }
-               }
-       }
-       ++dbg;
-}
diff --git a/src/plasma.c b/src/plasma.c
deleted file mode 100644 (file)
index 5caf4f4..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-// Just a test with a run of the mill plasma
-
-#include <stdlib.h>
-#include <math.h>
-
-#include "demo.h"
-#include "screen.h"
-
-static int init(void);
-static void destroy(void);
-static void start(long trans_time);
-static void draw(void);
-
-static struct screen scr = {
-       "plasma",
-       init,
-       destroy,
-       start,
-       0,
-       draw
-};
-
-static unsigned long startingTime;
-
-#define PSIN_SIZE 4096
-#define PPAL_SIZE 256
-
-static unsigned char *psin1, *psin2, *psin3;
-static unsigned short *plasmaPal;
-
-static unsigned short myBuffer[320 * 240];
-
-
-struct screen *plasma_screen(void)
-{
-       return &scr;
-}
-
-static int init(void)
-{
-       int i;
-
-       psin1 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE);
-       psin2 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE);
-       psin3 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE);
-
-       for (i = 0; i < PSIN_SIZE; i++)
-       {
-               psin1[i] = (unsigned char)(sin((double)i / 45.0) * 63.0 + 63.0);
-               psin2[i] = (unsigned char)(sin((double)i / 75.0) * 42.0 + 42.0);
-               psin3[i] = (unsigned char)(sin((double)i / 32.0) * 88.0 + 88.0);
-       }
-
-       plasmaPal = (unsigned short*)malloc(sizeof(unsigned short) * PPAL_SIZE);
-       for (i=0; i<PPAL_SIZE; i++)
-       {
-               int r, g, b;
-               int c = i;
-               if (c > 127) c = 255 - c;
-               c >>= 2;
-               g = 31 - c;
-               r = c;
-               b = g;
-               plasmaPal[i] = (r<<11) | (g<<5) | b;
-       }
-
-       return 0;
-}
-
-static void destroy(void)
-{
-       free(psin1);
-       free(psin2);
-       free(psin3);
-}
-
-static void start(long trans_time)
-{
-       startingTime = time_msec;
-}
-
-static void draw(void)
-{
-       int x, y;
-       unsigned char c;
-       unsigned char s1, s2;
-
-       float dt = (float)(time_msec - startingTime) / 1000.0f;
-       int t1 = sin(0.1f * dt) * 132 + 132;
-       int t2 = sin(0.2f * dt) * 248 + 248;
-       int t3 = sin(0.5f * dt) * 380 + 380;
-
-       unsigned int *vram32 = (unsigned int*)fb_pixels;
-       unsigned int p0, p1;
-       for (y = 0; y < fb_height; y++)
-       {
-               s1 = psin2[y + t2];
-               s2 = psin3[y + t1];
-               for (x = 0; x < fb_width; x+=2)
-               {
-                       c = psin1[x + t1] + s1 + psin3[x + y + t3] + psin1[psin2[x + t2] + s2 + t3];
-                       p0 = plasmaPal[c];
-                       c = psin1[x + 1 + t1] + s1 + psin3[x + 1 + y + t3] + psin1[psin2[x + 1 + t2] + s2 + t3];
-                       p1 = plasmaPal[c];
-
-                       *vram32++ = (p1 << 16) | p0;
-               }
-       }
-
-       swap_buffers(0);
-}
diff --git a/src/polytest.c b/src/polytest.c
deleted file mode 100644 (file)
index 0b05313..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include "screen.h"
-#include "demo.h"
-#include "3dgfx.h"
-#include "gfxutil.h"
-#include "polyfill.h"  /* just for struct pimage */
-#include "cfgopt.h"
-#include "mesh.h"
-#include "bsptree.h"
-
-static int init(void);
-static void destroy(void);
-static void start(long trans_time);
-static void draw(void);
-static void draw_lowres_raster(void);
-static void keypress(int key);
-static int gen_texture(struct pimage *img, int xsz, int ysz);
-
-static struct screen scr = {
-       "polytest",
-       init,
-       destroy,
-       start, 0,
-       draw,
-       keypress
-};
-
-static float cam_theta, cam_phi = 25;
-static float cam_dist = 3;
-static struct g3d_mesh cube, torus;
-static struct bsptree torus_bsp;
-
-static struct pimage tex;
-
-static int use_bsp = 0;
-
-#define LOWRES_SCALE   10
-static uint16_t *lowres_pixels;
-static int lowres_width, lowres_height;
-
-struct screen *polytest_screen(void)
-{
-       return &scr;
-}
-
-static int init(void)
-{
-       int i;
-
-       gen_cube_mesh(&cube, 1.0, 0);
-       gen_torus_mesh(&torus, 1.0, 0.25, 24, 12);
-       /* scale texcoords */
-       for(i=0; i<torus.vcount; i++) {
-               torus.varr[i].u *= 4.0;
-               torus.varr[i].v *= 2.0;
-       }
-
-       /*
-       init_bsp(&torus_bsp);
-       if(bsp_add_mesh(&torus_bsp, &torus) == -1) {
-               fprintf(stderr, "failed to construct torus BSP tree\n");
-               return -1;
-       }
-       */
-
-       gen_texture(&tex, 128, 128);
-
-#ifdef DEBUG_POLYFILL
-       lowres_width = fb_width / LOWRES_SCALE;
-       lowres_height = fb_height / LOWRES_SCALE;
-       lowres_pixels = malloc(lowres_width * lowres_height * 2);
-       scr.draw = draw_debug;
-#endif
-
-       return 0;
-}
-
-static void destroy(void)
-{
-       free(lowres_pixels);
-       free(cube.varr);
-       free(torus.varr);
-       free(torus.iarr);
-       /*
-       destroy_bsp(&torus_bsp);
-       */
-}
-
-static void start(long trans_time)
-{
-       g3d_matrix_mode(G3D_PROJECTION);
-       g3d_load_identity();
-       g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
-
-       g3d_enable(G3D_CULL_FACE);
-       g3d_enable(G3D_LIGHTING);
-       g3d_enable(G3D_LIGHT0);
-
-       g3d_polygon_mode(G3D_GOURAUD);
-       g3d_enable(G3D_TEXTURE_2D);
-}
-
-static void update(void)
-{
-       mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
-}
-
-
-static void draw(void)
-{
-       float vdir[3];
-       const float *mat;
-
-       update();
-
-       memset(fb_pixels, 0, fb_width * fb_height * 2);
-
-       g3d_matrix_mode(G3D_MODELVIEW);
-       g3d_load_identity();
-       g3d_translate(0, 0, -cam_dist);
-       if(opt.sball) {
-               g3d_mult_matrix(sball_matrix);
-       } else {
-               g3d_rotate(cam_phi, 1, 0, 0);
-               g3d_rotate(cam_theta, 0, 1, 0);
-       }
-
-       g3d_light_pos(0, -10, 10, 20);
-
-       g3d_mtl_diffuse(0.4, 0.7, 1.0);
-       g3d_set_texture(tex.width, tex.height, tex.pixels);
-
-       if(use_bsp) {
-               /* calc world-space view direction */
-               mat = g3d_get_matrix(G3D_MODELVIEW, 0);
-               /* transform (0, 0, -1) with transpose(mat3x3) */
-               vdir[0] = -mat[2];
-               vdir[1] = -mat[6];
-               vdir[2] = -mat[10];
-
-               draw_bsp(&torus_bsp, vdir[0], vdir[1], vdir[2]);
-       } else {
-               zsort_mesh(&torus);
-               draw_mesh(&torus);
-       }
-
-       /*draw_mesh(&cube);*/
-       swap_buffers(fb_pixels);
-}
-
-static void draw_debug(void)
-{
-       update();
-
-       memset(lowres_pixels, 0, lowres_width * lowres_height * 2);
-
-       g3d_matrix_mode(G3D_MODELVIEW);
-       g3d_load_identity();
-       g3d_translate(0, 0, -cam_dist);
-       g3d_rotate(cam_phi, 1, 0, 0);
-       g3d_rotate(cam_theta, 0, 1, 0);
-
-       g3d_framebuffer(lowres_width, lowres_height, lowres_pixels);
-       /*zsort(&torus);*/
-       draw_mesh(&cube);
-
-       draw_lowres_raster();
-
-
-       g3d_framebuffer(fb_width, fb_height, fb_pixels);
-
-       g3d_polygon_mode(G3D_WIRE);
-       draw_mesh(&cube);
-       g3d_polygon_mode(G3D_FLAT);
-
-       swap_buffers(fb_pixels);
-}
-
-
-static void draw_huge_pixel(uint16_t *dest, int dest_width, uint16_t color)
-{
-       int i, j;
-       uint16_t grid_color = PACK_RGB16(127, 127, 127);
-
-       for(i=0; i<LOWRES_SCALE; i++) {
-               for(j=0; j<LOWRES_SCALE; j++) {
-                       dest[j] = i == 0 || j == 0 ? grid_color : color;
-               }
-               dest += dest_width;
-       }
-}
-
-static void draw_lowres_raster(void)
-{
-       int i, j;
-       uint16_t *sptr = lowres_pixels;
-       uint16_t *dptr = fb_pixels;
-
-       for(i=0; i<lowres_height; i++) {
-               for(j=0; j<lowres_width; j++) {
-                       draw_huge_pixel(dptr, fb_width, *sptr++);
-                       dptr += LOWRES_SCALE;
-               }
-               dptr += fb_width * LOWRES_SCALE - fb_width;
-       }
-}
-
-static void keypress(int key)
-{
-       switch(key) {
-       case 'b':
-               use_bsp = !use_bsp;
-               printf("drawing with %s\n", use_bsp ? "BSP tree" : "z-sorting");
-               break;
-       }
-}
-
-static int gen_texture(struct pimage *img, int xsz, int ysz)
-{
-       int i, j;
-       uint16_t *pix;
-
-       if(!(img->pixels = malloc(xsz * ysz * sizeof *pix))) {
-               return -1;
-       }
-       pix = img->pixels;
-
-       for(i=0; i<ysz; i++) {
-               for(j=0; j<xsz; j++) {
-                       int val = i ^ j;
-
-                       *pix++ = PACK_RGB16(val, val, val);
-               }
-       }
-
-       img->width = xsz;
-       img->height = ysz;
-       return 0;
-}
diff --git a/src/scr/bump.c b/src/scr/bump.c
new file mode 100644 (file)
index 0000000..b82594b
--- /dev/null
@@ -0,0 +1,328 @@
+// Bump effect (not moving yet of course, I have many ideas on this to commit before it's ready)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "demo.h"
+#include "screen.h"
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void draw(void);
+
+static struct screen scr = {
+       "bump",
+       init,
+       destroy,
+       start,
+       0,
+       draw
+};
+
+struct point {
+       int x, y;
+};
+
+#define NUM_BIG_LIGHTS 3
+#define BIG_LIGHT_WIDTH 256
+#define BIG_LIGHT_HEIGHT BIG_LIGHT_WIDTH
+
+#define NUM_PARTICLES 64
+#define PARTICLE_LIGHT_WIDTH 32
+#define PARTICLE_LIGHT_HEIGHT 32
+
+
+static unsigned long startingTime;
+
+static unsigned char *heightmap;
+static unsigned short *lightmap;
+static int *bumpOffset;
+
+static unsigned short *bigLight[NUM_BIG_LIGHTS];
+static struct point bigLightPoint[NUM_BIG_LIGHTS];
+
+static unsigned short *particleLight;
+static struct point particlePoint[NUM_PARTICLES];
+
+struct screen *bump_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       int i, j, x, y, c, r, g, b;
+
+       const int numBlurs = 3;
+       const int lightRadius = BIG_LIGHT_WIDTH / 2;
+       const int particleRadius = PARTICLE_LIGHT_WIDTH / 2;
+
+       const int bigLightSize = BIG_LIGHT_WIDTH * BIG_LIGHT_HEIGHT;
+       const int particleLightSize = PARTICLE_LIGHT_WIDTH * PARTICLE_LIGHT_HEIGHT;
+       const int fb_size = fb_width * fb_height;
+
+       // Just some parameters to temporary test the colors of 3 lights
+       // if every light uses it's own channel bits, it's better
+       const float rgbMul[9] = { 1.0f, 0.0f, 0.0f, 
+                                                                 0.0f, 1.0f, 0.0f,
+                                                                 0.0f, 0.0f, 1.0f};
+
+       heightmap = malloc(sizeof(*heightmap) * fb_size);
+       lightmap = malloc(sizeof(*lightmap) * fb_size);
+       bumpOffset = malloc(sizeof(*bumpOffset) * fb_size);
+
+       for (i = 0; i < NUM_BIG_LIGHTS; i++)
+               bigLight[i] = malloc(sizeof(*bigLight[i]) * bigLightSize);
+
+       particleLight = malloc(sizeof(*particleLight) * particleLightSize);
+
+       memset(lightmap, 0, sizeof(*lightmap) * fb_size);
+       memset(bumpOffset, 0, sizeof(*bumpOffset) * fb_size);
+       memset(particlePoint, 0, sizeof(*particlePoint) * NUM_PARTICLES);
+
+       // Create random junk
+       for (i = 0; i < fb_size; i++)
+               heightmap[i] = rand() & 255;
+
+       // Blur to smooth
+       for (j = 0; j < numBlurs; j++)
+               for (i = 0; i < fb_size; i++)
+                       heightmap[i] = (heightmap[abs((i - 1) % fb_size)] + heightmap[abs((i + 1) % fb_size)] + heightmap[abs((i - fb_width) % fb_size)] + heightmap[abs((i + fb_width) % fb_size)]) >> 2;
+
+       // Inclination precalculation
+       i = 0;
+       for (y = 0; y < fb_height; y++)
+       {
+               for (x = 0; x < fb_width; x++)
+               {
+                       const float offsetPower = 0.75f;
+                       int dx, dy, xp, yp;
+
+                       dx = i < fb_size - 1 ? (int)((heightmap[i] - heightmap[i + 1]) * offsetPower) : 0;
+                       dy = i < fb_size - fb_width ? (int)((heightmap[i] - heightmap[i + fb_width]) * offsetPower) : 0;
+
+                       xp = x + dx;
+                       if (xp < 0) xp = 0;
+                       if (xp > fb_width - 1) xp = fb_width - 1;
+
+                       yp = y + dy;
+                       if (yp < 0) yp = 0;
+                       if (yp > fb_height - 1) yp = fb_height - 1;
+
+                       bumpOffset[i++] = yp * fb_width + xp;
+               }
+       }
+
+       // Generate three lights
+       i = 0;
+       for (y = 0; y < BIG_LIGHT_HEIGHT; y++)
+       {
+               int yc = y - (BIG_LIGHT_HEIGHT / 2);
+               for (x = 0; x < BIG_LIGHT_WIDTH; x++)
+               {
+                       int xc = x - (BIG_LIGHT_WIDTH / 2);
+                       float d = (float)sqrt(xc * xc + yc * yc);
+                       float invDist = ((float)lightRadius - (float)sqrt(xc * xc + yc * yc)) / (float)lightRadius;
+                       if (invDist < 0.0f) invDist = 0.0f;
+
+                       c = (int)(invDist * 63);
+                       r = c >> 1;
+                       g = c;
+                       b = c >> 1;
+
+                       for (j = 0; j < NUM_BIG_LIGHTS; j++)
+                       {
+                               bigLight[j][i] = ((int)(r * rgbMul[j * 3]) << 11) | ((int)(g * rgbMul[j * 3 + 1]) << 5) | (int)(b * rgbMul[j * 3 + 2]);
+                       }
+                       i++;
+               }
+       }
+
+       i = 0;
+       for (y = 0; y < PARTICLE_LIGHT_HEIGHT; y++)
+       {
+               int yc = y - (PARTICLE_LIGHT_HEIGHT / 2);
+               for (x = 0; x < PARTICLE_LIGHT_WIDTH; x++)
+               {
+                       int xc = x - (PARTICLE_LIGHT_WIDTH / 2);
+
+                       float invDist = ((float)particleRadius - (float)sqrt(xc * xc + yc * yc)) / (float)particleRadius;
+                       if (invDist < 0.0f) invDist = 0.0f;
+
+                       c = (int)(pow(invDist, 0.75f) * 63);
+                       particleLight[i++] = ((c >> 1) << 11) | (c << 5) | (c >> 1);
+               }
+       }
+
+       return 0;
+}
+
+static void destroy(void)
+{
+}
+
+static void start(long trans_time)
+{
+       startingTime = time_msec;
+}
+
+static void eraseArea(struct point *p, int width, int height)
+{
+       int x, y, dx;
+       unsigned short *dst;
+
+       int x0 = p->x;
+       int y0 = p->y;
+       int x1 = p->x + width;
+       int y1 = p->y + height;
+
+       if (x0 < 0) x0 = 0;
+       if (y0 < 0) y0 = 0;
+       if (x1 > fb_width) x1 = fb_width;
+       if (y1 > fb_height) y1 = fb_height;
+
+       dx = x1 - x0;
+
+       dst = lightmap + y0 * fb_width + x0;
+
+       for (y = y0; y < y1; y++)
+       {
+               for (x = x0; x < x1; x++)
+               {
+                       *dst++ = 0;
+               }
+               dst += fb_width - dx;
+       }
+}
+
+
+static void renderLight(struct point *p, int width, int height, unsigned short *light)
+{
+       int x, y, dx;
+       unsigned short *src, *dst;
+
+       int x0 = p->x;
+       int y0 = p->y;
+       int x1 = p->x + width;
+       int y1 = p->y + height;
+
+       int xl = 0;
+       int yl = 0;
+
+       if (x0 < 0)
+       {
+               xl = -x0;
+               x0 = 0;
+       }
+
+       if (y0 < 0)
+       {
+               yl = -y0;
+               y0 = 0;
+       }
+
+       if (x1 > fb_width) x1 = fb_width;
+       if (y1 > fb_height) y1 = fb_height;
+
+       dx = x1 - x0;
+
+       dst = lightmap + y0 * fb_width + x0;
+       src = light + yl * width + xl;
+
+       for (y = y0; y < y1; y++)
+       {
+               for (x = x0; x < x1; x++)
+               {
+                       *dst++ |= *src++;
+               }
+               dst += fb_width - dx;
+               src += width - dx;
+       }
+}
+
+static void eraseLights()
+{
+       int i;
+       for (i = 0; i < NUM_BIG_LIGHTS; i++)
+               eraseArea(&bigLightPoint[i], BIG_LIGHT_WIDTH, BIG_LIGHT_HEIGHT);
+}
+
+static void renderLights()
+{
+       int i;
+       for (i = 0; i < NUM_BIG_LIGHTS; i++)
+               renderLight(&bigLightPoint[i], BIG_LIGHT_WIDTH, BIG_LIGHT_HEIGHT, bigLight[i]);
+}
+
+static void renderParticles()
+{
+       int i;
+       for (i = 0; i < NUM_PARTICLES; i++)
+               renderLight(&particlePoint[i], PARTICLE_LIGHT_WIDTH, PARTICLE_LIGHT_HEIGHT, particleLight);
+}
+
+static void animateLights()
+{
+       struct point center;
+       float dt = (float)(time_msec - startingTime) / 1000.0f;
+       float tt = 1.0f - sin(dt);
+       float disperse = tt * 64.0f;
+
+       center.x = (fb_width >> 1) - (BIG_LIGHT_WIDTH / 2);
+       center.y = (fb_height >> 1) - (BIG_LIGHT_HEIGHT / 2);
+
+       bigLightPoint[0].x = center.x + sin(1.2f * dt) * (144.0f + disperse);
+       bigLightPoint[0].y = center.y + sin(0.8f * dt) * (148.0f + disperse);
+
+       bigLightPoint[1].x = center.x + sin(1.5f * dt) * (156.0f + disperse);
+       bigLightPoint[1].y = center.y + sin(1.1f * dt) * (92.0f + disperse);
+
+       bigLightPoint[2].x = center.x + sin(2.0f * dt) * (112.0f + disperse);
+       bigLightPoint[2].y = center.y + sin(1.3f * dt) * (136.0f + disperse);
+}
+
+static void renderBump(unsigned short *vram)
+{
+       int i;
+       for (i = 0; i < fb_width * fb_height; i++)
+       {
+               unsigned short c = lightmap[bumpOffset[i]];
+               *vram++ = c;
+       }
+}
+
+static void animateParticles()
+{
+       int i;
+       struct point center;
+       float dt = (float)(time_msec - startingTime) / 2000.0f;
+       float tt = sin(dt);
+
+       center.x = (fb_width >> 1) - (PARTICLE_LIGHT_WIDTH / 2);
+       center.y = (fb_height >> 1) - (PARTICLE_LIGHT_HEIGHT / 2);
+
+       for (i = 0; i < NUM_PARTICLES; i++)
+       {
+               particlePoint[i].x = center.x + (sin(1.2f * (i*i*i + dt)) * 74.0f + sin(0.6f * (i + dt)) * 144.0f) * tt;
+               particlePoint[i].y = center.y + (sin(1.8f * (i + dt)) * 68.0f + sin(0.5f * (i*i + dt)) * 132.0f) * tt;
+       }
+}
+
+static void draw(void)
+{
+       memset(lightmap, 0, fb_width * fb_height * sizeof(*lightmap));
+
+       //eraseLights();
+       animateLights();
+       renderLights();
+
+       animateParticles();
+       renderParticles();
+
+       renderBump((unsigned short*)fb_pixels);
+
+       swap_buffers(0);
+}
diff --git a/src/scr/fract.c b/src/scr/fract.c
new file mode 100644 (file)
index 0000000..6eeb678
--- /dev/null
@@ -0,0 +1,95 @@
+#include <string.h>
+#include <limits.h>
+#include "demo.h"
+#include "screen.h"
+#include "gfxutil.h"
+
+struct vec2x {
+       long x, y;
+};
+
+static int init(void);
+static void destroy(void);
+static void draw(void);
+static int julia(long x, long y, long cx, long cy, int max_iter);
+
+static struct screen scr = {
+       "fract",
+       init,
+       destroy,
+       0, 0,
+       draw
+};
+
+/*static long aspect_24x8 = (long)(1.3333333 * 256.0);*/
+static long xscale_24x8 = (long)(1.3333333 * 1.2 * 256.0);
+static long yscale_24x8 = (long)(1.2 * 256.0);
+static int cx, cy;
+static int max_iter = 50;
+
+#define WALK_SIZE      20
+
+struct screen *fract_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       return 0;
+}
+
+static void destroy(void)
+{
+}
+
+static void draw(void)
+{
+       int i, j;
+       unsigned short *pixels = fb_pixels;
+
+       cx = mouse_x;
+       cy = mouse_y;
+
+       for(i=0; i<fb_height; i++) {
+               for(j=0; j<fb_width; j++) {
+                       unsigned char pidx = julia(j, i, cx, cy, max_iter) & 0xff;
+                       *pixels++ = (pidx >> 3) | ((pidx >> 2) << 5) | ((pidx >> 3) << 11);
+               }
+       }
+
+       pixels = fb_pixels;
+       pixels[mouse_y * fb_width + mouse_x] = 0xffe;
+       swap_buffers(0);
+}
+
+static long normalize_coord(long x, long range)
+{
+       /* 2 * x / range - 1*/
+       return (x << 17) / range - 65536;
+}
+
+static int julia(long x, long y, long cx, long cy, int max_iter)
+{
+       int i;
+
+       /* convert to fixed point roughly [-1, 1] */
+       x = (normalize_coord(x, fb_width) >> 8) * xscale_24x8;
+       y = (normalize_coord(y, fb_height) >> 8) * yscale_24x8;
+       cx = (normalize_coord(cx, fb_width) >> 8) * xscale_24x8;
+       cy = (normalize_coord(cy, fb_height) >> 8) * yscale_24x8;
+
+       for(i=0; i<max_iter; i++) {
+               /* z_n = z_{n-1}**2 + c */
+               long px = x >> 8;
+               long py = y >> 8;
+
+               if(px * px + py * py > (4 << 16)) {
+                       break;
+               }
+               x = px * px - py * py + cx;
+               y = (px * py << 1) + cy;
+       }
+
+       return i < max_iter ? (256 * i / max_iter) : 0;
+}
diff --git a/src/scr/greets.c b/src/scr/greets.c
new file mode 100644 (file)
index 0000000..8b128c6
--- /dev/null
@@ -0,0 +1,184 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include "demo.h"
+#include "3dgfx.h"
+#include "screen.h"
+#include "cfgopt.h"
+#include "imago2.h"
+#include "util.h"
+#include "gfxutil.h"
+#include "timer.h"
+#include "smoketxt.h"
+
+#ifdef MSDOS
+#include "dos/gfx.h"   /* for wait_vsync assembly macro */
+#else
+void wait_vsync(void);
+#endif
+
+#define BLUR_RAD       5
+
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void draw(void);
+
+
+static struct screen scr = {
+       "greets",
+       init,
+       destroy,
+       start, 0,
+       draw
+};
+
+static long start_time;
+
+static struct smktxt *stx;
+
+static uint16_t *cur_smokebuf, *prev_smokebuf;
+static int smokebuf_size;
+#define smokebuf_start (cur_smokebuf < prev_smokebuf ? cur_smokebuf : prev_smokebuf)
+#define swap_smoke_buffers() \
+       do { \
+               uint16_t *tmp = cur_smokebuf; \
+               cur_smokebuf = prev_smokebuf; \
+               prev_smokebuf = tmp; \
+       } while(0)
+
+static float cam_theta, cam_phi = 25;
+static float cam_dist = 3;
+
+struct screen *greets_screen(void)
+{
+       return &scr;
+}
+
+
+static int init(void)
+{
+       if(!(stx = create_smktxt("data/greets1.png", "data/vfield1"))) {
+               return -1;
+       }
+
+       smokebuf_size = fb_width * fb_height * sizeof *cur_smokebuf;
+       if(!(cur_smokebuf = malloc(smokebuf_size * 2))) {
+               perror("failed to allocate smoke framebuffer");
+               return -1;
+       }
+       prev_smokebuf = cur_smokebuf + fb_width * fb_height;
+
+       return 0;
+}
+
+static void destroy(void)
+{
+       free(smokebuf_start);
+       destroy_smktxt(stx);
+}
+
+static void start(long trans_time)
+{
+       g3d_matrix_mode(G3D_PROJECTION);
+       g3d_load_identity();
+       g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
+
+       memset(smokebuf_start, 0, smokebuf_size * 2);
+
+       start_time = time_msec;
+}
+
+static void update(void)
+{
+       static long prev_msec;
+       static int prev_mx, prev_my;
+       static unsigned int prev_bmask;
+
+       long msec = time_msec - start_time;
+       float dt = (msec - prev_msec) / 1000.0f;
+       prev_msec = msec;
+
+       if(mouse_bmask) {
+               if((mouse_bmask ^ prev_bmask) == 0) {
+                       int dx = mouse_x - prev_mx;
+                       int dy = mouse_y - prev_my;
+
+                       if(dx || dy) {
+                               if(mouse_bmask & 1) {
+                                       cam_theta += dx * 1.0;
+                                       cam_phi += dy * 1.0;
+
+                                       if(cam_phi < -90) cam_phi = -90;
+                                       if(cam_phi > 90) cam_phi = 90;
+                               }
+                               if(mouse_bmask & 4) {
+                                       cam_dist += dy * 0.5;
+
+                                       if(cam_dist < 0) cam_dist = 0;
+                               }
+                       }
+               }
+       }
+       prev_mx = mouse_x;
+       prev_my = mouse_y;
+       prev_bmask = mouse_bmask;
+
+       update_smktxt(stx, dt);
+}
+
+static void draw(void)
+{
+       int i, j;
+       uint16_t *dest, *src;
+       unsigned long msec;
+       static unsigned long last_swap;
+
+       update();
+
+       g3d_matrix_mode(G3D_MODELVIEW);
+       g3d_load_identity();
+       g3d_translate(0, 0, -cam_dist);
+       g3d_rotate(cam_phi, 1, 0, 0);
+       g3d_rotate(cam_theta, 0, 1, 0);
+       if(opt.sball) {
+               g3d_mult_matrix(sball_matrix);
+       }
+
+       memcpy(cur_smokebuf, prev_smokebuf, smokebuf_size);
+
+       g3d_framebuffer(fb_width, fb_height, cur_smokebuf);
+       draw_smktxt(stx);
+       g3d_framebuffer(fb_width, fb_height, fb_pixels);
+
+       dest = fb_pixels;
+       src = cur_smokebuf;
+       for(i=0; i<fb_height; i++) {
+               for(j=0; j<fb_width; j++) {
+                       unsigned int alpha = *src++;
+                       *dest++ = PACK_RGB16(alpha, alpha, alpha);
+               }
+       }
+
+       /*perf_start();*/
+       blur_grey_horiz(prev_smokebuf, cur_smokebuf, fb_width, fb_height, BLUR_RAD, 240);
+       /*
+       perf_end();
+       printf("blur perf: %lu\n", (unsigned long)perf_interval_count);
+       */
+       blur_grey_vert(cur_smokebuf, prev_smokebuf, fb_width, fb_height, BLUR_RAD, 240);
+       swap_smoke_buffers();
+
+       msec = get_msec();
+       if(msec - last_swap < 16) {
+               wait_vsync();
+       }
+       if(!opt.vsync) {
+               wait_vsync();
+       }
+       swap_buffers(fb_pixels);
+       last_swap = get_msec();
+}
diff --git a/src/scr/grise.c b/src/scr/grise.c
new file mode 100644 (file)
index 0000000..94e3850
--- /dev/null
@@ -0,0 +1,691 @@
+#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 */
+
+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);
+
+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 */
+
+/* Every backBuffer scanline is guaranteed to have that many dummy pixels before and after */
+#define PIXEL_PADDING 32
+
+/* Make sure this is less than PIXEL_PADDING*/
+#define MAX_DISPLACEMENT 16
+
+#define MIN_SCROLL PIXEL_PADDING
+#define MAX_SCROLL (backgroundW - fb_width - MIN_SCROLL)
+
+#define FAR_SCROLL_SPEED 15.0f
+#define NEAR_SCROLL_SPEED 120.0f
+
+#define HORIZON_HEIGHT 100
+#define REFLECTION_HEIGHT (240 - HORIZON_HEIGHT)
+
+#define NORMALMAP_SCANLINE 372
+
+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 convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount);
+static void processNormal();
+static void initScrollTables();
+static void updateScrollTables(float dt);
+
+
+
+static unsigned short *background = 0;
+static int backgroundW = 0;
+static int backgroundH = 0;
+
+static unsigned int lastFrameTime = 0;
+static float lastFrameDuration = 0.0f;
+
+static short *displacementMap;
+
+static unsigned short *backBuffer;
+
+static float scrollScaleTable[REFLECTION_HEIGHT];
+static float scrollTable[REFLECTION_HEIGHT];
+static int scrollTableRounded[REFLECTION_HEIGHT];
+static int scrollModTable[REFLECTION_HEIGHT];
+static float nearScrollAmount = 0.0f;
+
+static unsigned char miniFXBuffer[1024];
+
+static RLEBitmap *grobj = 0;
+static RLEBitmap *rlePropeller = 0;
+
+static struct screen scr = {
+       "galaxyrise",
+       init,
+       destroy,
+       start,
+       0,
+       draw
+};
+
+struct screen *grise_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       unsigned char *tmpBitmap;
+       int tmpBitmapW, tmpBitmapH;
+
+       /* Allocate back buffer */
+       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))) {
+               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 */
+
+       /* Load reflected objects */
+       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;
+       }
+
+       grobj = rleEncode(0, tmpBitmap, tmpBitmapW, tmpBitmapH);
+
+       img_free_pixels(tmpBitmap);
+
+       initScrollTables();
+
+       processNormal();
+
+       return 0;
+}
+
+static void destroy(void)
+{
+       free(backBuffer);
+       backBuffer = 0;
+
+       img_free_pixels(background);
+
+       rleDestroy(grobj);
+}
+
+static void start(long trans_time)
+{
+       lastFrameTime = time_msec;
+}
+
+
+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;
+       int scanline = 0;
+       int i = 0;
+       short *dispScanline;
+       int d;
+       int accum = 0;
+       int md, sc;
+       int scrolledIndex;
+
+       lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
+       lastFrameTime = time_msec;
+
+       /* Update mini-effects here */
+       updatePropeller(4.0f * time_msec / 1000.0f);
+
+       /* First, render the horizon */
+       for (scanline = 0; scanline < HORIZON_HEIGHT; scanline++) {
+               memcpy(dst, src, fb_width * 2);
+               src += backgroundW;
+               dst += BB_SIZE;
+       }
+
+       /* Create scroll offsets for all scanlines of the normalmap */
+       updateScrollTables(lastFrameDuration);
+
+       /* Render the baked reflection one scanline below its place, so that
+        * the displacement that follows will be done in a cache-friendly way
+        */
+       src -= PIXEL_PADDING; /* We want to also fill the PADDING pixels here */
+       dst = backBuffer + (HORIZON_HEIGHT + 1) * BB_SIZE;
+       for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
+               memcpy(dst, src, (fb_width + PIXEL_PADDING) * 2);
+               src += backgroundW;
+               dst += BB_SIZE;
+       }
+
+       /* 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);
+
+       /* Perform displacement */
+       dst = backBuffer + HORIZON_HEIGHT * BB_SIZE + PIXEL_PADDING;
+       src = dst + BB_SIZE; /* The pixels to be displaced are 1 scanline below */
+       dispScanline = displacementMap;
+       for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
+
+               md = scrollModTable[scanline];
+               sc = scrollTableRounded[scanline];
+               accum = 0;
+
+               for (i = 0; i < fb_width; i++) {
+                       /* Try to immitate modulo without the division */
+                       if (i == md) accum += md;
+                       scrolledIndex = i - accum + sc;
+                       if (scrolledIndex >= md) scrolledIndex -= md;
+
+                       /* Displace */
+                       d = dispScanline[scrolledIndex];
+                       *dst++ = src[i + d];
+               }
+               src += backgroundW;
+               dst += BB_SIZE - fb_width;
+               dispScanline += backgroundW;
+       }
+
+       /* 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);
+
+       /* Blit effect to framebuffer */
+       src = backBuffer + PIXEL_PADDING;
+       dst = fb_pixels;
+       for (scanline = 0; scanline < fb_height; scanline++) {
+               memcpy(dst, src, fb_width * 2);
+               src += BB_SIZE;
+               dst += fb_width;
+       }
+
+       swap_buffers(0);
+}
+
+/* src and dst can be the same */
+static void convert32To16(unsigned int *src32, unsigned short *dst16, unsigned int pixelCount) {
+       unsigned int p;
+       while (pixelCount) {
+               p = *src32++;
+               *dst16++ =      ((p << 8) & 0xF800)             /* R */
+                       |               ((p >> 5) & 0x07E0)             /* G */
+                       |               ((p >> 19) & 0x001F);   /* B */
+               pixelCount--;
+       }
+}
+
+/* Normal map preprocessing */
+/* Scale normal with depth and unpack R component (horizontal component) */
+static void processNormal() {
+       int scanline;
+       int i;
+       int x;
+       short maxDisplacement = 0;
+       short minDisplacement = 256;
+       unsigned short *dst;
+       short *dst2;
+       unsigned int *normalmap = (unsigned int*)background;
+       normalmap += NORMALMAP_SCANLINE * backgroundW;
+       dst = (unsigned short*)normalmap;
+       displacementMap = (short*)dst;
+       dst2 = displacementMap;
+
+       for (scanline = 0; scanline < REFLECTION_HEIGHT; scanline++) {
+               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);
+                       } else {
+                               *dst = 0;
+                       }
+                       dst++;
+               }
+               normalmap += backgroundW;
+       }
+
+       if (maxDisplacement == minDisplacement) {
+               printf("Warning: grise normalmap fucked up\n");
+               return;
+       }
+
+       /* 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*/
+                       dst2++;
+               }
+       }
+}
+
+static float distanceScale(int scanline) {
+       float farScale, t;
+       farScale = (float)NEAR_SCROLL_SPEED / (float)FAR_SCROLL_SPEED;
+       t = (float)scanline / ((float)REFLECTION_HEIGHT - 1);
+       return 1.0f / (1.0f / farScale + (1.0f - 1.0f / farScale) * t);
+}
+
+static void initScrollTables() {
+       int i = 0;
+       for (i = 0; i < REFLECTION_HEIGHT; i++) {
+               scrollScaleTable[i] = distanceScale(i);
+               scrollTable[i] = 0.0f;
+               scrollTableRounded[i] = 0;
+       }
+}
+
+
+static void updateScrollTables(float dt) {
+       int i = 0;
+
+       nearScrollAmount += dt * NEAR_SCROLL_SPEED;
+       nearScrollAmount = (float) fmod(nearScrollAmount, 512.0f);
+
+       for (i = 0; i < REFLECTION_HEIGHT; i++) {
+               scrollTable[i] = nearScrollAmount / scrollScaleTable[i];
+               scrollTableRounded[i] = (int)(scrollTable[i] + 0.5f) % scrollModTable[i];
+       }
+}
+
+/* -------------------------------------------------------------------------------------------------
+ *                                   RLE 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)
+
+static struct {
+       int circleX[3];
+       int circleY[3];
+} propellerState;
+
+static void updatePropeller(float t) {
+       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;
+
+       /* 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 */
+       rlePropeller = rleEncode(rlePropeller, miniFXBuffer, 32, 32);
+
+       /* Distribute the produced streaks so that they don't produce garbage when interpolated */
+       rleDistributeStreaks(rlePropeller);
+}
diff --git a/src/scr/hairball.c b/src/scr/hairball.c
new file mode 100644 (file)
index 0000000..89c45c3
--- /dev/null
@@ -0,0 +1,317 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+#include "demo.h"
+#include "3dgfx.h"
+#include "vmath.h"
+#include "screen.h"
+#include "util.h"
+#include "cfgopt.h"
+#include "mesh.h"
+
+
+#ifdef MSDOS
+#include "dos/gfx.h"   /* for wait_vsync assembly macro */
+#else
+void wait_vsync(void);
+#endif
+
+#define NSPAWNPOS      64
+#define SPAWN_RATE     16.0f
+//#define GRAV         (-6.0f)
+#define GRAV           0.0f
+#define HAIR_LENGTH 20
+
+struct particle {
+       vec3_t pos;
+       vec3_t vel;
+       int r, g, b, a;
+       int life;
+
+       struct particle *next;
+};
+
+struct hairball {
+       vec3_t pos;
+       quat_t rot;
+       float xform[16];
+
+       struct particle *plist[NSPAWNPOS];
+};
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void draw(void);
+static void update_hairball(struct hairball *hb, float dt);
+static void draw_hairball(struct hairball *hb);
+
+static struct particle *palloc(void);
+void pfree(struct particle *p);
+
+
+static struct screen scr = {
+       "hairball",
+       init,
+       destroy,
+       start, 0,
+       draw
+};
+
+static long start_time;
+
+static float cam_theta, cam_phi = 15;
+static float cam_dist = 8;
+
+static vec3_t *spawnpos, *spawndir;
+static struct hairball hball;
+static struct g3d_mesh sphmesh;
+
+struct screen *hairball_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       int i, j, numpt = 0;
+
+       gen_sphere_mesh(&sphmesh, 1.0f, 12, 6);
+
+       hball.xform[0] = hball.xform[5] = hball.xform[10] = hball.xform[15] = 1.0f;
+       hball.rot.w = 1.0f;
+
+       if(!(spawnpos = malloc(NSPAWNPOS * sizeof *spawnpos)) ||
+                       !(spawndir = malloc(NSPAWNPOS * sizeof *spawndir))) {
+               fprintf(stderr, "failed to allocate spawnpos/dir array\n");
+               return -1;
+       }
+
+       while(numpt < NSPAWNPOS) {
+               float best_dist = -1.0f;
+               for(i=0; i<100; i++) {
+                       vec3_t pos = sphrand(1.0f);
+
+                       float mindist = FLT_MAX;
+                       for(j=0; j<numpt; j++) {
+                               float dx = pos.x - spawnpos[i].x;
+                               float dy = pos.y - spawnpos[i].y;
+                               float dz = pos.z - spawnpos[i].z;
+                               float dsq = dx * dx + dy * dy + dz * dz;
+                               if(dsq < mindist) {
+                                       mindist = dsq;
+                               }
+                       }
+
+                       if(mindist > best_dist) {
+                               spawnpos[numpt] = pos;
+                               best_dist = mindist;
+                       }
+               }
+
+               spawndir[numpt] = spawnpos[numpt];
+               ++numpt;
+       }
+
+       return 0;
+}
+
+static void destroy(void)
+{
+}
+
+static void start(long trans_time)
+{
+       g3d_matrix_mode(G3D_PROJECTION);
+       g3d_load_identity();
+       g3d_perspective(50.0, 1.33333, 0.5, 100.0);
+
+       start_time = time_msec;
+}
+
+static void update(void)
+{
+       static float prev_mx, prev_my;
+       static long prev_msec;
+       int mouse_dx, mouse_dy;
+       long msec = time_msec - start_time;
+       float dt = (msec - prev_msec) / 1000.0f;
+       prev_msec = msec;
+
+       mouse_dx = mouse_x - prev_mx;
+       mouse_dy = mouse_y - prev_my;
+       prev_mx = mouse_x;
+       prev_my = mouse_y;
+
+
+       if(opt.sball) {
+               memcpy(hball.xform, sball_matrix, 16 * sizeof(float));
+
+               hball.pos.x = hball.xform[12];
+               hball.pos.y = hball.xform[13];
+               hball.pos.z = hball.xform[14];
+       } else {
+               if(mouse_bmask & MOUSE_BN_MIDDLE) {
+                       hball.pos.x += mouse_dx * 0.05;
+                       hball.pos.y -= mouse_dy * 0.05;
+               }
+
+               quat_to_mat(hball.xform, hball.rot);
+               hball.xform[12] = hball.pos.x;
+               hball.xform[13] = hball.pos.y;
+               hball.xform[14] = hball.pos.z;
+       }
+
+       update_hairball(&hball, dt);
+
+       mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
+}
+
+static void draw(void)
+{
+       unsigned long msec;
+       static unsigned long last_swap;
+
+       update();
+
+       memset(fb_pixels, 0, fb_width * fb_height * 2);
+
+       g3d_matrix_mode(G3D_MODELVIEW);
+       g3d_load_identity();
+       g3d_translate(0, 0, -cam_dist);
+       g3d_rotate(cam_phi, 1, 0, 0);
+       g3d_rotate(cam_theta, 0, 1, 0);
+
+       draw_hairball(&hball);
+
+       msec = get_msec();
+       if(msec - last_swap < 16) {
+               wait_vsync();
+       }
+       if(!opt.vsync) {
+               wait_vsync();
+       }
+       swap_buffers(fb_pixels);
+       last_swap = get_msec();
+}
+
+static void update_hairball(struct hairball *hb, float dt)
+{
+       int i, j, spawn_count;
+       struct particle pdummy, *prev, *p;
+       static float spawn_acc;
+
+       /* update particles */
+       for(i=0; i<NSPAWNPOS; i++) {
+               pdummy.next = hb->plist[i];
+               prev = &pdummy;
+               while(prev && prev->next) {
+                       p = prev->next;
+                       if(--p->life <= 0) {
+                               prev->next = p->next;
+                               pfree(p);
+                               prev = prev->next;
+                               continue;
+                       }
+
+                       p->pos.x += p->vel.x * dt;
+                       p->pos.y += p->vel.y * dt;
+                       p->pos.z += p->vel.z * dt;
+                       p->vel.y += GRAV * dt;
+
+                       p->r = p->g = p->b = (p->life << 8) / HAIR_LENGTH - 1;
+
+                       prev = p;
+               }
+
+               hb->plist[i] = pdummy.next;
+       }
+
+       /* spawn new particles */
+       spawn_acc += dt;
+       if(spawn_acc >= (1.0f / SPAWN_RATE)) {
+               for(i=0; i<NSPAWNPOS; i++) {
+                       struct particle *p = palloc();
+                       float *mat = hb->xform;
+                       vec3_t pos = spawnpos[i];
+                       vec3_t dir = spawndir[i];
+
+                       p->pos.x = mat[0] * pos.x + mat[4] * pos.y + mat[8] * pos.z + mat[12];
+                       p->pos.y = mat[1] * pos.x + mat[5] * pos.y + mat[9] * pos.z + mat[13];
+                       p->pos.z = mat[2] * pos.x + mat[6] * pos.y + mat[10] * pos.z + mat[14];
+
+                       p->vel.x = mat[0] * dir.x + mat[4] * dir.y + mat[8] * dir.z;
+                       p->vel.y = mat[1] * dir.x + mat[5] * dir.y + mat[9] * dir.z;
+                       p->vel.z = mat[2] * dir.x + mat[6] * dir.y + mat[10] * dir.z;
+                       p->life = HAIR_LENGTH;
+
+                       p->next = hb->plist[i];
+                       hb->plist[i] = p;
+               }
+               spawn_acc -= 1.0f / SPAWN_RATE;
+       }
+}
+
+static void draw_hairball(struct hairball *hb)
+{
+       int i, col;
+       struct particle *p;
+       vec3_t prevpos;
+       vec3_t start[NSPAWNPOS];
+
+       for(i=0; i<NSPAWNPOS; i++) {
+               start[i].x = hb->xform[0] * spawnpos[i].x + hb->xform[4] * spawnpos[i].y + hb->xform[8] * spawnpos[i].z + hb->xform[12];
+               start[i].y = hb->xform[1] * spawnpos[i].x + hb->xform[5] * spawnpos[i].y + hb->xform[9] * spawnpos[i].z + hb->xform[13];
+               start[i].z = hb->xform[2] * spawnpos[i].x + hb->xform[6] * spawnpos[i].y + hb->xform[10] * spawnpos[i].z + hb->xform[14];
+       }
+
+       g3d_begin(G3D_LINES);
+       for(i=0; i<NSPAWNPOS; i++) {
+               if(start[i].z >= hb->pos.z) continue;
+               p = hb->plist[i];
+               prevpos = start[i];
+               while(p) {
+                       g3d_color3b(p->r, p->g, p->b);
+                       g3d_vertex(prevpos.x, prevpos.y, prevpos.z);
+                       g3d_vertex(p->pos.x, p->pos.y, p->pos.z);
+                       prevpos = p->pos;
+                       p = p->next;
+               }
+       }
+       g3d_end();
+
+
+       g3d_push_matrix();
+       g3d_mult_matrix(hb->xform);
+       zsort_mesh(&sphmesh);
+       draw_mesh(&sphmesh);
+       g3d_pop_matrix();
+
+       g3d_begin(G3D_LINES);
+       for(i=0; i<NSPAWNPOS; i++) {
+               if(start[i].z < hb->pos.z) continue;
+               p = hb->plist[i];
+               prevpos = start[i];
+               while(p) {
+                       g3d_color3b(p->r, p->g, p->b);
+                       g3d_vertex(prevpos.x, prevpos.y, prevpos.z);
+                       g3d_vertex(p->pos.x, p->pos.y, p->pos.z);
+                       prevpos = p->pos;
+                       p = p->next;
+               }
+       }
+       g3d_end();
+
+}
+
+
+static struct particle *palloc(void)
+{
+       return malloc(sizeof(struct particle));
+}
+
+void pfree(struct particle *p)
+{
+       free(p);
+}
diff --git a/src/scr/infcubes.c b/src/scr/infcubes.c
new file mode 100644 (file)
index 0000000..dd1bd33
--- /dev/null
@@ -0,0 +1,174 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "demo.h"
+#include "3dgfx.h"
+#include "screen.h"
+#include "cfgopt.h"
+#include "polyfill.h"
+#include "imago2.h"
+#include "gfxutil.h"
+#include "mesh.h"
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void draw(void);
+static int gen_phong_tex(struct pimage *img, int xsz, int ysz, float sexp,
+               float offx, float offy, int dr, int dg, int db, int sr, int sg, int sb);
+
+static struct screen scr = {
+       "infcubes",
+       init,
+       destroy,
+       start, 0,
+       draw
+};
+
+static float cam_theta = -29, cam_phi = 35;
+static float cam_dist = 6;
+static struct pimage tex_inner, tex_outer;
+static struct g3d_mesh mesh_cube, mesh_cube2;
+
+struct screen *infcubes_screen(void)
+{
+       return &scr;
+}
+
+#define PHONG_TEX_SZ   128
+
+static int init(void)
+{
+       static const float scalemat[16] = {-6, 0, 0, 0, 0, -6, 0, 0, 0, 0, -6, 0, 0, 0, 0, 1};
+       /*
+       if(!(tex_inner.pixels = img_load_pixels("data/crate.jpg", &tex_inner.width,
+                                       &tex_inner.height, IMG_FMT_RGB24))) {
+               fprintf(stderr, "infcubes: failed to load crate texture\n");
+               return -1;
+       }
+       convimg_rgb24_rgb16(tex_inner.pixels, (unsigned char*)tex_inner.pixels, tex_inner.width, tex_inner.height);
+       */
+       gen_phong_tex(&tex_inner, PHONG_TEX_SZ, PHONG_TEX_SZ, 5.0f, 0, 0, 10, 50, 92, 192, 192, 192);
+
+       if(!(tex_outer.pixels = img_load_pixels("data/refmap1.jpg", &tex_outer.width,
+                                       &tex_outer.height, IMG_FMT_RGB24))) {
+               fprintf(stderr, "infcubes: failed to load outer texture\n");
+               return -1;
+       }
+       convimg_rgb24_rgb16(tex_outer.pixels, (unsigned char*)tex_outer.pixels, tex_outer.width, tex_outer.height);
+       /*gen_phong_tex(&tex_outer, PHONG_TEX_SZ, PHONG_TEX_SZ, 5.0f, 50, 50, 50, 255, 255, 255);*/
+
+       /*
+       if(gen_cube_mesh(&mesh_cube, 1.0f, 3) == -1) {
+               return -1;
+       }
+       */
+       if(load_mesh(&mesh_cube, "data/bevelbox.obj") == -1) {
+               return -1;
+       }
+       if(load_mesh(&mesh_cube2, "data/bevelbox.obj") == -1) {
+               return -1;
+       }
+       apply_mesh_xform(&mesh_cube2, scalemat);
+       normalize_mesh_normals(&mesh_cube2);
+       return 0;
+}
+
+static void destroy(void)
+{
+       img_free_pixels(tex_inner.pixels);
+}
+
+static void start(long trans_time)
+{
+       g3d_matrix_mode(G3D_PROJECTION);
+       g3d_load_identity();
+       g3d_perspective(70.0, 1.3333333, 0.5, 100.0);
+
+       g3d_enable(G3D_CULL_FACE);
+       g3d_disable(G3D_LIGHTING);
+       g3d_enable(G3D_LIGHT0);
+}
+
+static void update(void)
+{
+       mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
+}
+
+static void draw(void)
+{
+       float t = (float)time_msec / 16.0f;
+       update();
+
+       g3d_matrix_mode(G3D_MODELVIEW);
+       g3d_load_identity();
+       g3d_translate(0, 0, -cam_dist);
+       g3d_rotate(cam_phi, 1, 0, 0);
+       g3d_rotate(cam_theta, 0, 1, 0);
+       if(opt.sball) {
+               g3d_mult_matrix(sball_matrix);
+       }
+
+       memset(fb_pixels, 0, fb_width * fb_height * 2);
+
+       g3d_polygon_mode(G3D_FLAT);
+       g3d_enable(G3D_TEXTURE_2D);
+       g3d_enable(G3D_TEXTURE_GEN);
+
+       g3d_push_matrix();
+       g3d_rotate(t, 1, 0, 0);
+       g3d_rotate(t, 0, 1, 0);
+       g3d_set_texture(tex_outer.width, tex_outer.height, tex_outer.pixels);
+       draw_mesh(&mesh_cube2);
+       g3d_pop_matrix();
+
+       g3d_set_texture(tex_inner.width, tex_inner.height, tex_inner.pixels);
+       draw_mesh(&mesh_cube);
+       g3d_disable(G3D_TEXTURE_GEN);
+
+       swap_buffers(fb_pixels);
+}
+
+static int gen_phong_tex(struct pimage *img, int xsz, int ysz, float sexp,
+               float offx, float offy, int dr, int dg, int db, int sr, int sg, int sb)
+{
+       int i, j;
+       float u, v, du, dv;
+       uint16_t *pix;
+
+       if(!(img->pixels = malloc(xsz * ysz * sizeof *pix))) {
+               return -1;
+       }
+       pix = img->pixels;
+
+       du = 2.0f / (float)(xsz - 1);
+       dv = 2.0f / (float)(ysz - 1);
+
+       v = -1.0f - offy;
+       for(i=0; i<ysz; i++) {
+               u = -1.0f - offx;
+               for(j=0; j<xsz; j++) {
+                       float d = sqrt(u * u + v * v);
+                       float val = pow(cos(d * M_PI / 2.0f), sexp);
+                       int ival = abs(val * 255.0f);
+
+                       int r = dr + ival * sr / 256;
+                       int g = dg + ival * sg / 256;
+                       int b = db + ival * sb / 256;
+
+                       if(r > 255) r = 255;
+                       if(g > 255) g = 255;
+                       if(b > 255) b = 255;
+
+                       *pix++ = PACK_RGB16(r, g, b);
+
+                       u += du;
+               }
+               v += dv;
+       }
+
+       img->width = xsz;
+       img->height = ysz;
+       return 0;
+}
diff --git a/src/scr/metaball.c b/src/scr/metaball.c
new file mode 100644 (file)
index 0000000..9404912
--- /dev/null
@@ -0,0 +1,193 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include "screen.h"
+#include "demo.h"
+#include "3dgfx.h"
+#include "gfxutil.h"
+#include "util.h"
+#include "metasurf.h"
+#include "mesh.h"
+
+struct metaball {
+       float energy;
+       float pos[3];
+};
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void draw(void);
+
+static void calc_voxel_field(void);
+
+static struct screen scr = {
+       "metaballs",
+       init,
+       destroy,
+       start, 0,
+       draw
+};
+
+static float cam_theta, cam_phi = 25;
+static float cam_dist = 10;
+static struct g3d_mesh mmesh;
+
+static struct metasurface *msurf;
+
+#define VOL_SZ 32
+#define VOL_SCALE      10.0f
+#define VOX_DIST       (VOL_SCALE / VOL_SZ)
+#define VOL_HALF_SCALE (VOL_SCALE * 0.5f)
+
+#define NUM_MBALLS     3
+static struct metaball mball[NUM_MBALLS];
+
+static int dbg;
+
+struct screen *metaballs_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       mball[0].energy = 1.2;
+       mball[1].energy = 0.8;
+       mball[2].energy = 1.0;
+
+       if(!(msurf = msurf_create())) {
+               fprintf(stderr, "failed to initialize metasurf\n");
+               return -1;
+       }
+       msurf_set_resolution(msurf, VOL_SZ, VOL_SZ, VOL_SZ);
+       msurf_set_bounds(msurf, -VOL_HALF_SCALE, -VOL_HALF_SCALE, -VOL_HALF_SCALE,
+                       VOL_HALF_SCALE, VOL_HALF_SCALE, VOL_HALF_SCALE);
+       msurf_set_threshold(msurf, 1.7);
+       msurf_set_inside(msurf, MSURF_GREATER);
+
+       mmesh.prim = G3D_TRIANGLES;
+       mmesh.varr = 0;
+       mmesh.iarr = 0;
+       mmesh.vcount = mmesh.icount = 0;
+
+       return 0;
+}
+
+static void destroy(void)
+{
+       msurf_free(msurf);
+}
+
+static void start(long trans_time)
+{
+       g3d_matrix_mode(G3D_PROJECTION);
+       g3d_load_identity();
+       g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
+
+       g3d_enable(G3D_CULL_FACE);
+       g3d_enable(G3D_LIGHTING);
+       g3d_enable(G3D_LIGHT0);
+
+       g3d_polygon_mode(G3D_GOURAUD);
+}
+
+static void update(void)
+{
+       int i, j;
+       float tsec = time_msec / 1000.0f;
+       static float phase[] = {0.0, M_PI / 3.0, M_PI * 0.8};
+       static float speed[] = {0.8, 1.4, 1.0};
+       static float scale[][3] = {{1, 2, 0.8}, {0.5, 1.6, 0.6}, {1.5, 0.7, 0.5}};
+       static float offset[][3] = {{0, 0, 0}, {0.25, 0, 0}, {-0.2, 0.15, 0.2}};
+
+       mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
+
+       for(i=0; i<NUM_MBALLS; i++) {
+               float t = (tsec + phase[i]) * speed[i];
+
+               for(j=0; j<3; j++) {
+                       float x = sin(t + j * M_PI / 2.0);
+                       mball[i].pos[j] = offset[i][j] + x * scale[i][j];
+               }
+       }
+
+       calc_voxel_field();
+       msurf_polygonize(msurf);
+
+       mmesh.vcount = msurf_vertex_count(msurf);
+       mmesh.varr = msurf_vertices(msurf);
+}
+
+static void draw(void)
+{
+       int i, j;
+
+       update();
+
+       memset(fb_pixels, 0, fb_width * fb_height * 2);
+
+       for(i=0; i<120; i++) {
+               for(j=0; j<160; j++) {
+                       fb_pixels[(i + 60) * 320 + (j + 80)] = 0x1e7;
+               }
+       }
+       g3d_viewport(80, 60, 160, 120);
+
+       g3d_matrix_mode(G3D_MODELVIEW);
+       g3d_load_identity();
+       g3d_translate(0, 0, -cam_dist);
+       g3d_rotate(cam_phi, 1, 0, 0);
+       g3d_rotate(cam_theta, 0, 1, 0);
+
+       g3d_light_pos(0, -10, 10, 20);
+
+       zsort_mesh(&mmesh);
+
+       g3d_mtl_diffuse(0.6, 0.6, 0.6);
+
+       draw_mesh(&mmesh);
+
+       g3d_viewport(0, 0, fb_width, fb_height);
+
+       swap_buffers(fb_pixels);
+}
+
+static void calc_voxel_field(void)
+{
+       int i, j, k, b;
+       float *voxptr;
+
+       if(!(voxptr = msurf_voxels(msurf))) {
+               fprintf(stderr, "failed to allocate voxel field\n");
+               abort();
+       }
+
+       for(i=0; i<VOL_SZ; i++) {
+               float z = -VOL_HALF_SCALE + i * VOX_DIST;
+
+               for(j=0; j<VOL_SZ; j++) {
+                       float y = -VOL_HALF_SCALE + j * VOX_DIST;
+
+                       for(k=0; k<VOL_SZ; k++) {
+                               float x = -VOL_HALF_SCALE + k * VOX_DIST;
+
+                               float val = 0.0f;
+                               for(b=0; b<NUM_MBALLS; b++) {
+                                       float dx = mball[b].pos[0] - x;
+                                       float dy = mball[b].pos[1] - y;
+                                       float dz = mball[b].pos[2] - z;
+
+                                       float lensq = dx * dx + dy * dy + dz * dz;
+
+                                       val += lensq == 0.0f ? 1024.0f : mball[b].energy / lensq;
+                               }
+
+                               *voxptr++ = val;
+                       }
+               }
+       }
+       ++dbg;
+}
diff --git a/src/scr/plasma.c b/src/scr/plasma.c
new file mode 100644 (file)
index 0000000..5caf4f4
--- /dev/null
@@ -0,0 +1,111 @@
+// Just a test with a run of the mill plasma
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "demo.h"
+#include "screen.h"
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void draw(void);
+
+static struct screen scr = {
+       "plasma",
+       init,
+       destroy,
+       start,
+       0,
+       draw
+};
+
+static unsigned long startingTime;
+
+#define PSIN_SIZE 4096
+#define PPAL_SIZE 256
+
+static unsigned char *psin1, *psin2, *psin3;
+static unsigned short *plasmaPal;
+
+static unsigned short myBuffer[320 * 240];
+
+
+struct screen *plasma_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       int i;
+
+       psin1 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE);
+       psin2 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE);
+       psin3 = (unsigned char*)malloc(sizeof(unsigned char) * PSIN_SIZE);
+
+       for (i = 0; i < PSIN_SIZE; i++)
+       {
+               psin1[i] = (unsigned char)(sin((double)i / 45.0) * 63.0 + 63.0);
+               psin2[i] = (unsigned char)(sin((double)i / 75.0) * 42.0 + 42.0);
+               psin3[i] = (unsigned char)(sin((double)i / 32.0) * 88.0 + 88.0);
+       }
+
+       plasmaPal = (unsigned short*)malloc(sizeof(unsigned short) * PPAL_SIZE);
+       for (i=0; i<PPAL_SIZE; i++)
+       {
+               int r, g, b;
+               int c = i;
+               if (c > 127) c = 255 - c;
+               c >>= 2;
+               g = 31 - c;
+               r = c;
+               b = g;
+               plasmaPal[i] = (r<<11) | (g<<5) | b;
+       }
+
+       return 0;
+}
+
+static void destroy(void)
+{
+       free(psin1);
+       free(psin2);
+       free(psin3);
+}
+
+static void start(long trans_time)
+{
+       startingTime = time_msec;
+}
+
+static void draw(void)
+{
+       int x, y;
+       unsigned char c;
+       unsigned char s1, s2;
+
+       float dt = (float)(time_msec - startingTime) / 1000.0f;
+       int t1 = sin(0.1f * dt) * 132 + 132;
+       int t2 = sin(0.2f * dt) * 248 + 248;
+       int t3 = sin(0.5f * dt) * 380 + 380;
+
+       unsigned int *vram32 = (unsigned int*)fb_pixels;
+       unsigned int p0, p1;
+       for (y = 0; y < fb_height; y++)
+       {
+               s1 = psin2[y + t2];
+               s2 = psin3[y + t1];
+               for (x = 0; x < fb_width; x+=2)
+               {
+                       c = psin1[x + t1] + s1 + psin3[x + y + t3] + psin1[psin2[x + t2] + s2 + t3];
+                       p0 = plasmaPal[c];
+                       c = psin1[x + 1 + t1] + s1 + psin3[x + 1 + y + t3] + psin1[psin2[x + 1 + t2] + s2 + t3];
+                       p1 = plasmaPal[c];
+
+                       *vram32++ = (p1 << 16) | p0;
+               }
+       }
+
+       swap_buffers(0);
+}
diff --git a/src/scr/polytest.c b/src/scr/polytest.c
new file mode 100644 (file)
index 0000000..0b05313
--- /dev/null
@@ -0,0 +1,242 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "screen.h"
+#include "demo.h"
+#include "3dgfx.h"
+#include "gfxutil.h"
+#include "polyfill.h"  /* just for struct pimage */
+#include "cfgopt.h"
+#include "mesh.h"
+#include "bsptree.h"
+
+static int init(void);
+static void destroy(void);
+static void start(long trans_time);
+static void draw(void);
+static void draw_lowres_raster(void);
+static void keypress(int key);
+static int gen_texture(struct pimage *img, int xsz, int ysz);
+
+static struct screen scr = {
+       "polytest",
+       init,
+       destroy,
+       start, 0,
+       draw,
+       keypress
+};
+
+static float cam_theta, cam_phi = 25;
+static float cam_dist = 3;
+static struct g3d_mesh cube, torus;
+static struct bsptree torus_bsp;
+
+static struct pimage tex;
+
+static int use_bsp = 0;
+
+#define LOWRES_SCALE   10
+static uint16_t *lowres_pixels;
+static int lowres_width, lowres_height;
+
+struct screen *polytest_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       int i;
+
+       gen_cube_mesh(&cube, 1.0, 0);
+       gen_torus_mesh(&torus, 1.0, 0.25, 24, 12);
+       /* scale texcoords */
+       for(i=0; i<torus.vcount; i++) {
+               torus.varr[i].u *= 4.0;
+               torus.varr[i].v *= 2.0;
+       }
+
+       /*
+       init_bsp(&torus_bsp);
+       if(bsp_add_mesh(&torus_bsp, &torus) == -1) {
+               fprintf(stderr, "failed to construct torus BSP tree\n");
+               return -1;
+       }
+       */
+
+       gen_texture(&tex, 128, 128);
+
+#ifdef DEBUG_POLYFILL
+       lowres_width = fb_width / LOWRES_SCALE;
+       lowres_height = fb_height / LOWRES_SCALE;
+       lowres_pixels = malloc(lowres_width * lowres_height * 2);
+       scr.draw = draw_debug;
+#endif
+
+       return 0;
+}
+
+static void destroy(void)
+{
+       free(lowres_pixels);
+       free(cube.varr);
+       free(torus.varr);
+       free(torus.iarr);
+       /*
+       destroy_bsp(&torus_bsp);
+       */
+}
+
+static void start(long trans_time)
+{
+       g3d_matrix_mode(G3D_PROJECTION);
+       g3d_load_identity();
+       g3d_perspective(50.0, 1.3333333, 0.5, 100.0);
+
+       g3d_enable(G3D_CULL_FACE);
+       g3d_enable(G3D_LIGHTING);
+       g3d_enable(G3D_LIGHT0);
+
+       g3d_polygon_mode(G3D_GOURAUD);
+       g3d_enable(G3D_TEXTURE_2D);
+}
+
+static void update(void)
+{
+       mouse_orbit_update(&cam_theta, &cam_phi, &cam_dist);
+}
+
+
+static void draw(void)
+{
+       float vdir[3];
+       const float *mat;
+
+       update();
+
+       memset(fb_pixels, 0, fb_width * fb_height * 2);
+
+       g3d_matrix_mode(G3D_MODELVIEW);
+       g3d_load_identity();
+       g3d_translate(0, 0, -cam_dist);
+       if(opt.sball) {
+               g3d_mult_matrix(sball_matrix);
+       } else {
+               g3d_rotate(cam_phi, 1, 0, 0);
+               g3d_rotate(cam_theta, 0, 1, 0);
+       }
+
+       g3d_light_pos(0, -10, 10, 20);
+
+       g3d_mtl_diffuse(0.4, 0.7, 1.0);
+       g3d_set_texture(tex.width, tex.height, tex.pixels);
+
+       if(use_bsp) {
+               /* calc world-space view direction */
+               mat = g3d_get_matrix(G3D_MODELVIEW, 0);
+               /* transform (0, 0, -1) with transpose(mat3x3) */
+               vdir[0] = -mat[2];
+               vdir[1] = -mat[6];
+               vdir[2] = -mat[10];
+
+               draw_bsp(&torus_bsp, vdir[0], vdir[1], vdir[2]);
+       } else {
+               zsort_mesh(&torus);
+               draw_mesh(&torus);
+       }
+
+       /*draw_mesh(&cube);*/
+       swap_buffers(fb_pixels);
+}
+
+static void draw_debug(void)
+{
+       update();
+
+       memset(lowres_pixels, 0, lowres_width * lowres_height * 2);
+
+       g3d_matrix_mode(G3D_MODELVIEW);
+       g3d_load_identity();
+       g3d_translate(0, 0, -cam_dist);
+       g3d_rotate(cam_phi, 1, 0, 0);
+       g3d_rotate(cam_theta, 0, 1, 0);
+
+       g3d_framebuffer(lowres_width, lowres_height, lowres_pixels);
+       /*zsort(&torus);*/
+       draw_mesh(&cube);
+
+       draw_lowres_raster();
+
+
+       g3d_framebuffer(fb_width, fb_height, fb_pixels);
+
+       g3d_polygon_mode(G3D_WIRE);
+       draw_mesh(&cube);
+       g3d_polygon_mode(G3D_FLAT);
+
+       swap_buffers(fb_pixels);
+}
+
+
+static void draw_huge_pixel(uint16_t *dest, int dest_width, uint16_t color)
+{
+       int i, j;
+       uint16_t grid_color = PACK_RGB16(127, 127, 127);
+
+       for(i=0; i<LOWRES_SCALE; i++) {
+               for(j=0; j<LOWRES_SCALE; j++) {
+                       dest[j] = i == 0 || j == 0 ? grid_color : color;
+               }
+               dest += dest_width;
+       }
+}
+
+static void draw_lowres_raster(void)
+{
+       int i, j;
+       uint16_t *sptr = lowres_pixels;
+       uint16_t *dptr = fb_pixels;
+
+       for(i=0; i<lowres_height; i++) {
+               for(j=0; j<lowres_width; j++) {
+                       draw_huge_pixel(dptr, fb_width, *sptr++);
+                       dptr += LOWRES_SCALE;
+               }
+               dptr += fb_width * LOWRES_SCALE - fb_width;
+       }
+}
+
+static void keypress(int key)
+{
+       switch(key) {
+       case 'b':
+               use_bsp = !use_bsp;
+               printf("drawing with %s\n", use_bsp ? "BSP tree" : "z-sorting");
+               break;
+       }
+}
+
+static int gen_texture(struct pimage *img, int xsz, int ysz)
+{
+       int i, j;
+       uint16_t *pix;
+
+       if(!(img->pixels = malloc(xsz * ysz * sizeof *pix))) {
+               return -1;
+       }
+       pix = img->pixels;
+
+       for(i=0; i<ysz; i++) {
+               for(j=0; j<xsz; j++) {
+                       int val = i ^ j;
+
+                       *pix++ = PACK_RGB16(val, val, val);
+               }
+       }
+
+       img->width = xsz;
+       img->height = ysz;
+       return 0;
+}
diff --git a/src/scr/smoketxt.c b/src/scr/smoketxt.c
new file mode 100644 (file)
index 0000000..841ca28
--- /dev/null
@@ -0,0 +1,371 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <errno.h>
+#include "imago2.h"
+#include "3dgfx.h"
+#include "smoketxt.h"
+#include "util.h"
+#include "noise.h"
+
+/* if defined, use bilinear interpolation for dispersion field vectors */
+#define BILERP_FIELD
+/* if defined randomize field vectors by RAND_FIELD_MAX */
+#define RANDOMIZE_FIELD
+
+#define RAND_FIELD_MAX 0.7
+
+#define DFL_PCOUNT             4000
+#define DFL_MAX_LIFE   7.0f
+#define DFL_PALPHA             1.0f
+#define DFL_ZBIAS              0.25
+#define DFL_DRAG               0.95
+#define DFL_FORCE              0.07
+#define DFL_FREQ               0.085
+
+struct vec2 {
+       float x, y;
+};
+
+struct vec3 {
+       float x, y, z;
+};
+
+struct particle {
+       float x, y, z;
+       float vx, vy, vz;       /* velocity */
+       int r, g, b;
+       float life;
+};
+
+struct emitter {
+       struct particle *plist;
+       int pcount;
+
+       struct vec3 wind;
+       float drag;
+       float max_life;
+
+       struct g3d_vertex *varr;
+};
+
+struct vfield {
+       struct vec2 pos, size;
+
+       int width, height;
+       int xshift;
+       struct vec2 *v;
+};
+
+
+struct smktxt {
+       struct emitter em;
+       struct vfield vfield;
+
+       unsigned char *img_pixels;
+       int img_xsz, img_ysz;
+};
+
+static int init_emitter(struct emitter *em, int num, unsigned char *map, int xsz, int ysz);
+static int load_vfield(struct vfield *vf, const char *fname);
+static void vfield_eval(struct vfield *vf, float x, float y, struct vec2 *dir);
+
+struct smktxt *create_smktxt(const char *imgname, const char *vfieldname)
+{
+       struct smktxt *stx;
+
+       if(!imgname) return 0;
+
+       if(!(stx = calloc(sizeof *stx, 1))) {
+               return 0;
+       }
+       if(!(stx->img_pixels = img_load_pixels(imgname, &stx->img_xsz, &stx->img_ysz, IMG_FMT_GREY8))) {
+               fprintf(stderr, "create_smktxt: failed to load particle spawnmap: %s\n", imgname);
+               free(stx);
+               return 0;
+       }
+
+       stx->em.pcount = DFL_PCOUNT;
+       stx->em.wind.z = 0.01;
+       stx->em.drag = DFL_DRAG;
+       stx->em.max_life = DFL_MAX_LIFE;
+
+       if(vfieldname) {
+               if(load_vfield(&stx->vfield, vfieldname) == -1) {
+                       img_free_pixels(stx->img_pixels);
+                       free(stx);
+                       return 0;
+               }
+       }
+
+       return stx;
+}
+
+void destroy_smktxt(struct smktxt *stx)
+{
+       if(!stx) return;
+
+       img_free_pixels(stx->img_pixels);
+       free(stx);
+}
+
+int gen_smktxt_vfield(struct smktxt *stx, int xres, int yres, float xfreq, float yfreq)
+{
+       int i, j;
+       unsigned int tmp;
+       struct vec2 *vptr;
+       struct vfield *vf = &stx->vfield;
+
+       if(!(vf->v = malloc(xres * yres * sizeof *vf->v))) {
+               fprintf(stderr, "failed to allocate %dx%d vector field\n", xres, yres);
+               return -1;
+       }
+
+       vf->width = xres;
+       vf->height = yres;
+       vf->pos.x = vf->pos.y = 0.0f;
+       vf->size.x = vf->size.y = 1.0f;
+
+       /* assume xres is pow2 otherwise fuck you */
+       tmp = xres - 1;
+       vf->xshift = 0;
+       while(tmp) {
+               ++vf->xshift;
+               tmp >>= 1;
+       }
+
+       vptr = vf->v;
+       for(i=0; i<yres; i++) {
+               for(j=0; j<xres; j++) {
+                       float x = noise3(j * xfreq, i * yfreq, 0.5);
+                       float y = noise3(j * xfreq, i * yfreq, 10.5);
+                       float len = sqrt(x * x + y * y);
+                       if(len == 0.0f) len = 1.0f;
+
+                       vptr->x = x / len;
+                       vptr->y = y / len;
+
+                       ++vptr;
+               }
+       }
+       return 0;
+}
+
+int dump_smktxt_vfield(struct smktxt *stx, const char *fname)
+{
+       FILE *fp;
+       int xsz, ysz;
+
+       if(!(fp = fopen(fname, "wb"))) {
+               fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
+               return -1;
+       }
+
+       xsz = stx->vfield.width;
+       ysz = stx->vfield.height;
+
+       fwrite(&xsz, sizeof xsz, 1, fp);
+       fwrite(&ysz, sizeof ysz, 1, fp);
+       fwrite(stx->vfield.v, sizeof *stx->vfield.v, xsz * ysz, fp);
+       fclose(fp);
+       return 0;
+}
+
+void set_smktxt_wind(struct smktxt *stx, float x, float y, float z)
+{
+       stx->em.wind.x = x;
+       stx->em.wind.y = y;
+       stx->em.wind.z = z;
+}
+
+void set_smktxt_plife(struct smktxt *stx, float life)
+{
+       stx->em.max_life = life;
+}
+
+void set_smktxt_pcount(struct smktxt *stx, int count)
+{
+       free(stx->em.plist);
+       stx->em.plist = 0;
+       stx->em.pcount = count;
+}
+
+void set_smktxt_drag(struct smktxt *stx, float drag)
+{
+       stx->em.drag = drag;
+}
+
+void update_smktxt(struct smktxt *stx, float dt)
+{
+       int i;
+       struct vec2 accel;
+       struct particle *p;
+       struct g3d_vertex *v;
+
+       if(!stx->em.plist) {
+               if(init_emitter(&stx->em, stx->em.pcount, stx->img_pixels, stx->img_xsz, stx->img_ysz) == -1) {
+                       fprintf(stderr, "failed to initialize emitter with %d particles\n", stx->em.pcount);
+                       return;
+               }
+       }
+
+       p = stx->em.plist;
+       v = stx->em.varr;
+
+       for(i=0; i<stx->em.pcount; i++) {
+               vfield_eval(&stx->vfield, p->x, p->y, &accel);
+               p->x += p->vx * stx->em.drag * dt;
+               p->y += p->vy * stx->em.drag * dt;
+               p->z += p->vz * stx->em.drag * dt;
+               p->vx += (stx->em.wind.x + accel.x * DFL_FORCE) * dt;
+               p->vy += (stx->em.wind.y + accel.y * DFL_FORCE) * dt;
+               p->vz += (stx->em.wind.z + p->z * DFL_ZBIAS) * dt;
+               p->life -= dt;
+               if(p->life < 0.0f) p->life = 0.0f;
+
+               v->x = p->x;
+               v->y = p->y;
+               v->z = p->z;
+               v->w = 1.0f;
+               v->a = cround64(p->life * 255.0f / stx->em.max_life);
+               v->r = 0;
+               v->g = (v->a & 0xe0) >> 3;
+               v->b = (v->a & 0x1f) << 3;
+               ++v;
+
+               ++p;
+       }
+}
+
+void draw_smktxt(struct smktxt *stx)
+{
+       g3d_draw(G3D_POINTS, stx->em.varr, stx->em.pcount);
+}
+
+
+static int init_emitter(struct emitter *em, int num, unsigned char *map, int xsz, int ysz)
+{
+       int i, x, y;
+       float aspect = (float)xsz / (float)ysz;
+       struct particle *p;
+
+       free(em->varr);
+       if(!(em->varr = malloc(num * sizeof *em->varr))) {
+               fprintf(stderr, "failed to allocate particle vertex array (%d verts)\n", num);
+               return -1;
+       }
+
+       free(em->plist);
+       if(!(em->plist = malloc(num * sizeof *em->plist))) {
+               free(em->varr);
+               return -1;
+       }
+       em->pcount = num;
+
+       p = em->plist;
+       for(i=0; i<num; i++) {
+               do {
+                       x = rand() % xsz;
+                       y = rand() % ysz;
+               } while(map[y * xsz + x] < 128);
+
+               p->x = (float)x / (float)xsz - 0.5;
+               p->y = -(float)y / (float)xsz + 0.5 / aspect;
+               p->z = ((float)i / (float)num * 2.0 - 1.0) * 0.005;
+               p->r = p->g = p->b = 255;
+               p->vx = p->vy = p->vz = 0.0f;
+               p->life = em->max_life;
+               ++p;
+       }
+       return 0;
+}
+
+static int load_vfield(struct vfield *vf, const char *fname)
+{
+       FILE *fp;
+       int tmp;
+
+       if(!(fp = fopen(fname, "rb"))) {
+               fprintf(stderr, "failed to open vector field: %s\n", fname);
+               return -1;
+       }
+       if(fread(&vf->width, sizeof vf->width, 1, fp) < 1 ||
+                       fread(&vf->height, sizeof vf->height, 1, fp) < 1) {
+               fprintf(stderr, "load_vfield: unexpected end of file while reading header\n");
+               fclose(fp);
+               return -1;
+       }
+
+       /* assume xsz is pow2 otherwise fuck you */
+       tmp = vf->width - 1;
+       vf->xshift = 0;
+       while(tmp) {
+               ++vf->xshift;
+               tmp >>= 1;
+       }
+
+       if(!(vf->v = malloc(vf->width * vf->height * sizeof *vf->v))) {
+               fprintf(stderr, "failed to allocate %dx%d vector field\n", vf->width, vf->height);
+               fclose(fp);
+               return -1;
+       }
+       if(fread(vf->v, sizeof *vf->v, vf->width * vf->height, fp) < vf->width * vf->height) {
+               fprintf(stderr, "load_vfield: unexpected end of file while reading %dx%d vector field\n",
+                               vf->width, vf->height);
+               fclose(fp);
+               return -1;
+       }
+       fclose(fp);
+
+       vf->pos.x = vf->pos.y = 0;
+       vf->size.x = vf->size.y = 1;
+       return 0;
+}
+
+static void vfield_eval(struct vfield *vf, float x, float y, struct vec2 *dir)
+{
+       int px, py;
+       float tx, ty;
+       struct vec2 *p1, *p2;
+       struct vec2 left, right;
+
+       x = ((x - vf->pos.x) / vf->size.x + 0.5f) * vf->width;
+       y = ((y - vf->pos.y) / vf->size.y + 0.5f) * vf->height;
+       x = floor(x);
+       y = floor(y);
+
+       if(x < 0) x = 0;
+       if(y < 0) y = 0;
+       if(x > vf->width - 2) x = vf->width - 2;
+       if(y > vf->height - 2) y = vf->height - 2;
+
+       px = (int)x;
+       py = (int)y;
+
+       p1 = vf->v + (py << vf->xshift) + px;
+#ifdef BILERP_FIELD
+       p2 = p1 + vf->width;
+
+       tx = fmod(x, 1.0f);
+       ty = fmod(y, 1.0f);
+
+       left.x = p1->x + (p2->x - p1->x) * ty;
+       left.y = p1->y + (p2->y - p1->y) * ty;
+       ++p1;
+       ++p2;
+       right.x = p1->x + (p2->x - p1->x) * ty;
+       right.y = p1->y + (p2->y - p1->y) * ty;
+
+       dir->x = left.x + (right.x - left.x) * tx;
+       dir->y = left.y + (right.y - left.y) * ty;
+#else
+       dir->x = p1->x;
+       dir->y = p1->y;
+#endif
+
+#ifdef RANDOMIZE_FIELD
+       dir->x += ((float)rand() / RAND_MAX - 0.5) * RAND_FIELD_MAX;
+       dir->y += ((float)rand() / RAND_MAX - 0.5) * RAND_FIELD_MAX;
+#endif
+}
diff --git a/src/scr/smoketxt.h b/src/scr/smoketxt.h
new file mode 100644 (file)
index 0000000..42ba49d
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef SMOKE_TEXT_H_
+#define SMOKE_TEXT_H_
+
+struct smktxt;
+
+struct smktxt *create_smktxt(const char *imgname, const char *vfieldname);
+void destroy_smktxt(struct smktxt *stx);
+
+int gen_smktxt_vfield(struct smktxt *stx, int xres, int yres, float xfreq, float yfreq);
+int dump_smktxt_vfield(struct smktxt *stx, const char *fname);
+
+void set_smktxt_wind(struct smktxt *stx, float x, float y, float z);
+void set_smktxt_plife(struct smktxt *stx, float life);
+void set_smktxt_pcount(struct smktxt *stx, int count);
+void set_smktxt_drag(struct smktxt *stx, float drag);
+
+void update_smktxt(struct smktxt *stx, float dt);
+void draw_smktxt(struct smktxt *stx);
+
+
+#endif /* SMOKE_TEXT_ */
diff --git a/src/scr/thunder.c b/src/scr/thunder.c
new file mode 100644 (file)
index 0000000..cacb7b5
--- /dev/null
@@ -0,0 +1,441 @@
+/* thunder. c */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include "imago2.h"
+#include "demo.h"
+#include "screen.h"
+
+/* Render blur in half x half dimenstions. Add one pixel padding in all 
+ * directions (2 pixels horizontally, 2 pixels vertically).
+ */
+#define BLUR_BUFFER_WIDTH (320/2 + 2)
+#define BLUR_BUFFER_HEIGHT (240/2 + 2)
+#define BLUR_BUFFER_SIZE (BLUR_BUFFER_WIDTH * BLUR_BUFFER_HEIGHT)
+static unsigned char *blurBuffer, *blurBuffer2;
+
+#define BLUR_DARKEN 4
+
+#define THUNDER_RECT_SIZE 2
+#define THUNDER_RANDOMNESS 16
+#define THUNDER_SECONDS 0.075f
+
+#define VERTEX_COUNT 12
+#define PERSPECTIVE_NEUTRAL_DEPTH 0.5f
+#define NEAR_PLANE 0.01f
+#define ROTATION_SPEED 1.5f
+
+#define MESH_RANDOM_SEED 173
+
+#define MIN_FOGGED 40
+
+#define CAMERA_DISTANCE 1.1f
+
+/* TODO: Load palette from file */
+static unsigned short palette[256];
+
+typedef unsigned int PointSprite;
+#define MAX_POINT_SPRITES 1024
+static PointSprite pointSprites[MAX_POINT_SPRITES];
+int pointSpriteCount = 0;
+#define PACK_POINT_SPRITE(x, y, col) ((col << 16) | (x << 8) | y)
+#define UNPACK_COLOR(ps) (ps >> 16)
+#define UNPACK_X(ps) ((ps >> 8) & 0xFF)
+#define UNPACK_Y(ps) (ps & 0xFF)
+
+typedef struct {
+       float x,y,z;
+} MyVertex ;
+
+MyVertex vertexBuffer[VERTEX_COUNT];
+MyVertex vertexBufferAnimated[VERTEX_COUNT];
+MyVertex vertexBufferProjected[VERTEX_COUNT];
+
+void clearBlurBuffer();
+void applyBlur();
+void blitEffect();
+void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth);
+
+void initMesh();
+void projectMesh();
+void animateMesh();
+void renderMeshToPointSprites(int seed);
+void renderPointSprites();
+unsigned char fog(float z);
+void sortPointSprites();
+
+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 unsigned int lastFrameTime = 0;
+static float lastFrameDuration = 0.0f;
+static struct screen scr = {
+       "thunder",
+       init,
+       destroy,
+       start,
+       0,
+       draw
+};
+
+struct screen *thunder_screen(void)
+{
+       return &scr;
+}
+
+static int init(void)
+{
+       int i = 0;
+
+       blurBuffer = malloc(BLUR_BUFFER_SIZE);
+       blurBuffer2 = malloc(BLUR_BUFFER_SIZE);
+
+       clearBlurBuffer();
+
+       /* For now, map to blue */
+       for (i = 0; i < 256; i++) {
+               palette[i] = (i * i) >> 11;
+       }
+
+       initMesh();
+
+       return 0;
+}
+
+static void destroy(void)
+{
+       free(blurBuffer);
+       blurBuffer = 0;
+       
+       free(blurBuffer2);
+       blurBuffer2 = 0;
+}
+
+static void start(long trans_time)
+{
+       lastFrameTime = time_msec;
+}
+
+
+static float remainingThunderDuration = THUNDER_SECONDS;
+static int thunderPattern = 0;
+
+static void draw(void)
+{
+       lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
+       lastFrameTime = time_msec;
+
+       remainingThunderDuration -= lastFrameDuration;
+       if (remainingThunderDuration <= 0) {
+               thunderPattern++;
+               remainingThunderDuration = THUNDER_SECONDS;
+       }
+       
+       animateMesh();
+       projectMesh();
+       renderMeshToPointSprites(thunderPattern);
+       sortPointSprites();
+       renderPointSprites();
+       
+       
+       applyBlur();
+       blitEffect();
+
+       
+
+       swap_buffers(0);
+}
+
+void clearBlurBuffer() {
+       /* Clear the whole buffer (including its padding ) */
+       memset(blurBuffer, 0, BLUR_BUFFER_SIZE);
+       memset(blurBuffer2, 0, BLUR_BUFFER_SIZE);
+}
+
+
+void applyBlur() {
+       int i, j;
+       unsigned char *tmp;
+       unsigned char *src = blurBuffer + BLUR_BUFFER_WIDTH + 1;
+       unsigned char *dst = blurBuffer2 + BLUR_BUFFER_WIDTH + 1;
+
+       for (j = 0; j < 120; j++) {
+               for (i = 0; i < 160; i++) {
+                       *dst = (*(src - 1) + *(src + 1) + *(src - BLUR_BUFFER_WIDTH) + *(src + BLUR_BUFFER_WIDTH)) >> 2;
+                       
+                       if (*dst > BLUR_DARKEN) *dst -= BLUR_DARKEN;
+                       else *dst = 0;
+
+                       dst++;
+                       src++;
+               }
+               /* Just skip the padding since we went through the scanline in the inner loop (except from the padding) */
+               src += 2;
+               dst += 2;
+       }
+
+       /* Swap blur buffers */
+       tmp = blurBuffer;
+       blurBuffer = blurBuffer2;
+       blurBuffer2 = tmp;
+}
+
+void blitEffect() {
+       unsigned int *dst1 = (unsigned int*) fb_pixels;
+       unsigned int *dst2 = dst1 + 160; /* We're writing two pixels at once */
+       unsigned char *src1 = blurBuffer + BLUR_BUFFER_WIDTH + 1;
+       unsigned char *src2 = src1 + BLUR_BUFFER_WIDTH;
+       unsigned char tl, tr, bl, br;
+       int i, j;
+
+       for (j = 0; j < 120; j++) {
+               for (i = 0; i < 160; i++) {
+                       tl = *src1;
+                       tr = (*src1 + *(src1 + 1)) >> 1;
+                       bl = (*src1 + *src2) >> 1;
+                       br = (tr + ((*src2 + *(src2 + 1)) >> 1)) >> 1;
+
+                       /* Pack 2 pixels in each 32 bit word */
+                       *dst1 = (palette[tr] << 16) | palette[tl];
+                       *dst2 = (palette[br] << 16) | palette[bl];
+
+                       dst1++;
+                       src1++;
+                       dst2++;
+                       src2++;
+               }
+               /* Again, skip padding */
+               src1 += 2;
+               src2 += 2;
+
+               /* For now, skip a scanline */
+               dst1 += 160;
+               dst2 += 160;
+       }
+
+}
+
+void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth) {
+       int mx, my, i, j;
+       unsigned char *dst;
+       unsigned char mc;
+
+       if (randomness <= 0) randomness = 1;
+       mx = ((x0 + x1) >> 1) + rand() % randomness - randomness / 2;
+       my = ((y0 + y1) >> 1) + rand() % randomness - randomness / 2;
+       mc = (c0 + c1) >> 1;
+
+       if (depth <= 0) return;
+
+       /* Insert a new sprite */
+       if (pointSpriteCount >= MAX_POINT_SPRITES) {
+               printf("PROBLEM");
+               return;
+       }
+       pointSprites[pointSpriteCount++] = PACK_POINT_SPRITE(mx, my, mc);
+
+       srand(seed);
+
+       thunder(x0, y0, mx, my, c0, mc, rand(), randomness >> 1, depth-1);
+       thunder(mx, my, x1, y1, mc, c1, rand(), randomness >> 1, depth - 1);
+}
+
+MyVertex randomVertex() {
+       MyVertex ret;
+       float l;
+
+       ret.x = rand() % 200 - 100; if (ret.x == 0) ret.x = 1;
+       ret.y = rand() % 200 - 100; if (ret.y == 0) ret.y = 1;
+       ret.z = rand() % 200 - 100; if (ret.z == 0) ret.z = 1;
+       
+       // Normalize
+       l = sqrt(ret.x * ret.x + ret.y * ret.y + ret.z * ret.z);
+       ret.x /= l;
+       ret.y /= l;
+       ret.z /= l;
+
+       return ret;
+}
+
+void initMesh() {
+       int i;
+
+       srand(MESH_RANDOM_SEED);
+
+       for (i = 0; i < VERTEX_COUNT; i++) {
+               vertexBuffer[i] = randomVertex();
+       }
+}
+
+void animateMesh() {
+       int i = 0;
+       MyVertex bx, by, bz;
+       float yRot;
+
+       yRot = ROTATION_SPEED * time_msec / 1000.0f;
+
+       /* Create rotated basis */
+       bx.x = cos(yRot);
+       bx.y = 0.0f;
+       bx.z = sin(yRot);
+
+       by.x = 0.0f;
+       by.y = 1.0f;
+       by.z = 0.0f;
+
+       bz.x = cos(yRot + M_PI/2.0f);
+       bz.y = 0.0f;
+       bz.z = sin(yRot + M_PI/2.0f);
+
+       for (i = 0; i < VERTEX_COUNT; i++) {
+               MyVertex v1, v2;
+               v1 = vertexBuffer[i];
+
+
+               v1.y *= sin(time_msec / 1000.0f + v1.x + v1.z);
+
+               /* O re panaia mou */
+               v2.x = v1.x * bx.x + v1.y * by.x + v1.z * bz.x;
+               v2.y = v1.x * bx.y + v1.y * by.y + v1.z * bz.y;
+               v2.z = v1.x * bx.z + v1.y * by.z + v1.z * bz.z;
+
+               v2.z += CAMERA_DISTANCE;
+
+               vertexBufferAnimated[i] = v2;
+       }
+}
+
+void projectMesh() {
+       int i = 0;
+
+       for (i = 0; i < VERTEX_COUNT; i++) {
+
+               if (vertexBufferAnimated[i].z <= NEAR_PLANE) {
+                       vertexBufferProjected[i].x = vertexBufferProjected[i].y = 1000.0f;
+                       vertexBufferProjected[i].z = -1.0f;
+                       continue;
+               }
+
+               vertexBufferProjected[i].x = vertexBufferAnimated[i].x * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
+               vertexBufferProjected[i].y = vertexBufferAnimated[i].y * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
+       }
+}
+
+void renderMeshToPointSprites(int seed) {
+       int vertex, j;
+       int sx, sy;
+       unsigned char color;
+       unsigned char *dst;
+       unsigned char fogAtOrigin;
+
+       fogAtOrigin = fog(CAMERA_DISTANCE);
+
+       pointSpriteCount = 0;
+       srand(seed);
+
+       for (vertex = 0; vertex < VERTEX_COUNT; vertex++) {
+               sx = (int)(vertexBufferProjected[vertex].x * 80) + 80;
+               sy = (int)(vertexBufferProjected[vertex].y * 60) + 60;
+
+               thunder(80, 60, sx, sy, fogAtOrigin, fog(vertexBufferAnimated[vertex].z), rand(), THUNDER_RANDOMNESS, 5);
+       }
+}
+
+void renderPointSprites() {
+       int i,j;
+       PointSprite sprite;
+       unsigned char *dst;
+       int sx, sy;
+       unsigned char color;
+
+       for (i = 0; i < pointSpriteCount; i++) {
+               sprite = pointSprites[i];
+
+               sx = UNPACK_X(sprite);
+               sy = UNPACK_Y(sprite);
+
+               if (sx < THUNDER_RECT_SIZE || sx >= 160 - THUNDER_RECT_SIZE || sy < THUNDER_RECT_SIZE || sy >= 120 - THUNDER_RECT_SIZE) continue;
+
+               dst = blurBuffer + BLUR_BUFFER_WIDTH + 1 + sx + sy * BLUR_BUFFER_WIDTH;
+
+               color = UNPACK_COLOR(sprite);
+
+               for (j = 0; j < THUNDER_RECT_SIZE; j++) {
+                       memset(dst, color, THUNDER_RECT_SIZE);
+                       dst += BLUR_BUFFER_WIDTH;
+               }
+       }
+}
+
+unsigned char fog(float z) {
+       unsigned int ret = (unsigned int) (((-(z - CAMERA_DISTANCE)) * 0.5f + 0.5f) * (255.0f - MIN_FOGGED)) + MIN_FOGGED;
+       if (ret > 255) ret = 255;
+       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 sortPointSprites() {
+       sort(pointSprites, pointSprites + pointSpriteCount);
+}
+
diff --git a/src/scr/tilemaze.c b/src/scr/tilemaze.c
new file mode 100644 (file)
index 0000000..6e2aa54
--- /dev/null
@@ -0,0 +1,157 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "tilemaze.h"
+#include "mesh.h"
+#include "treestor.h"
+#include "dynarr.h"
+#include "scene.h"
+
+struct object {
+       char *name;
+       struct g3d_mesh mesh;
+
+       void *texels;
+       int tex_width, tex_height;
+
+       struct object *next;
+};
+
+struct tile {
+       char *name;
+       struct object *objlist;
+};
+
+struct tilemaze {
+       struct tile *tileset;
+       int num_tiles;
+
+       struct object *objects;
+};
+
+void free_object(struct object *obj);
+
+struct tilemaze *load_tilemaze(const char *fname)
+{
+       struct tilemaze *tmz;
+
+       if(!(tmz = calloc(sizeof *tmz, 1))) {
+               return 0;
+       }
+       return tmz;
+}
+
+void destroy_tilemaze(struct tilemaze *tmz)
+{
+       if(!tmz) return;
+
+       free(tmz->tileset);
+
+       while(tmz->objects) {
+               struct object *o = tmz->objects;
+               tmz->objects = tmz->objects->next;
+
+               free(o->mesh.varr);
+               free(o->mesh.iarr);
+               free(o);
+       }
+
+       free(tmz);
+}
+
+void update_tilemaze(struct tilemaze *tmz)
+{
+}
+
+void draw_tilemaze(struct tilemaze *tmz)
+{
+}
+
+struct tile *load_tileset(const char *fname, int *count)
+{
+       int i;
+       struct tile *tiles = 0, *tile;
+       struct ts_node *ts = 0, *node;
+       struct ts_attr *attr;
+       struct object *obj;
+
+       if(!(ts = ts_load(fname))) {
+               fprintf(stderr, "load_tileset: failed to load: %s\n", fname);
+               goto err;
+       }
+       if(strcmp(ts->name, "tileset") != 0) {
+               fprintf(stderr, "load_tileset: %s is not a tileset file\n", fname);
+               goto err;
+       }
+
+       if(!(tiles = dynarr_alloc(sizeof *tiles, 0))) {
+               fprintf(stderr, "load_tileset: failed to create tiles array\n");
+               goto err;
+       }
+
+       node = ts->child_list;
+       while(node) {
+               if(strcmp(node->name, "tile") != 0) {
+                       fprintf(stderr, "load_tileset: skipping unexpected node %s in %s\n", node->name, fname);
+                       node = node->next;
+                       continue;
+               }
+
+               if(!(tile = malloc(sizeof *tile))) {
+                       fprintf(stderr, "load_tileset: failed to allocate tile\n");
+                       goto err;
+               }
+               if(!(tile->name = malloc(strlen(node->name) + 1))) {
+                       fprintf(stderr, "load_tileset: failed to allocate tile name\n");
+                       free(tile);
+                       goto err;
+               }
+               strcpy(tile->name, node->name);
+               tile->objlist = 0;
+
+               attr = node->attr_list;
+               while(attr) {
+                       /*
+                       if(strcmp(attr->name, "scn") == 0) {
+                               struct object *last;
+                               if(!(obj = load_objlist(attr->value.str, &last))) {
+                                       free(tile);
+                                       goto err;
+                               }
+                               last->next = tile->objlist;
+                               tile->objlist = obj;
+                       }
+                       */
+                       attr = attr->next;
+               }
+
+               node = node->next;
+       }
+
+err:
+       if(tiles) {
+               for(i=0; i<dynarr_size(tiles); i++) {
+                       free(tiles[i].name);
+                       obj = tiles[i].objlist;
+                       while(obj) {
+                               struct object *tmp = obj;
+                               obj = obj->next;
+                               free_object(obj);
+                       }
+               }
+               dynarr_free(tiles);
+       }
+       if(ts) ts_free_tree(ts);
+       return 0;
+}
+
+void free_object(struct object *obj)
+{
+       if(!obj) return;
+
+       free(obj->name);
+       free(obj->texels);
+       destroy_mesh(&obj->mesh);
+
+       free(obj);
+}
diff --git a/src/scr/tilemaze.h b/src/scr/tilemaze.h
new file mode 100644 (file)
index 0000000..a06acd8
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef TILEMAZE_H_
+#define TILEMAZE_H_
+
+struct tilemaze;
+
+struct tilemaze *load_tilemaze(const char *fname);
+void destroy_tilemaze(struct tilemaze *tmz);
+
+void update_tilemaze(struct tilemaze *tmz);
+void draw_tilemaze(struct tilemaze *tmz);
+
+#endif /* TILEMAZE_H_ */
diff --git a/src/scr/tunnel.c b/src/scr/tunnel.c
new file mode 100644 (file)
index 0000000..9071b74
--- /dev/null
@@ -0,0 +1,287 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include "imago2.h"
+#include "demo.h"
+#include "screen.h"
+#include "gfxutil.h"
+
+#ifndef M_PI
+#define M_PI   3.1415926535
+#endif
+
+#define VSCALE 1.5
+
+#define TEX_FNAME      "data/grid.png"
+#define TEX_USCALE     4
+#define TEX_VSCALE     2
+
+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 draw_tunnel_range(unsigned short *pixels, int xoffs, int yoffs, int starty, int num_lines, long tm);
+static int count_bits(unsigned int x);
+static int count_zeros(unsigned int x);
+
+static struct screen scr = {
+       "tunnel",
+       init,
+       destroy,
+       start,
+       stop,
+       draw
+};
+
+static int xsz, ysz, vxsz, vysz;
+static int pan_width, pan_height;
+static unsigned int *tunnel_map;
+static unsigned char *tunnel_fog;
+
+static int tex_xsz, tex_ysz;
+static unsigned int *tex_pixels;
+static int tex_xshift, tex_yshift;
+static unsigned int tex_xmask, tex_ymask;
+
+static long trans_start, trans_dur;
+static int trans_dir;
+
+
+struct screen *tunnel_screen(void)
+{
+       return &scr;
+}
+
+
+static int init(void)
+{
+       int i, j, n;
+       unsigned int *tmap;
+       unsigned char *fog;
+       float aspect = (float)fb_width / (float)fb_height;
+
+       xsz = fb_width;
+       ysz = fb_height;
+       vxsz = xsz * VSCALE;
+       vysz = ysz * VSCALE;
+
+       pan_width = vxsz - xsz;
+       pan_height = vysz - ysz;
+
+       if(!(tunnel_map = malloc(vxsz * vysz * sizeof *tunnel_map))) {
+               fprintf(stderr, "failed to allocate tunnel map\n");
+               return -1;
+       }
+       if(!(tunnel_fog = malloc(vxsz * vysz))) {
+               fprintf(stderr, "failed to allocate tunnel fog map\n");
+               return -1;
+       }
+
+       tmap = tunnel_map;
+       fog = tunnel_fog;
+
+       for(i=0; i<vysz; i++) {
+               float y = 2.0 * (float)i / (float)vysz - 1.0;
+               for(j=0; j<vxsz; j++) {
+                       float x = aspect * (2.0 * (float)j / (float)vxsz - 1.0);
+                       float tu = atan2(y, x) / M_PI * 0.5 + 0.5;
+                       float d = sqrt(x * x + y * y);
+                       float tv = d == 0.0 ? 0.0 : 1.0 / d;
+
+                       int tx = (int)(tu * 65535.0 * TEX_USCALE) & 0xffff;
+                       int ty = (int)(tv * 65535.0 * TEX_VSCALE) & 0xffff;
+
+                       int f = (int)(d * 192.0);
+
+                       *tmap++ = (tx << 16) | ty;
+                       *fog++ = f > 255 ? 255 : f;
+               }
+       }
+
+       if(!(tex_pixels = img_load_pixels(TEX_FNAME, &tex_xsz, &tex_ysz, IMG_FMT_RGBA32))) {
+               fprintf(stderr, "failed to load image " TEX_FNAME "\n");
+               return -1;
+       }
+       if((count_bits(tex_xsz) | count_bits(tex_ysz)) != 1) {
+               fprintf(stderr, "non-pow2 image (%dx%d)\n", tex_xsz, tex_ysz);
+               return -1;
+       }
+
+       /*tex_pixels = gen_test_image(&tex_xsz, &tex_ysz);*/
+
+       n = count_zeros(tex_xsz);
+       for(i=0; i<n; i++) {
+               tex_xmask |= 1 << i;
+       }
+       tex_xshift = n;
+
+       n = count_zeros(tex_ysz);
+       for(i=0; i<n; i++) {
+               tex_ymask |= 1 << i;
+       }
+       tex_yshift = n;
+
+       return 0;
+}
+
+static void destroy(void)
+{
+       free(tunnel_map);
+       free(tunnel_fog);
+       img_free_pixels(tex_pixels);
+}
+
+static void start(long trans_time)
+{
+       if(trans_time) {
+               trans_start = time_msec;
+               trans_dur = trans_time;
+               trans_dir = 1;
+       }
+}
+
+static void stop(long trans_time)
+{
+       if(trans_time) {
+               trans_start = time_msec;
+               trans_dur = trans_time;
+               trans_dir = -1;
+       }
+}
+
+#define NUM_WORK_ITEMS 8
+
+static void draw(void)
+{
+       int i, num_lines = ysz / NUM_WORK_ITEMS;
+       int draw_lines = num_lines;
+       float t;
+       int xoffs, yoffs;
+
+       if(trans_dir) {
+               long interval = time_msec - trans_start;
+               int progr = num_lines * interval / trans_dur;
+               if(trans_dir < 0) {
+                       draw_lines = num_lines - progr - 1;
+               } else {
+                       draw_lines = progr;
+               }
+               if(progr >= num_lines) {
+                       trans_dir = 0;
+               }
+       }
+
+       t = time_msec / 10000.0;
+       xoffs = (int)(cos(t * 3.0) * pan_width / 2) + pan_width / 2;
+       yoffs = (int)(sin(t * 4.0) * pan_height / 2) + pan_height / 2;
+
+       for(i=0; i<NUM_WORK_ITEMS; i++) {
+               int starty = i * num_lines;
+               int resty = starty + draw_lines;
+               int rest_lines = num_lines - draw_lines;
+               draw_tunnel_range(fb_pixels, xoffs, yoffs, starty, draw_lines, time_msec);
+               if(rest_lines) {
+                       memset(fb_pixels + resty * fb_width, 0, rest_lines * fb_width * 2);
+               }
+       }
+
+       swap_buffers(0);
+}
+
+static void tunnel_color(int *rp, int *gp, int *bp, long toffs, unsigned int tpacked, int fog)
+{
+       int r, g, b;
+       unsigned int col;
+       unsigned int tx = (((tpacked >> 16) & 0xffff) << tex_xshift) >> 16;
+       unsigned int ty = ((tpacked & 0xffff) << tex_yshift) >> 16;
+       tx += toffs;
+       ty += toffs << 1;
+
+       tx &= tex_xmask;
+       ty &= tex_ymask;
+
+       col = tex_pixels[(ty << tex_xshift) + tx];
+       r = col & 0xff;
+       g = (col >> 8) & 0xff;
+       b = (col >> 16) & 0xff;
+
+       *rp = (r * fog) >> 8;
+       *gp = (g * fog) >> 8;
+       *bp = (b * fog) >> 8;
+}
+
+static void draw_tunnel_range(unsigned short *pix, int xoffs, int yoffs, int starty, int num_lines, long tm)
+{
+       int i, j;
+       unsigned int *tmap = tunnel_map + (starty + yoffs) * vxsz + xoffs;
+       unsigned char *fog = tunnel_fog + (starty + yoffs) * vxsz + xoffs;
+
+       long toffs = tm / 8;
+       unsigned int *pixels = (unsigned int*)pix + starty * (fb_width >> 1);
+
+       for(i=0; i<num_lines; i++) {
+               for(j=0; j<(xsz>>1); j++) {
+                       unsigned int col;
+                       int r, g, b, idx = j << 1;
+
+                       tunnel_color(&r, &g, &b, toffs, tmap[idx], fog[idx]);
+                       col = PACK_RGB16(r, g, b);
+                       tunnel_color(&r, &g, &b, toffs, tmap[idx + 1], fog[idx + 1]);
+                       col |= PACK_RGB16(r, g, b) << 16;
+                       *pixels++ = col;
+               }
+               tmap += vxsz;
+               fog += vxsz;
+       }
+}
+
+static int count_bits(unsigned int x)
+{
+       int i, nbits = 0;
+       for(i=0; i<32; i++) {
+               if(x & 1) ++nbits;
+               x >>= 1;
+       }
+       return nbits;
+}
+
+static int count_zeros(unsigned int x)
+{
+       int i, num = 0;
+       for(i=0; i<32; i++) {
+               if(x & 1) break;
+               ++num;
+               x >>= 1;
+       }
+       return num;
+}
+
+/*
+static unsigned int *gen_test_image(int *wptr, int *hptr)
+{
+       int i, j;
+       int xsz = 256, ysz = 256;
+       unsigned int *pixels, *pix;
+
+       if(!(pixels = malloc(xsz * ysz * sizeof *pix))) {
+               return 0;
+       }
+       pix = pixels;
+
+       for(i=0; i<ysz; i++) {
+               for(j=0; j<xsz; j++) {
+                       int val = i ^ j;
+
+                       *pix++ = PACK_RGB32(val, val / 2, val / 4);
+               }
+       }
+
+       *wptr = xsz;
+       *hptr = ysz;
+       return pixels;
+}
+*/
diff --git a/src/smoketxt.c b/src/smoketxt.c
deleted file mode 100644 (file)
index 841ca28..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <errno.h>
-#include "imago2.h"
-#include "3dgfx.h"
-#include "smoketxt.h"
-#include "util.h"
-#include "noise.h"
-
-/* if defined, use bilinear interpolation for dispersion field vectors */
-#define BILERP_FIELD
-/* if defined randomize field vectors by RAND_FIELD_MAX */
-#define RANDOMIZE_FIELD
-
-#define RAND_FIELD_MAX 0.7
-
-#define DFL_PCOUNT             4000
-#define DFL_MAX_LIFE   7.0f
-#define DFL_PALPHA             1.0f
-#define DFL_ZBIAS              0.25
-#define DFL_DRAG               0.95
-#define DFL_FORCE              0.07
-#define DFL_FREQ               0.085
-
-struct vec2 {
-       float x, y;
-};
-
-struct vec3 {
-       float x, y, z;
-};
-
-struct particle {
-       float x, y, z;
-       float vx, vy, vz;       /* velocity */
-       int r, g, b;
-       float life;
-};
-
-struct emitter {
-       struct particle *plist;
-       int pcount;
-
-       struct vec3 wind;
-       float drag;
-       float max_life;
-
-       struct g3d_vertex *varr;
-};
-
-struct vfield {
-       struct vec2 pos, size;
-
-       int width, height;
-       int xshift;
-       struct vec2 *v;
-};
-
-
-struct smktxt {
-       struct emitter em;
-       struct vfield vfield;
-
-       unsigned char *img_pixels;
-       int img_xsz, img_ysz;
-};
-
-static int init_emitter(struct emitter *em, int num, unsigned char *map, int xsz, int ysz);
-static int load_vfield(struct vfield *vf, const char *fname);
-static void vfield_eval(struct vfield *vf, float x, float y, struct vec2 *dir);
-
-struct smktxt *create_smktxt(const char *imgname, const char *vfieldname)
-{
-       struct smktxt *stx;
-
-       if(!imgname) return 0;
-
-       if(!(stx = calloc(sizeof *stx, 1))) {
-               return 0;
-       }
-       if(!(stx->img_pixels = img_load_pixels(imgname, &stx->img_xsz, &stx->img_ysz, IMG_FMT_GREY8))) {
-               fprintf(stderr, "create_smktxt: failed to load particle spawnmap: %s\n", imgname);
-               free(stx);
-               return 0;
-       }
-
-       stx->em.pcount = DFL_PCOUNT;
-       stx->em.wind.z = 0.01;
-       stx->em.drag = DFL_DRAG;
-       stx->em.max_life = DFL_MAX_LIFE;
-
-       if(vfieldname) {
-               if(load_vfield(&stx->vfield, vfieldname) == -1) {
-                       img_free_pixels(stx->img_pixels);
-                       free(stx);
-                       return 0;
-               }
-       }
-
-       return stx;
-}
-
-void destroy_smktxt(struct smktxt *stx)
-{
-       if(!stx) return;
-
-       img_free_pixels(stx->img_pixels);
-       free(stx);
-}
-
-int gen_smktxt_vfield(struct smktxt *stx, int xres, int yres, float xfreq, float yfreq)
-{
-       int i, j;
-       unsigned int tmp;
-       struct vec2 *vptr;
-       struct vfield *vf = &stx->vfield;
-
-       if(!(vf->v = malloc(xres * yres * sizeof *vf->v))) {
-               fprintf(stderr, "failed to allocate %dx%d vector field\n", xres, yres);
-               return -1;
-       }
-
-       vf->width = xres;
-       vf->height = yres;
-       vf->pos.x = vf->pos.y = 0.0f;
-       vf->size.x = vf->size.y = 1.0f;
-
-       /* assume xres is pow2 otherwise fuck you */
-       tmp = xres - 1;
-       vf->xshift = 0;
-       while(tmp) {
-               ++vf->xshift;
-               tmp >>= 1;
-       }
-
-       vptr = vf->v;
-       for(i=0; i<yres; i++) {
-               for(j=0; j<xres; j++) {
-                       float x = noise3(j * xfreq, i * yfreq, 0.5);
-                       float y = noise3(j * xfreq, i * yfreq, 10.5);
-                       float len = sqrt(x * x + y * y);
-                       if(len == 0.0f) len = 1.0f;
-
-                       vptr->x = x / len;
-                       vptr->y = y / len;
-
-                       ++vptr;
-               }
-       }
-       return 0;
-}
-
-int dump_smktxt_vfield(struct smktxt *stx, const char *fname)
-{
-       FILE *fp;
-       int xsz, ysz;
-
-       if(!(fp = fopen(fname, "wb"))) {
-               fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
-               return -1;
-       }
-
-       xsz = stx->vfield.width;
-       ysz = stx->vfield.height;
-
-       fwrite(&xsz, sizeof xsz, 1, fp);
-       fwrite(&ysz, sizeof ysz, 1, fp);
-       fwrite(stx->vfield.v, sizeof *stx->vfield.v, xsz * ysz, fp);
-       fclose(fp);
-       return 0;
-}
-
-void set_smktxt_wind(struct smktxt *stx, float x, float y, float z)
-{
-       stx->em.wind.x = x;
-       stx->em.wind.y = y;
-       stx->em.wind.z = z;
-}
-
-void set_smktxt_plife(struct smktxt *stx, float life)
-{
-       stx->em.max_life = life;
-}
-
-void set_smktxt_pcount(struct smktxt *stx, int count)
-{
-       free(stx->em.plist);
-       stx->em.plist = 0;
-       stx->em.pcount = count;
-}
-
-void set_smktxt_drag(struct smktxt *stx, float drag)
-{
-       stx->em.drag = drag;
-}
-
-void update_smktxt(struct smktxt *stx, float dt)
-{
-       int i;
-       struct vec2 accel;
-       struct particle *p;
-       struct g3d_vertex *v;
-
-       if(!stx->em.plist) {
-               if(init_emitter(&stx->em, stx->em.pcount, stx->img_pixels, stx->img_xsz, stx->img_ysz) == -1) {
-                       fprintf(stderr, "failed to initialize emitter with %d particles\n", stx->em.pcount);
-                       return;
-               }
-       }
-
-       p = stx->em.plist;
-       v = stx->em.varr;
-
-       for(i=0; i<stx->em.pcount; i++) {
-               vfield_eval(&stx->vfield, p->x, p->y, &accel);
-               p->x += p->vx * stx->em.drag * dt;
-               p->y += p->vy * stx->em.drag * dt;
-               p->z += p->vz * stx->em.drag * dt;
-               p->vx += (stx->em.wind.x + accel.x * DFL_FORCE) * dt;
-               p->vy += (stx->em.wind.y + accel.y * DFL_FORCE) * dt;
-               p->vz += (stx->em.wind.z + p->z * DFL_ZBIAS) * dt;
-               p->life -= dt;
-               if(p->life < 0.0f) p->life = 0.0f;
-
-               v->x = p->x;
-               v->y = p->y;
-               v->z = p->z;
-               v->w = 1.0f;
-               v->a = cround64(p->life * 255.0f / stx->em.max_life);
-               v->r = 0;
-               v->g = (v->a & 0xe0) >> 3;
-               v->b = (v->a & 0x1f) << 3;
-               ++v;
-
-               ++p;
-       }
-}
-
-void draw_smktxt(struct smktxt *stx)
-{
-       g3d_draw(G3D_POINTS, stx->em.varr, stx->em.pcount);
-}
-
-
-static int init_emitter(struct emitter *em, int num, unsigned char *map, int xsz, int ysz)
-{
-       int i, x, y;
-       float aspect = (float)xsz / (float)ysz;
-       struct particle *p;
-
-       free(em->varr);
-       if(!(em->varr = malloc(num * sizeof *em->varr))) {
-               fprintf(stderr, "failed to allocate particle vertex array (%d verts)\n", num);
-               return -1;
-       }
-
-       free(em->plist);
-       if(!(em->plist = malloc(num * sizeof *em->plist))) {
-               free(em->varr);
-               return -1;
-       }
-       em->pcount = num;
-
-       p = em->plist;
-       for(i=0; i<num; i++) {
-               do {
-                       x = rand() % xsz;
-                       y = rand() % ysz;
-               } while(map[y * xsz + x] < 128);
-
-               p->x = (float)x / (float)xsz - 0.5;
-               p->y = -(float)y / (float)xsz + 0.5 / aspect;
-               p->z = ((float)i / (float)num * 2.0 - 1.0) * 0.005;
-               p->r = p->g = p->b = 255;
-               p->vx = p->vy = p->vz = 0.0f;
-               p->life = em->max_life;
-               ++p;
-       }
-       return 0;
-}
-
-static int load_vfield(struct vfield *vf, const char *fname)
-{
-       FILE *fp;
-       int tmp;
-
-       if(!(fp = fopen(fname, "rb"))) {
-               fprintf(stderr, "failed to open vector field: %s\n", fname);
-               return -1;
-       }
-       if(fread(&vf->width, sizeof vf->width, 1, fp) < 1 ||
-                       fread(&vf->height, sizeof vf->height, 1, fp) < 1) {
-               fprintf(stderr, "load_vfield: unexpected end of file while reading header\n");
-               fclose(fp);
-               return -1;
-       }
-
-       /* assume xsz is pow2 otherwise fuck you */
-       tmp = vf->width - 1;
-       vf->xshift = 0;
-       while(tmp) {
-               ++vf->xshift;
-               tmp >>= 1;
-       }
-
-       if(!(vf->v = malloc(vf->width * vf->height * sizeof *vf->v))) {
-               fprintf(stderr, "failed to allocate %dx%d vector field\n", vf->width, vf->height);
-               fclose(fp);
-               return -1;
-       }
-       if(fread(vf->v, sizeof *vf->v, vf->width * vf->height, fp) < vf->width * vf->height) {
-               fprintf(stderr, "load_vfield: unexpected end of file while reading %dx%d vector field\n",
-                               vf->width, vf->height);
-               fclose(fp);
-               return -1;
-       }
-       fclose(fp);
-
-       vf->pos.x = vf->pos.y = 0;
-       vf->size.x = vf->size.y = 1;
-       return 0;
-}
-
-static void vfield_eval(struct vfield *vf, float x, float y, struct vec2 *dir)
-{
-       int px, py;
-       float tx, ty;
-       struct vec2 *p1, *p2;
-       struct vec2 left, right;
-
-       x = ((x - vf->pos.x) / vf->size.x + 0.5f) * vf->width;
-       y = ((y - vf->pos.y) / vf->size.y + 0.5f) * vf->height;
-       x = floor(x);
-       y = floor(y);
-
-       if(x < 0) x = 0;
-       if(y < 0) y = 0;
-       if(x > vf->width - 2) x = vf->width - 2;
-       if(y > vf->height - 2) y = vf->height - 2;
-
-       px = (int)x;
-       py = (int)y;
-
-       p1 = vf->v + (py << vf->xshift) + px;
-#ifdef BILERP_FIELD
-       p2 = p1 + vf->width;
-
-       tx = fmod(x, 1.0f);
-       ty = fmod(y, 1.0f);
-
-       left.x = p1->x + (p2->x - p1->x) * ty;
-       left.y = p1->y + (p2->y - p1->y) * ty;
-       ++p1;
-       ++p2;
-       right.x = p1->x + (p2->x - p1->x) * ty;
-       right.y = p1->y + (p2->y - p1->y) * ty;
-
-       dir->x = left.x + (right.x - left.x) * tx;
-       dir->y = left.y + (right.y - left.y) * ty;
-#else
-       dir->x = p1->x;
-       dir->y = p1->y;
-#endif
-
-#ifdef RANDOMIZE_FIELD
-       dir->x += ((float)rand() / RAND_MAX - 0.5) * RAND_FIELD_MAX;
-       dir->y += ((float)rand() / RAND_MAX - 0.5) * RAND_FIELD_MAX;
-#endif
-}
diff --git a/src/smoketxt.h b/src/smoketxt.h
deleted file mode 100644 (file)
index 42ba49d..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef SMOKE_TEXT_H_
-#define SMOKE_TEXT_H_
-
-struct smktxt;
-
-struct smktxt *create_smktxt(const char *imgname, const char *vfieldname);
-void destroy_smktxt(struct smktxt *stx);
-
-int gen_smktxt_vfield(struct smktxt *stx, int xres, int yres, float xfreq, float yfreq);
-int dump_smktxt_vfield(struct smktxt *stx, const char *fname);
-
-void set_smktxt_wind(struct smktxt *stx, float x, float y, float z);
-void set_smktxt_plife(struct smktxt *stx, float life);
-void set_smktxt_pcount(struct smktxt *stx, int count);
-void set_smktxt_drag(struct smktxt *stx, float drag);
-
-void update_smktxt(struct smktxt *stx, float dt);
-void draw_smktxt(struct smktxt *stx);
-
-
-#endif /* SMOKE_TEXT_ */
diff --git a/src/thunder.c b/src/thunder.c
deleted file mode 100644 (file)
index cacb7b5..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/* thunder. c */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include "imago2.h"
-#include "demo.h"
-#include "screen.h"
-
-/* Render blur in half x half dimenstions. Add one pixel padding in all 
- * directions (2 pixels horizontally, 2 pixels vertically).
- */
-#define BLUR_BUFFER_WIDTH (320/2 + 2)
-#define BLUR_BUFFER_HEIGHT (240/2 + 2)
-#define BLUR_BUFFER_SIZE (BLUR_BUFFER_WIDTH * BLUR_BUFFER_HEIGHT)
-static unsigned char *blurBuffer, *blurBuffer2;
-
-#define BLUR_DARKEN 4
-
-#define THUNDER_RECT_SIZE 2
-#define THUNDER_RANDOMNESS 16
-#define THUNDER_SECONDS 0.075f
-
-#define VERTEX_COUNT 12
-#define PERSPECTIVE_NEUTRAL_DEPTH 0.5f
-#define NEAR_PLANE 0.01f
-#define ROTATION_SPEED 1.5f
-
-#define MESH_RANDOM_SEED 173
-
-#define MIN_FOGGED 40
-
-#define CAMERA_DISTANCE 1.1f
-
-/* TODO: Load palette from file */
-static unsigned short palette[256];
-
-typedef unsigned int PointSprite;
-#define MAX_POINT_SPRITES 1024
-static PointSprite pointSprites[MAX_POINT_SPRITES];
-int pointSpriteCount = 0;
-#define PACK_POINT_SPRITE(x, y, col) ((col << 16) | (x << 8) | y)
-#define UNPACK_COLOR(ps) (ps >> 16)
-#define UNPACK_X(ps) ((ps >> 8) & 0xFF)
-#define UNPACK_Y(ps) (ps & 0xFF)
-
-typedef struct {
-       float x,y,z;
-} MyVertex ;
-
-MyVertex vertexBuffer[VERTEX_COUNT];
-MyVertex vertexBufferAnimated[VERTEX_COUNT];
-MyVertex vertexBufferProjected[VERTEX_COUNT];
-
-void clearBlurBuffer();
-void applyBlur();
-void blitEffect();
-void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth);
-
-void initMesh();
-void projectMesh();
-void animateMesh();
-void renderMeshToPointSprites(int seed);
-void renderPointSprites();
-unsigned char fog(float z);
-void sortPointSprites();
-
-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 unsigned int lastFrameTime = 0;
-static float lastFrameDuration = 0.0f;
-static struct screen scr = {
-       "thunder",
-       init,
-       destroy,
-       start,
-       0,
-       draw
-};
-
-struct screen *thunder_screen(void)
-{
-       return &scr;
-}
-
-static int init(void)
-{
-       int i = 0;
-
-       blurBuffer = malloc(BLUR_BUFFER_SIZE);
-       blurBuffer2 = malloc(BLUR_BUFFER_SIZE);
-
-       clearBlurBuffer();
-
-       /* For now, map to blue */
-       for (i = 0; i < 256; i++) {
-               palette[i] = (i * i) >> 11;
-       }
-
-       initMesh();
-
-       return 0;
-}
-
-static void destroy(void)
-{
-       free(blurBuffer);
-       blurBuffer = 0;
-       
-       free(blurBuffer2);
-       blurBuffer2 = 0;
-}
-
-static void start(long trans_time)
-{
-       lastFrameTime = time_msec;
-}
-
-
-static float remainingThunderDuration = THUNDER_SECONDS;
-static int thunderPattern = 0;
-
-static void draw(void)
-{
-       lastFrameDuration = (time_msec - lastFrameTime) / 1000.0f;
-       lastFrameTime = time_msec;
-
-       remainingThunderDuration -= lastFrameDuration;
-       if (remainingThunderDuration <= 0) {
-               thunderPattern++;
-               remainingThunderDuration = THUNDER_SECONDS;
-       }
-       
-       animateMesh();
-       projectMesh();
-       renderMeshToPointSprites(thunderPattern);
-       sortPointSprites();
-       renderPointSprites();
-       
-       
-       applyBlur();
-       blitEffect();
-
-       
-
-       swap_buffers(0);
-}
-
-void clearBlurBuffer() {
-       /* Clear the whole buffer (including its padding ) */
-       memset(blurBuffer, 0, BLUR_BUFFER_SIZE);
-       memset(blurBuffer2, 0, BLUR_BUFFER_SIZE);
-}
-
-
-void applyBlur() {
-       int i, j;
-       unsigned char *tmp;
-       unsigned char *src = blurBuffer + BLUR_BUFFER_WIDTH + 1;
-       unsigned char *dst = blurBuffer2 + BLUR_BUFFER_WIDTH + 1;
-
-       for (j = 0; j < 120; j++) {
-               for (i = 0; i < 160; i++) {
-                       *dst = (*(src - 1) + *(src + 1) + *(src - BLUR_BUFFER_WIDTH) + *(src + BLUR_BUFFER_WIDTH)) >> 2;
-                       
-                       if (*dst > BLUR_DARKEN) *dst -= BLUR_DARKEN;
-                       else *dst = 0;
-
-                       dst++;
-                       src++;
-               }
-               /* Just skip the padding since we went through the scanline in the inner loop (except from the padding) */
-               src += 2;
-               dst += 2;
-       }
-
-       /* Swap blur buffers */
-       tmp = blurBuffer;
-       blurBuffer = blurBuffer2;
-       blurBuffer2 = tmp;
-}
-
-void blitEffect() {
-       unsigned int *dst1 = (unsigned int*) fb_pixels;
-       unsigned int *dst2 = dst1 + 160; /* We're writing two pixels at once */
-       unsigned char *src1 = blurBuffer + BLUR_BUFFER_WIDTH + 1;
-       unsigned char *src2 = src1 + BLUR_BUFFER_WIDTH;
-       unsigned char tl, tr, bl, br;
-       int i, j;
-
-       for (j = 0; j < 120; j++) {
-               for (i = 0; i < 160; i++) {
-                       tl = *src1;
-                       tr = (*src1 + *(src1 + 1)) >> 1;
-                       bl = (*src1 + *src2) >> 1;
-                       br = (tr + ((*src2 + *(src2 + 1)) >> 1)) >> 1;
-
-                       /* Pack 2 pixels in each 32 bit word */
-                       *dst1 = (palette[tr] << 16) | palette[tl];
-                       *dst2 = (palette[br] << 16) | palette[bl];
-
-                       dst1++;
-                       src1++;
-                       dst2++;
-                       src2++;
-               }
-               /* Again, skip padding */
-               src1 += 2;
-               src2 += 2;
-
-               /* For now, skip a scanline */
-               dst1 += 160;
-               dst2 += 160;
-       }
-
-}
-
-void thunder(int x0, int y0, int x1, int y1, unsigned char c0, unsigned char c1, int seed, int randomness, int depth) {
-       int mx, my, i, j;
-       unsigned char *dst;
-       unsigned char mc;
-
-       if (randomness <= 0) randomness = 1;
-       mx = ((x0 + x1) >> 1) + rand() % randomness - randomness / 2;
-       my = ((y0 + y1) >> 1) + rand() % randomness - randomness / 2;
-       mc = (c0 + c1) >> 1;
-
-       if (depth <= 0) return;
-
-       /* Insert a new sprite */
-       if (pointSpriteCount >= MAX_POINT_SPRITES) {
-               printf("PROBLEM");
-               return;
-       }
-       pointSprites[pointSpriteCount++] = PACK_POINT_SPRITE(mx, my, mc);
-
-       srand(seed);
-
-       thunder(x0, y0, mx, my, c0, mc, rand(), randomness >> 1, depth-1);
-       thunder(mx, my, x1, y1, mc, c1, rand(), randomness >> 1, depth - 1);
-}
-
-MyVertex randomVertex() {
-       MyVertex ret;
-       float l;
-
-       ret.x = rand() % 200 - 100; if (ret.x == 0) ret.x = 1;
-       ret.y = rand() % 200 - 100; if (ret.y == 0) ret.y = 1;
-       ret.z = rand() % 200 - 100; if (ret.z == 0) ret.z = 1;
-       
-       // Normalize
-       l = sqrt(ret.x * ret.x + ret.y * ret.y + ret.z * ret.z);
-       ret.x /= l;
-       ret.y /= l;
-       ret.z /= l;
-
-       return ret;
-}
-
-void initMesh() {
-       int i;
-
-       srand(MESH_RANDOM_SEED);
-
-       for (i = 0; i < VERTEX_COUNT; i++) {
-               vertexBuffer[i] = randomVertex();
-       }
-}
-
-void animateMesh() {
-       int i = 0;
-       MyVertex bx, by, bz;
-       float yRot;
-
-       yRot = ROTATION_SPEED * time_msec / 1000.0f;
-
-       /* Create rotated basis */
-       bx.x = cos(yRot);
-       bx.y = 0.0f;
-       bx.z = sin(yRot);
-
-       by.x = 0.0f;
-       by.y = 1.0f;
-       by.z = 0.0f;
-
-       bz.x = cos(yRot + M_PI/2.0f);
-       bz.y = 0.0f;
-       bz.z = sin(yRot + M_PI/2.0f);
-
-       for (i = 0; i < VERTEX_COUNT; i++) {
-               MyVertex v1, v2;
-               v1 = vertexBuffer[i];
-
-
-               v1.y *= sin(time_msec / 1000.0f + v1.x + v1.z);
-
-               /* O re panaia mou */
-               v2.x = v1.x * bx.x + v1.y * by.x + v1.z * bz.x;
-               v2.y = v1.x * bx.y + v1.y * by.y + v1.z * bz.y;
-               v2.z = v1.x * bx.z + v1.y * by.z + v1.z * bz.z;
-
-               v2.z += CAMERA_DISTANCE;
-
-               vertexBufferAnimated[i] = v2;
-       }
-}
-
-void projectMesh() {
-       int i = 0;
-
-       for (i = 0; i < VERTEX_COUNT; i++) {
-
-               if (vertexBufferAnimated[i].z <= NEAR_PLANE) {
-                       vertexBufferProjected[i].x = vertexBufferProjected[i].y = 1000.0f;
-                       vertexBufferProjected[i].z = -1.0f;
-                       continue;
-               }
-
-               vertexBufferProjected[i].x = vertexBufferAnimated[i].x * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
-               vertexBufferProjected[i].y = vertexBufferAnimated[i].y * PERSPECTIVE_NEUTRAL_DEPTH / vertexBufferAnimated[i].z;
-       }
-}
-
-void renderMeshToPointSprites(int seed) {
-       int vertex, j;
-       int sx, sy;
-       unsigned char color;
-       unsigned char *dst;
-       unsigned char fogAtOrigin;
-
-       fogAtOrigin = fog(CAMERA_DISTANCE);
-
-       pointSpriteCount = 0;
-       srand(seed);
-
-       for (vertex = 0; vertex < VERTEX_COUNT; vertex++) {
-               sx = (int)(vertexBufferProjected[vertex].x * 80) + 80;
-               sy = (int)(vertexBufferProjected[vertex].y * 60) + 60;
-
-               thunder(80, 60, sx, sy, fogAtOrigin, fog(vertexBufferAnimated[vertex].z), rand(), THUNDER_RANDOMNESS, 5);
-       }
-}
-
-void renderPointSprites() {
-       int i,j;
-       PointSprite sprite;
-       unsigned char *dst;
-       int sx, sy;
-       unsigned char color;
-
-       for (i = 0; i < pointSpriteCount; i++) {
-               sprite = pointSprites[i];
-
-               sx = UNPACK_X(sprite);
-               sy = UNPACK_Y(sprite);
-
-               if (sx < THUNDER_RECT_SIZE || sx >= 160 - THUNDER_RECT_SIZE || sy < THUNDER_RECT_SIZE || sy >= 120 - THUNDER_RECT_SIZE) continue;
-
-               dst = blurBuffer + BLUR_BUFFER_WIDTH + 1 + sx + sy * BLUR_BUFFER_WIDTH;
-
-               color = UNPACK_COLOR(sprite);
-
-               for (j = 0; j < THUNDER_RECT_SIZE; j++) {
-                       memset(dst, color, THUNDER_RECT_SIZE);
-                       dst += BLUR_BUFFER_WIDTH;
-               }
-       }
-}
-
-unsigned char fog(float z) {
-       unsigned int ret = (unsigned int) (((-(z - CAMERA_DISTANCE)) * 0.5f + 0.5f) * (255.0f - MIN_FOGGED)) + MIN_FOGGED;
-       if (ret > 255) ret = 255;
-       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 sortPointSprites() {
-       sort(pointSprites, pointSprites + pointSpriteCount);
-}
-
diff --git a/src/tilemaze.c b/src/tilemaze.c
deleted file mode 100644 (file)
index 6e2aa54..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "tilemaze.h"
-#include "mesh.h"
-#include "treestor.h"
-#include "dynarr.h"
-#include "scene.h"
-
-struct object {
-       char *name;
-       struct g3d_mesh mesh;
-
-       void *texels;
-       int tex_width, tex_height;
-
-       struct object *next;
-};
-
-struct tile {
-       char *name;
-       struct object *objlist;
-};
-
-struct tilemaze {
-       struct tile *tileset;
-       int num_tiles;
-
-       struct object *objects;
-};
-
-void free_object(struct object *obj);
-
-struct tilemaze *load_tilemaze(const char *fname)
-{
-       struct tilemaze *tmz;
-
-       if(!(tmz = calloc(sizeof *tmz, 1))) {
-               return 0;
-       }
-       return tmz;
-}
-
-void destroy_tilemaze(struct tilemaze *tmz)
-{
-       if(!tmz) return;
-
-       free(tmz->tileset);
-
-       while(tmz->objects) {
-               struct object *o = tmz->objects;
-               tmz->objects = tmz->objects->next;
-
-               free(o->mesh.varr);
-               free(o->mesh.iarr);
-               free(o);
-       }
-
-       free(tmz);
-}
-
-void update_tilemaze(struct tilemaze *tmz)
-{
-}
-
-void draw_tilemaze(struct tilemaze *tmz)
-{
-}
-
-struct tile *load_tileset(const char *fname, int *count)
-{
-       int i;
-       struct tile *tiles = 0, *tile;
-       struct ts_node *ts = 0, *node;
-       struct ts_attr *attr;
-       struct object *obj;
-
-       if(!(ts = ts_load(fname))) {
-               fprintf(stderr, "load_tileset: failed to load: %s\n", fname);
-               goto err;
-       }
-       if(strcmp(ts->name, "tileset") != 0) {
-               fprintf(stderr, "load_tileset: %s is not a tileset file\n", fname);
-               goto err;
-       }
-
-       if(!(tiles = dynarr_alloc(sizeof *tiles, 0))) {
-               fprintf(stderr, "load_tileset: failed to create tiles array\n");
-               goto err;
-       }
-
-       node = ts->child_list;
-       while(node) {
-               if(strcmp(node->name, "tile") != 0) {
-                       fprintf(stderr, "load_tileset: skipping unexpected node %s in %s\n", node->name, fname);
-                       node = node->next;
-                       continue;
-               }
-
-               if(!(tile = malloc(sizeof *tile))) {
-                       fprintf(stderr, "load_tileset: failed to allocate tile\n");
-                       goto err;
-               }
-               if(!(tile->name = malloc(strlen(node->name) + 1))) {
-                       fprintf(stderr, "load_tileset: failed to allocate tile name\n");
-                       free(tile);
-                       goto err;
-               }
-               strcpy(tile->name, node->name);
-               tile->objlist = 0;
-
-               attr = node->attr_list;
-               while(attr) {
-                       /*
-                       if(strcmp(attr->name, "scn") == 0) {
-                               struct object *last;
-                               if(!(obj = load_objlist(attr->value.str, &last))) {
-                                       free(tile);
-                                       goto err;
-                               }
-                               last->next = tile->objlist;
-                               tile->objlist = obj;
-                       }
-                       */
-                       attr = attr->next;
-               }
-
-               node = node->next;
-       }
-
-err:
-       if(tiles) {
-               for(i=0; i<dynarr_size(tiles); i++) {
-                       free(tiles[i].name);
-                       obj = tiles[i].objlist;
-                       while(obj) {
-                               struct object *tmp = obj;
-                               obj = obj->next;
-                               free_object(obj);
-                       }
-               }
-               dynarr_free(tiles);
-       }
-       if(ts) ts_free_tree(ts);
-       return 0;
-}
-
-void free_object(struct object *obj)
-{
-       if(!obj) return;
-
-       free(obj->name);
-       free(obj->texels);
-       destroy_mesh(&obj->mesh);
-
-       free(obj);
-}
diff --git a/src/tilemaze.h b/src/tilemaze.h
deleted file mode 100644 (file)
index a06acd8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef TILEMAZE_H_
-#define TILEMAZE_H_
-
-struct tilemaze;
-
-struct tilemaze *load_tilemaze(const char *fname);
-void destroy_tilemaze(struct tilemaze *tmz);
-
-void update_tilemaze(struct tilemaze *tmz);
-void draw_tilemaze(struct tilemaze *tmz);
-
-#endif /* TILEMAZE_H_ */
diff --git a/src/tunnel.c b/src/tunnel.c
deleted file mode 100644 (file)
index 9071b74..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include "imago2.h"
-#include "demo.h"
-#include "screen.h"
-#include "gfxutil.h"
-
-#ifndef M_PI
-#define M_PI   3.1415926535
-#endif
-
-#define VSCALE 1.5
-
-#define TEX_FNAME      "data/grid.png"
-#define TEX_USCALE     4
-#define TEX_VSCALE     2
-
-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 draw_tunnel_range(unsigned short *pixels, int xoffs, int yoffs, int starty, int num_lines, long tm);
-static int count_bits(unsigned int x);
-static int count_zeros(unsigned int x);
-
-static struct screen scr = {
-       "tunnel",
-       init,
-       destroy,
-       start,
-       stop,
-       draw
-};
-
-static int xsz, ysz, vxsz, vysz;
-static int pan_width, pan_height;
-static unsigned int *tunnel_map;
-static unsigned char *tunnel_fog;
-
-static int tex_xsz, tex_ysz;
-static unsigned int *tex_pixels;
-static int tex_xshift, tex_yshift;
-static unsigned int tex_xmask, tex_ymask;
-
-static long trans_start, trans_dur;
-static int trans_dir;
-
-
-struct screen *tunnel_screen(void)
-{
-       return &scr;
-}
-
-
-static int init(void)
-{
-       int i, j, n;
-       unsigned int *tmap;
-       unsigned char *fog;
-       float aspect = (float)fb_width / (float)fb_height;
-
-       xsz = fb_width;
-       ysz = fb_height;
-       vxsz = xsz * VSCALE;
-       vysz = ysz * VSCALE;
-
-       pan_width = vxsz - xsz;
-       pan_height = vysz - ysz;
-
-       if(!(tunnel_map = malloc(vxsz * vysz * sizeof *tunnel_map))) {
-               fprintf(stderr, "failed to allocate tunnel map\n");
-               return -1;
-       }
-       if(!(tunnel_fog = malloc(vxsz * vysz))) {
-               fprintf(stderr, "failed to allocate tunnel fog map\n");
-               return -1;
-       }
-
-       tmap = tunnel_map;
-       fog = tunnel_fog;
-
-       for(i=0; i<vysz; i++) {
-               float y = 2.0 * (float)i / (float)vysz - 1.0;
-               for(j=0; j<vxsz; j++) {
-                       float x = aspect * (2.0 * (float)j / (float)vxsz - 1.0);
-                       float tu = atan2(y, x) / M_PI * 0.5 + 0.5;
-                       float d = sqrt(x * x + y * y);
-                       float tv = d == 0.0 ? 0.0 : 1.0 / d;
-
-                       int tx = (int)(tu * 65535.0 * TEX_USCALE) & 0xffff;
-                       int ty = (int)(tv * 65535.0 * TEX_VSCALE) & 0xffff;
-
-                       int f = (int)(d * 192.0);
-
-                       *tmap++ = (tx << 16) | ty;
-                       *fog++ = f > 255 ? 255 : f;
-               }
-       }
-
-       if(!(tex_pixels = img_load_pixels(TEX_FNAME, &tex_xsz, &tex_ysz, IMG_FMT_RGBA32))) {
-               fprintf(stderr, "failed to load image " TEX_FNAME "\n");
-               return -1;
-       }
-       if((count_bits(tex_xsz) | count_bits(tex_ysz)) != 1) {
-               fprintf(stderr, "non-pow2 image (%dx%d)\n", tex_xsz, tex_ysz);
-               return -1;
-       }
-
-       /*tex_pixels = gen_test_image(&tex_xsz, &tex_ysz);*/
-
-       n = count_zeros(tex_xsz);
-       for(i=0; i<n; i++) {
-               tex_xmask |= 1 << i;
-       }
-       tex_xshift = n;
-
-       n = count_zeros(tex_ysz);
-       for(i=0; i<n; i++) {
-               tex_ymask |= 1 << i;
-       }
-       tex_yshift = n;
-
-       return 0;
-}
-
-static void destroy(void)
-{
-       free(tunnel_map);
-       free(tunnel_fog);
-       img_free_pixels(tex_pixels);
-}
-
-static void start(long trans_time)
-{
-       if(trans_time) {
-               trans_start = time_msec;
-               trans_dur = trans_time;
-               trans_dir = 1;
-       }
-}
-
-static void stop(long trans_time)
-{
-       if(trans_time) {
-               trans_start = time_msec;
-               trans_dur = trans_time;
-               trans_dir = -1;
-       }
-}
-
-#define NUM_WORK_ITEMS 8
-
-static void draw(void)
-{
-       int i, num_lines = ysz / NUM_WORK_ITEMS;
-       int draw_lines = num_lines;
-       float t;
-       int xoffs, yoffs;
-
-       if(trans_dir) {
-               long interval = time_msec - trans_start;
-               int progr = num_lines * interval / trans_dur;
-               if(trans_dir < 0) {
-                       draw_lines = num_lines - progr - 1;
-               } else {
-                       draw_lines = progr;
-               }
-               if(progr >= num_lines) {
-                       trans_dir = 0;
-               }
-       }
-
-       t = time_msec / 10000.0;
-       xoffs = (int)(cos(t * 3.0) * pan_width / 2) + pan_width / 2;
-       yoffs = (int)(sin(t * 4.0) * pan_height / 2) + pan_height / 2;
-
-       for(i=0; i<NUM_WORK_ITEMS; i++) {
-               int starty = i * num_lines;
-               int resty = starty + draw_lines;
-               int rest_lines = num_lines - draw_lines;
-               draw_tunnel_range(fb_pixels, xoffs, yoffs, starty, draw_lines, time_msec);
-               if(rest_lines) {
-                       memset(fb_pixels + resty * fb_width, 0, rest_lines * fb_width * 2);
-               }
-       }
-
-       swap_buffers(0);
-}
-
-static void tunnel_color(int *rp, int *gp, int *bp, long toffs, unsigned int tpacked, int fog)
-{
-       int r, g, b;
-       unsigned int col;
-       unsigned int tx = (((tpacked >> 16) & 0xffff) << tex_xshift) >> 16;
-       unsigned int ty = ((tpacked & 0xffff) << tex_yshift) >> 16;
-       tx += toffs;
-       ty += toffs << 1;
-
-       tx &= tex_xmask;
-       ty &= tex_ymask;
-
-       col = tex_pixels[(ty << tex_xshift) + tx];
-       r = col & 0xff;
-       g = (col >> 8) & 0xff;
-       b = (col >> 16) & 0xff;
-
-       *rp = (r * fog) >> 8;
-       *gp = (g * fog) >> 8;
-       *bp = (b * fog) >> 8;
-}
-
-static void draw_tunnel_range(unsigned short *pix, int xoffs, int yoffs, int starty, int num_lines, long tm)
-{
-       int i, j;
-       unsigned int *tmap = tunnel_map + (starty + yoffs) * vxsz + xoffs;
-       unsigned char *fog = tunnel_fog + (starty + yoffs) * vxsz + xoffs;
-
-       long toffs = tm / 8;
-       unsigned int *pixels = (unsigned int*)pix + starty * (fb_width >> 1);
-
-       for(i=0; i<num_lines; i++) {
-               for(j=0; j<(xsz>>1); j++) {
-                       unsigned int col;
-                       int r, g, b, idx = j << 1;
-
-                       tunnel_color(&r, &g, &b, toffs, tmap[idx], fog[idx]);
-                       col = PACK_RGB16(r, g, b);
-                       tunnel_color(&r, &g, &b, toffs, tmap[idx + 1], fog[idx + 1]);
-                       col |= PACK_RGB16(r, g, b) << 16;
-                       *pixels++ = col;
-               }
-               tmap += vxsz;
-               fog += vxsz;
-       }
-}
-
-static int count_bits(unsigned int x)
-{
-       int i, nbits = 0;
-       for(i=0; i<32; i++) {
-               if(x & 1) ++nbits;
-               x >>= 1;
-       }
-       return nbits;
-}
-
-static int count_zeros(unsigned int x)
-{
-       int i, num = 0;
-       for(i=0; i<32; i++) {
-               if(x & 1) break;
-               ++num;
-               x >>= 1;
-       }
-       return num;
-}
-
-/*
-static unsigned int *gen_test_image(int *wptr, int *hptr)
-{
-       int i, j;
-       int xsz = 256, ysz = 256;
-       unsigned int *pixels, *pix;
-
-       if(!(pixels = malloc(xsz * ysz * sizeof *pix))) {
-               return 0;
-       }
-       pix = pixels;
-
-       for(i=0; i<ysz; i++) {
-               for(j=0; j<xsz; j++) {
-                       int val = i ^ j;
-
-                       *pix++ = PACK_RGB32(val, val / 2, val / 4);
-               }
-       }
-
-       *wptr = xsz;
-       *hptr = ysz;
-       return pixels;
-}
-*/