Exemplo n.º 1
0
/*
 * Parse a <properties> node into a list of property objects.
 */
static GHashTable *parse_properties(xmlNode *node)
{
	GHashTable *props = g_hash_table_new_full(&g_str_hash, &g_str_equal, &g_free, &g_free);

	xmlNode *properties_node = get_first_child_for_name(node, "properties");
	if (!properties_node) {
		return props;
	}

	GSList *properties_list = get_children_for_name(properties_node, "property");
	GSList *property_item = properties_list;
	while (property_item) {
		xmlNode *property_node = (xmlNode*)property_item->data;
		property_item = g_slist_next(property_item);

		char *name = g_strdup(get_xml_attribute(property_node, "name"));
		char *value = get_xml_attribute(property_node, "value");
		if (!value) {
			value = (char*)xmlNodeGetContent(property_node);
		}

		value = g_strdup(value);
		g_hash_table_insert(props, name, value);
	}

	g_slist_free(properties_list);
	return props;
}
Exemplo n.º 2
0
static inline float * get_float_points (xmlNode *node, const char *name, int *num_points)
{
    assert (node);
    assert (name);
    assert (num_points);

    char *attr = get_xml_attribute (node, name);

    if (attr) {
        int i = 0;
        float *points = NULL;
        LIST *nums_str = split (attr, " ,");

        if (!_al_list_is_empty (nums_str)) {
            *num_points = _al_list_size (nums_str) / 2;
            points = al_malloc (*num_points * 2 * sizeof (float));

            LIST_ITEM *item = _al_list_front (nums_str);
            while (item) {
                points[i++] = atof ((char *)_al_list_item_data (item));
                item = _al_list_next (nums_str, item);
            }
        }
        _al_list_destroy (nums_str);
        return points;
    }

    return NULL;
}
Exemplo n.º 3
0
 LOCAL_EXTERN int get_action_info_by_name(const gchar *key, const gchar **names, const gchar **values, gchar **name, UI_CALLBACK *info)
 {
	static const struct _action
	{
		const gchar	* name;				/**< Name of the action */
		GCallback	  callback;			/**< Callback for "activated/toggled" signal */
	}
	action[] =
	{
		// Offline actions
		{	"Connect",			G_CALLBACK(action_connect)			},
		{	"LoadScreenDump",	G_CALLBACK(action_loadscreendump)	},
		{ 	"SetHostname",		G_CALLBACK(action_sethostname)		},
		{	"TestPattern",		G_CALLBACK(lib3270_testpattern)		},

		// Online actions
		{	"Redraw",			G_CALLBACK(action_redraw)			},
		{	"SaveScreen",		G_CALLBACK(action_savescreen)		},
		{	"PrintScreen",		G_CALLBACK(action_printscreen)		},
		{	"DumpScreen",		G_CALLBACK(action_dumpscreen)		},
		{	"Disconnect",		G_CALLBACK(action_disconnect)		},

		// Select actions
		{	"SelectField",		G_CALLBACK(action_selectfield)		},

		{ 	"SelectRight",		G_CALLBACK(action_selectright)		},
		{ 	"SelectLeft",		G_CALLBACK(action_selectleft)		},
		{ 	"SelectUp",			G_CALLBACK(action_selectup)			},
		{ 	"SelectDown",		G_CALLBACK(action_selectdown)		},

		{	"SelectionRight",	G_CALLBACK(action_selectionright)	},
		{	"SelectionLeft",	G_CALLBACK(action_selectionleft)	},
		{	"SelectionUp",		G_CALLBACK(action_selectionup)		},
		{	"SelectionDown",	G_CALLBACK(action_selectiondown)	},

		// Cursor Movement
		{ 	"CursorRight",		G_CALLBACK(action_Right)			},
		{ 	"CursorLeft",		G_CALLBACK(action_Left)				},
		{ 	"CursorUp",			G_CALLBACK(action_Up)				},
		{ 	"CursorDown",		G_CALLBACK(action_Down)				},
		{ 	"Newline",			G_CALLBACK(action_Newline)			},

		{	"NextField",		G_CALLBACK(lib3270_tab)				},
		{	"PreviousField",	G_CALLBACK(lib3270_backtab)			},

		{	"kpadd",			G_CALLBACK(action_kpadd)			},
		{	"kpsubtract",		G_CALLBACK(action_kpsubtract)		},

		// Edit actions
		{	"PasteNext",		G_CALLBACK(action_pastenext)		},
		{	"PasteTextFile",	G_CALLBACK(action_pastetextfile)	},
		{	"Reselect",			G_CALLBACK(action_reselect)				},
		{	"SelectAll",		G_CALLBACK(action_selectall)		},
		{	"EraseInput",		G_CALLBACK(erase_input_action)		},
		{	"Clear",			G_CALLBACK(clear_action)			},

		{	"Reset",			G_CALLBACK(action_Reset)			},
		{	"Escape",			G_CALLBACK(action_Reset)			},

		// File-transfer actions
		{	"Download",			G_CALLBACK(action_download)			},
		{	"Upload",   		G_CALLBACK(action_upload)			},

		// Selection actions
		{	"Append",			G_CALLBACK(action_append)			},
		{	"Unselect",			G_CALLBACK(action_unselect)			},
		{	"Copy",				G_CALLBACK(action_copy)				},
		{	"CopyAsTable",		G_CALLBACK(action_copyastable)		},

		{	"CopyAsImage",		G_CALLBACK(action_copyasimage)		},

		{	"PrintSelected",	G_CALLBACK(action_printselected)	},
		{	"SaveSelected",		G_CALLBACK(action_saveselected)		},

		{	"PrintClipboard",	G_CALLBACK(action_printclipboard)	},
		{	"SaveClipboard",	G_CALLBACK(action_saveclipboard)	},
		{	"Paste",			G_CALLBACK(action_paste)			},

		{	"FileMenu",			NULL								},
		{	"FTMenu",			NULL								},
		{	"NetworkMenu",		NULL								},
		{	"HelpMenu",			NULL								},
		{	"EditMenu",			NULL								},
		{	"OptionsMenu",		NULL								},
		{	"SettingsMenu",		NULL								},
		{	"ScriptsMenu",		NULL								},
		{	"ViewMenu",			NULL								},
		{	"InputMethod",		NULL								},
		{	"ToolbarMenu",		NULL								},
		{	"DebugMenu",		NULL								},
		{	"FontSettings",		NULL								},
		{	"Preferences",		NULL								},
		{	"Network",			NULL								},
		{	"Properties",		NULL								},
		{	"ScreenSizes",		NULL								},
		{	"About",			G_CALLBACK(action_about)			},
		{	"Quit",				G_CALLBACK(action_quit)				},
		{	"SelectColors",		G_CALLBACK(action_selectcolors)		},

		{	"Save",				NULL								},

		{ 	"Return",			G_CALLBACK(action_enter)			},
		{ 	"Enter",			G_CALLBACK(action_enter)			},

		// Lib3270 calls
		{ "EraseEOF",			G_CALLBACK(lib3270_eraseeof)		},
		{ "EraseEOL",			G_CALLBACK(lib3270_eraseeol)		},
		{ "Home",				G_CALLBACK(lib3270_firstfield)		},
		{ "DeleteWord",			G_CALLBACK(lib3270_deleteword)		},
		{ "EraseField",			G_CALLBACK(lib3270_deletefield)		},
		{ "Delete",				G_CALLBACK(lib3270_delete)			},
		{ "Erase",				G_CALLBACK(lib3270_erase)			},
		{ "SysREQ",				G_CALLBACK(lib3270_sysreq)			},
		{ "Attn",				G_CALLBACK(lib3270_attn)			},
		{ "Break",				G_CALLBACK(lib3270_break)			},
		{ "Dup",				G_CALLBACK(lib3270_dup)				},

		{ "FirstField",			G_CALLBACK(lib3270_firstfield)		},

	};

	int			f;

	if(name)
		*name = NULL;

	memset(info,0,sizeof(UI_CALLBACK));

	if(!g_ascii_strcasecmp(key,"pfkey"))
	{
		info->type 		= UI_CALLBACK_TYPE_DEFAULT;
		info->label		= "pfkey";
		info->callback	= G_CALLBACK(action_pfkey);
		info->user_data = (gpointer) atoi(get_xml_attribute(names, values, "id"));
		if(name)
			*name = g_strdup_printf("pf%02d",(int) info->user_data);
		return 0;
	}

	if(!g_ascii_strcasecmp(key,"pakey"))
	{
		info->type 		= UI_CALLBACK_TYPE_DEFAULT;
		info->label		= "pakey";
		info->callback	= G_CALLBACK(action_pakey);
		info->user_data = (gpointer) atoi(get_xml_attribute(names, values, "id"));
		if(name)
			*name = g_strdup_printf("pa%02d",(int) info->user_data);
		return 0;
	}

	if(!g_ascii_strcasecmp(key,"toggle"))
	{
		// Check for lib3270 toggles
		const gchar *id = get_xml_attribute(names, values, "id");

		for(f=0;f<N_TOGGLES;f++)
		{
			if(!g_ascii_strcasecmp(id,get_toggle_name(f)))
			{
				info->type 		= UI_CALLBACK_TYPE_TOGGLE;
				info->callback	= G_CALLBACK(toggle_action);
				info->user_data = (gpointer) f;
				if(name)
					*name = g_strconcat("Toggle",get_toggle_name(f),NULL);
				return 0;
			}
		}

		// Check for GUI toggles
		for(f=0;f<G_N_ELEMENTS(gui_toggle_info);f++)
		{
			if(!g_ascii_strcasecmp(id,gui_toggle_info[f].name))
			{
				info->type 		= UI_CALLBACK_TYPE_TOGGLE;
				info->callback	= G_CALLBACK(toggle_gui);
				info->user_data = (gpointer) f;
				if(name)
					*name = g_strconcat("Toggle",gui_toggle_info[f].name,NULL);
				return 0;
			}
		}

		if(!g_ascii_strcasecmp(id,"gdkdebug"))
		{
			info->type 		= UI_CALLBACK_TYPE_TOGGLE;
			info->callback	= G_CALLBACK(action_ToggleGDKDebug);
			info->user_data = (gpointer) f;
			if(name)
				*name = g_strdup("ToggleGDKDebug");
			return 0;
		}

		return EINVAL;
	}

	if(!g_ascii_strcasecmp(key,"toggleset"))
	{
		const gchar *id = get_xml_attribute(names, values, "id");

		for(f=0;f<N_TOGGLES;f++)
		{
			if(!g_ascii_strcasecmp(id,get_toggle_name(f)))
			{
				info->type 		= UI_CALLBACK_TYPE_DEFAULT;
//				info->label		= toggle_info[f].set_label ? toggle_info[f].set_label : toggle_info[f].do_label;
				info->callback	= G_CALLBACK(toggle_set_action);
				info->user_data = (gpointer) f;
				if(name)
					*name = g_strconcat("ToggleSet",get_toggle_name(f),NULL);
				return 0;
			}
		}
		return EINVAL;
	}

	if(!g_ascii_strcasecmp(key,"togglereset"))
	{
		const gchar *id = get_xml_attribute(names, values, "id");

		for(f=0;f<N_TOGGLES;f++)
		{
			if(!g_ascii_strcasecmp(id,get_toggle_name(f)))
			{
				info->type 		= UI_CALLBACK_TYPE_DEFAULT;
//				info->label		= toggle_info[f].reset_label ? toggle_info[f].reset_label : toggle_info[f].do_label;
				info->callback	= G_CALLBACK(toggle_reset_action);
				info->user_data = (gpointer) f;
				if(name)
					*name = g_strconcat("ToggleReset",get_toggle_name(f),NULL);
				return 0;
			}
		}
		return EINVAL;
	}

	// Search internal actions
	for(f=0;f<G_N_ELEMENTS(action);f++)
	{
		if(!g_ascii_strcasecmp(key,action[f].name))
		{
			info->type = UI_CALLBACK_TYPE_DEFAULT;
//			info->label = action[f].label;
			info->callback = action[f].callback;
			return 0;
		}
	}

	// Search for plugin actions
	if(strchr(key,'.'))
	{
		gchar	*plugin_name = g_strdup(key);
		gchar	*entry_name	 = strchr(plugin_name,'.');
		GModule *plugin;

		*(entry_name++) = 0;

		plugin = get_plugin_by_name(plugin_name);
		if(plugin)
		{
			gpointer cbk;

			if(get_symbol_by_name(plugin,&cbk,"action_%s_activated",entry_name))
			{
				info->type 		= UI_CALLBACK_TYPE_DEFAULT;
				info->callback	= (GCallback) cbk;
				info->user_data	= (gpointer) topwindow;

			}
			else if(get_symbol_by_name(plugin,&cbk,"action_%s_toggled",entry_name))
			{
				info->type		= UI_CALLBACK_TYPE_TOGGLE;
				info->callback	= (GCallback) cbk;
				info->user_data	= (gpointer) topwindow;

			}
		}

		g_free(plugin_name);
		if(info->callback)
			return 0;
	}

	// Check if it's an external program action
	if(!g_ascii_strncasecmp(key,"call",4) && strlen(key) > 5 && g_ascii_isspace(*(key+4)))
	{

	}

	return ENOENT;
 }
