diff --git a/src/ai.c b/src/ai.c index 25492b6..7557073 100644 --- a/src/ai.c +++ b/src/ai.c @@ -62,8 +62,9 @@ #define AI_SECONDARY (1<<1) /* Firing secondary weapon. */ /* file info. */ -#define AI_PREFIX "../scripts/ai/" +#define AI_PREFIX "../scripts/ai/" #define AI_SUFFIX ".lua" +#define AI_INCLUDE "include/" /* AI profiles. */ static AI_Profile* profiles = NULL; @@ -237,9 +238,11 @@ int ai_init(void) { /* Load the profiles. */ for(i = 0; i < nfiles; i++) - if((strncmp(files[i], AI_PREFIX, strlen(AI_PREFIX))==0 && - strncmp(files[i] + strlen(files[i]) - strlen(AI_SUFFIX), - AI_SUFFIX, strlen(AI_SUFFIX))==0)) + if((strncmp(files[i], AI_PREFIX, strlen(AI_PREFIX))==0) && /* prefixed. */ + (strncmp(files[i] + strlen(AI_PREFIX), AI_INCLUDE, /* Not an include. */ + strlen(AI_INCLUDE)) != 0) && + (strncmp(files[i] + strlen(files[i]) - strlen(AI_PREFIX), /* Suffixed. */ + AI_SUFFIX, strlen(AI_SUFFIX))==0)) if(ai_loadProfile(files[i])) WARN("Error loading AI profile '%s'", files[i]); diff --git a/src/menu.c b/src/menu.c index 1fe3100..1206792 100644 --- a/src/menu.c +++ b/src/menu.c @@ -7,7 +7,7 @@ #include "pilot.h" #include "space.h" #include "player.h" -#include "plasmaf.h" +#include "perlin.h" #include "mission.h" #include "ltime.h" #include "save.h" @@ -68,7 +68,7 @@ void menu_main(void) { unsigned int bwid, wid; glTexture* tex; - tex = pf_genFractal(SCREEN_W, SCREEN_H, 5.); + tex = noise_genCloud(SCREEN_W, SCREEN_H, 5.); /* Create background image window. */ bwid = window_create("BG", -1, -1, SCREEN_W, SCREEN_H); diff --git a/src/perlin.c b/src/perlin.c new file mode 100644 index 0000000..7b26b9d --- /dev/null +++ b/src/perlin.c @@ -0,0 +1,283 @@ +#include +#include +#include + +#include "log.h" +#include "rng.h" + +#include "perlin.h" + +#define LERP(a, b, x) (a + x * (b - a)) +#define ABS(a) ((a)<0?-(a):(a)) +#define CLAMP(a, b, x) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x))) + +typedef struct { + int ndim; + unsigned char map[256]; /* Randomized map of indexes into buffer. */ + float buffer[256][NOISE_MAX_DIMENSIONS]; // Random 256 x ndim buffer. */ + /* Fractal stuff. */ + float H; + float lacunarity; + float exponent[NOISE_MAX_OCTAVES]; +} perlin_data_t; + +static float* noise_genMap(const int w, const int h, float rug); + +static float lattice(perlin_data_t* data, int ix, float fx, int iy, + float fy, int iz, float fz, int iw, float fw) { + + int n[4] = { ix, iy, iz, iw }; + float f[4] = { fx, fy, fz, fw }; + int nindex = 0; + int i; + float value = 0; + + for(i = 0; i < data->ndim; i++) + nindex = data->map[(nindex + n[i]) & 0xFF]; + for(i = 0; i < data->ndim; i++) + value += data->buffer[nindex][i] * f[i]; + + return value; +} + +#define DEFAULT_SEED 0x15687436 +#define DELTA 1e-6f +#define SWAP(a, b, t) t = a; a = b; b = t + +#define FLOOR(a) ((int) a - (a < 0 && a != (int)a)) +#define CUBIC(a) (a * a * (3 - 2 * a)) + +static void normalize(perlin_data_t* data, float* f) { + float magnitude = 0; + int i; + for(i = 0; i < data->ndim; i++) + magnitude += f[i] * f[i]; + magnitude = 1 / sqrtf(magnitude); + for(i = 0; i < data->ndim; i++) + f[i] *= magnitude; +} + +noise_t noise_new(int ndim, float hurst, float lacunarity) { + perlin_data_t* data=(perlin_data_t*)calloc(sizeof(perlin_data_t), 1); + int i, j; + unsigned char tmp; + float f = 1; + data->ndim = ndim; + for(i = 0; i < 256; i++) { + data->map[i] = (unsigned char) i; + for(j = 0; j < data->ndim; j++) + data->buffer[i][j] = RNGF()-0.5; + normalize(data, data->buffer[i]); + } + + while(--i) { + j = RNG(0, 255); + SWAP(data->map[i], data->map[j], tmp); + } + + data->H = hurst; + data->lacunarity = lacunarity; + for(i = 0; i < NOISE_MAX_OCTAVES; i++) { + /*exponent[i] = powf(f, -H); */ + data->exponent[i] = 1.0f / f; + f *= lacunarity; + } + return (noise_t)data; +} + +float noise_get(noise_t noise, float *f ) +{ + perlin_data_t* data = (perlin_data_t*) noise; + int n[NOISE_MAX_DIMENSIONS]; /* Indexes to pass to lattice function */ + int i; + float r[NOISE_MAX_DIMENSIONS]; /* Remainders to pass to lattice function */ + float w[NOISE_MAX_DIMENSIONS]; /* Cubic values to pass to interpolation function */ + float value; + + for(i=0; indim; i++) { + n[i] = FLOOR(f[i]); + r[i] = f[i] - n[i]; + w[i] = CUBIC(r[i]); + } + + switch(data->ndim) { + case 1: + value = LERP(lattice(data,n[0], r[0],0,0,0,0,0,0), + lattice(data,n[0]+1, r[0]-1,0,0,0,0,0,0), + w[0]); + break; + case 2: + value = LERP(LERP(lattice(data,n[0], r[0], n[1], r[1],0,0,0,0), + lattice(data,n[0]+1, r[0]-1, n[1], r[1],0,0,0,0), + w[0]), + LERP(lattice(data,n[0], r[0], n[1]+1, r[1]-1,0,0,0,0), + lattice(data,n[0]+1, r[0]-1, n[1]+1, r[1]-1,0,0,0,0), + w[0]), + w[1]); + break; + case 3: + value = LERP(LERP(LERP(lattice(data,n[0], r[0], n[1], r[1], n[2], r[2],0,0), + lattice(data,n[0]+1, r[0]-1, n[1], r[1], n[2], r[2],0,0), + w[0]), + LERP(lattice(data,n[0], r[0], n[1]+1, r[1]-1, n[2], r[2],0,0), + lattice(data,n[0]+1, r[0]-1, n[1]+1, r[1]-1, n[2], r[2],0,0), + w[0]), + w[1]), + LERP(LERP(lattice(data,n[0], r[0], n[1], r[1], n[2]+1, r[2]-1,0,0), + lattice(data,n[0]+1, r[0]-1, n[1], r[1], n[2]+1, r[2]-1,0,0), + w[0]), + LERP(lattice(data,n[0], r[0], n[1]+1, r[1]-1, n[2]+1, r[2]-1,0,0), + lattice(data,n[0]+1, r[0]-1, n[1]+1, r[1]-1, n[2]+1, r[2]-1,0,0), + w[0]), + w[1]), + w[2]); + break; + case 4: + default: + value = LERP(LERP(LERP(LERP(lattice(data,n[0], r[0], n[1], r[1], n[2], r[2], n[3], r[3]), + lattice(data,n[0]+1, r[0]-1, n[1], r[1], n[2], r[2], n[3], r[3]), + w[0]), + LERP(lattice(data,n[0], r[0], n[1]+1, r[1]-1, n[2], r[2], n[3], r[3]), + lattice(data,n[0]+1, r[0]-1, n[1]+1, r[1]-1, n[2], r[2], n[3], r[3]), + w[0]), + w[1]), + LERP(LERP(lattice(data,n[0], r[0], n[1], r[1], n[2]+1, r[2]-1, n[3], r[3]), + lattice(data,n[0]+1, r[0]-1, n[1], r[1], n[2]+1, r[2]-1, n[3], r[3]), + w[0]), + LERP(lattice(data,n[0], r[0], n[1]+1, r[1]-1, n[2]+1, r[2]-1,0,0), + lattice(data,n[0]+1, r[0]-1, n[1]+1, r[1]-1, n[2]+1, r[2]-1, n[3], r[3]), + w[0]), + w[1]), + w[2]), + LERP(LERP(LERP(lattice(data,n[0], r[0], n[1], r[1], n[2], r[2], n[3]+1, r[3]-1), + lattice(data,n[0]+1, r[0]-1, n[1], r[1], n[2], r[2], n[3]+1, r[3]-1), + w[0]), + LERP(lattice(data,n[0], r[0], n[1]+1, r[1]-1, n[2], r[2], n[3]+1, r[3]-1), + lattice(data,n[0]+1, r[0]-1, n[1]+1, r[1]-1, n[2], r[2], n[3]+1, r[3]-1), + w[0]), + w[1]), + LERP(LERP(lattice(data,n[0], r[0], n[1], r[1], n[2]+1, r[2]-1, n[3]+1, r[3]-1), + lattice(data,n[0]+1, r[0]-1, n[1], r[1], n[2]+1, r[2]-1, n[3]+1, r[3]-1), + w[0]), + LERP(lattice(data,n[0], r[0], n[1]+1, r[1]-1, n[2]+1, r[2]-1,0,0), + lattice(data,n[0]+1, r[0]-1, n[1]+1, r[1]-1, n[2]+1, r[2]-1, n[3]+1, r[3]-1), + w[0]), + w[1]), + w[2]), + w[3]); + break; + } + return CLAMP(-0.99999f, 0.99999f, value); +} + +float noise_fbm(noise_t noise, float* f, float octaves) { + float tf[NOISE_MAX_DIMENSIONS]; + perlin_data_t* data = (perlin_data_t*) noise; + /* Init locals. */ + float value = 0; + int i, j; + memcpy(tf, f, sizeof(float) * data->ndim); + + /* Inner loop for spectral construction, where the fractal is build. */ + for(i = 0; i < (int)octaves; i++) { + value += noise_get(noise, tf) * data->exponent[i]; + for(j = 0; j < data->ndim; j++) tf[j] *= data->lacunarity; + } + + /* Take care of remainder in octaves. */ + octaves -= (int)octaves; + if(octaves > DELTA) + value += octaves * noise_get(noise, tf) * data->exponent[i]; + return CLAMP(-0.99999f, 0.99999f, value); +} + +float noise_turbulence(noise_t noise, float* f, float octaves) { + float tf[NOISE_MAX_DIMENSIONS]; + perlin_data_t* data = (perlin_data_t*) noise; + /* Init locals. */ + float value = 0; + int i, j; + memcpy(tf, f, sizeof(float) * data->ndim); + + /* Inner loop of spectral construction, where the fractal is built. */ + for(i = 0; i < (int)octaves; i++) { + value += ABS(noise_get(noise, tf)) * data->exponent[i]; + for(j = 0; j < data->ndim; j++) tf[j] *= data->lacunarity; + } + + /* Take care of remainders in octaves. */ + octaves -= (int)octaves; + if(octaves > DELTA) + value += octaves * ABS(noise_get(noise, tf)) * data->exponent[i]; + return CLAMP(-0.99999f, 0.99999f, value); +} + +void noise_delete(noise_t noise) { + free((perlin_data_t*)noise); +} + +static float* noise_genMap(const int w, const int h, float rug) { + int x, y; + float f[2]; + float octaves; + float hurst; + float lacunarity; + noise_t noise; + float* map; + float value; + + octaves = 3.; + hurst = NOISE_DEFAULT_HURST; + lacunarity = NOISE_DEFAULT_LACUNARITY; + + noise = noise_new(2, hurst, lacunarity); + + map = malloc(sizeof(float)*w*h); + + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { + f[0] = rug * (float)x / (float)w; + f[1] = rug * (float)y / (float)h; + + /*value = noise_get(noise, f);*/ + /*value = noise_fbm(noise, f, octaves);*/ + value = noise_turbulence(noise, f, octaves); + + value = value + 0.3; + map[y*w+x] = (value < 1.) ? value : 1.; + } + } + + noise_delete(noise); + + return map; +} + +glTexture* noise_genCloud(const int w, const int h, double rug) { + int i; + float* map; + SDL_Surface* sur; + uint32_t* pix; + glTexture* tex; + double c; + + map = noise_genMap(w, h, rug); + + sur = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RGBMASK); + pix = sur->pixels; + + /* Convert from mapping to actual colours. */ + SDL_LockSurface(sur); + for(i = 0; i < h*w; i++) { + c = map[i]; + pix[i] = RMASK + BMASK + GMASK + (AMASK & (uint32_t)(AMASK*c)); + } + SDL_UnlockSurface(sur); + + free(map); + + tex = gl_loadImage(sur); + + return tex; +} + diff --git a/src/perlin.h b/src/perlin.h new file mode 100644 index 0000000..ba7748e --- /dev/null +++ b/src/perlin.h @@ -0,0 +1,25 @@ +#pragma once +#include "opengl.h" + +typedef void* noise_t; + +#define NOISE_MAX_OCTAVES 128 +#define NOISE_MAX_DIMENSIONS 4 +#define NOISE_DEFAULT_HURST 0.5f +#define NOISE_DEFAULT_LACUNARITY 2.0f + +noise_t noise_new(int dimensions, float hurst, float lacunarity); + +/* Basic perlin noise. */ +float noise_get(noise_t noise, float *f); + +/* Fractional brownian motion. */ +float noise_fbm(noise_t noise, float* f, float octaves); + +/* Turbulence. */ +float noise_turbulence(noise_t noise, float* f, float octaves); + +void noise_delete(noise_t noise); + +glTexture* noise_genCloud(const int w, const int h, double rug); + diff --git a/src/rng.c b/src/rng.c index 3a89fba..114d42d 100644 --- a/src/rng.c +++ b/src/rng.c @@ -108,7 +108,7 @@ unsigned int randint(void) { } /* Return a random double. */ -static double m_div = (double)(0xFFFFFFFF) + 1.; +static double m_div = (double)(0xFFFFFFFF); double randfp(void) { double m = (double)mt_getInt(); return m / m_div; diff --git a/src/rng.h b/src/rng.h index 9b4576a..95a3069 100644 --- a/src/rng.h +++ b/src/rng.h @@ -1,7 +1,7 @@ #pragma once #define RNG(L,H) ((int)L + (int)((double)(H-L+1) * randfp())) /* L <= RNG <= H */ -#define RNGF() (randfp()) +#define RNGF() (randfp()) /* 0. <= RNGF <= 1. */ void rng_init(void); unsigned int randint(void);