B Info Scenes Reading SceneObj (.sco) files

Users who are viewing this thread

Since Swyter asked on the bugtracker, I might as well post this. Can't really be bothered to convert it to a civil programming language though.
Code:
#include <stdio.h>
#include <stdlib.h>

#define SCO_MAGIC -717
#define GROUND_PAINT_MAGIC -11873882
#define GROUND_PAINT_ELEVATION_MAGIC -7793
#define GROUND_PAINT_LEVELING_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_LEVELING_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;
}
Yes, it's full of bad coding practices. Deal with it. :cool:
 
A matrix is basically the world that all the models are placed in.  Think of it like the boundaries.  Otherwise, you'd have nothing since the space (sizewise) is limitless.  That's probably what the movie draws it's name from. 
 
cmpxchg8b said:
Since Madoc PMed me, I might as well post this. Can't really be bothered to convert it to a civil programming language though.
Yes, it's full of bad coding practices. Deal with it. :cool:
Fixed  :razz:

Thanks. I'm going to enjoy working on a Scene editor! You wouldn't have any insights on terrain generation would you?
 
MadocComadrin said:
You wouldn't have any insights on terrain generation would you?
Yeah, I do: don't even bother, the complexity on that thing is off the scale. :???:
If you want to do it anyway, and you still haven't looked at it, here's the terrain keys format:
Code:
value			key no.			shift			num bits

seed_1			0			0			31
seed_2			1			0			31
deep_water	 	1			31			1
seed_3			2			0			31
size_x			3			0			10
size_y			3			10			10
shade_occluded 		3			30			1
place_river 		3			31			1
valley			4			0			7
hill_height		4			7			7
ruggedness		4			14			7
vegetation		4			21			7
region_type		4			28			4
region_detail		5			0			2
disable_grass		5			2			2
 
Thank you, everything documented over here:
Code:
http://mbmodwiki.ollclan.eu/SceneObj

Feel free to edit or enhance it.
The hard part is done.

PS: Didn't saw this topic until today. Ty again.
 
Back
Top Bottom