Всадники Кальрадии
		Модификации => Обмен опытом: Mount&Blade => Обмен опытом (в помощь мододелу) => Инструментарий => Тема начата: Janycz от 26 Марта, 2013, 12:34
		
			
			- 
				Автор: cmpxchg8b
Оригинал: http://mbmodwiki.ollclan.eu/SceneObj (http://mbmodwiki.ollclan.eu/SceneObj)
Это сам парсер, он написан на стандартном C (но я не знаю зачем он вообще нужен):
#include <stdio.h>
#include <stdlib.h>
 
#define SCO_MAGIC -717
#define GROUND_PAINT_MAGIC -11873882
#define GROUND_PAINT_ELEVATION_MAGIC -7793
#define GROUND_PAINT_COLOR_MAGIC -12565
 
typedef struct vector
{
	float x;
	float y;
	float z;
} vector_t;
 
typedef struct matrix
{
	vector_t v0;
	vector_t v1;
	vector_t v2;
	vector_t o;
} matrix_t;
 
typedef struct ground_paint_layer
{
	char *ground_spec_id;
	int ground_spec_no;
	float *cells;
} ground_paint_layer_t;
 
typedef struct ground_paint
{
	int size_x;
	int size_y;
	int num_layers;
	ground_paint_layer_t *layers;
} ground_paint_t;
 
typedef struct ai_mesh_vertex
{
	vector_t position;
} ai_mesh_vertex_t;
 
typedef struct ai_mesh_edge
{
	int start_vertex;
	int end_vertex;
} ai_mesh_edge_t;
 
typedef struct ai_mesh_face
{
	int num_vertices;
	int vertices[4];
	int edges[4];
	int unknown;
} ai_mesh_face_t;
 
typedef struct ai_mesh
{
	int num_vertices;
	int num_edges;
	int num_faces;
	ai_mesh_vertex_t *vertices;
	ai_mesh_edge_t *edges;
	ai_mesh_face_t *faces;
} ai_mesh_t;
 
typedef struct mission_object
{
	char *id;
	int meta_type; // 0 = scene prop, 1 = entry point, 2 = scene item, 4 = flora, 5 = passage
	int sub_kind_no;
	int variation_id;
	int variation_id_2;
	matrix_t position;
	vector_t scale;
} mission_object_t;
 
typedef struct sco_file
{
	int version;
	int num_mission_objects;
	mission_object_t *mission_objects;
	ai_mesh_t *ai_mesh;
	ground_paint_t *ground_paint;
} sco_file_t;
 
void read(FILE *file, size_t size, void *dest)
{
	if (dest)
		fread(dest, size, 1, file);
}
 
void read_int(FILE *file, int *dest)
{
	read(file, 4, dest);
}
 
void read_char(FILE *file, char *dest)
{
	read(file, 1, dest);
}
 
void read_float(FILE *file, float *dest)
{
	read(file, 4, dest);
}
 
void read_string(FILE *file, char **dest)
{
	int length;
 
	read_int(file, &length);
	*dest = malloc(length + 1);
	read(file, length, *dest);
	(*dest)[length] = '\0';
}
 
void read_vector(FILE *file, vector_t *dest)
{
	read_float(file, &dest->x);
	read_float(file, &dest->y);
	read_float(file, &dest->z);
}
 
void read_matrix(FILE *file, matrix_t *dest)
{
	read_vector(file, &dest->v0);
	read_vector(file, &dest->v1);
	read_vector(file, &dest->v2);
	read_vector(file, &dest->o);
}
 
