diff --git a/src/lephisto.c b/src/lephisto.c index 39c5db3..4be0aac 100644 --- a/src/lephisto.c +++ b/src/lephisto.c @@ -24,12 +24,15 @@ #include "toolkit.h" #include "pilot.h" #include "sound.h" +#include "music.h" #include "spfx.h" #include "economy.h" #include "menu.h" #include "mission.h" +#include "misn_lua.h" #include "lfile.h" -#include "music.h" +#include "nebulae.h" + #define XML_START_ID "Start" #define START_DATA "../dat/start.xml" @@ -128,8 +131,17 @@ int main(int argc, char** argv) { exit(EXIT_FAILURE); } + /* OpenGL */ + if(gl_init()) { /* Init video output. */ + ERR("Initializing video output failed, exiting..."); + SDL_Quit(); + exit(EXIT_FAILURE); + } window_caption(); + /* Time to try to load the nebulae. */ + nebu_init(); + /* OpenAL sound. */ if(nosound) LOG("Sound is disabled!"); @@ -210,6 +222,7 @@ int main(int argc, char** argv) { ai_exit(); /* Stop the Lua AI magicness. */ joystick_exit(); /* Release joystick. */ input_exit(); /* Clean up keybindings. */ + nebu_exit(); /* Destroys the nebulae. */ gl_exit(); /* Kills video output. */ sound_exit(); /* Kills the sound. */ SDL_Quit(); /* Quits SDL. */ diff --git a/src/lfile.c b/src/lfile.c index 2c35bdc..e428fd9 100644 --- a/src/lfile.c +++ b/src/lfile.c @@ -33,7 +33,7 @@ char* lfile_basePath(void) { /* Check if a directory exists, and create it if it doesn't. */ /* Based on lephisto_base. */ -int lfile_dirMakeExist(char* path) { +int lfile_dirMakeExist(const char* path) { char file[PATH_MAX]; #ifdef LINUX @@ -59,7 +59,7 @@ int lfile_dirMakeExist(char* path) { } /* Check if a file exists. */ -int lfile_fileExists(char* path, ...) { +int lfile_fileExists(const char* path, ...) { char file[PATH_MAX], name[PATH_MAX]; va_list ap; size_t l; @@ -86,7 +86,7 @@ int lfile_fileExists(char* path, ...) { } /* List all the files in a dir (besides . and ..). */ -char** lfile_readDir(int* lfiles, char* path) { +char** lfile_readDir(int* lfiles, const char* path) { char file[PATH_MAX]; char** files; diff --git a/src/lfile.h b/src/lfile.h index d6de045..da61cde 100644 --- a/src/lfile.h +++ b/src/lfile.h @@ -1,7 +1,12 @@ #pragma once char* lfile_basePath(void); -int lfile_dirMakeExist(char* path); -int lfile_fileExists(char* path, ...); -char** lfile_readDir(int* lfiles, char* path); + +/* Create if doesn't exist, 0 success. */ +int lfile_dirMakeExist(const char* path); + +/* Return 1 on exit. */ +int lfile_fileExists(const char* path, ...); + +char** lfile_readDir(int* lfiles, const char* path); diff --git a/src/nebulae.c b/src/nebulae.c new file mode 100644 index 0000000..e2e42b4 --- /dev/null +++ b/src/nebulae.c @@ -0,0 +1,200 @@ +#include +#include "nebulae.h" + +#ifdef _POSIX_SOURCE +#include +#include +#include +#endif + +#include "lephisto.h" +#include "log.h" +#include "lfile.h" +#include "perlin.h" + +/* -- CUSTOM NEBULAE FORMAT. -- + * Header (16 byte string). + * Dimesnions (4 byte w and 4 byte h). + * Body (1 byte per pixel). + */ + +#define NEBU_FORMAT_HEADER 16 /* Size of header. */ +#define NEBU_VERSION "1" /* Will be used for version checking. */ + +#define NEBULAE_Z 32 /* Z plane. */ +#define NEBULAE_PATH "gen/nebu_%02d.nebu" + +/* The nebulae textures. */ +static GLuint nebu_textures[NEBULAE_Z]; +static int nebu_w, nebu_h, nebu_pw, nebu_ph; + +static int nebu_checkCompat(const char* file); +static void saveNebulae(float* map, const uint32_t w, const uint32_t h, + const char* file); +static unsigned char* loadNebulae(const char* file, int* w, int* h); + +void nebu_init(void) { + int i; + char nebu_file[PATH_MAX]; + unsigned char* nebu_padded; + int w, h; + unsigned char* nebu_data; + + /* Set expected sizes. */ + nebu_w = SCREEN_W; + nebu_h = SCREEN_H; + nebu_pw = gl_pot(nebu_w); + nebu_ph = gl_pot(nebu_h); + + /* Load each, checking for compatibility and padding. */ + nebu_padded = malloc(nebu_pw * nebu_ph); + glGenTextures(NEBULAE_Z, nebu_textures); + for(i = 0; i < NEBULAE_Z; i++) { + snprintf(nebu_file, PATH_MAX, NEBULAE_PATH, i); + + if(nebu_checkCompat(nebu_file)) { /* Incompatable. */ + LOG("No nebulae found, generating (this may take a while)."); + + /* So we generate and reload. */ + free(nebu_padded); + nebu_generate(nebu_w, nebu_h); + nebu_init(); + return; + } + + /* Load the file. */ + nebu_data = loadNebulae(nebu_file, &w, &h); + memcpy(nebu_padded, nebu_data, w*h); + + /* Load the textures. */ + glBindTexture(GL_TEXTURE_2D, nebu_textures[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, nebu_pw, nebu_ph, + 0, GL_ALPHA, GL_UNSIGNED_BYTE, nebu_padded); + gl_checkErr(); + + free(nebu_data); /* No longer need the data. */ + } + free(nebu_padded); +} + +/* Clean up the nebu subsystem. */ +void nebu_exit(void) { + glDeleteTextures(NEBULAE_Z, nebu_textures); +} + +/* Force generation of new nebulae. */ +void nebu_generate(const int w, const int h) { + int i; + float* nebu; + char nebu_file[PATH_MAX]; + + /* Generate all the nebulae. */ + nebu = noise_genNebulaeMap(w, h, NEBULAE_Z, 15.); + lfile_dirMakeExist("gen"); + + /* Save each nebulae as an image. */ + for(i = 0; i < NEBULAE_Z; i++) { + snprintf(nebu_file, PATH_MAX, NEBULAE_PATH, i); + saveNebulae(&nebu[i*w*h], w, h, nebu_file); + } + + /* Cleanup. */ + free(nebu); +} + +/* Check the validity of a nebulae. 0 on success. */ +static int nebu_checkCompat(const char* file) { + if(lfile_fileExists(file) == 0) /* First check to see if file exists. */ + return -1; + return 0; +} + +/* Save a nebulae. */ +static void saveNebulae(float* map, const uint32_t w, const uint32_t h, + const char* file) { + + int x, y; + char* buf; + unsigned char c; + int cur; + ssize_t size; + char file_path[PATH_MAX]; + + size = w*h + 16 + 4; + buf = malloc(size); + + /* Write the header. */ + memset(buf, '0', 16); + snprintf(buf, NEBU_FORMAT_HEADER, "LEPHISTO NEBU v" NEBU_VERSION); + cur = 16; + memcpy(&buf[cur], &w, 4); + memcpy(&buf[cur], &h, 4); + cur += 8; + + /* The Body. */ + for(y = 0; y < (int)h; y++) + for(x = 0; x < (int)w; x++) { + c = (unsigned char) 255.*map[y*w + x]; + memcpy(&buf[cur++], &c, 1); + } + + /* Write to a file. */ + snprintf(file_path, PATH_MAX, "%s%s", lfile_basePath(), file); +#ifdef _POSIX_SOURCE + int fd; + fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + + if(fd < 0) { + ERR("Unable to open file %s: %s", file, strerror(errno)); + return; + } + if(write(fd, buf, size) != size) { + ERR("Error writing nebulae to %s: %s", file, strerror(errno)); + return; + } + close(fd); +#else +#error "Needs implementation." +#endif +} + +/* Load the nebulae from file. */ +static unsigned char* loadNebulae(const char* file, int* w, int* h) { + unsigned char* buf; + char header[16]; + uint32_t tw, th; + ssize_t len; + char file_path[PATH_MAX]; + +#ifdef _POSIX_SOURCE +#define READ(b, l) \ + len = read(fd, b, l); \ + if(len < l) {\ + WARN("Read too few bytes from %s: %s", file, strerror(errno)); \ + return NULL; \ + } + + int fd; + snprintf(file_path, PATH_MAX, "%s%s", lfile_basePath(), file); + fd = open(file, O_RDONLY); + if(fd < 0) { + ERR("Unable to open file %s: %s", file_path, strerror(errno)); + return NULL; + } + READ(header, 16); + READ(&tw, 4); + READ(&th, 4); + buf = malloc(tw*th); + READ(buf, tw*th); +#else +#error "Needs implementation." +#endif + (*w) = (int)tw; + (*h) = (int)th; + + return buf; +} + diff --git a/src/nebulae.h b/src/nebulae.h new file mode 100644 index 0000000..f992062 --- /dev/null +++ b/src/nebulae.h @@ -0,0 +1,10 @@ +#pragma once +#include "opengl.h" + +/* Try to find nebulae to load, or generate if there isn't any. */ +void nebu_init(void); + +void nebu_exit(void); + +void nebu_generate(const int w, const int h); + diff --git a/src/opengl.c b/src/opengl.c index 6840bb7..e7e9e1d 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -39,7 +39,6 @@ static glTexList* texture_list = NULL; static int SDL_VFlipSurface(SDL_Surface* surface); static int SDL_IsTrans(SDL_Surface* s, int x, int y); static uint8_t* SDL_MapTrans(SDL_Surface* s); -static int pot(int n); /* glTexture. */ static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh); static glTexture* gl_loadNewImage(const char* path); @@ -58,7 +57,7 @@ static GLboolean gl_hasExt(char* name); */ /* Get the closest power of two. */ -static int pot(int n) { +int gl_pot(int n) { int i = 1; while(i < n) i<<=1; @@ -249,8 +248,8 @@ static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh) { SDL_Rect rtemp; /* Make size power of two. */ - potw = pot(surface->w); - poth = pot(surface->h); + potw = gl_pot(surface->w); + poth = gl_pot(surface->h); if(rw)*rw = potw; if(rh)*rh = poth; diff --git a/src/opengl.h b/src/opengl.h index ac11926..200bb4a 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -102,6 +102,7 @@ int gl_init(void); void gl_exit(void); /* Misc. */ +int gl_pot(int n); int gl_isTrans(const glTexture* t, const int x, const int y); void gl_getSpriteFromDir(int* x, int* y, const glTexture* t, const double dir); void gl_screenshot(const char* filename);