/** * @file RSETerrain.c * @date 23/08/2022 * @author JackCarterSmith * @copyright GPL-v3.0 * @brief HMP terrain parser and export to Waveform OBJ format and grey-scale PNG heightmap. * */ #include #include #include #if defined(_WIN32) #include #else #include #include #endif #include "options.h" #include #include #include "terrain_export.h" /* * Internal functions declarations */ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS* opt_ptr); static void createSubDir(char *dirName); static unsigned short checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char* p_args[]); static void dispHelp(); /* * - MAIN - */ int main(int argc, char *argv[]) { T_PROG_OPTIONS _opts; unsigned char p; // Hello world! printf("\n*~[ Rogue Squadron Extractor (RSE) - RSPTerrainLib v%s ]~*\n", RSPTerrain_getVersion()); // Check for arguments if (argc < 2) { printf("\n[ERR] No input file/commands specified!\n"); dispHelp(); return RSPLIB_ERROR_ARGS_NULL; } // Create options for programs according to user's arguments. p = checkInputArgs(&_opts, argc, argv); if ( p == RSPLIB_ERROR_GENERIC ) return RSPLIB_SUCCESS; else if ( p != RSPLIB_SUCCESS ) return p; return mainProcess(argc, argv, &_opts); } /* * Private functions definition */ static unsigned int mainProcess(int args_cnt, char* args_value[], T_PROG_OPTIONS* p_opts) { unsigned short file_index; RSPTERRAIN_PARAMETERS libParams; T_RSPTERRAIN_HMP* hmpStruct = NULL; T_RSPTERRAIN_HEIGHTMAP* terrainHM = NULL; T_RSPTERRAIN_MESH* terrainMesh = NULL; libParams.raw = p_opts->raw & 0x7; libParams.negative = p_opts->negative_HM; // Invert it by default to correspond to in-game rendering libParams.invertZ = !p_opts->inverted_Z; // Invert it by default to correspond to in-game rendering // Manage multiple inputs files for ( file_index = p_opts->input_files_cnt; file_index < args_cnt; file_index++ ) { printf("\n=============================================\n[INFO] - Parsing file: %s ...\n", args_value[file_index]); // Allocate T_RSPTERRAIN_HMP structure to store extracted datas. hmpStruct = calloc(1, sizeof(T_RSPTERRAIN_HMP)); if (hmpStruct) { // Parse data from HMP file and put in T_RSPTERRAIN_HMP structure. if (RSPTerrain_processHMPFile(hmpStruct, args_value[file_index], libParams) != RSPLIB_SUCCESS) { printf("[ERR] Failed to parse datas from %s\n", args_value[file_index]); RSPTerrain_freeHMP(hmpStruct); free(hmpStruct); return RSPLIB_ERROR_PROCESS; } } else return RSPLIB_ERROR_MEMORY; // Create output folders structure. if (p_opts->output_dir) createSubDir(args_value[file_index]); // Allocate terrain full heighmap format terrainHM = calloc(1, sizeof(T_RSPTERRAIN_HEIGHTMAP)); if (terrainHM) { if (RSPTerrain_terrainToHeightmap(terrainHM, hmpStruct) == RSPLIB_SUCCESS) { // Export terrain as a PNG greyscale heightmap if (exportHeightmapPNG(terrainHM, args_value[file_index], p_opts) == RSPLIB_SUCCESS) printf("[INFO] Successfully exported heightmap to PNG format.\n"); else printf("[ERR] Failed to export heightmap to PNG format!\n"); } else { printf("[ERR] Failed to process tilesmap to heightmap!\n"); } RSPTerrain_freeHeightmap(terrainHM); } else { RSPTerrain_freeHMP(hmpStruct); free(hmpStruct); return RSPLIB_ERROR_MEMORY; } // Allocate mesh object for 3D terrain generation //#ifndef TEXTURE_MODULE TODO: Next version: detect presence of external library to manage texture handling... terrainMesh = calloc(1, sizeof(T_RSPTERRAIN_MESH)); if (terrainMesh) { if (RSPTerrain_terrainToMesh(terrainMesh, hmpStruct, TERRAIN_MESH_SCALE) == RSPLIB_SUCCESS) { // Export terrain as a blank OBJ terrain if (exportHeightmapOBJ(terrainMesh, args_value[file_index], p_opts) == RSPLIB_SUCCESS) printf("[INFO] Successfully exported terrain in OBJ format.\n"); else printf("[ERR] Failed to export terrain in OBJ format!\n"); } else { printf("[ERR] Failed to process tilesmap to mesh!\n"); } RSPTerrain_freeMesh(terrainMesh); } else { RSPTerrain_freeHMP(hmpStruct); free(hmpStruct); return RSPLIB_ERROR_MEMORY; } //#endif RSPTerrain_freeHMP(hmpStruct); free(hmpStruct); } return RSPLIB_SUCCESS; } static unsigned short checkInputArgs(T_PROG_OPTIONS* opt_ptr, int p_arg_nbr, char* p_args[]) { char test[256]; int i; // Set default options opt_ptr->raw = 0; opt_ptr->output_dir = 1; opt_ptr->export_mtl = 1; if (p_arg_nbr > 1) { for ( i = 1; i < p_arg_nbr; i++) { strcpy(test, p_args[i]); if (p_args[i][0] != '-') break; if (strcmp(p_args[i], "-h") == 0) { dispHelp(); return RSPLIB_ERROR_GENERIC; } else if (strcmp(p_args[i], "-v") == 0) { opt_ptr->verbose_mode = 1; printf("[OPTN] Verbose enabled.\n"); } else if (strcmp(p_args[i], "-vv") == 0) { opt_ptr->verbose_mode = 1; opt_ptr->debug_mode = 1; printf("[OPTN] Debug enabled.\n"); } else if (strcmp(p_args[i], "-vvv") == 0) { opt_ptr->verbose_mode = 1; opt_ptr->debug_mode = 1; opt_ptr->god_mode = 1; printf("[OPTN] God damn it!\n"); } else if (strcmp(p_args[i], "-no-subdir") == 0) { opt_ptr->output_dir = 0; printf("[OPTN] Export to current directory.\n"); } else if (strcmp(p_args[i], "-no-mtl") == 0) { opt_ptr->export_mtl = 0; printf("[OPTN] Export to current directory.\n"); } else if (strcmp(p_args[i], "-invZ") == 0) { opt_ptr->inverted_Z = 1; printf("[OPTN] Invert Z axis.\n"); } else if (strcmp(p_args[i], "-neg") == 0) { opt_ptr->negative_HM = 1; printf("[OPTN] Negative heightmap output mode.\n"); } else { printf("[ERR] Unknown option: %s\n", p_args[i]); } } opt_ptr->input_files_cnt = i; return RSPLIB_SUCCESS; } return RSPLIB_ERROR_ARGS_NULL; } static void createSubDir(char *dirName) { if (dirName == NULL) return; char _dir[1024]; snprintf(_dir, 1024, "%s-out", dirName); #ifdef _WIN32 CreateDirectory(_dir, NULL); #else mkdir(_dir, 0755); #endif } static void dispHelp() { printf("\n"); printf("Options:\n -h Print this message\n"); printf(" -v -vv Activate verbose console output\n"); printf(" -no-subdir Export models inside current folder\n"); printf(" -no-mtl Disable texture exporting\n"); printf(" -invZ Invert Z axis when parsing\n"); printf(" -neg Negative heightmap output\n"); printf("\n"); printf("Usage: RSE-Terrain [options] \n"); printf("\n"); }