#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;}
0 Пользователей и 1 Гость просматривают эту тему.