Browse Source

-Fix some crashes in unwrapper
-Add emission lighting to raytrace mode, fixes #14686

Juan Linietsky 7 years ago
parent
commit
8b01b2e85c

+ 1 - 1
modules/thekla_unwrap/register_types.cpp

@@ -65,7 +65,7 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
 	Thekla::atlas_set_default_options(&options);
 	options.packer_options.witness.packing_quality = 1;
 	options.packer_options.witness.texel_area = 1.0 / p_texel_size;
-	options.packer_options.witness.conservative = true;
+	options.packer_options.witness.conservative = false;
 
 	//generate
 	Thekla::Atlas_Error err;

File diff suppressed because it is too large
+ 540 - 569
thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.cpp


+ 32 - 39
thirdparty/thekla_atlas/nvmesh/param/AtlasPacker.h

@@ -5,59 +5,52 @@
 #define NV_MESH_ATLASPACKER_H
 
 #include "nvcore/RadixSort.h"
-#include "nvmath/Vector.h"
-#include "nvmath/Random.h"
 #include "nvimage/BitMap.h"
 #include "nvimage/Image.h"
+#include "nvmath/Random.h"
+#include "nvmath/Vector.h"
 
 #include "nvmesh/nvmesh.h"
 
+namespace nv {
+class Atlas;
+class Chart;
 
-namespace nv
-{
-    class Atlas;
-    class Chart;
-
-    struct AtlasPacker
-    {
-        AtlasPacker(Atlas * atlas);
-        ~AtlasPacker();
+struct AtlasPacker {
+	AtlasPacker(Atlas *atlas);
+	~AtlasPacker();
 
-        void packCharts(int quality, float texelArea, bool blockAligned, bool conservative);
-        float computeAtlasUtilization() const;
+	void packCharts(int quality, float texelArea, bool blockAligned, bool conservative);
+	float computeAtlasUtilization() const;
 
-    private:
+private:
+	void findChartLocation(int quality, const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r);
+	void findChartLocation_bruteForce(const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r);
+	void findChartLocation_random(const BitMap *bitmap, Vector2::Arg extents, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int minTrialCount);
 
-        void findChartLocation(int quality, const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r);
-        void findChartLocation_bruteForce(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r);
-        void findChartLocation_random(const BitMap * bitmap, Vector2::Arg extents, int w, int h, int * best_x, int * best_y, int * best_w, int * best_h, int * best_r, int minTrialCount);
+	void drawChartBitmapDilate(const Chart *chart, BitMap *bitmap, int padding);
+	void drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vector2 &scale, const Vector2 &offset);
 
-        void drawChartBitmapDilate(const Chart * chart, BitMap * bitmap, int padding);
-        void drawChartBitmap(const Chart * chart, BitMap * bitmap, const Vector2 & scale, const Vector2 & offset);
-        
-        bool canAddChart(const BitMap * bitmap, int w, int h, int x, int y, int r);
-        void addChart(const BitMap * bitmap, int w, int h, int x, int y, int r, Image * debugOutput);
-        //void checkCanAddChart(const Chart * chart, int w, int h, int x, int y, int r);
-        void addChart(const Chart * chart, int w, int h, int x, int y, int r, Image * debugOutput);
-        
+	bool canAddChart(const BitMap *bitmap, int w, int h, int x, int y, int r);
+	void addChart(const BitMap *bitmap, int w, int h, int x, int y, int r, Image *debugOutput);
+	//void checkCanAddChart(const Chart * chart, int w, int h, int x, int y, int r);
+	void addChart(const Chart *chart, int w, int h, int x, int y, int r, Image *debugOutput);
 
-        static bool checkBitsCallback(void * param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
-        static bool setBitsCallback(void * param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
+	static bool checkBitsCallback(void *param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
+	static bool setBitsCallback(void *param, int x, int y, Vector3::Arg bar, Vector3::Arg dx, Vector3::Arg dy, float coverage);
 
-    private:
+private:
+	Atlas *m_atlas;
+	BitMap m_bitmap;
+	//Image m_debug_bitmap;
+	RadixSort m_radix;
 
-        Atlas * m_atlas;
-        BitMap m_bitmap;
-        Image m_debug_bitmap;
-        RadixSort m_radix;
+	uint m_width;
+	uint m_height;
 
-        uint m_width;
-        uint m_height;
-        
-        MTRand m_rand;
-       
-    };
+	MTRand m_rand;
+};
 
-} // nv namespace
+} // namespace nv
 
 #endif // NV_MESH_ATLASPACKER_H

+ 211 - 214
thirdparty/thekla_atlas/thekla/thekla_atlas.cpp

@@ -4,8 +4,8 @@
 #include <cfloat>
 
 #include "nvmesh/halfedge/Edge.h"
-#include "nvmesh/halfedge/Mesh.h"
 #include "nvmesh/halfedge/Face.h"
+#include "nvmesh/halfedge/Mesh.h"
 #include "nvmesh/halfedge/Vertex.h"
 #include "nvmesh/param/Atlas.h"
 
@@ -14,258 +14,255 @@
 
 #include "nvcore/Array.inl"
 
+#include <stdio.h>
 
 using namespace Thekla;
 using namespace nv;
 
-
-inline Atlas_Output_Mesh * set_error(Atlas_Error * error, Atlas_Error code) {
-    if (error) *error = code;
-    return NULL;
+inline Atlas_Output_Mesh *set_error(Atlas_Error *error, Atlas_Error code) {
+	if (error) *error = code;
+	return NULL;
 }
 
+static void input_to_mesh(const Atlas_Input_Mesh *input, HalfEdge::Mesh *mesh, Atlas_Error *error) {
 
+	Array<uint> canonicalMap;
+	canonicalMap.reserve(input->vertex_count);
 
-static void input_to_mesh(const Atlas_Input_Mesh * input, HalfEdge::Mesh * mesh, Atlas_Error * error) {
-
-    Array<uint> canonicalMap;
-    canonicalMap.reserve(input->vertex_count);
+	for (int i = 0; i < input->vertex_count; i++) {
+		const Atlas_Input_Vertex &input_vertex = input->vertex_array[i];
+		const float *pos = input_vertex.position;
+		const float *nor = input_vertex.normal;
+		const float *tex = input_vertex.uv;
 
-    for (int i = 0; i < input->vertex_count; i++) {
-        const Atlas_Input_Vertex & input_vertex = input->vertex_array[i];
-        const float * pos = input_vertex.position;
-        const float * nor = input_vertex.normal;
-        const float * tex = input_vertex.uv;
+		HalfEdge::Vertex *vertex = mesh->addVertex(Vector3(pos[0], pos[1], pos[2]));
+		vertex->nor.set(nor[0], nor[1], nor[2]);
+		vertex->tex.set(tex[0], tex[1]);
 
-        HalfEdge::Vertex * vertex = mesh->addVertex(Vector3(pos[0], pos[1], pos[2]));
-        vertex->nor.set(nor[0], nor[1], nor[2]);
-        vertex->tex.set(tex[0], tex[1]);
+		canonicalMap.append(input_vertex.first_colocal);
+	}
 
-        canonicalMap.append(input_vertex.first_colocal);
-    }
+	mesh->linkColocalsWithCanonicalMap(canonicalMap);
 
-    mesh->linkColocalsWithCanonicalMap(canonicalMap);
+	const int face_count = input->face_count;
 
+	int non_manifold_faces = 0;
+	for (int i = 0; i < face_count; i++) {
+		const Atlas_Input_Face &input_face = input->face_array[i];
 
-    const int face_count = input->face_count;
+		int v0 = input_face.vertex_index[0];
+		int v1 = input_face.vertex_index[1];
+		int v2 = input_face.vertex_index[2];
 
-    int non_manifold_faces = 0;
-    for (int i = 0; i < face_count; i++) {
-        const Atlas_Input_Face & input_face = input->face_array[i];
+		HalfEdge::Face *face = mesh->addFace(v0, v1, v2);
+		if (face != NULL) {
+			face->material = input_face.material_index;
+		} else {
+			non_manifold_faces++;
+		}
+	}
 
-        int v0 = input_face.vertex_index[0];
-        int v1 = input_face.vertex_index[1];
-        int v2 = input_face.vertex_index[2];
+	mesh->linkBoundary();
 
-        HalfEdge::Face * face = mesh->addFace(v0, v1, v2);
-        if (face != NULL) {
-            face->material = input_face.material_index;
-        }
-        else {
-            non_manifold_faces++;
-        }
-    }
-
-    mesh->linkBoundary();
-
-    if (non_manifold_faces != 0 && error != NULL) {
-        *error = Atlas_Error_Invalid_Mesh_Non_Manifold;
-    }
+	if (non_manifold_faces != 0 && error != NULL) {
+		*error = Atlas_Error_Invalid_Mesh_Non_Manifold;
+	}
 }
 
-static Atlas_Output_Mesh * mesh_atlas_to_output(const HalfEdge::Mesh * mesh, const Atlas & atlas, Atlas_Error * error) {
+static Atlas_Output_Mesh *mesh_atlas_to_output(const HalfEdge::Mesh *mesh, const Atlas &atlas, Atlas_Error *error) {
 
-    Atlas_Output_Mesh * output = new Atlas_Output_Mesh;
+	Atlas_Output_Mesh *output = new Atlas_Output_Mesh;
 
-    const MeshCharts * charts = atlas.meshAt(0);
+	const MeshCharts *charts = atlas.meshAt(0);
 
-    // Allocate vertices.
-    const int vertex_count = charts->vertexCount();
-    output->vertex_count = vertex_count;
-    output->vertex_array = new Atlas_Output_Vertex[vertex_count];
+	// Allocate vertices.
+	const int vertex_count = charts->vertexCount();
+	output->vertex_count = vertex_count;
+	output->vertex_array = new Atlas_Output_Vertex[vertex_count];
 
-    int w = 0;
-    int h = 0;
+	int w = 0;
+	int h = 0;
 
-    // Output vertices.
-    const int chart_count = charts->chartCount();
-    for (int i = 0; i < chart_count; i++) {
-        const Chart * chart = charts->chartAt(i);
-        uint vertexOffset = charts->vertexCountBeforeChartAt(i);
+	// Output vertices.
+	const int chart_count = charts->chartCount();
+	for (int i = 0; i < chart_count; i++) {
+		const Chart *chart = charts->chartAt(i);
+		uint vertexOffset = charts->vertexCountBeforeChartAt(i);
 
-        const uint chart_vertex_count = chart->vertexCount();
-        for (uint v = 0; v < chart_vertex_count; v++) {
-            Atlas_Output_Vertex & output_vertex = output->vertex_array[vertexOffset + v]; 
+		const uint chart_vertex_count = chart->vertexCount();
+		for (uint v = 0; v < chart_vertex_count; v++) {
+			Atlas_Output_Vertex &output_vertex = output->vertex_array[vertexOffset + v];
 
-            uint original_vertex = chart->mapChartVertexToOriginalVertex(v);
-            output_vertex.xref = original_vertex;
+			uint original_vertex = chart->mapChartVertexToOriginalVertex(v);
+			output_vertex.xref = original_vertex;
 
-            Vector2 uv = chart->chartMesh()->vertexAt(v)->tex;
-            output_vertex.uv[0] = uv.x;
-            output_vertex.uv[1] = uv.y;
-            w = max(w, ftoi_ceil(uv.x));
-            h = max(h, ftoi_ceil(uv.y));
-        }
-    }
+			Vector2 uv = chart->chartMesh()->vertexAt(v)->tex;
+			output_vertex.uv[0] = uv.x;
+			output_vertex.uv[1] = uv.y;
+			w = max(w, ftoi_ceil(uv.x));
+			h = max(h, ftoi_ceil(uv.y));
+		}
+	}
 
-    const int face_count = mesh->faceCount();
-    output->index_count = face_count * 3;
-    output->index_array = new int[face_count * 3];
+	const int face_count = mesh->faceCount();
+	output->index_count = face_count * 3;
+	output->index_array = new int[face_count * 3];
 
-    // Set face indices.
-    for (int f = 0; f < face_count; f++) {
-        uint c = charts->faceChartAt(f);
-        uint i = charts->faceIndexWithinChartAt(f);
-        uint vertexOffset = charts->vertexCountBeforeChartAt(c);
+	int face_ofs = 0;
+	// Set face indices.
+	for (int f = 0; f < face_count; f++) {
+		uint c = charts->faceChartAt(f);
+		uint i = charts->faceIndexWithinChartAt(f);
+		uint vertexOffset = charts->vertexCountBeforeChartAt(c);
 
-        const Chart * chart = charts->chartAt(c);
-        nvDebugCheck(chart->faceAt(i) == f);
+		const Chart *chart = charts->chartAt(c);
+		nvDebugCheck(chart->faceAt(i) == f);
 
-        const HalfEdge::Face * face = chart->chartMesh()->faceAt(i);
-        const HalfEdge::Edge * edge = face->edge;
+		if (i >= chart->chartMesh()->faceCount()) {
+			printf("WARNING: Faces may be missing in the final vertex, which could not be packed\n");
 
-        output->index_array[3*f+0] = vertexOffset + edge->vertex->id;
-        output->index_array[3*f+1] = vertexOffset + edge->next->vertex->id;
-        output->index_array[3*f+2] = vertexOffset + edge->next->next->vertex->id;
-    }
+			continue;
+		}
+		const HalfEdge::Face *face = chart->chartMesh()->faceAt(i);
+		const HalfEdge::Edge *edge = face->edge;
 
-    *error = Atlas_Error_Success;
-    output->atlas_width = w;
-    output->atlas_height = h;
+		output->index_array[3 * face_ofs + 0] = vertexOffset + edge->vertex->id;
+		output->index_array[3 * face_ofs + 1] = vertexOffset + edge->next->vertex->id;
+		output->index_array[3 * face_ofs + 2] = vertexOffset + edge->next->next->vertex->id;
+		face_ofs++;
+	}
 
-    return output;
-}
+	output->index_count = face_ofs * 3;
 
+	*error = Atlas_Error_Success;
+	output->atlas_width = w;
+	output->atlas_height = h;
 
-void Thekla::atlas_set_default_options(Atlas_Options * options) {
-    if (options != NULL) {
-        // These are the default values we use on The Witness.
-
-        options->charter = Atlas_Charter_Default;
-        options->charter_options.witness.proxy_fit_metric_weight = 2.0f;
-        options->charter_options.witness.roundness_metric_weight = 0.01f;
-        options->charter_options.witness.straightness_metric_weight = 6.0f;
-        options->charter_options.witness.normal_seam_metric_weight = 4.0f;
-        options->charter_options.witness.texture_seam_metric_weight = 0.5f;
-        options->charter_options.witness.max_chart_area = FLT_MAX;
-        options->charter_options.witness.max_boundary_length = FLT_MAX;
-
-        options->mapper = Atlas_Mapper_Default;
-
-        options->packer = Atlas_Packer_Default;
-        options->packer_options.witness.packing_quality = 0;
-        options->packer_options.witness.texel_area = 8;
-        options->packer_options.witness.block_align = true;
-        options->packer_options.witness.conservative = false;
-    }
+	return output;
 }
 
-
-Atlas_Output_Mesh * Thekla::atlas_generate(const Atlas_Input_Mesh * input, const Atlas_Options * options, Atlas_Error * error) {
-    // Validate args.
-    if (input == NULL || options == NULL || error == NULL) return set_error(error, Atlas_Error_Invalid_Args);
-
-    // Validate options.
-    if (options->charter != Atlas_Charter_Witness) {
-        return set_error(error, Atlas_Error_Invalid_Options);
-    }
-    if (options->charter == Atlas_Charter_Witness) {
-        // @@ Validate input options!
-    }
-
-    if (options->mapper != Atlas_Mapper_LSCM) {
-        return set_error(error, Atlas_Error_Invalid_Options);
-    }
-    if (options->mapper == Atlas_Mapper_LSCM) {
-        // No options.
-    }
-
-    if (options->packer != Atlas_Packer_Witness) {
-        return set_error(error, Atlas_Error_Invalid_Options);
-    }
-    if (options->packer == Atlas_Packer_Witness) {
-        // @@ Validate input options!
-    }
-
-    // Validate input mesh.
-    for (int i = 0; i < input->face_count; i++) {
-        int v0 = input->face_array[i].vertex_index[0];
-        int v1 = input->face_array[i].vertex_index[1];
-        int v2 = input->face_array[i].vertex_index[2];
-
-        if (v0 < 0 || v0 >= input->vertex_count || 
-            v1 < 0 || v1 >= input->vertex_count || 
-            v2 < 0 || v2 >= input->vertex_count)
-        {
-            return set_error(error, Atlas_Error_Invalid_Mesh);
-        }
-    }
-
-
-    // Build half edge mesh.
-    AutoPtr<HalfEdge::Mesh> mesh(new HalfEdge::Mesh);
-
-    input_to_mesh(input, mesh.ptr(), error);
-
-    if (*error == Atlas_Error_Invalid_Mesh) {
-        return NULL;
-    }
-
-    Atlas atlas;
-
-    // Charter.
-    if (options->charter == Atlas_Charter_Extract) {
-        return set_error(error, Atlas_Error_Not_Implemented);
-    }
-    else if (options->charter == Atlas_Charter_Witness) {
-        SegmentationSettings segmentation_settings;
-        segmentation_settings.proxyFitMetricWeight = options->charter_options.witness.proxy_fit_metric_weight;
-        segmentation_settings.roundnessMetricWeight = options->charter_options.witness.roundness_metric_weight;
-        segmentation_settings.straightnessMetricWeight = options->charter_options.witness.straightness_metric_weight;
-        segmentation_settings.normalSeamMetricWeight = options->charter_options.witness.normal_seam_metric_weight;
-        segmentation_settings.textureSeamMetricWeight = options->charter_options.witness.texture_seam_metric_weight;
-        segmentation_settings.maxChartArea = options->charter_options.witness.max_chart_area;
-        segmentation_settings.maxBoundaryLength = options->charter_options.witness.max_boundary_length;
-
-        Array<uint> uncharted_materials;
-        atlas.computeCharts(mesh.ptr(), segmentation_settings, uncharted_materials);
-    }
-    
-    if (atlas.hasFailed())
-        return NULL;
-
-    // Mapper.
-    if (options->mapper == Atlas_Mapper_LSCM) {
-        atlas.parameterizeCharts();
-    }
-
-    if (atlas.hasFailed())
-        return NULL;
-
-    // Packer.
-    if (options->packer == Atlas_Packer_Witness) {
-        int packing_quality = options->packer_options.witness.packing_quality;
-        float texel_area = options->packer_options.witness.texel_area;
-        int block_align = options->packer_options.witness.block_align;
-        int conservative = options->packer_options.witness.conservative;
-
-        /*float utilization =*/ atlas.packCharts(packing_quality, texel_area, block_align, conservative);
-    }
-    
-    if (atlas.hasFailed())
-        return NULL;
-
-
-    // Build output mesh.
-    return mesh_atlas_to_output(mesh.ptr(), atlas, error);
+void Thekla::atlas_set_default_options(Atlas_Options *options) {
+	if (options != NULL) {
+		// These are the default values we use on The Witness.
+
+		options->charter = Atlas_Charter_Default;
+		options->charter_options.witness.proxy_fit_metric_weight = 2.0f;
+		options->charter_options.witness.roundness_metric_weight = 0.01f;
+		options->charter_options.witness.straightness_metric_weight = 6.0f;
+		options->charter_options.witness.normal_seam_metric_weight = 4.0f;
+		options->charter_options.witness.texture_seam_metric_weight = 0.5f;
+		options->charter_options.witness.max_chart_area = FLT_MAX;
+		options->charter_options.witness.max_boundary_length = FLT_MAX;
+
+		options->mapper = Atlas_Mapper_Default;
+
+		options->packer = Atlas_Packer_Default;
+		options->packer_options.witness.packing_quality = 0;
+		options->packer_options.witness.texel_area = 8;
+		options->packer_options.witness.block_align = true;
+		options->packer_options.witness.conservative = false;
+	}
 }
 
-
-void Thekla::atlas_free(Atlas_Output_Mesh * output) {
-    if (output != NULL) {
-        delete [] output->vertex_array;
-        delete [] output->index_array;
-        delete output;
-    }
+Atlas_Output_Mesh *Thekla::atlas_generate(const Atlas_Input_Mesh *input, const Atlas_Options *options, Atlas_Error *error) {
+	// Validate args.
+	if (input == NULL || options == NULL || error == NULL) return set_error(error, Atlas_Error_Invalid_Args);
+
+	// Validate options.
+	if (options->charter != Atlas_Charter_Witness) {
+		return set_error(error, Atlas_Error_Invalid_Options);
+	}
+	if (options->charter == Atlas_Charter_Witness) {
+		// @@ Validate input options!
+	}
+
+	if (options->mapper != Atlas_Mapper_LSCM) {
+		return set_error(error, Atlas_Error_Invalid_Options);
+	}
+	if (options->mapper == Atlas_Mapper_LSCM) {
+		// No options.
+	}
+
+	if (options->packer != Atlas_Packer_Witness) {
+		return set_error(error, Atlas_Error_Invalid_Options);
+	}
+	if (options->packer == Atlas_Packer_Witness) {
+		// @@ Validate input options!
+	}
+
+	// Validate input mesh.
+	for (int i = 0; i < input->face_count; i++) {
+		int v0 = input->face_array[i].vertex_index[0];
+		int v1 = input->face_array[i].vertex_index[1];
+		int v2 = input->face_array[i].vertex_index[2];
+
+		if (v0 < 0 || v0 >= input->vertex_count ||
+				v1 < 0 || v1 >= input->vertex_count ||
+				v2 < 0 || v2 >= input->vertex_count) {
+			return set_error(error, Atlas_Error_Invalid_Mesh);
+		}
+	}
+
+	// Build half edge mesh.
+	AutoPtr<HalfEdge::Mesh> mesh(new HalfEdge::Mesh);
+
+	input_to_mesh(input, mesh.ptr(), error);
+
+	if (*error == Atlas_Error_Invalid_Mesh) {
+		return NULL;
+	}
+
+	Atlas atlas;
+
+	// Charter.
+	if (options->charter == Atlas_Charter_Extract) {
+		return set_error(error, Atlas_Error_Not_Implemented);
+	} else if (options->charter == Atlas_Charter_Witness) {
+		SegmentationSettings segmentation_settings;
+		segmentation_settings.proxyFitMetricWeight = options->charter_options.witness.proxy_fit_metric_weight;
+		segmentation_settings.roundnessMetricWeight = options->charter_options.witness.roundness_metric_weight;
+		segmentation_settings.straightnessMetricWeight = options->charter_options.witness.straightness_metric_weight;
+		segmentation_settings.normalSeamMetricWeight = options->charter_options.witness.normal_seam_metric_weight;
+		segmentation_settings.textureSeamMetricWeight = options->charter_options.witness.texture_seam_metric_weight;
+		segmentation_settings.maxChartArea = options->charter_options.witness.max_chart_area;
+		segmentation_settings.maxBoundaryLength = options->charter_options.witness.max_boundary_length;
+
+		Array<uint> uncharted_materials;
+		atlas.computeCharts(mesh.ptr(), segmentation_settings, uncharted_materials);
+	}
+
+	if (atlas.hasFailed())
+		return NULL;
+
+	// Mapper.
+	if (options->mapper == Atlas_Mapper_LSCM) {
+		atlas.parameterizeCharts();
+	}
+
+	if (atlas.hasFailed())
+		return NULL;
+
+	// Packer.
+	if (options->packer == Atlas_Packer_Witness) {
+		int packing_quality = options->packer_options.witness.packing_quality;
+		float texel_area = options->packer_options.witness.texel_area;
+		int block_align = options->packer_options.witness.block_align;
+		int conservative = options->packer_options.witness.conservative;
+
+		/*float utilization =*/atlas.packCharts(packing_quality, texel_area, block_align, conservative);
+	}
+
+	if (atlas.hasFailed())
+		return NULL;
+
+	// Build output mesh.
+	return mesh_atlas_to_output(mesh.ptr(), atlas, error);
 }
 
+void Thekla::atlas_free(Atlas_Output_Mesh *output) {
+	if (output != NULL) {
+		delete[] output->vertex_array;
+		delete[] output->index_array;
+		delete output;
+	}
+}

Some files were not shown because too many files changed in this diff