diff options
Diffstat (limited to 'src/mapcat.c')
-rw-r--r-- | src/mapcat.c | 334 |
1 files changed, 182 insertions, 152 deletions
diff --git a/src/mapcat.c b/src/mapcat.c index 6420cf5..d9bff86 100644 --- a/src/mapcat.c +++ b/src/mapcat.c @@ -19,34 +19,56 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA #define DEBUG #include "common.h" -typedef struct { - float def[9]; - char *shader; - float texmap[8]; - elist_header_t list; -} brush_face_t; - -typedef struct { - brush_face_t *faces; - elist_header_t list; -} brush_t; - -typedef struct { - char *key; - char *value; - elist_header_t list; -} entity_key_t; - -typedef struct { - char *classname; - brush_t *brushes; - entity_key_t *keys; - - elist_header_t list; -} entity_t; - -entity_t *worldspawn; -entity_t *entities; +// +// freeing +// + +static void free_entity_keys(entity_t *entity) +{ + entity_key_t *key, *next; + + for (key = entity->keys; key; key = next) { + next = elist_next(key, list); + + free(key->key); + free(key->value); + free(key); + } +} + +static void free_brush(brush_t *brush) +{ + brush_face_t *face, *face_next; + + for (face = brush->faces; face; face = face_next) { + face_next = elist_next(face, list); + + free(face->shader); + free(face); + } + + free(brush); +} + +// this frees an entity_t and its children +static void free_entity(entity_t *entity) +{ + brush_t *brush, *next; + + free_entity_keys(entity); + free(entity->classname); + + for (brush = entity->brushes; brush; brush = next) { + next = elist_next(brush, list); + free_brush(brush); + } + + free(entity); +} + +// +// reading +// static int read_entity_key(lexer_state_t *ls, entity_t *entity) { @@ -174,79 +196,18 @@ static int read_brush_faces(lexer_state_t *ls, brush_t *brush) return 0; } -static void free_entity_keys(entity_t *entity) -{ - entity_key_t *key, *next; - - for (key = entity->keys; key; key = next) { - next = elist_next(key, list); - - free(key->key); - free(key->value); - free(key); - } -} - -static void free_brush(brush_t *brush) -{ - brush_face_t *face, *face_next; - - for (face = brush->faces; face; face = face_next) { - face_next = elist_next(face, list); - - free(face->shader); - free(face); - } - - free(brush); -} - -// this frees an entity_t and its children -// note: this function does NOT unlink the entity from the global list -static void free_entity(entity_t *entity) -{ - brush_t *brush, *next; - - free_entity_keys(entity); - free(entity->classname); - - for (brush = entity->brushes; brush; brush = next) { - next = elist_next(brush, list); - free_brush(brush); - } - - free(entity); -} - -static void merge_into_worldspawn(entity_t *entity) -{ - // the first worldspawn becomes the output's worldspawn. - // other worldspawn's brushes are appended to it - if (!worldspawn) { - worldspawn = entity; - return; - } - - // keep only the original key-value pairs - free_entity_keys(entity); - - elist_append_list(worldspawn->brushes, entity->brushes, list); - - free(entity); -} - static bool brush_discard(brush_t *brush) { brush_face_t *face; elist_for(face, brush->faces, list) - if (!strcmp(face->shader, "mapcat_discard")) + if (!strcmp(face->shader, MAPCAT_DISCARD_SHADER)) return true; return false; } -static int read_entity(lexer_state_t *ls) +static int read_entity(lexer_state_t *ls, map_t *map) { entity_t *entity; @@ -311,18 +272,26 @@ static int read_entity(lexer_state_t *ls) goto error; } - if (brush_discard(brush)) + if (brush_discard(brush)) { free_brush(brush); - else + map->num_discarded_brushes++; + } else { elist_append(&entity->brushes, brush, list); + map->num_brushes++; + } } no_brushes: + if (!strcmp(entity->classname, "worldspawn")) { + if (map->worldspawn) { + lexer_perror(ls, "this entity is a worldspawn, but a " + "worldspawn was already read earlier"); + goto error; + } - if (entity->classname && !strcmp(entity->classname, "worldspawn")) - merge_into_worldspawn(entity); - else - elist_append(&entities, entity, list); + map->worldspawn = entity; + } else + elist_append(&map->entities, entity, list); return 0; error: @@ -330,45 +299,15 @@ error: return 1; } +// +// writing +// -int mapcat_load(const char *path) -{ - int rv = 1; - lexer_state_t lexer; - vstr_t token; - - vstr_init(&token); - - if (lexer_open(&lexer, path, &token)) { - perror(path); - return 1; - } - - while (1) { - int ret; - - ret = lexer_assert_or_eof(&lexer, "{", - "the beginning of an entity"); - if (ret == -1) - break; - if (ret > 0) - goto out; - - if (read_entity(&lexer)) - goto out; - } - - rv = 0; -out: - vstr_free(&token); - return rv; -} - -static int write_brush(FILE *fp, brush_t *brush) +static int write_brush(FILE *fp, const brush_t *brush) { - brush_face_t *face; + const brush_face_t *face; - elist_for(face, brush->faces, list) { + elist_cfor(face, brush->faces, list) { size_t i; for (i = 0; i < 9; i += 3) { @@ -397,18 +336,19 @@ static int write_brush(FILE *fp, brush_t *brush) return 0; } -static int write_entity(FILE *fp, entity_t *entity) +static int write_entity(FILE *fp, const entity_t *entity) { - entity_key_t *key; - brush_t *brush; + const entity_key_t *key; + const brush_t *brush; size_t brush_counter = 0; - fprintf(fp, "\"classname\" \"%s\"\n", entity->classname); + if (entity->classname) + fprintf(fp, "\"classname\" \"%s\"\n", entity->classname); - elist_for(key, entity->keys, list) + elist_cfor(key, entity->keys, list) fprintf(fp, "\"%s\" \"%s\"\n", key->key, key->value); - elist_for(brush, entity->brushes, list) { + elist_cfor(brush, entity->brushes, list) { fprintf(fp, "// brush %zu\n{\n", brush_counter); write_brush(fp, brush); fprintf(fp, "}\n"); @@ -421,11 +361,70 @@ static int write_entity(FILE *fp, entity_t *entity) return 0; } -int mapcat_save(const char *path) +// +// entry points +// + +void map_init(map_t *map) +{ + memset(map, 0, sizeof(*map)); +} + +void map_free(map_t *map) +{ + entity_t *entity, *next; + + if (map->worldspawn) + free_entity(map->worldspawn); + + for (entity = map->entities; entity; entity = next) { + next = elist_next(entity, list); + free_entity(entity); + } +} + +int map_read(map_t *map, const char *path) +{ + int rv = 1; + lexer_state_t lexer; + vstr_t token; + + vstr_init(&token); + + if (lexer_open(&lexer, path, &token)) { + perror(path); + return 1; + } + + while (1) { + int ret; + + ret = lexer_assert_or_eof(&lexer, "{", + "the beginning of an entity"); + if (ret == -1) + break; + if (ret > 0) + goto out; + + if (read_entity(&lexer, map)) + goto out; + } + + rv = 0; +out: + vstr_free(&token); + + if (rv) + map_free(map); + + return rv; +} + +int map_write(const map_t *map, const char *path) { int rv = 1; FILE *fp; - entity_t *entity; + const entity_t *entity; size_t entity_counter = 1; // worldspawn is #0 fp = fopen(path, "w"); @@ -434,16 +433,16 @@ int mapcat_save(const char *path) goto out; } - if (!worldspawn) { + if (!map->worldspawn) { fprintf(stderr, "error: worldspawn is missing\n"); goto out; } fprintf(fp, "// entity 0\n{\n"); - write_entity(fp, worldspawn); + write_entity(fp, map->worldspawn); fprintf(fp, "}\n"); - elist_for(entity, entities, list) { + elist_cfor(entity, map->entities, list) { fprintf(fp, "// entity %zu\n{\n", entity_counter); if (write_entity(fp, entity)) { @@ -469,15 +468,46 @@ out: return rv; } -void mapcat_free(void) +//RETURN VALUE +// always 0 (this function cannot fail (yet)) +// slave is left in invalid state after this function returns, do not use it +int map_merge(map_t *master, map_t *slave) { - entity_t *entity, *next; + if (!master->worldspawn) { + // the first worldspawn is kept intact + master->worldspawn = slave->worldspawn; + } else if (slave->worldspawn) { + // worldspawns of subsequent maps are discarded, except their + // brushes, which are appended to the master's worldspawn + elist_append_list(&master->worldspawn->brushes, + slave->worldspawn->brushes, list); + + free_entity_keys(slave->worldspawn); + free(slave->worldspawn->classname); + free(slave->worldspawn); + } - if (worldspawn) - free_entity(worldspawn); + // entities are always kept intact + elist_append_list(&master->entities, slave->entities, list); - for (entity = entities; entity; entity = next) { - next = elist_next(entity, list); - free_entity(entity); - } + master->num_entities += slave->num_entities; + master->num_discarded_entities += slave->num_discarded_entities; + master->num_brushes += slave->num_brushes; + master->num_discarded_brushes += slave->num_discarded_brushes; + + return 0; +} + +void map_print_stats(const char *path, const map_t *map) +{ + size_t ents_with_worldspawn; + + ents_with_worldspawn = map->num_entities + (map->worldspawn ? 1 : 0); + + printf("%s: ", path); + printf("%zu entit%s (%zu discarded), %zu brush%s (%zu discarded)\n", + ents_with_worldspawn, (ents_with_worldspawn == 1 ? "y" : "ies"), + map->num_discarded_entities, + map->num_brushes, (map->num_brushes == 1 ? "" : "es"), + map->num_discarded_brushes); } |