Exemplo n.º 4
0
/*
 * Decodes map data from a <data> node
 */
static void decode_layer_data(xmlNode *data_node, ALLEGRO_MAP_LAYER *layer)
{
	char *str = g_strstrip((char *)data_node->children->content);
	int datalen = layer->width * layer->height;
	layer->data = (char *)calloc(datalen, sizeof(char));

	char *encoding = get_xml_attribute(data_node, "encoding");
	if (!encoding) {
		int i = 0;
		GSList *tiles = get_children_for_name(data_node, "tile");
		GSList *tile_item = tiles;
		while (tile_item) {
			xmlNode *tile_node = (xmlNode*)tile_item->data;
			tile_item = g_slist_next(tile_item);
			char *gid = get_xml_attribute(tile_node, "gid");
			layer->data[i] = atoi(gid);
			i++;
		}

		g_slist_free(tiles);
	}
	else if (!strcmp(encoding, "base64")) {
		// decompress
		gsize rawlen;
		unsigned char *rawdata = g_base64_decode(str, &rawlen);

		// check the compression
		char *compression = get_xml_attribute(data_node, "compression");
		if (compression != NULL) {
			if (strcmp(compression, "zlib") && strcmp(compression, "gzip")) {
				fprintf(stderr, "Error: unknown compression format '%s'\n", compression);
				return;
			}

			// set up files used by zlib to decompress the data
			ALLEGRO_PATH *srcpath;
			ALLEGRO_FILE *datasrc = al_make_temp_file("XXXXXX", &srcpath);
			al_fwrite(datasrc, rawdata, rawlen);
			al_fseek(datasrc, 0, ALLEGRO_SEEK_SET);
			//al_fclose(datasrc);
			//datasrc = al_fopen(al_path_cstr(srcpath, ALLEGRO_NATIVE_PATH_SEP), "rb");
			ALLEGRO_FILE *datadest = al_make_temp_file("XXXXXX", NULL);

			// decompress and print an error if it failed
			int status = inf(datasrc, datadest);
			if (status)
				zerr(status);

			// flush data and get the file length
			al_fflush(datadest);
			int len = al_fsize(datadest);

			// read in the file
			al_fseek(datadest, 0, ALLEGRO_SEEK_SET);
			char *data = (char *)calloc(len, sizeof(char));
			if (al_fread(datadest, data, len) != len) {
				fprintf(stderr, "Error: failed to read in map data\n");
				return;
			}

			// every tile id takes 4 bytes
			int i;
			for (i = 0; i<len; i += 4) {
				int tileid = 0;
				tileid |= data[i];
				tileid |= data[i+1] << 8;
				tileid |= data[i+2] << 16;
				tileid |= data[i+3] << 24;

				layer->data[i/4] = tileid;
			}
			/*	printf("layer dimensions: %dx%d, data length = %d\n",
						layer->width, layer->height, len); */

			al_destroy_path(srcpath);
			al_fclose(datasrc);
			al_fclose(datadest);
			al_free(data);
		}
		else {
			// TODO: verify that this still works
			int i;
			for (i = 0; i<rawlen; i += 4) {
				int tileid = 0;
				tileid |= rawdata[i];
				tileid |= rawdata[i+1] << 8;
				tileid |= rawdata[i+2] << 16;
				tileid |= rawdata[i+3] << 24;

				layer->data[i/4] = tileid;
			}
		}

		g_free(rawdata);
	}
	else if (!strcmp(encoding, "csv")) {
		int i;
		for (i = 0; i<datalen; i++) {
			char *id = strtok((i == 0 ? str : NULL), ",");
			layer->data[i] = atoi(id);
		}
	}
	else {
		fprintf(stderr, "Error: unknown encoding format '%s'\n", encoding);
	}
}
Exemplo n.º 5
0
/*
 * Parse a map file into an `ALLEGRO_MAP` struct. By default, relative values of `dir`
 * will be resolved relative to the path of the running executable. To change this,
 * call `al_find_resources_as(RELATIVE_TO_CWD);` first.
 */
