cg_main.c (6569B)
1 /* Copyright (C) 2022 Université de Pau et des Pays de l'Adour UPPA 2 * Copyright (C) 2022 CNRS 3 * Copyright (C) 2022 Sorbonne Université 4 * Copyright (C) 2022 Université Paul Sabatier 5 * Copyright (C) 2022 |Meso|Star> (contact@meso-star.com) 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "cg.h" 21 #include "cg_args.h" 22 #include "cg_building.h" 23 #include "cg_city.h" 24 #include "cg_city_parsing.h" 25 #include "cg_catalog.h" 26 #include "cg_catalog_parsing.h" 27 #include "cg_vertex_denoiser.h" 28 #include "cg_cyaml.h" 29 30 #include <rsys/rsys.h> 31 #include <rsys/clock_time.h> 32 #include <rsys/logger.h> 33 #include <rsys/mem_allocator.h> 34 #include <star/scad.h> 35 36 static int 37 check_memory_allocator(struct mem_allocator* allocator) { 38 if(MEM_ALLOCATED_SIZE(allocator)) { 39 char dump[4096]; 40 MEM_DUMP(allocator, dump, sizeof(dump)/sizeof(char)); 41 fprintf(stderr, "%s\n", dump); 42 fprintf(stderr, "Memory leaks.\n"); 43 return 1; 44 } 45 return 0; 46 } 47 48 static void cg_log 49 (enum cyaml_log_e level, 50 void *_ctx, 51 const char *fmt, 52 va_list args) 53 { 54 struct logger* logger = (struct logger*)_ctx; 55 enum log_type type; 56 ASSERT(logger && fmt); 57 58 switch(level) { 59 case CYAML_LOG_ERROR: type = LOG_ERROR; break; 60 case CYAML_LOG_WARNING: type = LOG_WARNING; break; 61 case CYAML_LOG_NOTICE: type = LOG_OUTPUT; break; 62 default: return; /* Do not log this level of messages */ 63 } 64 logger_vprint(logger, type, fmt, args); 65 } 66 67 static void* cg_mem 68 (void *ctx, 69 void *ptr, 70 size_t size) 71 { 72 struct mem_allocator* allocator = (struct mem_allocator*)ctx; 73 ASSERT(allocator); 74 if(size == 0) { 75 /* free() request */ 76 MEM_RM(allocator, ptr); 77 return NULL; 78 } else { 79 return MEM_REALLOC(allocator, ptr, size); 80 } 81 } 82 83 int main 84 (int argc, char** argv) 85 { 86 int err = EXIT_SUCCESS; 87 res_T res = RES_OK; 88 struct args* args = NULL; 89 struct city* city = NULL; 90 struct logger logger; 91 struct mem_allocator allocator; 92 struct parsed_city* parsed_city = NULL; 93 struct parsed_catalog* parsed_catalog = NULL; 94 struct catalog* catalog = NULL; 95 int logger_initialized = 0, allocator_initialized = 0; 96 const struct cyaml_config config = { 97 .log_fn = cg_log, 98 .log_ctx = &logger, 99 .mem_fn = cg_mem, 100 .mem_ctx = &allocator, 101 .log_level = CYAML_LOG_WARNING, /* Logging errors and warnings only. */ 102 .flags = CYAML_CFG_DEFAULT, 103 }; 104 struct time t0, dt; 105 char buf[128]; 106 107 time_current(&t0); 108 /* init allocator and logger */ 109 ERR(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); 110 allocator_initialized = 1; 111 ERR(logger_init(&allocator, &logger)); 112 logger_initialized = 1; 113 114 /* Active logging for args parsing */ 115 logger_set_stream(&logger, LOG_OUTPUT, log_prt_fn, NULL); 116 logger_set_stream(&logger, LOG_WARNING, log_warn_fn, NULL); 117 logger_set_stream(&logger, LOG_ERROR, log_err_fn, NULL); 118 119 /* parse command line */ 120 ERR(parse_args(&allocator, &logger, argc, argv, &args)); 121 if(args->print_help) { 122 short_help(); 123 goto exit; 124 } 125 else if(args->print_version) { 126 print_version(); 127 goto exit; 128 } 129 130 /* Deactivate some logging according to the -V arg */ 131 if(args->verbosity_level < 1) 132 logger_set_stream(&logger, LOG_ERROR, NULL, NULL); 133 if(args->verbosity_level < 2) 134 logger_set_stream(&logger, LOG_WARNING, NULL, NULL); 135 if(args->verbosity_level < 3) 136 logger_set_stream(&logger, LOG_OUTPUT, NULL, NULL); 137 138 #ifndef NDEBUG 139 if(args->verbosity_level == 3) { 140 logger_print(&logger, LOG_WARNING, 141 "Running debug binary with increased verbosity.\n"); 142 } else { 143 logger_print(&logger, LOG_WARNING, 144 "Running debug binary.\n"); 145 } 146 #endif 147 148 /* Parse catalog. 149 * No semantic validation is done at this stage */ 150 ERR(parse_catalog(&args->catalog_files, &allocator, &logger, &config, 151 &parsed_catalog)); 152 153 /* Create catalog from parsed data. 154 * Semantic validation is done along the process as well as the emission of 155 * informative logs */ 156 ERR(create_catalog(&allocator, &logger, parsed_catalog, &catalog)); 157 release_parsed_catalog(&config, parsed_catalog); 158 parsed_catalog = NULL; 159 160 /* Parse city description. 161 * No semantic validation is done at this stage */ 162 ERR(parse_city(args->city_filename, &allocator, &logger, &config, &parsed_city)); 163 164 /* Create city with parsed data. 165 * Semantic validation is done along the process as well as the emission of 166 * informative logs */ 167 ERR(create_city(&allocator, &logger, args, parsed_city, catalog, &city)); 168 release_parsed_city(&config, parsed_city); 169 parsed_city = NULL; 170 release_args(args); 171 args = NULL; 172 173 ERR(city_cad_build(city)); 174 /* As buildings can be removed at the CAD generation step, ground CAD must be 175 * generated after buildings CAD */ 176 ERR(city_ground_build(city)); 177 178 exit: 179 if(logger_initialized && city) { 180 size_t count, denoised_count; 181 count = vertex_denoiser_get_count(city->denoiser); 182 denoised_count = vertex_denoiser_get_denoised_count(city->denoiser); 183 if(denoised_count > 0) { 184 logger_print(&logger, LOG_OUTPUT, "Denoised %lu / %lu vertices.\n", 185 denoised_count, count); 186 } 187 time_sub(&dt, time_current(&dt), &t0); 188 time_dump(&dt, TIME_MIN | TIME_SEC, NULL, buf, sizeof(buf)); 189 logger_print(&logger, LOG_OUTPUT, "Total run time: %s.\n", buf); 190 } 191 release_city(city); 192 release_catalog(catalog); 193 if(args) release_args(args); 194 if(logger_initialized) logger_release(&logger); 195 if(allocator_initialized) { 196 if(check_memory_allocator(&allocator)) err = EXIT_FAILURE; 197 mem_shutdown_proxy_allocator(&allocator); 198 CHK(mem_allocated_size() == 0); 199 } 200 return err; 201 error: 202 release_parsed_catalog(&config, parsed_catalog); 203 release_parsed_city(&config, parsed_city); 204 err = EXIT_FAILURE; 205 if(logger_initialized) { 206 logger_print(&logger, LOG_ERROR, "City generator failed.\n"); 207 if(city && !city->keep_running_on_errors) 208 logger_print(&logger, LOG_ERROR, "Try to re-run with option -k.\n"); 209 } 210 goto exit; 211 }