diff options
Diffstat (limited to 'src')
| -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");  }  | 
