RSE-Terrain/RSETerrain/src/terrain_export.c
JackCarterSmith 3b82ac3e61
All checks were successful
JCS-Prod/RSE-Terrain/pipeline/pr-master This commit looks good
JCS-Prod/RSE-Terrain/pipeline/head This commit looks good
Final review
2022-08-24 18:44:11 +02:00

174 lines
5.3 KiB
C

/**
* @file terrain_export.c
* @date 23/08/2022
* @author JackCarterSmith
* @copyright GPL-v3.0
* @brief Export datas to heightmap PNG and Waveform OBJ format.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "options.h"
#include <RSPTerrain_datatypes.h>
#include <RSPTerrain_errordefs.h>
#include <zlib.h>
#include <png.h>
#include "obj/obj.h"
#include "terrain_export.h"
unsigned char exportHeightmapPNG(const T_RSPTERRAIN_HEIGHTMAP* heightmap, const char *out_path, T_PROG_OPTIONS* p_opts) {
char export_path[1024];
FILE *_png_f = NULL;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
size_t x,z;
png_byte **row_ptrs = NULL;
//int pixel_size = 3;
//int depth = 8; //bit par color channel (RGB)
if (heightmap == NULL || out_path == NULL)
return RSPLIB_ERROR_ARGS_NULL;
#ifdef _WIN32
if (p_opts->output_dir)
snprintf(export_path, 1024, "%s-out\\heightmap.png", out_path);
else
snprintf(export_path, 1024, "%s-heightmap.png", out_path);
#else
if (p_opts->output_dir)
snprintf(export_path, 1024, "%s-out/heightmap.png", out_path);
else
snprintf(export_path, 1024, "%s-heightmap.png", out_path);
#endif
// Open export file and add PNG header
_png_f = fopen(export_path, "wb");
if (_png_f == NULL) return RSPLIB_ERROR_MEMORY;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(_png_f);
return RSPLIB_ERROR_MEMORY;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
fclose(_png_f);
return RSPLIB_ERROR_MEMORY;
}
// Set image attributes
png_set_IHDR(png_ptr, info_ptr, heightmap->width * RSPTERRAINLIB_TILE_SAMPLING, heightmap->height * RSPTERRAINLIB_TILE_SAMPLING, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// Store PNG datas in buffer
row_ptrs = png_malloc(png_ptr, heightmap->height * RSPTERRAINLIB_TILE_SAMPLING * sizeof(png_byte *));
for ( z = 0; z < heightmap->height * RSPTERRAINLIB_TILE_SAMPLING; z++ ) {
png_byte *row = png_malloc(png_ptr, heightmap->width * RSPTERRAINLIB_TILE_SAMPLING * sizeof(unsigned char) * 3);
row_ptrs[z] = row;
for ( x = 0; x < heightmap->width * RSPTERRAINLIB_TILE_SAMPLING; x++ ) {
*row++ = heightmap->heightmap[x][z];
*row++ = heightmap->heightmap[x][z];
*row++ = heightmap->heightmap[x][z];
}
}
// Write pixels datas
png_init_io(png_ptr, _png_f);
png_set_rows(png_ptr, info_ptr, row_ptrs);
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
// Clean up
for ( z = 0; z < heightmap->height * RSPTERRAINLIB_TILE_SAMPLING; z++ ) {
png_free(png_ptr, row_ptrs[z]);
}
png_free(png_ptr, row_ptrs);
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(_png_f);
return RSPLIB_SUCCESS;
}
unsigned char exportHeightmapOBJ(const T_RSPTERRAIN_MESH* terrain_mesh, const char *out_path, T_PROG_OPTIONS* p_opts) {
char export_path[1024];
char objExport_name[128];
char mtlExport_name[128];
obj* objConstruct = NULL;
unsigned int i,j;
int surfID = 0;
float vertexBuff[3] = {0};
int indicesBuff[3] = {0};
if (terrain_mesh == NULL || out_path == NULL)
return RSPLIB_ERROR_ARGS_NULL;
#ifdef _WIN32
if (p_opts->output_dir) {
snprintf(export_path, 1024, "%s-out\\", out_path);
snprintf(objExport_name, 128, "heightmap.obj");
snprintf(mtlExport_name, 128, "heightmap.mtl");
} else {
snprintf(objExport_name, 128, "%s-heightmap.obj", out_path);
snprintf(mtlExport_name, 128, "%s-heightmap.mtl", out_path);
}
#else
if (p_opts->output_dir) {
snprintf(export_path, 1024, "%s-out/", out_path);
snprintf(objExport_name, 128, "heightmap.obj");
snprintf(mtlExport_name, 128, "heightmap.mtl");
} else {
snprintf(objExport_name, 128, "%s-heightmap.obj", out_path);
snprintf(mtlExport_name, 128, "%s-heightmap.mtl", out_path);
}
#endif
objConstruct = obj_create(NULL);
// Build face/surface material group
surfID = obj_add_surf(objConstruct);
obj_add_mtrl(objConstruct);
// Build vertex container
for ( i = 0; i < terrain_mesh->vertices_count; i++ ) {
vertexBuff[0] = terrain_mesh->verticesmap[i].x;
vertexBuff[1] = terrain_mesh->verticesmap[i].y;
vertexBuff[2] = terrain_mesh->verticesmap[i].z;
obj_set_vert_v(objConstruct, obj_add_vert(objConstruct), vertexBuff);
}
// Build indices container
// Each tile contains 2 triangles, build both of them.
// 1-2 2
// |/ /|
// 3 3-4
for ( j = 0; j < terrain_mesh->height - 1; j++ ) {
for ( i = 0; i < terrain_mesh->width - 1; i++ ) {
indicesBuff[0] = j * terrain_mesh->width + i;
indicesBuff[1] = indicesBuff[0] + 1;
indicesBuff[2] = indicesBuff[0] + terrain_mesh->width;
obj_set_poly(objConstruct, surfID, obj_add_poly(objConstruct, surfID), indicesBuff);
indicesBuff[0] = indicesBuff[1];
indicesBuff[1] = indicesBuff[2] + 1;
//indicesBuff[2] = indicesBuff[0] + stride;
obj_set_poly(objConstruct, surfID, obj_add_poly(objConstruct, surfID), indicesBuff);
}
}
if (p_opts->export_mtl) {
if (p_opts->output_dir)
obj_write(objConstruct, objExport_name, mtlExport_name, export_path, 8);
else
obj_write(objConstruct, objExport_name, mtlExport_name, NULL, 8);
} else {
if (p_opts->output_dir)
obj_write(objConstruct, objExport_name, NULL, export_path, 8);
else
obj_write(objConstruct, objExport_name, NULL, NULL, 8);
}
obj_delete(objConstruct);
return NO_ERROR;
}