ALLEGRO_MAP *al_open_map(const char *dir, const char *filename)
{
	char *cwd = al_get_current_directory();
	if (!cwd) {
		fprintf(stderr, "failed to get cwd; errno = %d", al_get_errno());
		return NULL;
	}

	// `resources` will point to either cwd or the location of the running executable,
	// depending on what was passed in for `rel`.
	ALLEGRO_PATH *resources;
	switch (resources_rel_to) {
		case RELATIVE_TO_EXE:
			resources = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
			break;

		case RELATIVE_TO_CWD:
			resources = al_create_path_for_directory(cwd);
			break;

		default:
			fprintf(stderr, "unexpected value for `resources_rel_to` in al_open_map(): %d\n",
					resources_rel_to);
			al_free(cwd);
			return NULL;
	}

	ALLEGRO_PATH *map_dir = al_create_path_for_directory(dir);

	// Change directory to <cwd>/dir if dir is relative, otherwise dir.
	ALLEGRO_PATH *new_path = (al_join_paths(resources, map_dir) ? resources : map_dir);
	const char *new_path_cstr = al_path_cstr(new_path, ALLEGRO_NATIVE_PATH_SEP);
	if (!al_change_directory(new_path_cstr)) {
		fprintf(stderr, "Error: failed to cd into `%s` in al_open_map().\n",
				new_path_cstr);

		al_destroy_path(resources);
		al_destroy_path(map_dir);
		al_free(cwd);
		return NULL;
	}

	al_destroy_path(resources);
	al_destroy_path(map_dir);

	// Read in the data file
	xmlDoc *doc = xmlReadFile(filename, NULL, 0);
	if (!doc) {
		fprintf(stderr, "Error: failed to parse map data: %s\n", filename);
		al_free(cwd);
		return NULL;
	}

	// Get the root element, <map>
	xmlNode *root = xmlDocGetRootElement(doc);

	// Get some basic info
	ALLEGRO_MAP *map = MALLOC(ALLEGRO_MAP);
	map->width = atoi(get_xml_attribute(root, "width"));
	map->height = atoi(get_xml_attribute(root, "height"));
	map->tile_width = atoi(get_xml_attribute(root, "tilewidth"));
	map->tile_height = atoi(get_xml_attribute(root, "tileheight"));
	map->orientation = g_strdup(get_xml_attribute(root, "orientation"));
	map->tile_layer_count = 0;
	map->object_layer_count = 0;

	// Get the tilesets
	GSList *tilesets = get_children_for_name(root, "tileset");
	map->tilesets = NULL;

	GSList *tileset_item = tilesets;
	while (tileset_item) {
		xmlNode *tileset_node = (xmlNode*)tileset_item->data;
		tileset_item = g_slist_next(tileset_item);

		ALLEGRO_MAP_TILESET *tileset = MALLOC(ALLEGRO_MAP_TILESET);
		tileset->firstgid = atoi(get_xml_attribute(tileset_node, "firstgid"));
		tileset->tilewidth = atoi(get_xml_attribute(tileset_node, "tilewidth"));
		tileset->tileheight = atoi(get_xml_attribute(tileset_node, "tileheight"));
		tileset->name = g_strdup(get_xml_attribute(tileset_node, "name"));

		// Get this tileset's image
		xmlNode *image_node = get_first_child_for_name(tileset_node, "image");
		tileset->width = atoi(get_xml_attribute(image_node, "width"));
		tileset->height = atoi(get_xml_attribute(image_node, "height"));
		tileset->source = g_strdup(get_xml_attribute(image_node, "source"));
		tileset->bitmap = al_load_bitmap(tileset->source);
		if (!tileset->bitmap) {
			fprintf(stderr, "Error: no bitmap available; did you load the image addon?\n");
		}

		// Get this tileset's tiles
		GSList *tiles = get_children_for_name(tileset_node, "tile");
		tileset->tiles = NULL;

		GSList *tile_item = tiles;
		while (tile_item) {
			xmlNode *tile_node = (xmlNode*)tile_item->data;
			tile_item = g_slist_next(tile_item);

			ALLEGRO_MAP_TILE *tile = MALLOC(ALLEGRO_MAP_TILE);
			tile->id = tileset->firstgid + atoi(get_xml_attribute(tile_node, "id"));
			tile->tileset = tileset;
			tile->bitmap = NULL;

			// Get this tile's properties
			tile->properties = parse_properties(tile_node);

			// TODO: add a destructor
			tileset->tiles = g_slist_prepend(tileset->tiles, tile);
		}

		g_slist_free(tiles);
		//tileset->tiles = g_slist_reverse(tileset->tiles);

		// TODO: add a destructor
		map->tilesets = g_slist_prepend(map->tilesets, tileset);
	}

	g_slist_free(tilesets);
	//map->tilesets = g_slist_reverse(map->tilesets);

	// Create the map's master list of tiles
	cache_tile_list(map);

	// Get the layers
	GSList *layers = get_children_for_either_name(root, "layer", "objectgroup");
	map->layers = NULL;

	GSList *layer_item = layers;
	while (layer_item) {
		xmlNode *layer_node = (xmlNode*)layer_item->data;
		layer_item = g_slist_next(layer_item);

		ALLEGRO_MAP_LAYER *layer = MALLOC(ALLEGRO_MAP_LAYER);
		layer->name = g_strdup(get_xml_attribute(layer_node, "name"));
		layer->properties = parse_properties(layer_node);

		char *layer_visible = get_xml_attribute(layer_node, "visible");
		layer->visible = (layer_visible != NULL ? atoi(layer_visible) : 1);

		char *layer_opacity = get_xml_attribute(layer_node, "opacity");
		layer->opacity = (layer_opacity != NULL ? atof(layer_opacity) : 1.0);

		if (!strcmp((const char*)layer_node->name, "layer")) {
			layer->type = TILE_LAYER;
			layer->width = atoi(get_xml_attribute(layer_node, "width"));
			layer->height = atoi(get_xml_attribute(layer_node, "height"));
			decode_layer_data(get_first_child_for_name(layer_node, "data"), layer);

			// Create any missing tile objects
			unsigned i, j;
			for (i = 0; i < layer->height; i++) {
				for (j = 0; j < layer->width; j++) {
					char id = al_get_single_tile_id(layer, j, i);

					if (id == 0) {
						continue;
					}

					ALLEGRO_MAP_TILE *tile = al_get_tile_for_id(map, id);
					if (!tile) {
						// wasn't defined in the map file, presumably because it had no properties
						tile = MALLOC(ALLEGRO_MAP_TILE);
						tile->id = id;
						tile->properties = g_hash_table_new(NULL, NULL);
						tile->tileset = NULL;
						tile->bitmap = NULL;

						// locate its tilemap
						GSList *tilesets = map->tilesets;
						ALLEGRO_MAP_TILESET *tileset_ref;
						while (tilesets) {
							ALLEGRO_MAP_TILESET *tileset = (ALLEGRO_MAP_TILESET*)tilesets->data;
							tilesets = g_slist_next(tilesets);
							if (tileset->firstgid <= id) {
								if (!tile->tileset || tileset->firstgid > tile->tileset->firstgid) {
									tileset_ref = tileset;
								}
							}

						}

						tile->tileset = tileset_ref;
						tileset_ref->tiles = g_slist_prepend(tileset_ref->tiles, tile);
						g_hash_table_insert(map->tiles, GINT_TO_POINTER(tile->id), tile);
					}

					// create this tile's bitmap if it hasn't been yet
					if (!tile->bitmap) {
						ALLEGRO_MAP_TILESET *tileset = tile->tileset;
						int id = tile->id - tileset->firstgid;
						int width = tileset->width / tileset->tilewidth;
						int x = (id % width) * tileset->tilewidth;
						int y = (id / width) * tileset->tileheight;
						if (tileset->bitmap) {
							tile->bitmap = al_create_sub_bitmap(
									tileset->bitmap,
									x, y,
									tileset->tilewidth,
									tileset->tileheight);
						}
					}
				}
			}
			map->tile_layer_count++;
			map->tile_layers = g_slist_prepend(map->tile_layers, layer);
		} else if (!strcmp((const char*)layer_node->name, "objectgroup")) {
			layer->type = OBJECT_LAYER;
			layer->objects = NULL;
			layer->object_count = 0;
			// TODO: color?
			GSList *objects = get_children_for_name(layer_node, "object");
			GSList *object_item = objects;
			while (object_item) {
				xmlNode *object_node = (xmlNode*)object_item->data;
				object_item = g_slist_next(object_item);

				ALLEGRO_MAP_OBJECT *object = MALLOC(ALLEGRO_MAP_OBJECT);
				object->layer = layer;
				object->name = g_strdup(get_xml_attribute(object_node, "name"));
				object->type = g_strdup(get_xml_attribute(object_node, "type"));
				object->x = atoi(get_xml_attribute(object_node, "x"));
				object->y = atoi(get_xml_attribute(object_node, "y"));
				object->bitmap = NULL;

				char *object_width = get_xml_attribute(object_node, "width");
				object->width = (object_width ? atoi(object_width) : 0);

				char *object_height = get_xml_attribute(object_node, "height");
				object->height = (object_height ? atoi(object_height) : 0);

				char *gid = get_xml_attribute(object_node, "gid");
				object->gid = (gid ? atoi(gid) : 0);

				char *object_visible = get_xml_attribute(object_node, "visible");
				object->visible = (object_visible ? atoi(object_visible) : 1);

				// Get the object's properties
				object->properties = parse_properties(object_node);
				layer->objects = g_slist_prepend(layer->objects, object);
				layer->object_count++;
			}
			map->object_layer_count++;
			map->object_layers = g_slist_prepend(map->object_layers, layer);
		} else {
			fprintf(stderr, "Error: found invalid layer node \"%s\"\n", layer_node->name);
			continue;
		}

		map->layers = g_slist_prepend(map->layers, layer);
	}

	g_slist_free(layers);

	// If any objects have a tile gid, cache their image
	layer_item = map->layers;
	while (layer_item) {
		ALLEGRO_MAP_LAYER *layer = (ALLEGRO_MAP_LAYER*)layer_item->data;
		layer_item = g_slist_next(layer_item);
		if (layer->type != OBJECT_LAYER) {
			continue;
		}

		GSList *objects = layer->objects;
		while (objects) {
			ALLEGRO_MAP_OBJECT *object = (ALLEGRO_MAP_OBJECT*)objects->data;
			objects = g_slist_next(objects);
			if (!object->gid) {
				continue;
			}

			object->bitmap = al_get_tile_for_id(map, object->gid)->bitmap;
			object->width = map->tile_width;
			object->height = map->tile_height;
		}
	}

	xmlFreeDoc(doc);
	al_change_directory(cwd);
	al_free(cwd);

	return map;
}
Exemplo n.º 6
0
TILED_MAP* tiled_load_tmx_file (const char *filename)
{
    TILED_MAP *map;
    xmlDoc *doc;
    xmlNode *root;
    char *str;

    if (!filename)
        return NULL;

    LIBXML_TEST_VERSION

    doc = xmlReadFile (filename, NULL, 0);
    if (!doc)
        return NULL;

    ALLEGRO_PATH *mapdir = al_create_path (filename);
    al_set_path_filename (mapdir, NULL);

    if (!al_change_directory (al_path_cstr (mapdir, ALLEGRO_NATIVE_PATH_SEP))) {
        printf ("Failed to change directory.");
    }

    al_destroy_path (mapdir);

    root = xmlDocGetRootElement (doc);

    map = al_malloc (sizeof (TILED_MAP));
    map->width = get_int (root, "width", 0);
    map->height = get_int (root, "height", 0);
    map->tile_width = get_int (root, "tilewidth", 0);
    map->tile_height = get_int (root, "tileheight", 0);
    map->strings = _al_list_create ();
    map->properties = get_properties (root, map);
    map->tiles = NULL;

    str = get_xml_attribute (root, "orientation");
    if (!strcmp (str, "orthogonal"))
        map->orientation = ORIENTATION_ORTHOGONAL;
    else if (!strcmp (str, "isometric"))
        map->orientation = ORIENTATION_ISOMETRIC;
    else if (!strcmp (str, "staggered"))
        map->orientation = ORIENTATION_STAGGERED;
    else
        map->orientation = ORIENTATION_UNKNOWN;

    // Tilesets
    LIST *tileset_nodes = get_children_for_name (root, 1, "tileset");
    map->tilesets = create_list (_al_list_size (tileset_nodes));

    LIST_ITEM *tileset_item = _al_list_front (tileset_nodes);
    while (tileset_item) {
        xmlNode *tileset_node = _al_list_item_data (tileset_item);
        TILED_TILESET *tileset = al_malloc (sizeof (TILED_TILESET));
        tileset->first_gid = get_int (tileset_node, "firstgid", 1);
        tileset->tile_width = get_int (tileset_node, "tilewidth", 0);
        tileset->tile_height = get_int (tileset_node, "tileheight", 0);
        tileset->name = get_str (tileset_node, "name");
        tileset->properties = get_properties (tileset_node, map);

        xmlNode *image_node = get_first_child_for_name (tileset_node, "image");
        tileset->image_width = get_int (image_node, "width", 0);
        tileset->image_height = get_int (image_node, "height", 0);
        tileset->image_source = get_str (image_node, "source");
        tileset->bitmap = al_load_bitmap (tileset->image_source);

        LIST *tile_nodes = get_children_for_name (tileset_node, 1, "tile");

        int tiles_per_row = tileset->image_width / tileset->tile_width;
        tileset->num_tiles = (tileset->image_width * tileset->image_height) /
                             (tileset->tile_width * tileset->tile_height);

        TILED_TILE *tile;
        tileset->tiles = al_malloc (tileset->num_tiles * sizeof (TILED_TILE));
        for (int i = 0; i < tileset->num_tiles; i++) {
            tile = &tileset->tiles[i];
            tile->id = i;
            tile->gid = i + tileset->first_gid;
            tile->tileset = tileset;
            tile->properties = NULL;

            int x = (i % tiles_per_row) * tileset->tile_width;
            int y = (i / tiles_per_row) * tileset->tile_height;
            tile->bitmap = al_create_sub_bitmap(tileset->bitmap, x, y,
                                                tileset->tile_width,
                                                tileset->tile_height);

            map->tiles = aa_insert (map->tiles, &tile->gid, tile, intcmp);
        }

		LIST_ITEM *tile_item = _al_list_front (tile_nodes);
		while (tile_item) {
			xmlNode *tile_node = (xmlNode*)_al_list_item_data (tile_item);
            int id = get_int (tile_node, "id", 0);

            tile = &tileset->tiles[id];
            tile->properties = get_properties (tile_node, map);

			tile_item = _al_list_next (tile_nodes, tile_item);
		}

		_al_list_destroy (tile_nodes);
		_al_list_push_back_ex (map->tilesets, tileset, dtor_tileset);
		tileset_item = _al_list_next (tileset_nodes, tileset_item);
    }

    _al_list_destroy (tileset_nodes);

    // Layers
    LIST *layer_nodes = get_children_for_name (root, 2, "layer", "objectgroup");
    map->layers = create_list (_al_list_size (layer_nodes));
    map->layers_fore = _al_list_create ();
    map->layers_back = _al_list_create ();

    LIST_ITEM *layer_item = _al_list_front (layer_nodes);
    while (layer_item) {
        xmlNode *layer_node = _al_list_item_data (layer_item);
        TILED_LAYER *layer = NULL;

        const char* type_str = (const char *)layer_node->name;
        if (!strcmp (type_str, "layer")) {
            layer = al_malloc (sizeof (TILED_LAYER_TILE));
            layer->type = LAYER_TYPE_TILE;
        }
        else if (!strcmp (type_str, "objectgroup")) {
            layer = al_malloc (sizeof (TILED_LAYER_OBJECT));
            layer->type = LAYER_TYPE_OBJECT;
        }

        layer->name = get_str (layer_node, "name");
        layer->width = get_int (layer_node, "width", 0);
        layer->height = get_int (layer_node, "height", 0);
        layer->opacity = get_float (layer_node, "opacity", 1.0);
        layer->map = map;
        layer->properties = get_properties (layer_node, map);

        char *order = aa_search (layer->properties, "order", charcmp);

        if (layer->type == LAYER_TYPE_TILE) {
            TILED_LAYER_TILE *tile_layer = (TILED_LAYER_TILE *)layer;
            tile_layer->tiles = al_malloc (layer->height * sizeof (TILED_TILE*));

            xmlNode *data_node = get_first_child_for_name (layer_node, "data");
            LIST *tile_nodes = get_children_for_name (data_node, 1, "tile");

            LIST_ITEM *tile_item = _al_list_front (tile_nodes);
            for (int j = 0; j < layer->height; j++) {
                tile_layer->tiles[j] = al_malloc (layer->width * sizeof (TILED_TILE*));
                for (int k = 0; k < layer->width; k++) {
                    xmlNode *tile_node = (xmlNode*)_al_list_item_data (tile_item);
                    int id = get_int (tile_node, "gid", 0);

                    if (id == 0) {
                        tile_layer->tiles[j][k] = NULL;
                    } else {
                        TILED_TILE *tile = aa_search (map->tiles, &id, intcmp);
                        tile_layer->tiles[j][k] = tile;
                    }

                    tile_item = _al_list_next (tile_nodes, tile_item);
                }
            }
            _al_list_destroy (tile_nodes);
        } else if (layer->type == LAYER_TYPE_OBJECT) {
            TILED_LAYER_OBJECT *object_layer = (TILED_LAYER_OBJECT *)layer;

            object_layer->objects = _al_list_create ();
            LIST *object_nodes = get_children_for_name (layer_node, 1, "object");

            LIST_ITEM *object_item = _al_list_front (object_nodes);
            while (object_item) {
                xmlNode *object_node = (xmlNode*)_al_list_item_data (object_item);
                TILED_OBJECT *cobj = NULL;

                int width = get_int (object_node, "width", 0);
                int gid = get_int (object_node, "gid", 0);
                int px = get_int (object_node, "x", 0);
                int py = get_int (object_node, "y", 0);

                if (width > 0) {
                    TILED_OBJECT_RECT *obj = al_malloc (sizeof (TILED_OBJECT_RECT));
                    obj->object.type = OBJECT_TYPE_RECT;
                    obj->width = width;
                    obj->height = get_int (object_node, "height", 0);

                    cobj = (TILED_OBJECT *) obj;
                } else if (gid > 0) {
                    TILED_OBJECT_TILE *obj = al_malloc (sizeof (TILED_OBJECT_TILE));
                    obj->object.type = OBJECT_TYPE_TILE;
                    obj->tile = aa_search (map->tiles, &gid, intcmp);

                    cobj = (TILED_OBJECT *) obj;
                } else {
                    TILED_OBJECT_GEOM *obj = al_malloc (sizeof (TILED_OBJECT_GEOM));
                    obj->object.type = OBJECT_TYPE_GEOM;

                    xmlNode *poly_node = get_first_child_for_name (object_node, "polyline");
                    if (poly_node) {
                        obj->points = get_float_points (poly_node, "points", &obj->num_points);
                        offset_points (px, py, obj->points, obj->num_points);
                    } else {
                        poly_node = get_first_child_for_name (object_node, "polygon");
                        if (poly_node)
                            obj->points = get_float_points (poly_node, "points", &obj->num_points);
                            offset_points (px, py, obj->points, obj->num_points);
                    }
                    cobj = (TILED_OBJECT *) obj;
                }

                cobj->x = px;
                cobj->y = py;
                cobj->name = get_str (object_node, "name");
                cobj->type_str = get_str (object_node, "type");
                cobj->properties = get_properties (object_node, map);

                _al_list_push_back_ex (object_layer->objects, cobj, dtor_object);
                object_item = _al_list_next (object_nodes, object_item);
            }
            _al_list_destroy (object_nodes);
        }

		layer_item = _al_list_next (layer_nodes, layer_item);
        _al_list_push_back_ex (map->layers, layer, dtor_layer);
        if (order && !strcmp (order, "fore"))
            _al_list_push_back (map->layers_fore, layer);
        else
            _al_list_push_back (map->layers_back, layer);
    }
    _al_list_destroy (layer_nodes);

    xmlFreeDoc (doc);
    xmlCleanupParser ();

    ALLEGRO_PATH *respath = al_get_standard_path (ALLEGRO_RESOURCES_PATH);
    al_change_directory (al_path_cstr (respath, ALLEGRO_NATIVE_PATH_SEP));
    al_destroy_path (respath);

    return map;
}
Exemplo n.º 7
0
static inline char *get_str (xmlNode *node, const char *name)
{
    char *str = get_xml_attribute (node, name);
    return str ? strdup (str) : NULL;
}
Exemplo n.º 8
0
static inline float get_float (xmlNode *node, const char *name, float def)
{
    char *attr = get_xml_attribute (node, name);
    return attr ? atof (attr) : def;
}
Exemplo n.º 9
0
static inline int get_int (xmlNode *node, const char *name, int def)
{
    char *attr = get_xml_attribute (node, name);
    return attr ? atoi (attr) : def;
}