639 lines
19 KiB
C
639 lines
19 KiB
C
/**
|
|
* @file nebulae.c
|
|
*
|
|
* @brief Handle rendering and generating nebulae.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include "nebulae.h"
|
|
|
|
#include "SDL/SDL_image.h"
|
|
|
|
#include "lephisto.h"
|
|
#include "log.h"
|
|
#include "opengl.h"
|
|
#include "lfile.h"
|
|
#include "rng.h"
|
|
#include "menu.h"
|
|
#include "player.h"
|
|
#include "pause.h"
|
|
#include "perlin.h"
|
|
|
|
#define NEBULAE_Z 16 /**< Z plane. */
|
|
#define NEBULAE_PUFFS 32 /**< Amount of puffs to generate. */
|
|
#define NEBULAE_PATH_BG "gen/nebu_bg_%dx%d_%02d.png" /**< Nebulae path format. */
|
|
|
|
#define NEBULAE_PUFF_BUFFER 300 /**< Nebulae buffer. */
|
|
|
|
/* Extern. */
|
|
extern double gui_xoff, gui_yoff;
|
|
extern Vec2 shake_pos;
|
|
extern void loadscreen_render(double done, const char* msg);
|
|
|
|
/* The nebulae textures. */
|
|
static GLuint nebu_textures[NEBULAE_Z]; /**< BG Nebulae textures. */
|
|
static int nebu_w = 0; /**< BG Nebulae width. */
|
|
static int nebu_h = 0; /**< BG Nebulae height. */
|
|
static int nebu_pw; /**< BG Padded Nebulae width */
|
|
static int nebu_ph; /**< BG Padded Nebulae height. */
|
|
|
|
/* Information on rendering. */
|
|
static int cur_nebu[2] = { 0, 1 }; /**< Nebulae currently rendering. */
|
|
static unsigned int last_render = 0; /**< When they where last rendered. */
|
|
|
|
/* Nebuale properties. */
|
|
static double nebu_view = 0.; /**< How far player can see. */
|
|
static double nebu_dt = 0.; /**< How fast nebulae changes. */
|
|
|
|
/* Puff textures. */
|
|
static glTexture* nebu_pufftexs[NEBULAE_PUFFS]; /**< Nebulae puffs. */
|
|
|
|
/**
|
|
* @struct NebulaePuff
|
|
*
|
|
* @brief Represents a nebulae puff.
|
|
*/
|
|
typedef struct NebulaePuff_ {
|
|
double x; /**< X Position. */
|
|
double y; /**< Y Position. */
|
|
double height; /**< Height vs player. */
|
|
int tex; /**< Texture. */
|
|
} NebulaePuff;
|
|
static NebulaePuff* nebu_puffs = NULL; /**< Stack of puffs. */
|
|
static int nebu_npuffs = 0; /**< Number of puffs. */
|
|
|
|
static int nebu_checkCompat(const char* file);
|
|
static void nebu_loadTexture(SDL_Surface* sur, int w, int h, GLuint tex);
|
|
static int nebu_generate(void);
|
|
static void nebu_generatePuffs(void);
|
|
static int saveNebulae(float* map, const uint32_t w, const uint32_t h,
|
|
const char* file);
|
|
static SDL_Surface* loadNebulae(const char* file);
|
|
static SDL_Surface* nebu_surfaceFromNebulaeMap(float* map, const int w, const int h);
|
|
|
|
/**
|
|
* @fn int nebu_init(void)
|
|
*
|
|
* @brief Initializes the nebulae.
|
|
* @return 0 on success.
|
|
*/
|
|
int nebu_init(void) {
|
|
int i;
|
|
char nebu_file[PATH_MAX];
|
|
SDL_Surface* nebu_sur;
|
|
int ret;
|
|
|
|
/* Special code to regenerate the nebulae. */
|
|
if((nebu_w == -9) && (nebu_h == -9)) {
|
|
nebu_generate();
|
|
}
|
|
|
|
/* Set expected sizes. */
|
|
nebu_w = SCREEN_W;
|
|
nebu_h = SCREEN_H;
|
|
nebu_pw = gl_pot(nebu_w);
|
|
nebu_ph = gl_pot(nebu_h);
|
|
|
|
nebu_generatePuffs();
|
|
|
|
/* Load each, checking for compatibility and padding. */
|
|
glGenTextures(NEBULAE_Z, nebu_textures);
|
|
for(i = 0; i < NEBULAE_Z; i++) {
|
|
snprintf(nebu_file, PATH_MAX, NEBULAE_PATH_BG, nebu_w, nebu_h, i);
|
|
|
|
if(nebu_checkCompat(nebu_file)) { /* Incompatable. */
|
|
LOG("No nebulae found, generating (this may take a while).");
|
|
|
|
/* So we generate and reload. */
|
|
ret = nebu_generate();
|
|
if(ret != 0) /* An error has happened - break recursivity. */
|
|
return ret;
|
|
|
|
return nebu_init();
|
|
}
|
|
|
|
/* Load the file. */
|
|
nebu_sur = loadNebulae(nebu_file);
|
|
if((nebu_sur->w != nebu_w) || (nebu_sur->h != nebu_h))
|
|
WARN("Nebulae raw size doesn't match expected! (%dx%d instead of %dx%d)",
|
|
nebu_sur->w, nebu_sur->h, nebu_pw, nebu_ph);
|
|
|
|
/* Load the textures. */
|
|
nebu_loadTexture(nebu_sur, nebu_pw, nebu_ph, nebu_textures[i]);
|
|
}
|
|
|
|
DEBUG("Loaded %d Nebulae Layers", NEBULAE_Z);
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @fn static void nebu_loadTexture(SDL_Surface* sur, int w, int h, GLuint tex)
|
|
*
|
|
* @brief Load sur into tex, check for expected size of w and h.
|
|
* @param sur Surface to load into texture.
|
|
* @param w Expected width of surface.
|
|
* @param h Expected height of surface.
|
|
* @param tex Already generated texture to load into.
|
|
*/
|
|
static void nebu_loadTexture(SDL_Surface* sur, int w, int h, GLuint tex) {
|
|
SDL_Surface* nebu_sur;
|
|
|
|
nebu_sur = gl_prepareSurface(sur);
|
|
if((w != 0) && (h != 0) &&
|
|
((nebu_sur->w != w) || (nebu_sur->h != h))) {
|
|
|
|
WARN("Nebulae size doesn't match expected! (%dx%d instead of %dx%d)",
|
|
nebu_sur->w, nebu_sur->h, nebu_pw, nebu_ph);
|
|
return;
|
|
}
|
|
|
|
/* Load the textures. */
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
|
|
|
/* Store into opengl saving only alpha channel in video memory. */
|
|
SDL_LockSurface(nebu_sur);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, nebu_sur->w, nebu_sur->h,
|
|
0, GL_RGBA, GL_UNSIGNED_BYTE, nebu_sur->pixels);
|
|
SDL_UnlockSurface(nebu_sur);
|
|
|
|
SDL_FreeSurface(nebu_sur);
|
|
gl_checkErr();
|
|
}
|
|
|
|
/**
|
|
* @fn void nebu_exit(void)
|
|
*
|
|
* @brief Clean up the nebu subsystem.
|
|
*/
|
|
void nebu_exit(void) {
|
|
int i;
|
|
|
|
glDeleteTextures(NEBULAE_Z, nebu_textures);
|
|
|
|
for(i = 0; i < NEBULAE_PUFFS; i++)
|
|
gl_freeTexture(nebu_pufftexs[i]);
|
|
}
|
|
|
|
/**
|
|
* @fn void nebu_render(const double dt)
|
|
*
|
|
* @brief Render the nebulae.
|
|
* @param dt Current delta tick.
|
|
*/
|
|
void nebu_render(const double dt) {
|
|
unsigned int t;
|
|
double ndt;
|
|
double tw, th;
|
|
GLfloat col[4];
|
|
int tmp;
|
|
|
|
/* Calculate frame to draw. */
|
|
t = SDL_GetTicks();
|
|
ndt = (t - last_render) / 1000.;
|
|
if(ndt > nebu_dt) { /* Time to change. */
|
|
tmp = cur_nebu[0];
|
|
cur_nebu[0] += cur_nebu[0] - cur_nebu[1];
|
|
cur_nebu[1] = tmp;
|
|
if(cur_nebu[0]+1 > NEBULAE_Z)
|
|
cur_nebu[0] = NEBULAE_Z - 2;
|
|
else if(cur_nebu[0] < 0)
|
|
cur_nebu[0] = 1;
|
|
|
|
last_render = t;
|
|
ndt = 0.;
|
|
}
|
|
|
|
/* Set colour. */
|
|
col[0] = cPurple.r;
|
|
col[1] = cPurple.g;
|
|
col[2] = cPurple.b;
|
|
col[3] = ndt / nebu_dt;
|
|
|
|
tw = (double)nebu_w / (double)nebu_pw;
|
|
th = (double)nebu_h / (double)nebu_ph;
|
|
|
|
/* Set up the targets. */
|
|
/* Texture 0. */
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, nebu_textures[cur_nebu[1]]);
|
|
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
/* Texture 1. */
|
|
glActiveTexture(GL_TEXTURE1);
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, nebu_textures[cur_nebu[0]]);
|
|
|
|
/* Prepare it. */
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);
|
|
/* Colour. */
|
|
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, col);
|
|
|
|
/* Arguments. */
|
|
/* Arg0 */
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
|
|
/* Arg 1. */
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
|
|
/* Arg 2. */
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_CONSTANT);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
|
|
|
|
/* Compensate possible rubmle. */
|
|
if(!paused) {
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glTranslated(shake_pos.x, shake_pos.y, 0.);
|
|
}
|
|
|
|
/* Now render. */
|
|
glBegin(GL_QUADS);
|
|
glMultiTexCoord2d(GL_TEXTURE0, 0., 0.);
|
|
glMultiTexCoord2d(GL_TEXTURE1, 0., 0.);
|
|
glVertex2d(-SCREEN_W/2., -SCREEN_H/2.);
|
|
|
|
glMultiTexCoord2d(GL_TEXTURE0, tw, 0.);
|
|
glMultiTexCoord2d(GL_TEXTURE1, tw, 0.);
|
|
glVertex2d(SCREEN_W/2., -SCREEN_H/2.);
|
|
|
|
glMultiTexCoord2d(GL_TEXTURE0, tw, th);
|
|
glMultiTexCoord2d(GL_TEXTURE1, tw, th);
|
|
glVertex2d(SCREEN_W/2., SCREEN_H/2.);
|
|
|
|
glMultiTexCoord2d(GL_TEXTURE0, 0., th);
|
|
glMultiTexCoord2d(GL_TEXTURE1, 0., th);
|
|
glVertex2d(-SCREEN_W/2., SCREEN_H/2.);
|
|
glEnd();
|
|
|
|
if(!paused)
|
|
glPopMatrix(); /* GL_PROJECTION */
|
|
|
|
/* Set values to defaults. */
|
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glDisable(GL_TEXTURE_2D);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
|
glDisable(GL_TEXTURE_2D);
|
|
|
|
/* Did anything fail? */
|
|
gl_checkErr();
|
|
|
|
/* Now render the puffs. */
|
|
nebu_renderPuffs(dt, 1);
|
|
}
|
|
|
|
/**
|
|
* @fn void nebu_renderOverlay(const double dt)
|
|
*
|
|
* @brief Renders the nebulae overlay (hides what player can't see).
|
|
* @param dt Current delta tick.
|
|
*/
|
|
void nebu_renderOverlay(const double dt) {
|
|
#define ANG45 0.70710678118654757
|
|
#define COS225 0.92387953251128674
|
|
#define SIN225 0.38268343236508978
|
|
|
|
/* Render the puffs. */
|
|
nebu_renderPuffs(dt, 0);
|
|
|
|
/* Prepare the matrix. */
|
|
glMatrixMode(GL_PROJECTION);
|
|
glPushMatrix();
|
|
glTranslated(gui_xoff, gui_yoff, 0.);
|
|
if(!paused)
|
|
glTranslated(gui_xoff+shake_pos.x, gui_yoff+shake_pos.y, 0.);
|
|
|
|
/* Mask for area player can still see (partially). */
|
|
glShadeModel(GL_SMOOTH);
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
ACOLOUR(cPurple, 0.);
|
|
glVertex2d(0., 0.);
|
|
ACOLOUR(cPurple, 1.);
|
|
glVertex2d(-nebu_view, 0.);
|
|
glVertex2d(-nebu_view*COS225, nebu_view*SIN225);
|
|
glVertex2d(-nebu_view*ANG45, nebu_view*ANG45);
|
|
glVertex2d(-nebu_view*SIN225, nebu_view*COS225);
|
|
glVertex2d( 0., nebu_view);
|
|
glVertex2d( nebu_view*SIN225, nebu_view*COS225);
|
|
glVertex2d( nebu_view*ANG45, nebu_view*ANG45);
|
|
glVertex2d( nebu_view*COS225, nebu_view*SIN225);
|
|
glVertex2d( nebu_view, 0.);
|
|
glVertex2d( nebu_view*COS225, -nebu_view*SIN225);
|
|
glVertex2d( nebu_view*ANG45, -nebu_view*ANG45);
|
|
glVertex2d( nebu_view*SIN225, -nebu_view*COS225);
|
|
glVertex2d( 0., -nebu_view);
|
|
glVertex2d(-nebu_view*SIN225, -nebu_view*COS225);
|
|
glVertex2d(-nebu_view*ANG45, -nebu_view*ANG45);
|
|
glVertex2d(-nebu_view*COS225, -nebu_view*SIN225);
|
|
glVertex2d(-nebu_view, 0.);
|
|
glEnd(); /* GL_TRIANGLE_FAN */
|
|
|
|
/* Solid nebulae for areas the player can't see. */
|
|
glShadeModel(GL_FLAT);
|
|
ACOLOUR(cPurple, 1.);
|
|
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
/* Top left. */
|
|
glVertex2d(-SCREEN_W/2.-gui_xoff, SCREEN_H/2.-gui_yoff);
|
|
glVertex2d(-nebu_view, 0.);
|
|
glVertex2d(-nebu_view*COS225, nebu_view*SIN225);
|
|
glVertex2d(-nebu_view*ANG45, nebu_view*ANG45);
|
|
glVertex2d(-nebu_view*SIN225, nebu_view*COS225);
|
|
glVertex2d(0., nebu_view);
|
|
glVertex2d( SCREEN_W/2.-gui_xoff, SCREEN_H/2.-gui_yoff);
|
|
glEnd(); /* GL_TRIANGLE_FAN */
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
/* Top right. */
|
|
glVertex2d( SCREEN_W/2.-gui_xoff, SCREEN_H/2.-gui_yoff);
|
|
glVertex2d( 0., nebu_view);
|
|
glVertex2d( nebu_view*SIN225, nebu_view*COS225);
|
|
glVertex2d( nebu_view*ANG45, nebu_view*ANG45);
|
|
glVertex2d( nebu_view*COS225, nebu_view*SIN225);
|
|
glVertex2d( nebu_view, 0.);
|
|
glVertex2d( SCREEN_W/2.-gui_xoff, -SCREEN_H/2.-gui_yoff);
|
|
glEnd(); /* GL_TRIANGLE_FAN */
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
/* Bottom right. */
|
|
glVertex2d( SCREEN_W/2.-gui_xoff, -SCREEN_H/2.-gui_yoff);
|
|
glVertex2d( nebu_view, 0.);
|
|
glVertex2d( nebu_view*COS225, -nebu_view*SIN225);
|
|
glVertex2d( nebu_view*ANG45, -nebu_view*ANG45);
|
|
glVertex2d( nebu_view*SIN225, -nebu_view*COS225);
|
|
glVertex2d( 0., -nebu_view);
|
|
glVertex2d( -SCREEN_W/2.-gui_xoff, -SCREEN_H/2.-gui_yoff);
|
|
glEnd(); /* GL_TRIANGLE_FAN */
|
|
glBegin(GL_TRIANGLE_FAN);
|
|
/* Bottom left */
|
|
glVertex2d( -SCREEN_W/2.-gui_xoff, -SCREEN_H/2.-gui_yoff);
|
|
glVertex2d( 0., -nebu_view);
|
|
glVertex2d(-nebu_view*SIN225, -nebu_view*COS225);
|
|
glVertex2d(-nebu_view*ANG45, -nebu_view*ANG45);
|
|
glVertex2d(-nebu_view*COS225, -nebu_view*SIN225);
|
|
glVertex2d(-nebu_view, 0.);
|
|
glVertex2d(-SCREEN_W/2.-gui_xoff, SCREEN_H/2.-gui_yoff);
|
|
glEnd(); /* GL_TRIANGLE_FAN */
|
|
|
|
glPopMatrix();
|
|
|
|
gl_checkErr();
|
|
|
|
#undef ANG45
|
|
#undef COS225
|
|
#undef SIN225
|
|
}
|
|
|
|
/**
|
|
* @fn void nebu_renderPuffs(const double dt, int below_player)
|
|
*
|
|
* @brief Render the puffs.
|
|
* @param dt Current delta tick.
|
|
* @param below_player Render the puffs below player or above?
|
|
*/
|
|
void nebu_renderPuffs(const double dt, int below_player) {
|
|
int i;
|
|
|
|
/* Main menu shouldn't have puffs. */
|
|
if(menu_isOpen(MENU_MAIN)) return;
|
|
|
|
/* Seperate by layers. */
|
|
for(i = 0; i < nebu_npuffs; i++) {
|
|
if((below_player && (nebu_puffs[i].height < 1.)) ||
|
|
(!below_player && (nebu_puffs[i].height > 1.))) {
|
|
|
|
/* Calculate new position. */
|
|
if(!paused && (player != NULL)) {
|
|
nebu_puffs[i].x -= player->solid->vel.x * nebu_puffs[i].height * dt;
|
|
nebu_puffs[i].y -= player->solid->vel.y * nebu_puffs[i].height * dt;
|
|
}
|
|
|
|
/* Check boundaries. */
|
|
if(nebu_puffs[i].x > SCREEN_W + NEBULAE_PUFF_BUFFER)
|
|
nebu_puffs[i].x = -NEBULAE_PUFF_BUFFER;
|
|
else if(nebu_puffs[i].y > SCREEN_H + NEBULAE_PUFF_BUFFER)
|
|
nebu_puffs[i].y = -NEBULAE_PUFF_BUFFER;
|
|
else if(nebu_puffs[i].x < -NEBULAE_PUFF_BUFFER)
|
|
nebu_puffs[i].x = SCREEN_W + NEBULAE_PUFF_BUFFER;
|
|
else if(nebu_puffs[i].y < -NEBULAE_PUFF_BUFFER)
|
|
nebu_puffs[i].y = SCREEN_H + NEBULAE_PUFF_BUFFER;
|
|
|
|
/* Render. */
|
|
gl_blitStatic(nebu_pufftexs[nebu_puffs[i].tex],
|
|
nebu_puffs[i].x, nebu_puffs[i].y, &cPurple);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn void nebu_prep(double density, double volatility)
|
|
*
|
|
* @brief Prepares the nebulae to be rendered.
|
|
* @param density Density of the nebulae (0-1000).
|
|
* @param volatility Volatility of the nebulae (0-1000).
|
|
*/
|
|
void nebu_prep(double density, double volatility) {
|
|
(void)volatility;
|
|
int i;
|
|
|
|
nebu_view = 1000. - density; /* At density 1000 you're blind. */
|
|
nebu_dt = 2000. / (density + 100.); /* Faster at higher density. */
|
|
|
|
nebu_npuffs = density/4.;
|
|
nebu_puffs = realloc(nebu_puffs, sizeof(NebulaePuff)*nebu_npuffs);
|
|
for(i = 0; i < nebu_npuffs; i++) {
|
|
/* Position. */
|
|
nebu_puffs[i].x = (double)RNG(-NEBULAE_PUFF_BUFFER,
|
|
SCREEN_W + NEBULAE_PUFF_BUFFER);
|
|
nebu_puffs[i].y = (double)RNG(-NEBULAE_PUFF_BUFFER,
|
|
SCREEN_H + NEBULAE_PUFF_BUFFER);
|
|
|
|
/* Maybe make the size related. */
|
|
nebu_puffs[i].tex = RNG(0, NEBULAE_PUFFS-1);
|
|
nebu_puffs[i].height = RNGF() + 0.2;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn void nebu_forceGenerate(void)
|
|
*
|
|
* @brief Force generation of new nebulae on init.
|
|
*/
|
|
void nebu_forceGenerate(void) {
|
|
nebu_w = nebu_h = -9; /* Magic numbers. ^.^ */
|
|
}
|
|
|
|
/**
|
|
* @fn static int nebu_generate(void)
|
|
* @brief Generates the nebulae.
|
|
* @return 0 on success.
|
|
*/
|
|
static int nebu_generate(void) {
|
|
int i;
|
|
float* nebu;
|
|
char nebu_file[PATH_MAX];
|
|
int w, h;
|
|
int ret;
|
|
|
|
/* Warn user of what is happening. */
|
|
loadscreen_render(0.05, "Generating Nebulae...");
|
|
|
|
/* Get resolution. */
|
|
w = SCREEN_W;
|
|
h = SCREEN_H;
|
|
|
|
/* Try to make the directory first if it fails. */
|
|
lfile_dirMakeExist("%sgen", lfile_basePath());
|
|
|
|
/* Generate all the nebulae backgrounds. */
|
|
nebu = noise_genNebulaeMap(w, h, NEBULAE_Z, 5.);
|
|
|
|
/* Save each nebulae as an image. */
|
|
for(i = 0; i < NEBULAE_Z; i++) {
|
|
snprintf(nebu_file, PATH_MAX, NEBULAE_PATH_BG, w, h, i);
|
|
ret = saveNebulae(&nebu[i*w*h], w, h, nebu_file);
|
|
if(ret != 0) break; /* An error has happened. */
|
|
}
|
|
|
|
/* Cleanup. */
|
|
free(nebu);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @fn static void nebu_generatePuffs(void)
|
|
*
|
|
* @brief Generate nebulae puffs.
|
|
*/
|
|
static void nebu_generatePuffs(void) {
|
|
int i;
|
|
int w, h;
|
|
SDL_Surface* sur;
|
|
float* nebu;
|
|
|
|
/* Warn user of what is happening. */
|
|
loadscreen_render(0.05, "Generating Nebulae Puffs.");
|
|
|
|
/* Generate the nebulae puffs. */
|
|
for(i = 0; i < NEBULAE_PUFFS; i++) {
|
|
/* Generate the nebulae. */
|
|
w = h = RNG(20, 64);
|
|
nebu = noise_genNebulaePuffMap(w, h, 1.);
|
|
sur = nebu_surfaceFromNebulaeMap(nebu, w, h);
|
|
free(nebu);
|
|
|
|
/* Load the textures. */
|
|
nebu_pufftexs[i] = gl_loadImage(sur);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @fn static int nebu_checkCompat(const char* file)
|
|
*
|
|
* @brief Check the validity of a nebulae.
|
|
* @param file Path of the nebulae to check (relative to base directory).
|
|
* @return 0 on success.
|
|
*/
|
|
static int nebu_checkCompat(const char* file) {
|
|
/* First check to see if file exists. */
|
|
if(lfile_fileExists("%s%s", lfile_basePath(), file) == 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @fn static int saveNebulae(float* map, const uint32_t w, const uint32_t h,
|
|
* const char* file)
|
|
*
|
|
* @brief Save a nebulae.
|
|
* @param map Nebulae map to save.
|
|
* @param w Width of nebulae map.
|
|
* @param h Height of nebulae map.
|
|
* @param file Path to save into.
|
|
* @return 0 on success.
|
|
*/
|
|
static int saveNebulae(float* map, const uint32_t w, const uint32_t h,
|
|
const char* file) {
|
|
|
|
char file_path[PATH_MAX];
|
|
SDL_Surface* sur;
|
|
int ret;
|
|
|
|
/* Fix surface. */
|
|
sur = nebu_surfaceFromNebulaeMap(map, w, h);
|
|
|
|
/* Save. */
|
|
ret = 0;
|
|
snprintf(file_path, PATH_MAX, "%s%s", lfile_basePath(), file);
|
|
ret = SDL_savePNG(sur, file_path);
|
|
|
|
/* Cleanup. */
|
|
SDL_FreeSurface(sur);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @fn static SDL_Surface* loadNebulae(const char* file)
|
|
*
|
|
* @brief Loads the nebulae from file.
|
|
* @param file Path of the nebulae to load. Relative to base directory.
|
|
* @return An SDL surface with the nebulae.
|
|
*/
|
|
static SDL_Surface* loadNebulae(const char* file) {
|
|
char file_path[PATH_MAX];
|
|
SDL_Surface* sur;
|
|
|
|
/* Load the file. */
|
|
snprintf(file_path, PATH_MAX, "%s%s", lfile_basePath(), file);
|
|
|
|
sur = IMG_Load(file_path);
|
|
if(sur == NULL) {
|
|
ERR("Unable to load Nebulae image: %s", file);
|
|
return NULL;
|
|
}
|
|
|
|
return sur;
|
|
}
|
|
|
|
/**
|
|
* @fn SDL_Surface* nebu_surfaceFromNebulaeMap(float* map, const int w, const int h)
|
|
*
|
|
* @brief Generate an SDL_Surface from a 2d nebulae map.
|
|
* @param map Nebulae map to use.
|
|
* @param w Map width.
|
|
* @param h Map height.
|
|
* @return An SDL Surface with the nebulae.
|
|
*/
|
|
SDL_Surface* nebu_surfaceFromNebulaeMap(float* map, const int w, const int h) {
|
|
int i;
|
|
SDL_Surface* sur;
|
|
uint32_t* pix;
|
|
double c;
|
|
|
|
/* The good surface. */
|
|
sur = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, RGBAMASK);
|
|
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)((double)AMASK*c));
|
|
}
|
|
SDL_UnlockSurface(sur);
|
|
|
|
return sur;
|
|
}
|
|
|