int main(int argc, char **argv)
{
	if (argc < 2)
	{
		printf("Usage: %s filename\n", argv[0]);
		return EXIT_FAILURE;
	}
 
	FILE *file = fopen(argv[1], "rb");
 
	if (!file)
	{
		printf("ERROR: file %s not found\n", argv[1]);
		return EXIT_FAILURE;
	}
 
	fseek(file, 0, SEEK_END);
 
	long file_size = ftell(file);
 
	fseek(file, 0, SEEK_SET);
 
	printf("Reading %s\n", argv[1]);
 
	sco_file_t sco_file;
	int magic;
 
	read_int(file, &magic);
 
	if (magic == SCO_MAGIC)
	{
		read_int(file, &sco_file.version);
		read_int(file, &sco_file.num_mission_objects);
	}
	else
	{
		sco_file.version = 0;
		sco_file.num_mission_objects = magic;
	}
 
	printf("SCO file version: %d\n", sco_file.version);
	printf("Mission object count: %d\n", sco_file.num_mission_objects);
 
	sco_file.mission_objects = malloc(sco_file.num_mission_objects * sizeof(mission_object_t));
 
	for (int i = 0; i < sco_file.num_mission_objects; ++i)
	{
		read_int(file, &sco_file.mission_objects[i].meta_type);
		read_int(file, &sco_file.mission_objects[i].sub_kind_no);
		fseek(file, 4, SEEK_CUR); // unused
		read_matrix(file, &sco_file.mission_objects[i].position);
		read_string(file, &sco_file.mission_objects[i].id);
		read_int(file, &sco_file.mission_objects[i].variation_id);
 
		if (sco_file.version >= 2)
			read_int(file, &sco_file.mission_objects[i].variation_id_2);
		else
			sco_file.mission_objects[i].variation_id_2 = 0;
 
		if (sco_file.version >= 3)
			read_vector(file, &sco_file.mission_objects[i].scale);
		else
		{
			sco_file.mission_objects[i].scale.x = 1.0f;
			sco_file.mission_objects[i].scale.y = 1.0f;
			sco_file.mission_objects[i].scale.z = 1.0f;
		}
	}
 
	if (sco_file.version >= 4)
	{
		int ai_mesh_size;
 
		read_int(file, &ai_mesh_size);
 
		long start_pos = ftell(file);
 
		sco_file.ai_mesh = malloc(sizeof(ai_mesh_t));
 
		read_int(file, &sco_file.ai_mesh->num_vertices);
		sco_file.ai_mesh->vertices = malloc(sco_file.ai_mesh->num_vertices * sizeof(ai_mesh_vertex_t));
 
		printf("AI mesh vertex count: %d\n", sco_file.ai_mesh->num_vertices);
 
		for (int i = 0; i < sco_file.ai_mesh->num_vertices; ++i)
		{
			read_vector(file, &sco_file.ai_mesh->vertices[i].position);
		}
 
		read_int(file, &sco_file.ai_mesh->num_edges);
		sco_file.ai_mesh->edges = malloc(sco_file.ai_mesh->num_edges * sizeof(ai_mesh_edge_t));
 
		printf("AI mesh edge count: %d\n", sco_file.ai_mesh->num_edges);
 
		for (int i = 0; i < sco_file.ai_mesh->num_edges; ++i)
		{
			fseek(file, 4, SEEK_CUR); // unused
			read_int(file, &sco_file.ai_mesh->edges[i].start_vertex);
			read_int(file, &sco_file.ai_mesh->edges[i].end_vertex);
			fseek(file, 8, SEEK_CUR); // unused
		}
 
		read_int(file, &sco_file.ai_mesh->num_faces);
		sco_file.ai_mesh->faces = malloc(sco_file.ai_mesh->num_faces * sizeof(ai_mesh_face_t));
 
		printf("AI mesh face count: %d\n", sco_file.ai_mesh->num_faces);
 
		for (int i = 0; i < sco_file.ai_mesh->num_faces; ++i)
		{
			read_int(file, &sco_file.ai_mesh->faces[i].num_vertices);
 
			for (int j = 0; j < sco_file.ai_mesh->faces[i].num_vertices; ++j)
			{
				read_int(file, &sco_file.ai_mesh->faces[i].vertices[j]);
			}
 
			for (int j = 0; j < sco_file.ai_mesh->faces[i].num_vertices; ++j)
			{
				read_int(file, &sco_file.ai_mesh->faces[i].edges[j]);
			}
 
			read_int(file, &sco_file.ai_mesh->faces[i].unknown);
 
			if (sco_file.ai_mesh->faces[i].unknown > 0)
				read_int(file, &sco_file.ai_mesh->faces[i].unknown);
			else
				sco_file.ai_mesh->faces[i].unknown = 0;
		}
 
		long end_pos = ftell(file);
 
		if (end_pos - start_pos != ai_mesh_size)
		{
			printf("ERROR: failed to read AI mesh\n");
			fclose(file);
			return EXIT_FAILURE;
		}
	}
	else
		sco_file.ai_mesh = NULL;
 
	if (ftell(file) != file_size)
	{
		read_int(file, &magic);
 
		if (magic != GROUND_PAINT_MAGIC)
		{
			printf("ERROR: wrong ground paint magic\n");
			fclose(file);
			return EXIT_FAILURE;
		}
 
		int ground_paint_size;
 
		read_int(file, &ground_paint_size);
 
		long start_pos = ftell(file);
 
		sco_file.ground_paint = malloc(sizeof(ground_paint_t));
 
		read_int(file, &sco_file.ground_paint->num_layers);
		sco_file.ground_paint->layers = malloc(sco_file.ground_paint->num_layers * sizeof(ground_paint_layer_t));
 
		printf("Ground paint layer count: %d\n", sco_file.ground_paint->num_layers);
 
		read_int(file, &sco_file.ground_paint->size_x);
		read_int(file, &sco_file.ground_paint->size_y);
 
		for (int i = 0; i < sco_file.ground_paint->num_layers; ++i)
		{
			read_int(file, &sco_file.ground_paint->layers[i].ground_spec_no);
			read_string(file, &sco_file.ground_paint->layers[i].ground_spec_id);
 
			int has_cells;
 
			read_int(file, &has_cells);
 
			if (has_cells)
			{
				sco_file.ground_paint->layers[i].cells = malloc(sco_file.ground_paint->size_x * sco_file.ground_paint->size_y * sizeof(float));
 
				int empty = 1;
				int count;
 
				read_int(file, &count);
 
				for (int y = 0; y < sco_file.ground_paint->size_y; ++y)
				{
					for (int x = 0; x < sco_file.ground_paint->size_x; ++x)
					{
						if (!count)
						{
							empty = !empty;
							read_int(file, &count);
						}
 
						count--;
 
						float value;
 
						if (empty)
						{
							if (sco_file.ground_paint->layers[i].ground_spec_no == GROUND_PAINT_COLOR_MAGIC)
								value = -1.0f;
							else
								value = 0.0f;
						}
						else
						{
							if (sco_file.ground_paint->layers[i].ground_spec_no < 0)
								read_float(file, &value);
							else
							{
								char cvalue;
 
								read_char(file, &cvalue);
								value = cvalue / 255.0f;
							}
						}
 
						sco_file.ground_paint->layers[i].cells[x * sco_file.ground_paint->size_y + y] = value;
					}
				}
			}
			else
				sco_file.ground_paint->layers[i].cells = NULL;
		}
 
		long end_pos = ftell(file);
 
		if (end_pos - start_pos != ground_paint_size)
		{
			printf("ERROR: failed to read ground paint\n");
			fclose(file);
			return EXIT_FAILURE;
		}
	}
	else
		sco_file.ground_paint = NULL;
 
	fclose(file);
	return EXIT_SUCCESS;
}