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;