[Change] GUI's are now saved in XML and thrown into data pack file.

-- This allows for multiple gui's.
  -- Each ship can also have it's own gui if it so chooses.
This commit is contained in:
Allanis 2013-02-12 19:34:47 +00:00
parent e0f78e40a3
commit e1b23f928b
10 changed files with 290 additions and 61 deletions

48
dat/gui.xml Normal file
View File

@ -0,0 +1,48 @@
<GUIs>
<gui name="simple" gfx="simple">
<radar type="rectangle">
<w>128</w>
<h>128</h>
<x>11</x>
<y>10</y>
</radar>
<health>
<shield>
<w>129</w>
<h>10</h>
<x>10</x>
<y>201</y>
</shield>
<armor>
<w>129</w>
<h>10</h>
<x>10</x>
<y>218</y>
</armor>
<energy>
<w>129</w>
<h>10</h>
<x>10</x>
<y>236</y>
</energy>
</health>
<target>
<gfx>
<x>10</x>
<y>256</y>
</gfx>
<name>
<x>16</x>
<y>261</y>
</name>
<faction>
<x>16</x>
<y>274</y>
</faction>
<health>
<x>16</x>
<y>334</y>
</health>
</target>
</gui>
</GUIs>

View File

@ -2,6 +2,7 @@
<Ships>
<ship name="Merchant Ship">
<GFX>ship</GFX>
<GUI>simple</GUI>
<class>1</class>
<movement>
<thrust>400</thrust>
@ -28,6 +29,7 @@
</ship>
<ship name="Enemy Test">
<GFX>ship1</GFX>
<GUI>simple</GUI>
<class>1</class>
<movement>
<thrust>180</thrust>

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

Before

Width:  |  Height:  |  Size: 181 B

After

Width:  |  Height:  |  Size: 181 B

View File

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 326 B

View File

@ -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;

View File

@ -12,7 +12,7 @@
#define XML_NODE_TEXT 3
#define XML_GUI_ID "GUIs" // XML section identifier.
#define XML_GUI_ID "gui"
#define XML_GUI_TAG "gui"
#define GUI_DATA "../dat/gui.xml"
#define GUI_GFX "../gfx/gui/"
@ -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.
// -- 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.

View File

@ -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) {

View File

@ -34,6 +34,9 @@ typedef struct {
// Graphics.
gl_texture* gfx_space, *gfx_target;
// GUI interface.
char* gui;
// Characteristics.
int crew;
int mass;