-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
-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`
%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)
-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
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
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
---------------------------
+++ /dev/null
-// 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);
-}
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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();
-}
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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;
-}
+++ /dev/null
-// 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);
-}
+++ /dev/null
-#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;
-}
--- /dev/null
+// 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);
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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();
+}
--- /dev/null
+#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);
+}
--- /dev/null
+#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);
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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
+}
--- /dev/null
+#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_ */
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+#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);
+}
--- /dev/null
+#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_ */
--- /dev/null
+#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;
+}
+*/
+++ /dev/null
-#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
-}
+++ /dev/null
-#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_ */
+++ /dev/null
-/* 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);
-}
-
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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_ */
+++ /dev/null
-#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;
-}
-*/