diff options
-rw-r--r-- | src/common.c | 9 | ||||
-rw-r--r-- | src/common.h | 9 | ||||
-rw-r--r-- | src/mapcat.c | 190 |
3 files changed, 193 insertions, 15 deletions
diff --git a/src/common.c b/src/common.c index 1c057a2..14e66ed 100644 --- a/src/common.c +++ b/src/common.c @@ -98,3 +98,12 @@ float vstr_atof(vstr_t *vstr) vstr_termz(vstr); return atof(vstr->data); } + +size_t vstr_atoz(vstr_t *vstr) +{ + if (!vstr->size) + return 0; + + vstr_termz(vstr); + return strtoull(vstr->data, NULL, 10); +} diff --git a/src/common.h b/src/common.h index 0003d43..b005e2b 100644 --- a/src/common.h +++ b/src/common.h @@ -50,6 +50,7 @@ int vstr_cmp(vstr_t *vstr, const char *str); char *vstr_strdup(vstr_t *vstr); void vstr_termz(vstr_t *vstr); float vstr_atof(vstr_t *vstr); +size_t vstr_atoz(vstr_t *vstr); // lexer.c @@ -92,7 +93,14 @@ typedef struct { } brush_face_t; typedef struct { + size_t xres, yres; + float *def; // (xres * yres * 5) floats + char *shader; +} brush_patch_t; + +typedef struct { brush_face_t *faces; + brush_patch_t *patch; elist_header_t list; } brush_t; @@ -117,6 +125,7 @@ typedef struct { // note: num_entities doesn't include the worldspawn size_t num_entities, num_discarded_entities; size_t num_brushes, num_discarded_brushes; + size_t num_patches, num_discarded_patches; } map_t; void map_init(map_t *map); diff --git a/src/mapcat.c b/src/mapcat.c index 0039608..b33a694 100644 --- a/src/mapcat.c +++ b/src/mapcat.c @@ -40,11 +40,17 @@ 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); + if (brush->patch) { + free(brush->patch->shader); + free(brush->patch->def); + free(brush->patch); + } else { + for (face = brush->faces; face; face = face_next) { + face_next = elist_next(face, list); + + free(face->shader); + free(face); + } } free(brush); @@ -176,13 +182,109 @@ static int read_brush_face(lexer_state_t *ls, brush_t *brush) return 0; } +static int read_brush_patch_points(lexer_state_t *ls, brush_patch_t *patch) +{ + size_t y, x; + + for (y = 0; y < patch->yres; y++) { + if (lexer_assert(ls, "(", "the beginning of a patch row")) + return 1; + + for (x = 0; x < patch->xres; x++) { + size_t offs; + + if (lexer_assert(ls, "(", "the beginning of a patch cell")) + return 1; + + offs = (y * patch->xres + x) * 5; + if (lexer_get_floats(ls, patch->def + offs, 5)) + return 1; + + if (lexer_assert(ls, ")", "the end of a patch cell")) + return 1; + } + + if (lexer_assert(ls, ")", "the end of a patch row")) + return 1; + } + + return 0; +} + +static int read_brush_patch(lexer_state_t *ls, brush_t *brush) +{ + if (lexer_assert(ls, "{", NULL)) + return 1; + + brush->patch = malloc(sizeof(brush_patch_t)); + if (!brush->patch) { + lexer_perror(ls, "out of memory\n"); + return 1; + } + + memset(brush->patch, 0, sizeof(*brush->patch)); + + if (lexer_get_token(ls)) { + lexer_perror_eg(ls, "the shader name"); + return 1; + } + + brush->patch->shader = vstr_strdup(ls->token); + if (!brush->patch->shader) { + lexer_perror_eg(ls, "out of memory\n"); + return 1; + } + + if (lexer_assert(ls, "(", NULL)) + return 1; + + if (lexer_get_token(ls)) { + lexer_perror_eg(ls, "this patch's Y resolution"); + return 1; + } + brush->patch->yres = vstr_atoz(ls->token); + + if (lexer_get_token(ls)) { + lexer_perror_eg(ls, "this patch's X resolution"); + return 1; + } + brush->patch->xres = vstr_atoz(ls->token); + + brush->patch->def = malloc(sizeof(float) * brush->patch->xres * + brush->patch->yres * 5); + if (!brush->patch->def) { + lexer_perror(ls, "out of memory\n"); + return 1; + } + + if (lexer_assert(ls, "0", NULL) || + lexer_assert(ls, "0", NULL) || + lexer_assert(ls, "0", NULL) || + lexer_assert(ls, ")", "the end of this patch's header") || + lexer_assert(ls, "(", "the beginning of this patch's points")) + return 1; + + if (read_brush_patch_points(ls, brush->patch)) + return 1; + + if (lexer_assert(ls, ")", "the end of this patch")) + return 1; + + if (lexer_assert(ls, "}", "the end of this brush")) + return 1; + + return 0; +} + static int read_brush_faces(lexer_state_t *ls, brush_t *brush) { while (1) { if (lexer_get_token(ls)) { - lexer_perror_eg(ls, "the beginning of a brush face " - " ('(') or the end of this brush" - " ('}')"); + bad_token: + lexer_perror_eg(ls, "the beginning of a brush face, " + " \"(\", the end of this brush" + " \"}\" or the beginning of a" + " patch \"patchDef2\""); return 1; } @@ -191,6 +293,11 @@ static int read_brush_faces(lexer_state_t *ls, brush_t *brush) return 1; } else if (!vstr_cmp(ls->token, "}")) break; + else if (!vstr_cmp(ls->token, "patchDef2")) { + if (read_brush_patch(ls, brush)) + return 1; + } else + goto bad_token; } return 0; @@ -200,6 +307,9 @@ static bool brush_discard(brush_t *brush) { brush_face_t *face; + if (brush->patch) + return !strcmp(brush->patch->shader, MAPCAT_DISCARD_SHADER); + elist_for(face, brush->faces, list) if (!strcmp(face->shader, MAPCAT_DISCARD_SHADER)) return true; @@ -273,11 +383,19 @@ static int read_entity(lexer_state_t *ls, map_t *map) } if (brush_discard(brush)) { + if (brush->patch) + map->num_discarded_patches++; + else + map->num_discarded_brushes++; + free_brush(brush); - map->num_discarded_brushes++; } else { elist_append(&entity->brushes, brush, list); - map->num_brushes++; + + if (brush->patch) + map->num_patches++; + else + map->num_brushes++; } } @@ -303,10 +421,40 @@ error: // writing // +static int write_brush_patch(FILE *fp, const brush_patch_t *patch) +{ + size_t y, x, i; + + fprintf(fp, "patchDef2\n{\n%s\n( %zu %zu 0 0 0 )\n(\n", + patch->shader, patch->yres, patch->xres); + + for (y = 0; y < patch->yres; y++) { + fprintf(fp, "("); + + for (x = 0; x < patch->xres; x++) { + size_t offs = (y * patch->xres + x) * 5; + + fprintf(fp, " ("); + for (i = 0; i < 5; i++) + fprintf(fp, " %f", patch->def[offs + i]); + fprintf(fp, " )"); + } + + fprintf(fp, " )\n"); + } + + fprintf(fp, ")\n}\n"); + + return 0; +} + static int write_brush(FILE *fp, const brush_t *brush) { const brush_face_t *face; + if (brush->patch) + return write_brush_patch(fp, brush->patch); + elist_cfor(face, brush->faces, list) { size_t i; @@ -506,9 +654,21 @@ void map_print_stats(const char *path, const map_t *map) 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); + + printf("%zu entit%s", ents_with_worldspawn, + (ents_with_worldspawn == 1 ? "y" : "ies")); + if (map->num_discarded_entities) + printf(" (%zu discarded)", map->num_discarded_entities); + + printf(", %zu brush%s", map->num_brushes, + (map->num_brushes == 1 ? "" : "es")); + if (map->num_discarded_brushes) + printf(" (%zu discarded)", map->num_discarded_brushes); + + printf(", %zu patch%s", map->num_patches, + (map->num_patches == 1 ? "" : "es")); + if (map->num_discarded_patches) + printf(" (%zu discarded)", map->num_discarded_patches); + + printf("\n"); } |