7bc9064955
- remove NEW_REGION_FILL macro - use glBlendFuncSeparate - some refactoring
458 lines
13 KiB
C++
458 lines
13 KiB
C++
|
|
|
|
// TnzCore includes
|
|
#include "tgl.h"
|
|
|
|
// TnzExt includes
|
|
#include "ext/ttexturesstorage.h"
|
|
#include "ext/plasticdeformerstorage.h"
|
|
|
|
// tcg includes
|
|
#include "tcg/tcg_iterator_ops.h"
|
|
|
|
#include "ext/meshutils.h"
|
|
|
|
#include <array>
|
|
|
|
//********************************************************************************************
|
|
// Templated drawing functions
|
|
//********************************************************************************************
|
|
|
|
namespace
|
|
{
|
|
|
|
struct NoColorFunction {
|
|
void faceColor(int f, int m) {}
|
|
void edgeColor(int e, int m) {}
|
|
void vertexColor(int v, int m) {}
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
template <typename VerticesContainer, typename PointType, typename ColorFunction>
|
|
inline void tglDrawEdges(const TTextureMesh &mesh, const VerticesContainer &vertices,
|
|
ColorFunction colorFunction)
|
|
{
|
|
// Draw the mesh wireframe
|
|
glBegin(GL_LINES);
|
|
|
|
TTextureMesh::edges_container::const_iterator et, eEnd = mesh.edges().end();
|
|
|
|
for (et = mesh.edges().begin(); et != eEnd; ++et) {
|
|
const TTextureMesh::edge_type &ed = *et;
|
|
|
|
int v0 = ed.vertex(0), v1 = ed.vertex(1);
|
|
|
|
const PointType &p0 = vertices[v0];
|
|
const PointType &p1 = vertices[v1];
|
|
|
|
colorFunction.edgeColor(et.index(), -1);
|
|
|
|
colorFunction.vertexColor(v0, -1);
|
|
glVertex2d(tcg::point_traits<PointType>::x(p0), tcg::point_traits<PointType>::y(p0));
|
|
|
|
colorFunction.vertexColor(v1, -1);
|
|
glVertex2d(tcg::point_traits<PointType>::x(p1), tcg::point_traits<PointType>::y(p1));
|
|
}
|
|
|
|
glEnd();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
template <typename ColorFunction>
|
|
inline void tglDrawFaces(const TMeshImage &meshImage, ColorFunction colorFunction)
|
|
{
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
int i = 0;
|
|
for (auto const& mesh : meshImage.meshes()) {
|
|
tcg::list<TTextureVertex> const & vertices = mesh->vertices();
|
|
int const m = i++;
|
|
|
|
// Draw the mesh wireframe
|
|
int j = 0;
|
|
for (auto const& ft : mesh->faces()) {
|
|
int const index = j++;
|
|
|
|
int v0, v1, v2;
|
|
mesh->faceVertices(index, v0, v1, v2);
|
|
|
|
TTextureVertex const& p0 = vertices[v0];
|
|
TTextureVertex const& p1 = vertices[v1];
|
|
TTextureVertex const& p2 = vertices[v2];
|
|
|
|
colorFunction.faceColor(index, m);
|
|
|
|
colorFunction.vertexColor(v0, m), glVertex2d(p0.P().x, p0.P().y);
|
|
colorFunction.vertexColor(v1, m), glVertex2d(p1.P().x, p1.P().y);
|
|
colorFunction.vertexColor(v2, m), glVertex2d(p2.P().x, p2.P().y);
|
|
}
|
|
}
|
|
|
|
glEnd();
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
template <typename ColorFunction>
|
|
inline void tglDrawFaces(const TMeshImage &meshImage, const PlasticDeformerDataGroup *group,
|
|
ColorFunction colorFunction)
|
|
{
|
|
glBegin(GL_TRIANGLES);
|
|
|
|
const std::vector<TTextureMeshP> &meshes = meshImage.meshes();
|
|
|
|
// Draw faces according to the group's sorted faces list
|
|
// Draw each face individually. Change tile and mesh data only if they change
|
|
int m = -1;
|
|
for (auto const& sft : group->m_sortedFaces) {
|
|
TTextureMesh const* mesh = nullptr;
|
|
double const* dstCoords = nullptr;
|
|
|
|
if (m != sft.second) {
|
|
m = sft.second;
|
|
mesh = meshes[m].getPointer();
|
|
dstCoords = group->m_datas[m].m_output.get();
|
|
}
|
|
|
|
int v0, v1, v2;
|
|
mesh->faceVertices(sft.first, v0, v1, v2);
|
|
|
|
double const * const d0 = dstCoords + (v0 << 1);
|
|
double const * const d1 = dstCoords + (v1 << 1);
|
|
double const * const d2 = dstCoords + (v2 << 1);
|
|
|
|
colorFunction.faceColor(sft.first, m);
|
|
|
|
colorFunction.vertexColor(v0, m), glVertex2d(d0[0], d0[1]);
|
|
colorFunction.vertexColor(v1, m), glVertex2d(d1[0], d1[1]);
|
|
colorFunction.vertexColor(v2, m), glVertex2d(d2[0], d2[1]);
|
|
}
|
|
|
|
glEnd();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
//********************************************************************************************
|
|
// Mesh Image Utility functions implementation
|
|
//********************************************************************************************
|
|
|
|
void transform(const TMeshImageP &meshImage, const TAffine &aff)
|
|
{
|
|
const std::vector<TTextureMeshP> &meshes = meshImage->meshes();
|
|
|
|
int m, mCount = meshes.size();
|
|
for (m = 0; m != mCount; ++m) {
|
|
TTextureMesh &mesh = *meshes[m];
|
|
|
|
tcg::list<TTextureMesh::vertex_type> &vertices = mesh.vertices();
|
|
|
|
tcg::list<TTextureMesh::vertex_type>::iterator vt, vEnd(vertices.end());
|
|
for (vt = vertices.begin(); vt != vEnd; ++vt)
|
|
vt->P() = aff * vt->P();
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
void tglDrawEdges(const TMeshImage &mi, const PlasticDeformerDataGroup *group)
|
|
{
|
|
const std::vector<TTextureMeshP> &meshes = mi.meshes();
|
|
|
|
int m, mCount = meshes.size();
|
|
if (group) {
|
|
for (m = 0; m != mCount; ++m)
|
|
tglDrawEdges<const TPointD *, TPointD, NoColorFunction>(
|
|
*meshes[m], (const TPointD *)group->m_datas[m].m_output.get(), NoColorFunction());
|
|
} else {
|
|
for (m = 0; m != mCount; ++m) {
|
|
const TTextureMesh &mesh = *meshes[m];
|
|
|
|
tglDrawEdges<tcg::list<TTextureMesh::vertex_type>, TTextureVertex, NoColorFunction>(
|
|
mesh, mesh.vertices(), NoColorFunction());
|
|
}
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
void tglDrawFaces(const TMeshImage &image, const PlasticDeformerDataGroup *group)
|
|
{
|
|
if (group)
|
|
tglDrawFaces(image, group, NoColorFunction());
|
|
else
|
|
tglDrawFaces(image, NoColorFunction());
|
|
}
|
|
|
|
//********************************************************************************************
|
|
// Colored drawing functions
|
|
//********************************************************************************************
|
|
|
|
namespace
|
|
{
|
|
|
|
struct LinearColorFunction {
|
|
typedef double (*ValueFunc)(const LinearColorFunction *cf, int m, int primitive);
|
|
|
|
public:
|
|
const TMeshImage &m_meshImg;
|
|
const PlasticDeformerDataGroup *m_group;
|
|
|
|
double m_min, m_max;
|
|
double *m_cMin, *m_cMax;
|
|
|
|
double m_dt;
|
|
bool m_degenerate;
|
|
|
|
ValueFunc m_func;
|
|
|
|
public:
|
|
LinearColorFunction(const TMeshImage &meshImg,
|
|
const PlasticDeformerDataGroup *group,
|
|
double min, double max,
|
|
double *cMin, double *cMax,
|
|
ValueFunc func)
|
|
: m_meshImg(meshImg), m_group(group), m_min(min), m_max(max), m_cMin(cMin), m_cMax(cMax), m_dt(max - min), m_degenerate(m_dt < 1e-4), m_func(func)
|
|
{
|
|
}
|
|
|
|
void operator()(int primitive, int m)
|
|
{
|
|
if (m_degenerate) {
|
|
glColor4d(0.5 * (m_cMin[0] + m_cMax[0]),
|
|
0.5 * (m_cMin[1] + m_cMax[1]),
|
|
0.5 * (m_cMin[2] + m_cMax[2]),
|
|
0.5 * (m_cMin[3] + m_cMax[3]));
|
|
return;
|
|
}
|
|
|
|
double val = m_func(this, m, primitive);
|
|
double t = (val - m_min) / m_dt, one_t = (m_max - val) / m_dt;
|
|
|
|
glColor4d(one_t * m_cMin[0] + t * m_cMax[0],
|
|
one_t * m_cMin[1] + t * m_cMax[1],
|
|
one_t * m_cMin[2] + t * m_cMax[2],
|
|
one_t * m_cMin[3] + t * m_cMax[3]);
|
|
}
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
struct LinearVertexColorFunction : public LinearColorFunction, public NoColorFunction {
|
|
LinearVertexColorFunction(const TMeshImage &meshImg,
|
|
const PlasticDeformerDataGroup *group,
|
|
double min, double max,
|
|
double *cMin, double *cMax,
|
|
ValueFunc func)
|
|
: LinearColorFunction(meshImg, group, min, max, cMin, cMax, func) {}
|
|
|
|
void vertexColor(int v, int m) { operator()(v, m); }
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
struct LinearFaceColorFunction : public LinearColorFunction, public NoColorFunction {
|
|
LinearFaceColorFunction(const TMeshImage &meshImg,
|
|
const PlasticDeformerDataGroup *group,
|
|
double min, double max,
|
|
double *cMin, double *cMax,
|
|
ValueFunc func)
|
|
: LinearColorFunction(meshImg, group, min, max, cMin, cMax, func) {}
|
|
|
|
void faceColor(int v, int m) { operator()(v, m); }
|
|
};
|
|
|
|
} // namespace
|
|
|
|
//===============================================================================
|
|
|
|
void tglDrawSO(const TMeshImage &image, double minColor[4], double maxColor[4],
|
|
const PlasticDeformerDataGroup *group, bool deformedDomain)
|
|
{
|
|
struct locals {
|
|
static double returnSO(const LinearColorFunction *cf, int m, int f)
|
|
{
|
|
return cf->m_group->m_datas[m].m_so[f];
|
|
}
|
|
};
|
|
|
|
double min = 0.0, max = 0.0;
|
|
if (group)
|
|
min = group->m_soMin, max = group->m_soMax;
|
|
|
|
LinearFaceColorFunction colorFunction(image, group, min, max, minColor, maxColor, locals::returnSO);
|
|
|
|
if (group && deformedDomain)
|
|
tglDrawFaces(image, group, colorFunction);
|
|
else
|
|
tglDrawFaces(image, colorFunction);
|
|
}
|
|
|
|
//-------------------------------------------------------------------------------
|
|
|
|
void tglDrawRigidity(const TMeshImage &image, double minColor[4], double maxColor[4],
|
|
const PlasticDeformerDataGroup *group, bool deformedDomain)
|
|
{
|
|
struct locals {
|
|
static double returnRigidity(const LinearColorFunction *cf, int m, int v)
|
|
{
|
|
return cf->m_meshImg.meshes()[m]->vertex(v).P().rigidity;
|
|
}
|
|
};
|
|
|
|
LinearVertexColorFunction colorFunction(image, group,
|
|
1.0, 1e4, minColor, maxColor, locals::returnRigidity);
|
|
|
|
if (group && deformedDomain)
|
|
tglDrawFaces(image, group, colorFunction);
|
|
else
|
|
tglDrawFaces(image, colorFunction);
|
|
}
|
|
|
|
//***********************************************************************************************
|
|
// Texturized drawing implementation
|
|
//***********************************************************************************************
|
|
|
|
void tglDraw(const TMeshImage &meshImage,
|
|
const DrawableTextureData &texData, const TAffine &meshToTexAff,
|
|
const PlasticDeformerDataGroup &group)
|
|
{
|
|
#ifdef _WIN32
|
|
static PFNGLBLENDFUNCSEPARATEPROC const glBlendFuncSeparate =
|
|
reinterpret_cast<PFNGLBLENDFUNCSEPARATEPROC>(::wglGetProcAddress("glBlendFuncSeparate"));
|
|
#endif
|
|
|
|
// Prepare OpenGL
|
|
glPushAttrib(GL_COLOR_BUFFER_BIT | GL_LINE_BIT | GL_HINT_BIT); // Preserve original status bits
|
|
|
|
glEnable(GL_BLEND);
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
|
|
glEnable(GL_LINE_SMOOTH);
|
|
glLineWidth(1.0f);
|
|
|
|
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
|
|
|
|
glBlendFuncSeparate(
|
|
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
|
|
GL_ONE , GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
auto const& tiles = texData.m_textureData->m_tileDatas;
|
|
|
|
// Prepare each tile's affine
|
|
std::unique_ptr<TAffine[]> tileAff(new TAffine[tiles.size()]);
|
|
{
|
|
std::size_t i = 0;
|
|
for (auto const& tile : tiles) {
|
|
TRectD const &rect = tile.m_tileGeometry;
|
|
TScale const scale(
|
|
1.0 / (rect.x1 - rect.x0),
|
|
1.0 / (rect.y1 - rect.y0));
|
|
TTranslation const translate(-rect.x0, -rect.y0);
|
|
tileAff[i] = scale * translate * meshToTexAff;
|
|
}
|
|
}
|
|
|
|
// Draw each face individually, according to the group's sorted faces list.
|
|
// Change tile and mesh data only if they change - improves performance
|
|
int m = -1;
|
|
TTextureMesh const * mesh = nullptr;
|
|
double const * dstCoords = nullptr;
|
|
GLuint texId = -1;
|
|
for (auto const& sft : group.m_sortedFaces) {
|
|
if (m != sft.second) {
|
|
// Change mesh if different from current
|
|
m = sft.second;
|
|
mesh = meshImage.meshes()[m].getPointer();
|
|
dstCoords = group.m_datas[m].m_output.get();
|
|
}
|
|
|
|
// Draw each face
|
|
TTextureMesh::face_type const& fc = mesh->face(sft.first);
|
|
TTextureMesh::edge_type const& ed0 = mesh->edge(fc.edge(0));
|
|
TTextureMesh::edge_type const& ed1 = mesh->edge(fc.edge(1));
|
|
TTextureMesh::edge_type const& ed2 = mesh->edge(fc.edge(2));
|
|
|
|
int const v0 = ed0.vertex(0);
|
|
int const v1 = ed0.vertex(1);
|
|
int const v2 = ed1.vertex((ed1.vertex(0) == v0) | (ed1.vertex(0) == v1));
|
|
|
|
// Edge X's Other Vertex Index (see below)
|
|
int const f = (ed1.vertex(0) == v1) | (ed1.vertex(1) == v1); // ed1 and ed2 will refer to vertexes
|
|
int const g = 1 - f; // with index 2 and these.
|
|
|
|
TPointD const& p0 = mesh->vertex(v0).P();
|
|
TPointD const& p1 = mesh->vertex(v1).P();
|
|
TPointD const& p2 = mesh->vertex(v2).P();
|
|
|
|
// Draw face against tile
|
|
std::size_t i = 0;
|
|
for (auto const& tileData : tiles) {
|
|
// Map each face vertex to tile coordinates
|
|
std::array<TPointD, 3> const s = {
|
|
tileAff[i] * p0,
|
|
tileAff[i] * p1,
|
|
tileAff[i] * p2,
|
|
};
|
|
++i;
|
|
|
|
// Test the face bbox - tile intersection
|
|
if ( (tmin(s[0].x, s[1].x, s[2].x) > 1.0)
|
|
|| (tmin(s[0].y, s[1].y, s[2].y) > 1.0)
|
|
|| (tmax(s[0].x, s[1].x, s[2].x) < 0.0)
|
|
|| (tmax(s[0].y, s[1].y, s[2].y) < 0.0)) {
|
|
continue;
|
|
}
|
|
|
|
// If the tile has changed, interrupt the glBegin/glEnd block and bind the
|
|
// OpenGL texture corresponding to the new tile
|
|
if (texId != tileData.m_textureId) {
|
|
texId = tileData.m_textureId;
|
|
|
|
// This must be OUTSIDE a glBegin/glEnd block
|
|
glBindTexture(GL_TEXTURE_2D, texId);
|
|
}
|
|
|
|
std::array<double const *, 3> const d = {
|
|
dstCoords + (v0 << 1),
|
|
dstCoords + (v1 << 1),
|
|
dstCoords + (v2 << 1),
|
|
};
|
|
|
|
// First, draw antialiased face edges on the mesh border.
|
|
glBegin(GL_LINES);
|
|
{
|
|
if (ed0.facesCount() < 2) {
|
|
glTexCoord2d(s[0].x, s[0].y), glVertex2d(d[0][0], d[0][1]);
|
|
glTexCoord2d(s[1].x, s[1].y), glVertex2d(d[1][0], d[1][1]);
|
|
}
|
|
|
|
if (ed1.facesCount() < 2) {
|
|
glTexCoord2d(s[f].x, s[f].y), glVertex2d(d[f][0], d[f][1]);
|
|
glTexCoord2d(s[2].x, s[2].y), glVertex2d(d[2][0], d[2][1]);
|
|
}
|
|
|
|
if (ed2.facesCount() < 2) {
|
|
glTexCoord2d(s[g].x, s[g].y), glVertex2d(d[g][0], d[g][1]);
|
|
glTexCoord2d(s[2].x, s[2].y), glVertex2d(d[2][0], d[2][1]);
|
|
}
|
|
}
|
|
glEnd();
|
|
|
|
// Finally, draw the face
|
|
glBegin(GL_TRIANGLES);
|
|
{
|
|
glTexCoord2d(s[0].x, s[0].y), glVertex2d(d[0][0], d[0][1]);
|
|
glTexCoord2d(s[1].x, s[1].y), glVertex2d(d[1][0], d[1][1]);
|
|
glTexCoord2d(s[2].x, s[2].y), glVertex2d(d[2][0], d[2][1]);
|
|
}
|
|
glEnd();
|
|
}
|
|
}
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0); // Unbind texture
|
|
|
|
glPopAttrib();
|
|
}
|