From 70c95853020f08a42cf3fa6236075f04ceb070db Mon Sep 17 00:00:00 2001 From: Allanis Date: Thu, 14 Feb 2013 19:29:26 +0000 Subject: [PATCH] [Add] Rudimentary screenshots. --- .gitignore | 2 +- dat/start.xml | 1 + src/main.c | 70 +++++++++++++++++++++++++++++++++++++++++++++------ src/opengl.c | 56 +++++++++++++++++++++++++++++++++++++++++ src/opengl.h | 1 + src/player.c | 61 ++++++++++++++++++++++++++++++++++++++------ src/space.h | 2 +- 7 files changed, 177 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 7093131..01f424f 100644 --- a/.gitignore +++ b/.gitignore @@ -28,5 +28,5 @@ *bin/data *pack *core - +*screenshot.png diff --git a/dat/start.xml b/dat/start.xml index af6b2c2..d17a8d9 100644 --- a/dat/start.xml +++ b/dat/start.xml @@ -1,4 +1,5 @@ + Dark Tides Lancer diff --git a/src/main.c b/src/main.c index b7ef1a0..7b2a732 100644 --- a/src/main.c +++ b/src/main.c @@ -21,8 +21,12 @@ #include "pack.h" #include "weapon.h" #include "faction.h" +#include "xml.h" #include "pilot.h" +#define XML_START_ID "Start" +#define START_DATA "../dat/start.xml" + #define CONF_FILE "conf" #define MINIMUM_FPS 0.5 @@ -34,8 +38,10 @@ static int quit = 0; // Primary loop. static unsigned int time = 0; // Calculate FPS and movement. // Just some default crap. -#define DATA_DEF "data" +#define DATA_DEF "data" // Default data pack file. +#define DATA_NAME_LEN 25 // Max length of data name. char* data = NULL; +char dataname[DATA_NAME_LEN]; static int show_fps = 1; // Default - True. static int max_fps = 0; @@ -43,6 +49,8 @@ static int max_fps = 0; static void print_usage(char** argv); static void display_fps(const double dt); +static void window_caption(void); +static void data_name(void); // Update. static void update_all(void); @@ -188,13 +196,26 @@ int main(int argc, char** argv) { namjoystick = strdup(optarg); break; case 'v': - LOG("Lephisto: version %d.%d.%d\n", VMAJOR, VMINOR, VREV); + LOG(APPNAME": version %d.%d.%d", VMAJOR, VMINOR, VREV); case 'h': print_usage(argv); exit(EXIT_SUCCESS); } } + + // Check if the data file is valid. + if(pack_check(data)) { + ERR("Data file '%s'not found", data); + WARN("You should specify which data file to use with '-d'"); + WARN("See -h or --help for more information."); + SDL_Quit(); + exit(EXIT_FAILURE); + } + data_name(); // Loads the data's name and friends. + LOG(" %s", dataname); + DEBUG(); + // Random numbers. rng_init(); @@ -214,11 +235,10 @@ int main(int argc, char** argv) { exit(EXIT_FAILURE); } - // Window. - SDL_WM_SetCaption(APPNAME, NULL); + window_caption(); // Input. - if(indjoystick >= 0 || namjoystick != NULL) { + if((indjoystick >= 0) || (namjoystick != NULL)) { if(joystick_init()) WARN("Error initializing joystick input"); if(namjoystick != NULL) { @@ -307,7 +327,7 @@ int main(int argc, char** argv) { // ======================================================== static double fps_dt = 1.; static void update_all(void) { - // dt in us. + // dt in ms/1000. double dt = (double)(SDL_GetTicks() - time) / 1000.; time = SDL_GetTicks(); @@ -319,7 +339,7 @@ static void update_all(void) { return; } // If FPS is limited. - else if(max_fps != 0 && dt < 1./max_fps) { + else if((max_fps != 0) && (dt < 1./max_fps)) { double delay = 1./max_fps - dt; SDL_Delay(delay); fps_dt += delay; // Make sure it displays the propper FPS. @@ -351,6 +371,7 @@ static void display_fps(const double dt) { fps_dt += dt; fps_cur += 1.; if(fps_dt > 1.) { + // Recalculate every second. fps = fps_cur / fps_dt; fps_dt = fps_cur = 0.; } @@ -360,3 +381,38 @@ static void display_fps(const double dt) { gl_print(NULL, &pos, NULL, "%3.2f", fps); } +static void data_name(void) { + uint32_t bufsize; + char* buf = pack_readfile(DATA, START_DATA, &bufsize); + + xmlNodePtr node; + xmlDocPtr doc = xmlParseMemory(buf, bufsize); + + node = doc->xmlChildrenNode; + if(!xml_isNode(node, XML_START_ID)) { + ERR("Maformed '"START_DATA"' file: missing root element '"XML_START_ID"'"); + return; + } + + node = node->xmlChildrenNode; // First node. + if(node == NULL) { + ERR("Malformed '"START_DATA"' file: does not contain elements"); + return; + } + do { + if(xml_isNode(node, "name")) + strncpy(dataname, xml_get(node), DATA_NAME_LEN); + } while((node = node->next)); + + xmlFreeDoc(doc); + free(buf); + xmlCleanupParser(); +} + +static void window_caption(void) { + char tmp[DATA_NAME_LEN+10]; + + snprintf(tmp, DATA_NAME_LEN+10, APPNAME" - %s", dataname); + SDL_WM_SetCaption(tmp, NULL); +} + diff --git a/src/opengl.c b/src/opengl.c index 285d8de..0a3f597 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -43,6 +44,8 @@ static int pot(int n); static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh); // Gl font. static void gl_fontMakeDList(FT_Face face, char ch, GLuint list_base, GLuint* tex_base, int* width_base); +// PNG. +int write_png(const char* file_name, png_bytep* rows, int w, int h, int colortype, int bitdepth); // ================ // MISC! @@ -133,6 +136,19 @@ static uint8_t* SDL_MapTrans(SDL_Surface* s) { return t; } +// Take a screenshot. +void gl_screenshot(const char* filename) { + SDL_Surface* screen = SDL_GetVideoSurface(); + unsigned rowbytes = screen->w * 4; + unsigned char screenbuf[screen->h][rowbytes], *rows[screen->h]; + int i; + + glReadPixels(0, 0, screen->w, screen->h, GL_RGBA, GL_UNSIGNED_BYTE, screenbuf); + + for(i = 0; i < screen->h; i++) rows[i] = screenbuf[screen->h - i - 1]; + write_png(filename, rows, screen->w, screen->h, PNG_COLOR_TYPE_RGBA, 8); +} + // ================ // TEXTURE! // ================ @@ -708,3 +724,43 @@ void gl_exit(void) { SDL_Quit(); } +// Saves a png. +int write_png(const char* file_name, png_bytep* rows, int w, int h, int colortype, int bitdepth) { + png_structp png_ptr; + png_infop info_ptr; + FILE* fp = NULL; + char* doing = "Open for writing"; + + if(!(fp = fopen(file_name, "wb"))) goto fail; + + doing = "Create png write struct"; + if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) goto fail; + + doing = "Create png info struct"; + if(!(info_ptr = png_create_info_struct(png_ptr))) goto fail; + if(setjmp(png_jmpbuf(png_ptr))) goto fail; + + doing = "Init IO"; + png_init_io(png_ptr, fp); + png_set_IHDR(png_ptr, info_ptr, w, h, bitdepth, colortype, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + doing = "Write info"; + png_write_info(png_ptr, info_ptr); + + doing = "Write image"; + png_write_image(png_ptr, rows); + + doing = "Write end"; + png_write_end(png_ptr, NULL); + + doing = "Closing file"; + if(0 != fclose(fp)) goto fail; + + return 0; + +fail: + WARN("write_png: Could not %s", doing); + return -1; +} + diff --git a/src/opengl.h b/src/opengl.h index c234eb0..35ab829 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -83,4 +83,5 @@ void gl_exit(void); // Misc. int gl_isTrans(const gl_texture* t, const int x, const int y); void gl_getSpriteFromDir(int* x, int* y, const gl_texture* t, const double dir); +void gl_screenshot(const char* filename); diff --git a/src/player.c b/src/player.c index 69cfd12..0b0ab63 100644 --- a/src/player.c +++ b/src/player.c @@ -20,7 +20,7 @@ #define START_DATA "../dat/start.xml" -#define POW2(x) ((x)*(x)) +#define pow2(x) ((x)*(x)) #define GFX_GUI_FRAME "../gfx/gui/frame.png" #define GFX_GUI_TARG_PILOT "../gfx/gui/pilot.png" @@ -38,8 +38,9 @@ typedef struct { } Keybind; static Keybind** player_input; // Contains the players keybindings. // Name of each keybinding. -const char* keybindNames[] = { "accel", "left", "right", "primary", "target", - "target_nearest", "mapzoomin", "mapzoomout", "end" }; // Need to terminate in "end". +const char* keybindNames[] = { "accel", "left", "right", // Movement. + "primary", "target", "target_nearest", "board", // Combat. + "mapzoomin", "mapzoomout", "screenshot", "end" }; // Misc. // Player stuff. Pilot* player = NULL; // extern in pilot.h @@ -138,6 +139,9 @@ static int gui_parse(const xmlNodePtr parent, const char* name); static void gui_renderPilot(const Pilot* p); static void gui_renderBar(const glColor* c, const Vec2* p, const Rect* r, const double w); +static void player_board(void); +static void player_screenshot(void); + // Create a new player. void player_new(void) { Ship* ship; @@ -529,28 +533,28 @@ static void rect_parse(const xmlNodePtr parent, double* x, double* y, double* w, do { if(xml_isNode(cur, "x")) { if(x != NULL) { - *x = (double)atoi((char*)cur->children->content); + *x = xml_getFloat(cur); param |= (1<<0); } else WARN("Extra parameter 'x' found for GUI node '%s'", parent->name); } else if(xml_isNode(cur, "y")) { if(y != NULL) { - *y = (double)atoi((char*)cur->children->content); + *y = xml_getFloat(cur); param |= (1<<1); } else WARN("Extra parameter 'y' found for GUI node '%s'", parent->name); } else if(xml_isNode(cur, "w")) { if(w != NULL) { - *w = (double)atoi((char*)cur->children->content); + *w = xml_getFloat(cur); param |= (1<<2); } else WARN("Extra parameter 'w' found for GUI node '%s'", parent->name); } else if(xml_isNode(cur, "h")) { if(h != NULL) { - *h = (double)atoi((char*)cur->children->content); + *h = xml_getFloat(cur); param |= (1<<3); } else WARN("Extra parameter 'h' found for GUI node '%s'", parent->name); @@ -736,6 +740,40 @@ void player_think(Pilot* player) { vect_pset(&player->solid->force, player->ship->thrust * player_acc, player->solid->dir); } +void player_board(void) { + Pilot* p; + + if(player_target == PLAYER_ID) { + player_message("You need a target to board first!"); + return; + } + p = pilot_get(player_target); + + if(!pilot_isFlag(p, PILOT_DISABLED)) { + player_message("You cannot board a ship that isn't disabled!"); + return; + } + if(vect_dist(&player->solid->pos, &p->solid->pos) > p->ship->gfx_space->sw * PILOT_SIZE_APROX) { + player_message("You are too far away to board your target"); + return; + } + if((pow2(VX(player->solid->vel)-VX(p->solid->vel)) + + pow2(VY(player->solid->vel)-VY(p->solid->vel))) > (double)pow2(MAX_HYPERSPACE_VEL)) { + + player_message("You are going too fact to board the ship"); + return; + } + player_message("Ship boarding isn't implemented yet! HAHA"); +} + +// Take a screenshot. +static void player_screenshot(void) { + char filename[20]; + // TODO not overwirte old screenshots. + strncpy(filename, "screenshot.png", 20); + gl_screenshot(filename); +} + // ================ // INPUT! // ================ @@ -748,8 +786,10 @@ void input_setDefault(void) { input_setKeybind("primary", KEYBIND_KEYBOARD, SDLK_SPACE, 0); input_setKeybind("target", KEYBIND_KEYBOARD, SDLK_TAB, 0); input_setKeybind("target_nearest", KEYBIND_KEYBOARD, SDLK_r, 0); + input_setKeybind("board", KEYBIND_KEYBOARD, SDLK_b, 0); input_setKeybind("mapzoomin", KEYBIND_KEYBOARD, SDLK_UP, 0); input_setKeybind("mapzoomout", KEYBIND_KEYBOARD, SDLK_DOWN, 0); + input_setKeybind("screenshot", KEYBIND_KEYBOARD, SDLK_F12, 0); } // Initialization/exit functions (does not assign keys). @@ -820,6 +860,10 @@ static void input_key(int keynum, double value, int abs) { else if(strcmp(player_input[keynum]->name, "target_nearest")==0) { if(value == KEY_PRESS) player_target = pilot_getHostile(); } + // Board those ships. + else if(strcmp(player_input[keynum]->name, "board")==0) { + if(value == KEY_PRESS) player_board(); + } // Zoom in. else if(strcmp(player_input[keynum]->name, "mapzoomin")==0) { if(value == KEY_PRESS && gui.radar.res < RADAR_RES_MAX) @@ -830,6 +874,9 @@ static void input_key(int keynum, double value, int abs) { if(value == KEY_PRESS && gui.radar.res > RADAR_RES_MIN) gui.radar.res -= RADAR_RES_INTERVAL; } + else if(strcmp(player_input[keynum]->name, "screenshot")==0) { + if(value == KEY_PRESS) player_screenshot(); + } //Make sure values are sane. player_acc = ABS(player_acc); diff --git a/src/space.h b/src/space.h index c1d2b12..f7d2d89 100644 --- a/src/space.h +++ b/src/space.h @@ -4,7 +4,7 @@ #include "pilot.h" #define MIN_HYPERSPACE_DIST 1500 -#define MAX_HYPERSPACE_VEL 3 +#define MAX_HYPERSPACE_VEL 10 // Planet types. I didn't take them from Star Trek, I promise. typedef enum {