Thekla: Revert to state before clang-format changes

The file was wrongly formatted in 8b01b2e85c,
for thirdparty code we keep the upstream style *if* we need to make changes at all.
This commit is contained in:
Rémi Verschelde 2017-12-20 00:15:52 +01:00
parent ff04c07912
commit eb39b7f5de
3 changed files with 1218 additions and 1130 deletions

View file

@ -3,19 +3,19 @@
#include "nvmesh.h" // pch
#include "AtlasPacker.h"
#include "nvmesh/halfedge/Face.h"
#include "nvmesh/halfedge/Vertex.h"
#include "nvmesh/halfedge/Face.h"
#include "nvmesh/param/Atlas.h"
#include "nvmesh/param/Util.h"
#include "nvmesh/raster/Raster.h"
#include "nvmath/Color.h"
#include "nvmath/ConvexHull.h"
#include "nvmath/Vector.inl"
#include "nvmath/ConvexHull.h"
#include "nvmath/Color.h"
#include "nvmath/ftoi.h"
#include "nvcore/StdStream.h" // fileOpen
#include "nvcore/StrLib.h" // debug
#include "nvcore/StdStream.h" // fileOpen
#include <float.h> // FLT_MAX
#include <limits.h> // UINT_MAX
@ -28,7 +28,8 @@ using namespace nv;
#include "nvimage/ImageIO.h"
namespace {
namespace
{
const uint TGA_TYPE_GREY = 3;
const uint TGA_TYPE_RGB = 2;
const uint TGA_ORIGIN_UPPER = 0x20;
@ -52,7 +53,8 @@ struct TgaHeader {
};
#pragma pack(pop)
static void outputDebugBitmap(const char *fileName, const BitMap &bitmap, int w, int h) {
static void outputDebugBitmap(const char * fileName, const BitMap & bitmap, int w, int h)
{
FILE * fp = fileOpen(fileName, "wb");
if (fp == NULL) return;
@ -85,7 +87,8 @@ static void outputDebugBitmap(const char *fileName, const BitMap &bitmap, int w,
fclose(fp);
}
static void outputDebugImage(const char *fileName, const Image &bitmap, int w, int h) {
static void outputDebugImage(const char * fileName, const Image & bitmap, int w, int h)
{
FILE * fp = fileOpen(fileName, "wb");
if (fp == NULL) return;
@ -119,7 +122,7 @@ static void outputDebugImage(const char *fileName, const Image &bitmap, int w, i
fclose(fp);
}
} // namespace
}
#endif // DEBUG_OUTPUT
@ -133,22 +136,24 @@ inline bool isAligned(int x, int a) {
return (x & (a - 1)) == 0;
}
AtlasPacker::AtlasPacker(Atlas *atlas) :
m_atlas(atlas),
m_bitmap(256, 256) {
AtlasPacker::AtlasPacker(Atlas * atlas) : m_atlas(atlas), m_bitmap(256, 256)
{
m_width = 0;
m_height = 0;
#if 0
m_debug_bitmap.allocate(256, 256);
m_debug_bitmap.fill(Color32(0,0,0,0));
#endif
}
AtlasPacker::~AtlasPacker() {
AtlasPacker::~AtlasPacker()
{
}
// This should compute convex hull and use rotating calipers to find the best box. Currently it uses a brute force method.
static bool computeBoundingBox(Chart *chart, Vector2 *majorAxis, Vector2 *minorAxis, Vector2 *minCorner, Vector2 *maxCorner) {
static bool computeBoundingBox(Chart * chart, Vector2 * majorAxis, Vector2 * minorAxis, Vector2 * minCorner, Vector2 * maxCorner)
{
// Compute list of boundary points.
Array<Vector2> points(16);
@ -276,23 +281,28 @@ static bool computeBoundingBox(Chart *chart, Vector2 *majorAxis, Vector2 *minorA
Vector2 maxs[N];
const int iterationCount = 1;
for (int j = 0; j < iterationCount; j++) {
for (int j = 0; j < iterationCount; j++)
{
// Init predefined directions.
for (int i = 0; i < N; i++) {
for (int i = 0; i < N; i++)
{
float angle = lerp(minAngle, maxAngle, float(i)/N);
axis[i].set(cosf(angle), sinf(angle));
}
// Compute box for each direction.
for (int i = 0; i < N; i++) {
for (int i = 0; i < N; i++)
{
mins[i].set(FLT_MAX, FLT_MAX);
maxs[i].set(-FLT_MAX, -FLT_MAX);
}
for (uint p = 0; p < points.count(); p++) {
for (uint p = 0; p < points.count(); p++)
{
Vector2 point = points[p];
for (int i = 0; i < N; i++) {
for (int i = 0; i < N; i++)
{
float x = dot(axis[i], point);
if (x < mins[i].x) mins[i].x = x;
if (x > maxs[i].x) maxs[i].x = x;
@ -309,16 +319,20 @@ static bool computeBoundingBox(Chart *chart, Vector2 *majorAxis, Vector2 *minorA
float best_area = FLT_MAX;
float second_best_area = FLT_MAX;
for (int i = 0; i < N; i++) {
for (int i = 0; i < N; i++)
{
float area = (maxs[i].x - mins[i].x) * (maxs[i].y - mins[i].y);
if (area < best_area) {
if (area < best_area)
{
second_best_area = best_area;
second_best = best;
best_area = area;
best = i;
} else if (area < second_best_area) {
}
else if (area < second_best_area)
{
second_best_area = area;
second_best = i;
}
@ -327,7 +341,8 @@ static bool computeBoundingBox(Chart *chart, Vector2 *majorAxis, Vector2 *minorA
nvDebugCheck(second_best != -1);
nvDebugCheck(best != second_best);
if (j != iterationCount - 1) {
if (j != iterationCount-1)
{
// Handle wrap-around during the first iteration.
if (j == 0) {
if (best == 0 && second_best == N-1) best = N;
@ -365,7 +380,9 @@ static bool computeBoundingBox(Chart *chart, Vector2 *majorAxis, Vector2 *minorA
return true;
}
void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned, bool conservative) {
void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned, bool conservative)
{
const uint chartCount = m_atlas->chartCount();
if (chartCount == 0) return;
@ -376,7 +393,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
chartExtents.resize(chartCount);
float meshArea = 0;
for (uint c = 0; c < chartCount; c++) {
for (uint c = 0; c < chartCount; c++)
{
Chart * chart = m_atlas->chartAt(c);
if (!chart->isVertexMapped() && !chart->isDisk()) {
@ -395,7 +413,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
// Arrange vertices in a rectangle.
extents.x = float(chart->vertexMapWidth);
extents.y = float(chart->vertexMapHeight);
} else {
}
else {
// Compute surface area to sort charts.
float chartArea = chart->computeSurfaceArea();
meshArea += chartArea;
@ -430,7 +449,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
// Translate, rotate and scale vertices. Compute extents.
HalfEdge::Mesh * mesh = chart->chartMesh();
const uint vertexCount = mesh->vertexCount();
for (uint i = 0; i < vertexCount; i++) {
for (uint i = 0; i < vertexCount; i++)
{
HalfEdge::Vertex * vertex = mesh->vertexAt(i);
//Vector2 t = vertex->tex - origin;
@ -463,7 +483,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
scale = 1024 / (limit + 1);
for (uint i = 0; i < vertexCount; i++) {
for (uint i = 0; i < vertexCount; i++)
{
HalfEdge::Vertex * vertex = mesh->vertexAt(i);
vertex->tex *= scale;
}
@ -473,6 +494,7 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
nvDebugCheck(extents.x <= 1024 && extents.y <= 1024);
}
// Scale the charts to use the entire texel area available. So, if the width is 0.1 we could scale it to 1 without increasing the lightmap usage and making a better
// use of it. In many cases this also improves the look of the seams, since vertices on the chart boundaries have more chances of being aligned with the texel centers.
@ -489,7 +511,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
// Align all chart extents to 4x4 blocks, but taking padding into account.
if (conservative) {
cw = align(cw + 2, 4) - 2;
} else {
}
else {
cw = align(cw + 1, 4) - 1;
}
}
@ -506,7 +529,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
// Align all chart extents to 4x4 blocks, but taking padding into account.
if (conservative) {
ch = align(ch + 2, 4) - 2;
} else {
}
else {
ch = align(ch + 1, 4) - 1;
}
}
@ -567,22 +591,24 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
}
}*/
// Init bit map.
m_bitmap.clearAll();
if (approximateExtent > m_bitmap.width()) {
m_bitmap.resize(approximateExtent, approximateExtent, false);
#if 0
m_debug_bitmap.resize(approximateExtent, approximateExtent);
m_debug_bitmap.fill(Color32(0,0,0,0));
#endif
}
int w = 0;
int h = 0;
#if 1
// Add sorted charts to bitmap.
for (uint i = 0; i < chartCount; i++) {
for (uint i = 0; i < chartCount; i++)
{
uint c = ranks[chartCount - i - 1]; // largest chart first
Chart * chart = m_atlas->chartAt(c);
@ -599,7 +625,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
chart_bitmap.resize(ftoi_ceil(chartExtents[c].x), ftoi_ceil(chartExtents[c].y), /*initValue=*/true);
// @@ Another alternative would be to try to map each vertex to a different texel trying to fill all the available unused texels.
} else {
}
else {
// @@ Add special cases for dot and line charts. @@ Lightmap rasterizer also needs to handle these special cases.
// @@ We could also have a special case for chart quads. If the quad surface <= 4 texels, align vertices with texel centers and do not add padding. May be very useful for foliage.
@ -621,7 +648,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
// Rasterize chart and dilate.
drawChartBitmapDilate(chart, &chart_bitmap, /*padding=*/1);
} else {
}
else {
// Init all bits to 0.
chart_bitmap.resize(ftoi_ceil(chartExtents[c].x) + 1, ftoi_ceil(chartExtents[c].y) + 1, /*initValue=*/false); // Add half a texels on each side.
@ -648,12 +676,11 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
h = align(h, 4);
// Resize bitmap if necessary.
if (uint(w) > m_bitmap.width() || uint(h) > m_bitmap.height()) {
if (uint(w) > m_bitmap.width() || uint(h) > m_bitmap.height())
{
//nvDebug("Resize bitmap (%d, %d).\n", nextPowerOfTwo(w), nextPowerOfTwo(h));
m_bitmap.resize(nextPowerOfTwo(U32(w)), nextPowerOfTwo(U32(h)), false);
#if 0
m_debug_bitmap.resize(nextPowerOfTwo(U32(w)), nextPowerOfTwo(U32(h)));
#endif
}
//nvDebug("Add chart at (%d, %d).\n", best_x, best_y);
@ -661,20 +688,20 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
addChart(&chart_bitmap, w, h, best_x, best_y, best_r, /*debugOutput=*/NULL);
// IC: Output chart again to debug bitmap.
#if 0
if (chart->isVertexMapped()) {
addChart(&chart_bitmap, w, h, best_x, best_y, best_r, &m_debug_bitmap);
}
else {
addChart(chart, w, h, best_x, best_y, best_r, &m_debug_bitmap);
}
#endif
//float best_angle = 2 * PI * best_r;
// Translate and rotate chart texture coordinates.
HalfEdge::Mesh * mesh = chart->chartMesh();
const uint vertexCount = mesh->vertexCount();
for (uint v = 0; v < vertexCount; v++) {
for (uint v = 0; v < vertexCount; v++)
{
HalfEdge::Vertex * vertex = mesh->vertexAt(v);
Vector2 t = vertex->tex;
@ -700,7 +727,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
#else // 0
// Add sorted charts to bitmap.
for (uint i = 0; i < chartCount; i++) {
for (uint i = 0; i < chartCount; i++)
{
uint c = ranks[chartCount - i - 1]; // largest chart first
Chart * chart = m_atlas->chartAt(c);
@ -709,8 +737,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
Vector2 scale(1, 1);
#if 0 // old method. \
//m_padding_x = 2*padding; \
#if 0 // old method.
//m_padding_x = 2*padding;
//m_padding_y = 2*padding;
#else
//m_padding_x = 0; //padding;
@ -755,7 +783,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
h = max(h, best_y + best_ch);
// Resize bitmap if necessary.
if (uint(w) > m_bitmap.width() || uint(h) > m_bitmap.height()) {
if (uint(w) > m_bitmap.width() || uint(h) > m_bitmap.height())
{
//nvDebug("Resize bitmap (%d, %d).\n", nextPowerOfTwo(w), nextPowerOfTwo(h));
m_bitmap.resize(nextPowerOfTwo(w), nextPowerOfTwo(h), false);
m_debug_bitmap.resize(nextPowerOfTwo(w), nextPowerOfTwo(h));
@ -780,7 +809,8 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
// Translate and rotate chart texture coordinates.
HalfEdge::Mesh * mesh = chart->chartMesh();
const uint vertexCount = mesh->vertexCount();
for (uint v = 0; v < vertexCount; v++) {
for (uint v = 0; v < vertexCount; v++)
{
HalfEdge::Vertex * vertex = mesh->vertexAt(v);
Vector2 t = vertex->tex * scale + offset;
@ -811,10 +841,10 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
nvCheck(isAligned(m_width, 4));
nvCheck(isAligned(m_height, 4));
#if 0
m_debug_bitmap.resize(m_width, m_height);
m_debug_bitmap.setFormat(Image::Format_ARGB);
#endif
#if DEBUG_OUTPUT
//outputDebugBitmap("debug_packer_final.tga", m_bitmap, w, h);
//outputDebugImage("debug_packer_final.tga", m_debug_bitmap, w, h);
@ -822,31 +852,38 @@ void AtlasPacker::packCharts(int quality, float texelsPerUnit, bool blockAligned
#endif
}
// IC: Brute force is slow, and random may take too much time to converge. We start inserting large charts in a small atlas. Using brute force is lame, because most of the space
// is occupied at this point. At the end we have many small charts and a large atlas with sparse holes. Finding those holes randomly is slow. A better approach would be to
// start stacking large charts as if they were tetris pieces. Once charts get small try to place them randomly. It may be interesting to try a intermediate strategy, first try
// along one axis and then try exhaustively along that axis.
void AtlasPacker::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 AtlasPacker::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)
{
int attempts = 256;
if (quality == 1) attempts = 4096;
if (quality == 2) attempts = 2048;
if (quality == 3) attempts = 1024;
if (quality == 4) attempts = 512;
if (quality == 0 || w * h < attempts) {
if (quality == 0 || w*h < attempts)
{
findChartLocation_bruteForce(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r);
} else {
}
else
{
findChartLocation_random(bitmap, extents, w, h, best_x, best_y, best_w, best_h, best_r, attempts);
}
}
#define BLOCK_SIZE 4
void AtlasPacker::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 AtlasPacker::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)
{
int best_metric = INT_MAX;
// Try two different orientations.
for (int r = 0; r < 2; r++) {
for (int r = 0; r < 2; r++)
{
int cw = bitmap->width();
int ch = bitmap->height();
if (r & 1) swap(cw, ch);
@ -870,7 +907,8 @@ void AtlasPacker::findChartLocation_bruteForce(const BitMap *bitmap, Vector2::Ar
continue;
}
if (canAddChart(bitmap, w, h, x, y, r)) {
if (canAddChart(bitmap, w, h, x, y, r))
{
best_metric = metric;
*best_x = x;
*best_y = y;
@ -878,7 +916,8 @@ void AtlasPacker::findChartLocation_bruteForce(const BitMap *bitmap, Vector2::Ar
*best_h = ch;
*best_r = r;
if (area == w * h) {
if (area == w*h)
{
// Chart is completely inside, do not look at any other location.
goto done;
}
@ -891,10 +930,13 @@ done:
nvDebugCheck (best_metric != INT_MAX);
}
void AtlasPacker::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 AtlasPacker::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)
{
int best_metric = INT_MAX;
for (int i = 0; i < minTrialCount || best_metric == INT_MAX; i++) {
for (int i = 0; i < minTrialCount || best_metric == INT_MAX; i++)
{
int r = m_rand.getRange(1);
int x = m_rand.getRange(w + 1); // + 1 to extend atlas in case atlas full. We may want to use a higher number to increase probability of extending atlas.
int y = m_rand.getRange(h + 1); // + 1 to extend atlas in case atlas full.
@ -921,7 +963,8 @@ void AtlasPacker::findChartLocation_random(const BitMap *bitmap, Vector2::Arg ex
continue;
}
if (canAddChart(bitmap, w, h, x, y, r)) {
if (canAddChart(bitmap, w, h, x, y, r))
{
best_metric = metric;
*best_x = x;
*best_y = y;
@ -929,7 +972,8 @@ void AtlasPacker::findChartLocation_random(const BitMap *bitmap, Vector2::Arg ex
*best_h = ch;
*best_r = r;
if (area == w * h) {
if (area == w*h)
{
// Chart is completely inside, do not look at any other location.
break;
}
@ -937,29 +981,37 @@ void AtlasPacker::findChartLocation_random(const BitMap *bitmap, Vector2::Arg ex
}
}
void AtlasPacker::drawChartBitmapDilate(const Chart *chart, BitMap *bitmap, int padding) {
void AtlasPacker::drawChartBitmapDilate(const Chart * chart, BitMap * bitmap, int padding)
{
const int w = bitmap->width();
const int h = bitmap->height();
const Vector2 extents = Vector2(float(w), float(h));
// Rasterize chart faces, check that all bits are not set.
const uint faceCount = chart->faceCount();
for (uint f = 0; f < faceCount; f++) {
for (uint f = 0; f < faceCount; f++)
{
const HalfEdge::Face * face = chart->chartMesh()->faceAt(f);
Vector2 vertices[4];
uint edgeCount = 0;
for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
if (edgeCount < 4) {
for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance())
{
if (edgeCount < 4)
{
vertices[edgeCount] = it.vertex()->tex + Vector2(0.5) + Vector2(float(padding), float(padding));
}
edgeCount++;
}
if (edgeCount == 3) {
if (edgeCount == 3)
{
Raster::drawTriangle(Raster::Mode_Antialiased, extents, true, vertices, AtlasPacker::setBitsCallback, bitmap);
} else {
}
else
{
Raster::drawQuad(Raster::Mode_Antialiased, extents, true, vertices, AtlasPacker::setBitsCallback, bitmap);
}
}
@ -994,7 +1046,9 @@ void AtlasPacker::drawChartBitmapDilate(const Chart *chart, BitMap *bitmap, int
}
}
void AtlasPacker::drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vector2 &scale, const Vector2 &offset) {
void AtlasPacker::drawChartBitmap(const Chart * chart, BitMap * bitmap, const Vector2 & scale, const Vector2 & offset)
{
const int w = bitmap->width();
const int h = bitmap->height();
const Vector2 extents = Vector2(float(w), float(h));
@ -1017,14 +1071,17 @@ void AtlasPacker::drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vect
// Rasterize chart faces, check that all bits are not set.
const uint faceCount = chart->chartMesh()->faceCount();
for (uint f = 0; f < faceCount; f++) {
for (uint f = 0; f < faceCount; f++)
{
const HalfEdge::Face * face = chart->chartMesh()->faceAt(f);
Vector2 vertices[4];
uint edgeCount = 0;
for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
if (edgeCount < 4) {
for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance())
{
if (edgeCount < 4)
{
vertices[edgeCount] = it.vertex()->tex * scale + offset + pad[i];
nvCheck(ftoi_ceil(vertices[edgeCount].x) >= 0);
nvCheck(ftoi_ceil(vertices[edgeCount].y) >= 0);
@ -1034,9 +1091,12 @@ void AtlasPacker::drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vect
edgeCount++;
}
if (edgeCount == 3) {
if (edgeCount == 3)
{
Raster::drawTriangle(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, AtlasPacker::setBitsCallback, bitmap);
} else {
}
else
{
Raster::drawQuad(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, AtlasPacker::setBitsCallback, bitmap);
}
}
@ -1076,7 +1136,8 @@ void AtlasPacker::drawChartBitmap(const Chart *chart, BitMap *bitmap, const Vect
}
}
bool AtlasPacker::canAddChart(const BitMap *bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r) {
bool AtlasPacker::canAddChart(const BitMap * bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r)
{
nvDebugCheck(r == 0 || r == 1);
// Check whether the two bitmaps overlap.
@ -1100,7 +1161,8 @@ bool AtlasPacker::canAddChart(const BitMap *bitmap, int atlas_w, int atlas_h, in
}
}
}
} else if (r == 1) {
}
else if (r == 1) {
for (int y = 0; y < h; y++) {
int xx = y + offset_x;
if (xx >= 0) {
@ -1160,6 +1222,7 @@ void AtlasPacker::checkCanAddChart(const Chart * chart, int w, int h, int x, int
}
#endif // 0
static Color32 chartColor = Color32(0);
static void selectRandomColor(MTRand & rand) {
// Pick random color for this chart. @@ Select random hue, but fixed saturation/luminance?
@ -1168,7 +1231,8 @@ static void selectRandomColor(MTRand &rand) {
chartColor.b = 128 + rand.getRange(127);
chartColor.a = 255;
}
static bool debugDrawCallback(void *param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area) {
static bool debugDrawCallback(void * param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area)
{
Image * image = (Image *)param;
if (area > 0.0) {
@ -1183,7 +1247,8 @@ static bool debugDrawCallback(void *param, int x, int y, Vector3::Arg, Vector3::
return true;
}
void AtlasPacker::addChart(const Chart *chart, int w, int h, int x, int y, int r, Image *debugOutput) {
void AtlasPacker::addChart(const Chart * chart, int w, int h, int x, int y, int r, Image * debugOutput)
{
nvDebugCheck(r == 0 || r == 1);
nvDebugCheck(debugOutput != NULL);
@ -1194,14 +1259,17 @@ void AtlasPacker::addChart(const Chart *chart, int w, int h, int x, int y, int r
// Rasterize chart faces, set bits.
const uint faceCount = chart->faceCount();
for (uint f = 0; f < faceCount; f++) {
for (uint f = 0; f < faceCount; f++)
{
const HalfEdge::Face * face = chart->chartMesh()->faceAt(f);
Vector2 vertices[4];
uint edgeCount = 0;
for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance()) {
if (edgeCount < 4) {
for (HalfEdge::Face::ConstEdgeIterator it(face->edges()); !it.isDone(); it.advance())
{
if (edgeCount < 4)
{
Vector2 t = it.vertex()->tex;
if (r == 1) swap(t.x, t.y);
vertices[edgeCount] = t + offset;
@ -1209,15 +1277,20 @@ void AtlasPacker::addChart(const Chart *chart, int w, int h, int x, int y, int r
edgeCount++;
}
if (edgeCount == 3) {
if (edgeCount == 3)
{
Raster::drawTriangle(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, debugDrawCallback, debugOutput);
} else {
}
else
{
Raster::drawQuad(Raster::Mode_Antialiased, extents, /*enableScissors=*/true, vertices, debugDrawCallback, debugOutput);
}
}
}
void AtlasPacker::addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r, Image *debugOutput) {
void AtlasPacker::addChart(const BitMap * bitmap, int atlas_w, int atlas_h, int offset_x, int offset_y, int r, Image * debugOutput)
{
nvDebugCheck(r == 0 || r == 1);
// Check whether the two bitmaps overlap.
@ -1238,8 +1311,7 @@ void AtlasPacker::addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int o
if (xx >= 0) {
if (bitmap->bitAt(x, y)) {
if (xx < atlas_w && yy < atlas_h) {
if (debugOutput)
debugOutput->pixel(xx, yy) = chartColor;
if (debugOutput) debugOutput->pixel(xx, yy) = chartColor;
else {
nvDebugCheck(m_bitmap.bitAt(xx, yy) == false);
m_bitmap.setBitAt(xx, yy);
@ -1250,7 +1322,8 @@ void AtlasPacker::addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int o
}
}
}
} else if (r == 1) {
}
else if (r == 1) {
for (int y = 0; y < h; y++) {
int xx = y + offset_x;
if (xx >= 0) {
@ -1259,8 +1332,7 @@ void AtlasPacker::addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int o
if (yy >= 0) {
if (bitmap->bitAt(x, y)) {
if (xx < atlas_w && yy < atlas_h) {
if (debugOutput)
debugOutput->pixel(xx, yy) = chartColor;
if (debugOutput) debugOutput->pixel(xx, yy) = chartColor;
else {
nvDebugCheck(m_bitmap.bitAt(xx, yy) == false);
m_bitmap.setBitAt(xx, yy);
@ -1274,7 +1346,10 @@ void AtlasPacker::addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int o
}
}
/*static*/ bool AtlasPacker::checkBitsCallback(void *param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float) {
/*static*/ bool AtlasPacker::checkBitsCallback(void * param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float)
{
BitMap * bitmap = (BitMap * )param;
nvDebugCheck(bitmap->bitAt(x, y) == false);
@ -1282,7 +1357,8 @@ void AtlasPacker::addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int o
return true;
}
/*static*/ bool AtlasPacker::setBitsCallback(void *param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area) {
/*static*/ bool AtlasPacker::setBitsCallback(void * param, int x, int y, Vector3::Arg, Vector3::Arg, Vector3::Arg, float area)
{
BitMap * bitmap = (BitMap * )param;
if (area > 0.0) {
@ -1292,6 +1368,8 @@ void AtlasPacker::addChart(const BitMap *bitmap, int atlas_w, int atlas_h, int o
return true;
}
float AtlasPacker::computeAtlasUtilization() const {
const uint w = m_width;
const uint h = m_height;

View file

@ -5,18 +5,21 @@
#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 {
namespace nv
{
class Atlas;
class Chart;
struct AtlasPacker {
struct AtlasPacker
{
AtlasPacker(Atlas * atlas);
~AtlasPacker();
@ -24,6 +27,7 @@ struct AtlasPacker {
float computeAtlasUtilization() const;
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);
@ -36,21 +40,24 @@ private:
//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);
private:
Atlas * m_atlas;
BitMap m_bitmap;
//Image m_debug_bitmap;
Image m_debug_bitmap;
RadixSort m_radix;
uint m_width;
uint m_height;
MTRand m_rand;
};
} // namespace nv
} // nv namespace
#endif // NV_MESH_ATLASPACKER_H

View file

@ -4,8 +4,8 @@
#include <cfloat>
#include "nvmesh/halfedge/Edge.h"
#include "nvmesh/halfedge/Face.h"
#include "nvmesh/halfedge/Mesh.h"
#include "nvmesh/halfedge/Face.h"
#include "nvmesh/halfedge/Vertex.h"
#include "nvmesh/param/Atlas.h"
@ -14,16 +14,18 @@
#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;
}
static void input_to_mesh(const Atlas_Input_Mesh * input, HalfEdge::Mesh * mesh, Atlas_Error * error) {
Array<uint> canonicalMap;
@ -44,6 +46,7 @@ static void input_to_mesh(const Atlas_Input_Mesh *input, HalfEdge::Mesh *mesh, A
mesh->linkColocalsWithCanonicalMap(canonicalMap);
const int face_count = input->face_count;
int non_manifold_faces = 0;
@ -57,7 +60,8 @@ static void input_to_mesh(const Atlas_Input_Mesh *input, HalfEdge::Mesh *mesh, A
HalfEdge::Face * face = mesh->addFace(v0, v1, v2);
if (face != NULL) {
face->material = input_face.material_index;
} else {
}
else {
non_manifold_faces++;
}
}
@ -108,7 +112,6 @@ static Atlas_Output_Mesh *mesh_atlas_to_output(const HalfEdge::Mesh *mesh, const
output->index_count = face_count * 3;
output->index_array = new int[face_count * 3];
int face_ofs = 0;
// Set face indices.
for (int f = 0; f < face_count; f++) {
uint c = charts->faceChartAt(f);
@ -118,22 +121,14 @@ static Atlas_Output_Mesh *mesh_atlas_to_output(const HalfEdge::Mesh *mesh, const
const Chart * chart = charts->chartAt(c);
nvDebugCheck(chart->faceAt(i) == f);
if (i >= chart->chartMesh()->faceCount()) {
printf("WARNING: Faces may be missing in the final vertex, which could not be packed\n");
continue;
}
const HalfEdge::Face * face = chart->chartMesh()->faceAt(i);
const HalfEdge::Edge * edge = face->edge;
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++;
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;
}
output->index_count = face_ofs * 3;
*error = Atlas_Error_Success;
output->atlas_width = w;
output->atlas_height = h;
@ -141,6 +136,7 @@ static Atlas_Output_Mesh *mesh_atlas_to_output(const HalfEdge::Mesh *mesh, const
return output;
}
void Thekla::atlas_set_default_options(Atlas_Options * options) {
if (options != NULL) {
// These are the default values we use on The Witness.
@ -164,6 +160,7 @@ void Thekla::atlas_set_default_options(Atlas_Options *options) {
}
}
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);
@ -198,11 +195,13 @@ Atlas_Output_Mesh *Thekla::atlas_generate(const Atlas_Input_Mesh *input, const A
if (v0 < 0 || v0 >= input->vertex_count ||
v1 < 0 || v1 >= input->vertex_count ||
v2 < 0 || v2 >= 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);
@ -217,7 +216,8 @@ Atlas_Output_Mesh *Thekla::atlas_generate(const Atlas_Input_Mesh *input, const A
// Charter.
if (options->charter == Atlas_Charter_Extract) {
return set_error(error, Atlas_Error_Not_Implemented);
} else if (options->charter == Atlas_Charter_Witness) {
}
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;
@ -255,10 +255,12 @@ Atlas_Output_Mesh *Thekla::atlas_generate(const Atlas_Input_Mesh *input, const A
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;
@ -266,3 +268,4 @@ void Thekla::atlas_free(Atlas_Output_Mesh *output) {
delete output;
}
}