diff --git a/dat/gui.xml b/dat/gui.xml new file mode 100644 index 0000000..7a13dbb --- /dev/null +++ b/dat/gui.xml @@ -0,0 +1,48 @@ + + + + 128 + 128 + 11 + 10 + + + + 129 + 10 + 10 + 201 + + + 129 + 10 + 10 + 218 + + + 129 + 10 + 10 + 236 + + + + + 10 + 256 + + + 16 + 261 + + + 16 + 274 + + + 16 + 334 + + + + diff --git a/dat/ship.xml b/dat/ship.xml index 698c3a1..3a30994 100644 --- a/dat/ship.xml +++ b/dat/ship.xml @@ -2,6 +2,7 @@ ship + simple 1 400 @@ -28,6 +29,7 @@ ship1 + simple 1 180 diff --git a/gfx/gui/frame.png b/gfx/gui/simple.png similarity index 100% rename from gfx/gui/frame.png rename to gfx/gui/simple.png diff --git a/gfx/gui/frame.xcf b/gfx/gui/simple.xcf similarity index 100% rename from gfx/gui/frame.xcf rename to gfx/gui/simple.xcf diff --git a/gfx/gui/pilot.png b/gfx/gui/simple_pilot.png similarity index 100% rename from gfx/gui/pilot.png rename to gfx/gui/simple_pilot.png diff --git a/gfx/gui/planet.png b/gfx/gui/simple_planet.png similarity index 100% rename from gfx/gui/planet.png rename to gfx/gui/simple_planet.png diff --git a/src/pilot.c b/src/pilot.c index 32a0947..7b2ecf4 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -33,8 +33,9 @@ static int nfleets = 0; // External. extern void ai_destroy(Pilot* p); // Ai. -extern void player_think(Pilot* pilot); // Player.c extern void ai_think(Pilot* pilot); // Ai.c +extern void player_think(Pilot* pilot); // Player.c +extern int gui_load(const char* name); // Player.c // Internal. static void pilot_update(Pilot* pilot, const double dt); void pilot_render(Pilot* pilot); @@ -242,6 +243,7 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction, AI_Profi pilot->render = NULL; pilot_setFlag(pilot, PILOT_PLAYER); // It's a player! player = pilot; + gui_load(pilot->ship->gui); // Load the GUI. } else { pilot->think = ai_think; pilot->render = pilot_render; diff --git a/src/player.c b/src/player.c index f5fb256..3c7e0eb 100644 --- a/src/player.c +++ b/src/player.c @@ -11,11 +11,11 @@ #define XML_NODE_START 1 #define XML_NODE_TEXT 3 -#define XML_GUI_ID "GUIs" // XML section identifier. -#define XML_GUI_ID "gui" +#define XML_GUI_ID "GUIs" // XML section identifier. +#define XML_GUI_TAG "gui" -#define GUI_DATA "../dat/gui.xml" -#define GUI_GFX "../gfx/gui/" +#define GUI_DATA "../dat/gui.xml" +#define GUI_GFX "../gfx/gui/" #define POW2(x) ((x)*(x)) @@ -125,9 +125,10 @@ static Msg* msg_stack; // External. extern void pilot_render(Pilot* pilot); // Extern is in Pilot.* // Internal. -//TODO: Gui shit. -void gui_renderPilot(Pilot* p); -void gui_renderBar(Color* c, Vec2* p, Rect* r, double w); +static void rect_parse(const xmlNodePtr parent, double* x, double* y, double* w, double* h); +static int gui_parse(const xmlNodePtr parent, const char* name); +static void gui_renderPilot(const Pilot* p); +static void gui_renderBar(const Color* c, const Vec2* p, const Rect* r, const double w); void player_message(const char* fmt, ...) { va_list ap; @@ -135,11 +136,13 @@ void player_message(const char* fmt, ...) { if(fmt == NULL) return; // Message not valid. + // Copy old messages back. for(i = 1; i < msg_max; i++) if(msg_stack[msg_max-i-1].str[0] != '\0') { strcpy(msg_stack[msg_max-i].str, msg_stack[msg_max-i-1].str); msg_stack[msg_max-i].t = msg_stack[msg_max-i-1].t; } + // Add the new one. va_start(ap, fmt); vsprintf(msg_stack[0].str, fmt, ap); va_end(ap); @@ -266,7 +269,7 @@ void player_render(void) { } // Renders a pilot. -void gui_renderPilot(Pilot* p) { +static void gui_renderPilot(const Pilot* p) { int x, y, sx, sy; x = (p->solid->pos.x - player->solid->pos.x) / gui.radar.res; @@ -294,7 +297,7 @@ void gui_renderPilot(Pilot* p) { } // Render a bar. -void gui_renderBar(Color* c, Vec2* p, Rect* r, double w) { +static void gui_renderBar(const Color* c, const Vec2* p, const Rect* r, const double w) { int x, y, sx, sy; glBegin(GL_QUADS); @@ -314,63 +317,232 @@ void gui_renderBar(Color* c, Vec2* p, Rect* r, double w) { int gui_init(void) { // Font. gl_fontInit(&gui.smallFont, NULL, 10); - // -- Targeting. - gui.gfx_targetPilot = gl_newSprite(GFX_GUI_TARG_PILOT, 2, 2); - gui.gfx_targetPlanet = gl_newSprite(GFX_GUI_TARG_PLANET, 2, 2); - // -- Frame. - gui.gfx_frame = gl_newImage(GFX_GUI_FRAME); - vect_csetmin(&gui.pos_frame, - gl_screen.w - gui.gfx_frame->w, // x. - gl_screen.h - gui.gfx_frame->h); // y. - gui_xoff = -gui.gfx_frame->w/2.; // Offset is only horizontal and on the right side. - // -- Radar. gui.radar.res = RADAR_RES_DEFAULT; - gui.radar.w = 128.; - gui.radar.h = 128.; - gui.radar.shape = RADAR_RECT; //RADAR_CIRCLE; - vect_csetmin(&gui.pos_radar, - VX(gui.pos_frame) + 11, // x - VY(gui.pos_frame) + gui.gfx_frame->h - 10); // y. - - // -- Bars. - gui.shield.w = gui.armor.w = gui.energy.w = 129; - gui.shield.h = gui.armor.h = gui.energy.h = 10; - vect_csetmin(&gui.pos_shield, - VX(gui.pos_frame) + 10, // x - VY(gui.pos_frame) + gui.gfx_frame->h - 201); // y. - - vect_csetmin(&gui.pos_armor, - VX(gui.pos_frame) + 10, // x - VY(gui.pos_frame) + gui.gfx_frame->h - 218); // y. - - vect_csetmin(&gui.pos_energy, - VX(gui.pos_frame) + 10, // x - VY(gui.pos_frame) + gui.gfx_frame->h - 236); // y. - - // Target. - vect_csetmin(&gui.pos_target, - VX(gui.pos_frame) + 10, - VY(gui.pos_frame) + gui.gfx_frame->h - 256 - SHIP_TARGET_H); - - vect_csetmin(&gui.pos_target_name, - VX(gui.pos_target) + 10, - VY(gui.pos_target) + SHIP_TARGET_H - 10 - gl_defFont.h); - - vect_csetmin(&gui.pos_target_faction, - VX(gui.pos_target_name), - VY(gui.pos_target_name) - gui.smallFont.h - 4); - - vect_csetmin(&gui.pos_target_health, - VX(gui.pos_target) + 10, - VY(gui.pos_target) +10); - - // Message system. - vect_csetmin(&gui.pos_msg, 20, 30); + // -- messages. + vect_csetmin(&gui.pos_msg, 20,30); msg_stack = calloc(msg_max, sizeof(Msg)); return 0; +} +// Attempts to load the actual gui. +int gui_load(const char* name) { + uint32_t bufsize; + char* buf = pack_readfile(DATA, GUI_DATA, &bufsize); + char* tmp; + int found = 0; + + xmlNodePtr node; + xmlDocPtr doc = xmlParseMemory(buf, bufsize); + + node = doc->xmlChildrenNode; + if(strcmp((char*)node->name, XML_GUI_ID)) { + ERR("Malformed '"GUI_DATA"' file: missing root element '"XML_GUI_ID"'"); + return -1; + } + + node = node->xmlChildrenNode; // First system node. + if(node == NULL) { + ERR("Malformed '"GUI_DATA"' file: does not contain elements"); + return -1; + } + + do { + if(node->type == XML_NODE_START && strcmp((char*)node->name, XML_GUI_TAG)==0) { + tmp = (char*)xmlGetProp(node, (xmlChar*)"name"); // Mallocs. + + // Is this the gui we are looking for? + if(strcmp(tmp, name)==0) { + found = 1; + + // Parse the xml node. + if(gui_parse(node, name)) WARN("Trouble loading GUI '%s'", name); + free(tmp); + break; + } + free(tmp); + } + } while((node = node->next)); + + xmlFreeDoc(doc); + free(buf); + xmlCleanupParser(); + + if(!found) { + WARN("GUI '%s' not found in '"GUI_DATA"'",name); + return -1; + } + return 0; +} + +static void rect_parse(const xmlNodePtr parent, double* x, double* y, double* w, double* h) { + xmlNodePtr cur; + int param; + + param = 0; + + cur = parent->children; + + do { + if(strcmp((char*)cur->name, "x")==0) { + if(x != NULL) { + *x = (double)atoi((char*)cur->children->content); + param |= (1<<0); + } else + WARN("Extra parameter 'x' found for GUI node '%s'", parent->name); + } + else if(strcmp((char*)cur->name, "y")==0) { + if(y != NULL) { + *y = (double)atoi((char*)cur->children->content); + param |= (1<<1); + } else + WARN("Extra parameter 'y' found for GUI node '%s'", parent->name); + } + else if(strcmp((char*)cur->name, "w")==0) { + if(w != NULL) { + *w = (double)atoi((char*)cur->children->content); + param |= (1<<2); + } else + WARN("Extra parameter 'w' found for GUI node '%s'", parent->name); + } + else if(strcmp((char*)cur->name, "h")==0) { + if(h != NULL) { + *h = (double)atoi((char*)cur->children->content); + param |= (1<<3); + } else + WARN("Extra parameter 'h' found for GUI node '%s'", parent->name); + } + } while((cur = cur->next)); + + // Check to see if we got everything we asked for. + if(x && !(param & (1<<0))) + WARN("Missing parameter 'x' for GUI node '%s'", parent->name); + else if(y && !(param & (1<<1))) + WARN("Missing parameter 'y' for GUI node '%s'", parent->name); + else if(w && !(param & (1<<2))) + WARN("Missing parameter 'w' for GUI node '%s'", parent->name); + else if(h && !(param & (1<<3))) + WARN("Missing parameter 'h' for GUI node '%s'", parent->name); +} + +// Parse a gui node. +static int gui_parse(const xmlNodePtr parent, const char* name) { + xmlNodePtr cur, node; + double x, y; + char* tmp, *tmp2; + + // Gfx. + // Set a property and not a node because it must be loaded first. + tmp2 = (char*)xmlGetProp(parent, (xmlChar*)"gfx"); + if(tmp2 == NULL) { + ERR("GUI '%s' has no gfx property", name); + return -1; + } + // Load gfx. + tmp = malloc((strlen(tmp2)+strlen(GUI_GFX)+12) * sizeof(char)); + // Frame. + snprintf(tmp, strlen(tmp2)+strlen(GUI_GFX)+5, GUI_GFX"%s.png", tmp2); + gui.gfx_frame = gl_newImage(tmp); + // Pilot. + snprintf(tmp, strlen(tmp2)+strlen(GUI_GFX)+11, GUI_GFX"%s_pilot.png", tmp2); + gui.gfx_targetPilot = gl_newSprite(tmp, 2, 2); + // Planet. + snprintf(tmp, strlen(tmp2)+strlen(GUI_GFX)+12, GUI_GFX"%s_planet.png", tmp2); + gui.gfx_targetPlanet = gl_newSprite(tmp, 2, 2); + free(tmp); + free(tmp2); + + // Frame (based on gfx). + vect_csetmin(&gui.pos_frame, + gl_screen.w - gui.gfx_frame->w, // x. + gl_screen.h - gui.gfx_frame->h); // h. + + // For rendering the player. Displaces it a little so it's centered onscreen. + gui_xoff = - gui.gfx_frame->w/2.; + + // Let's parse the data now. + node = parent->children; + do { + if(strcmp((char*)node->name, "radar")==0) { + tmp = (char*)xmlGetProp(node, (xmlChar*)"type"); + + // Make sure type is valid. + if(strcmp(tmp, "rectangle")==0) gui.radar.shape = RADAR_RECT; + else if(strcmp(tmp, "circle")==0) gui.radar.shape = RADAR_CIRCLE; + else { + WARN("Radar for GUI '%s' is missing 'type' tag or has invalid 'type' tag", name); + gui.radar.shape = RADAR_RECT; + } + free(tmp); + + rect_parse(node, &x, &y, &gui.radar.w, &gui.radar.h); + vect_csetmin(&gui.pos_radar, + VX(gui.pos_frame) + x, + VY(gui.pos_frame) + gui.gfx_frame->h - y); + } + // Health bars. + else if(strcmp((char*)node->name, "health")==0) { + cur = node->children; + do { + if(strcmp((char*)cur->name, "shield")==0) { + rect_parse(cur, &x, &y, &gui.shield.w, &gui.shield.h); + vect_csetmin(&gui.pos_shield, + VX(gui.pos_frame) + x, + VY(gui.pos_frame) + gui.gfx_frame->h - y); + } + + if(strcmp((char*)cur->name, "armor")==0) { + rect_parse(cur, &x, &y, &gui.armor.w, &gui.armor.h); + vect_csetmin(&gui.pos_armor, + VX(gui.pos_frame) + x, + VY(gui.pos_frame) + gui.gfx_frame->h - y); + } + + if(strcmp((char*)cur->name, "energy")==0) { + rect_parse(cur, &x, &y, &gui.energy.w, &gui.energy.h); + vect_csetmin(&gui.pos_energy, + VX(gui.pos_frame) + x, + VY(gui.pos_frame) + gui.gfx_frame->h - y); + } + } while((cur = cur->next)); + } + // Target. + else if(strcmp((char*)node->name, "target")==0) { + cur = node->children; + do { + if(strcmp((char*)cur->name, "gfx")==0) { + rect_parse(cur, &x, &y, NULL, NULL); + vect_csetmin(&gui.pos_target, + VX(gui.pos_frame) + x, + VY(gui.pos_frame) + gui.gfx_frame->h - y - SHIP_TARGET_H); + } + + if(strcmp((char*)cur->name, "name")==0) { + rect_parse(cur, &x, &y, NULL, NULL); + vect_csetmin(&gui.pos_target_name, + VX(gui.pos_frame) + x, + VY(gui.pos_frame) + gui.gfx_frame->h - y - gl_defFont.h); + } + + if(strcmp((char*)cur->name, "faction")==0) { + rect_parse(cur, &x, &y, NULL, NULL); + vect_csetmin(&gui.pos_target_faction, + VX(gui.pos_frame) + x, + VY(gui.pos_frame) + gui.gfx_frame->h - y - gui.smallFont.h); + } + + if(strcmp((char*)cur->name, "health")==0) { + rect_parse(cur, &x, &y, NULL, NULL); + vect_csetmin(&gui.pos_target_health, + VX(gui.pos_frame) + x, + VY(gui.pos_frame) + gui.gfx_frame->h - y - gui.smallFont.h); + } + } while((cur = cur->next)); + } + } while((node = node->next)); + + return 0; } // Free the GUI. diff --git a/src/ship.c b/src/ship.c index 417a121..39084b1 100644 --- a/src/ship.c +++ b/src/ship.c @@ -59,6 +59,8 @@ static Ship* ship_parse(xmlNodePtr parent) { tmp->gfx_target = gl_newImage(str); } + else if(strcmp((char*)node->name, "GUI")==0) + tmp->gui = strdup((char*)node->children->content); else if(strcmp((char*)node->name, "class")==0) tmp->class = atoi((char*)node->children->content); else if(strcmp((char*)node->name, "movement")==0) { diff --git a/src/ship.h b/src/ship.h index 0e7cbcd..0c52b32 100644 --- a/src/ship.h +++ b/src/ship.h @@ -34,6 +34,9 @@ typedef struct { // Graphics. gl_texture* gfx_space, *gfx_target; + // GUI interface. + char* gui; + // Characteristics. int crew; int mass;