v0.8.1.0 Release

v0.8.1.0 Release
This commit is contained in:
jdsouza90
2022-09-20 09:59:34 -07:00
parent 3bd2be62a4
commit cf68600c4f
691 changed files with 181019 additions and 22147 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,231 @@
/*###############################################################################
#
# Copyright 2019-2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __FACE_IO__
#define __FACE_IO__
#include <stdint.h>
enum FaceIOErr {
kIOErrNone,
kIOErrFileNotFound,
kIOErrFileOpen,
kIOErrEOF,
kIOErrRead,
kIOErrWrite,
kIOErrSyntax,
kIOErrFormat,
kIOErrNotValue,
kIOErrNullPointer,
kIOErrParameter,
};
const char* FaceIOErrorStringFromCode(FaceIOErr err);
/********************************************************************************
********************************************************************************
********************************************************************************
***** IO Adapter *****
********************************************************************************
********************************************************************************
********************************************************************************/
/********************************************************************************
* FaceIOAdapter.
* Subclass from this and supply the accessors.
********************************************************************************/
class FaceIOAdapter {
public:
virtual uint32_t getShapeMeanSize() const { return 0; } /* The size of the mean shape mean, in elements. */
virtual uint32_t getShapeModesSize() const { return 0; } /* The total size of all shape modes (numModes*modeSize) */
virtual uint32_t getShapeNumModes() const { return 0; } /* The number of shape modes. */
virtual uint32_t getShapeEigenvaluesSize() const { return 0; } /* The number of shape eigenvalues
(should equal the number of modes) */
virtual float* getShapeMean(uint32_t /*size*/) { return nullptr; } /* Get a pointer to the shape mean.
If a nonzero size if supplied, it is resized first. */
virtual float* getShapeModes(uint32_t /*modeSize*/, uint32_t /*numModes*/) { return nullptr; } /* Get a pointer to the
shape modes, resizing first, if the parameters are nonzero. */
virtual float* getShapeEigenvalues(uint32_t /*numModes*/) { return nullptr; } /* Get a pointer to the shape eigenvalues,
resizing first if numModes is nonzero. */
virtual uint32_t getColorMeanSize() const { return 0; } /* The color mean ... */
virtual uint32_t getColorModesSize() const { return 0; } /* ... and modes */
virtual uint32_t getColorNumModes() const { return 0; }
virtual uint32_t getColorEigenvaluesSize() const { return 0; }
virtual float* getColorMean(uint32_t /*size*/) { return nullptr; }
virtual float* getColorModes(uint32_t /*modeSize*/, uint32_t /*numModes*/) { return nullptr; }
virtual float* getColorEigenvalues(uint32_t /*numModes*/) { return nullptr; }
virtual void setTriangleListSize(uint32_t /*size*/) {} /* The triangle list */
virtual uint32_t getTriangleListSize() const = 0;
virtual uint16_t* getTriangleList(uint32_t /*size*/) { return nullptr; }
virtual void setTextureCoordinatesSize(uint32_t /*size*/) {} /* The texture coordinates */
virtual uint32_t getTextureCoordinatesSize() const { return 0; }
virtual float* getTextureCoordinates(uint32_t /*size*/) { return nullptr; }
virtual void setNumBlendShapes(uint32_t /*numShapes*/) {} /* The blend shapes */
virtual void setBlendShapeName(uint32_t /*i*/, const char* /*name*/) {}
virtual uint32_t getNumBlendShapes() const { return 0; }
virtual const char* getBlendShapeName(uint32_t /*i*/) const { return nullptr; }
virtual uint32_t getBlendShapeSize(uint32_t /*i*/) const { return 0; }
virtual float* getBlendShape(uint32_t /*i*/, uint32_t /*size*/) { return nullptr; }
virtual void setIbugLandmarkMappingsSize(uint32_t /*n*/) {} /* The mappings from IBUG landmarks to vertex index */
virtual uint32_t getIbugLandmarkMappingsSize() const { return 0; }
virtual uint16_t* getIbugLandmarkMappings(uint32_t /*size*/) { return nullptr; }
virtual void appendIbugLandmarkMapping(uint16_t /*i*/) {}
virtual void appendIbugLandmarkMapping(uint16_t /*i*/, uint16_t /*j*/) {}
virtual void setIbugRightContourSize(uint32_t /*n*/) {} /* The IBUG contour on the right side of the face */
virtual uint32_t getIbugRightContourSize() const { return 0; }
virtual uint16_t* getIbugRightContour(uint32_t /*size*/) { return nullptr; }
virtual void appendIbugRightContour(uint16_t /*i*/) {}
virtual void setIbugLeftContourSize(uint32_t /*n*/) {} /* The IBUG contour on the left side of the face */
virtual uint32_t getIbugLeftContourSize() const { return 0; }
virtual uint16_t* getIbugLeftContour(uint32_t /*size*/) { return nullptr; }
virtual void appendIbugLeftContour(uint16_t /*i*/) {}
virtual void setModelRightContourSize(uint32_t /*n*/) {} /* The right contour of our model */
virtual uint32_t getModelRightContourSize() const { return 0; }
virtual uint16_t* getModelRightContour(uint32_t /*size*/) { return nullptr; }
virtual void appendModelRightContour(uint16_t /*i*/) {}
virtual void setModelLeftContourSize(uint32_t /*n*/) {} /* The left contour of our model */
virtual uint32_t getModelLeftContourSize() const { return 0; }
virtual uint16_t* getModelLeftContour(uint32_t /*size*/) { return nullptr; }
virtual void appendModelLeftContour(uint16_t /*i*/) {}
virtual void setAdjacentFacesSize(uint32_t /*n*/) {} /* The topology of adjacent faces to each edge */
virtual uint32_t getAdjacentFacesSize() const { return 0; }
virtual uint16_t* getAdjacentFaces(uint32_t /*size*/) { return nullptr; }
virtual void appendAdjacentFace(uint16_t /*i*/) {}
virtual void appendAdjacentFaces(uint16_t /*i*/, uint16_t /*j*/) {}
virtual void setAdjacentVerticesSize(uint32_t /*n*/) {} /* The topology of adjacent vertices to each edge */
virtual uint32_t getAdjacentVerticesSize() const { return 0; }
virtual uint16_t* getAdjacentVertices(uint32_t /*size*/) { return nullptr; }
virtual void appendAdjacentVertex(uint16_t /*i*/) {}
virtual void appendAdjacentVertices(uint16_t /*i*/, uint16_t /*j*/) {}
virtual void setNvlmLandmarksSize(uint32_t /*n*/) {} /* The tracked landmarks */
virtual uint32_t getNvlmLandmarksSize() const { return 0; }
virtual uint16_t* getNvlmLandmarks(uint32_t /*size*/) { return nullptr; }
virtual void appendNvlmLandmark(uint16_t /*i*/) {}
virtual void setNvlmRightContourSize(uint32_t /*n*/) {} /* The tracked right jawline contour */
virtual uint32_t getNvlmRightContourSize() const { return 0; }
virtual uint16_t* getNvlmRightContour(uint32_t /*size*/) { return nullptr; }
virtual void appendNvlmRightContour(uint16_t /*i*/) {}
virtual void setNvlmLeftContourSize(uint32_t /*n*/) {}; /* The tracked left jawline contour */
virtual uint32_t getNvlmLeftContourSize() const { return 0; }
virtual uint16_t* getNvlmLeftContour(uint32_t /*size*/) { return nullptr; }
virtual void appendNvlmLeftContour(uint16_t /*i*/) {}
virtual void setNumPartitions(uint32_t /*n*/) {}
virtual void setPartitionName(uint32_t /*i*/, const char* /*name*/) {}
virtual void setPartitionMaterialName(uint32_t /*i*/, const char* /*name*/) {}
virtual void setPartition(uint32_t /*i*/, uint32_t /*faceIndex*/, uint32_t /*numFaces*/,
uint32_t /*vertexIndex*/, uint32_t /*numVertices*/, int32_t /*smoothingGroup*/) {}
virtual uint32_t getNumPartitions() const { return 0; }
virtual const char* getPartitionName(uint32_t /*i*/) const { return nullptr; }
virtual const char* getPartitionMaterialName(uint32_t /*i*/) const { return nullptr; }
virtual int16_t getPartition(uint32_t /*i*/, uint32_t* faceIndex, uint32_t* numFaces, uint32_t* vertexIndex,
uint32_t* numVertices, int32_t* smoothingGroup) const
{ if (faceIndex) *faceIndex = 0u; if (numFaces) *numFaces = 0u; if (vertexIndex) *vertexIndex = 0u;
if (numVertices) *numVertices = 0u; if (smoothingGroup) *smoothingGroup = -1; return /*partitionIndex*/-1;
}
/* Const accessors do not have the ability to resize. */
const float* getShapeMean() const { return const_cast<FaceIOAdapter*>(this)->getShapeMean(0); }
const float* getShapeModes() const { return const_cast<FaceIOAdapter*>(this)->getShapeModes(0, 0); }
const float* getShapeEigenvalues() const { return const_cast<FaceIOAdapter*>(this)->getShapeEigenvalues(0); }
const float* getColorMean() const { return const_cast<FaceIOAdapter*>(this)->getColorMean(0); }
const float* getColorModes() const { return const_cast<FaceIOAdapter*>(this)->getColorModes(0, 0); }
const float* getColorEigenvalues() const { return const_cast<FaceIOAdapter*>(this)->getColorEigenvalues(0); }
const float* getTextureCoordinates() const { return const_cast<FaceIOAdapter*>(this)->getTextureCoordinates(0); }
const uint16_t* getTriangleList() const { return const_cast<FaceIOAdapter*>(this)->getTriangleList(0); }
const float* getBlendShape(uint32_t i) const { return const_cast<FaceIOAdapter*>(this)->getBlendShape(i, 0); }
const uint16_t* getIbugLandmarkMappings() const { return const_cast<FaceIOAdapter*>(this)->getIbugLandmarkMappings(0); }
const uint16_t* getIbugRightContour() const { return const_cast<FaceIOAdapter*>(this)->getIbugRightContour(0); }
const uint16_t* getIbugLeftContour() const { return const_cast<FaceIOAdapter*>(this)->getIbugLeftContour(0); }
const uint16_t* getModelRightContour() const { return const_cast<FaceIOAdapter*>(this)->getModelRightContour(0); }
const uint16_t* getModelLeftContour() const { return const_cast<FaceIOAdapter*>(this)->getModelLeftContour(0); }
const uint16_t* getAdjacentFaces() const { return const_cast<FaceIOAdapter*>(this)->getAdjacentFaces(0); }
const uint16_t* getAdjacentVertices() const { return const_cast<FaceIOAdapter*>(this)->getAdjacentVertices(0); }
const uint16_t* getNvlmLandmarks() const { return const_cast<FaceIOAdapter*>(this)->getNvlmLandmarks(0); }
const uint16_t* getNvlmRightContour() const { return const_cast<FaceIOAdapter*>(this)->getNvlmRightContour(0); }
const uint16_t* getNvlmLeftContour() const { return const_cast<FaceIOAdapter*>(this)->getNvlmLeftContour(0); }
};
/** Write the face model as an NVF model.
* @param[in] fac the face I/O adapter for the target data structure.
* @param[in] fileName the desired name of the output file.
* @return kIOErrNone if the file was written completed successfully.
* @return kIOErrFileOpen if the file could not be opened.
* @return kIOErrWrite if an error occurred while writing the file.
*/
FaceIOErr WriteNVFFaceModel(FaceIOAdapter* fac, const char* fileName);
/** Read a face model from an NVF file.
* @param[in] fileName the name of the file to be read.
* @param[in,out] fac the face I/O adapter for the target data structure.
* @return kIOErrNone if the file was read successfully.
* @return kIOErrFileNotFound if the file was not found .
* @return kIOErrFileOpen if the file could not be opened.
* @return kIOErrRead if an error occurred while reading the file.
* @return kIOErrSyntax if a syntax error has been encountered while reading the file.
*/
FaceIOErr ReadNVFFaceModel(const char* fileName, FaceIOAdapter* fac);
/** Read a face model from five OES files.
* @param[in] shape the name of the shape file to be read.
* @param[in] ibugNumandmarks the number of Ibug landmarks.
* @param[in] blendShapes the name of the blend shapes file to be read.
* @param[in] contours the name of the contours file to be read.
* @param[in] topology the name of the topology file to be read.
* @param[in,out] fac the face I/O adapter for the target data structure.
* @return kIOErrNone if the file was read successfully.
* @return kIOErrFileNotFound if the file was not found .
* @return kIOErrFileOpen if the file could not be opened.
* @return kIOErrRead if an error occurred while reading the file.
* @return kIOErrSyntax if a syntax error has been encountered while reading the file.
*/
FaceIOErr ReadEOSFaceModel(const char* shape, const unsigned ibugNumLandmarks, const char* blendShapes,
const char* contours, const char* topology, FaceIOAdapter* fac);
/** Write the face model as a JSON model.
* @param[in] fac the face I/O adapter for the target data structure.
* @param[in] fileName the desired name of the output file.
* If NULL is supplied, it is written to the standard output.
* @return kIOErrNone if the file was written completed successfully.
* @return kIOErrFileOpen if the file could not be opened.
* @return kIOErrWrite if an error occurred while writing the file.
*/
FaceIOErr PrintJSONFaceModel(FaceIOAdapter* fac, const char* fileName);
#endif /* __FACE_IO__ */

View File

@@ -0,0 +1,314 @@
/*###############################################################################
#
# Copyright 2016-2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#include "GLMaterial.h"
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <sstream>
#include <vector>
#ifdef _MSC_VER
#define strcasecmp _stricmp
#endif // _MSC_VER
////////////////////////////////////////////////////////////////////////////////
///// UTILITY FUNCTIONS /////
////////////////////////////////////////////////////////////////////////////////
static void SplitString(const std::string &s, std::vector<std::string>&tokens) {
tokens.clear();
std::string token;
std::istringstream tokenStream(s);
while (std::getline(tokenStream, token, ' ')) {
if (0 == token.size())
continue;
tokens.push_back(token);
}
}
static void SetColorFromStringArray(GLSpectrum3f& color, std::string* strs) {
color.r = strtof(strs[0].c_str(), nullptr);
color.g = strtof(strs[1].c_str(), nullptr);
color.b = strtof(strs[2].c_str(), nullptr);
}
static bool StrToBool(const char* str) {
return strcasecmp(str, "true") == 0 ||
strcasecmp(str, "on") == 0 ||
strcasecmp(str, "yes") == 0 ||
strcasecmp(str, "1") == 0;
}
////////////////////////////////////////////////////////////////////////////////
///// GLMaterial /////
////////////////////////////////////////////////////////////////////////////////
GLMaterial::~GLMaterial() {
//if (diffuseTexture)
// delete diffuseTexture;
}
GLMaterial::GLMaterial() {
clear();
}
GLMaterial::GLMaterial(const GLMaterial& mtl) {
*this = mtl;
}
void GLMaterial::setTextureFile(const char* file) {
if (file) diffuseTextureFile = file;
else diffuseTextureFile.clear();
}
void GLMaterial::clear() {
diffuseColor.set(1.f, 1.f, 1.f);
ambientColor.set(0.f, 0.f, 0.f);
specularColor.set(0.f, 0.f, 0.f);
transmissionColor.set(0.f, 0.f, 0.f);
specularExponent = 0.f;
opacity = 1.f;
diffuseTexture = nullptr;
diffuseTextureFile.clear();
illuminationModel = kUnspecifiedIlluminationModel;
}
////////////////////////////////////////////////////////////////////////////////
///// GLMaterialLibrary /////
////////////////////////////////////////////////////////////////////////////////
struct GLMaterialName {
GLMaterial mtl;
std::string name;
GLMaterialName() {}
GLMaterialName(const GLMaterial& matParam, const char* nameParam) {
mtl = matParam;
name = nameParam;
}
};
struct GLMaterialLibrary::Impl {
std::vector<GLMaterialName> lib;
};
GLMaterialLibrary::GLMaterialLibrary() {
pimpl = new Impl;
}
GLMaterialLibrary::~GLMaterialLibrary() {
delete pimpl;
}
void GLMaterialLibrary::clear() {
pimpl->lib.clear();
}
unsigned GLMaterialLibrary::numMaterials() const {
return unsigned(pimpl->lib.size());
}
NvCV_Status GLMaterialLibrary::addMaterial(const GLMaterial& mtrl, const char* name) {
if (getMaterial(name))
return NVCV_ERR_SELECTOR;
pimpl->lib.emplace_back(mtrl, name);
return NVCV_SUCCESS;
}
NvCV_Status GLMaterialLibrary::addDiffuseMaterial(const GLSpectrum3f& color, const char* name) {
GLMaterial mtrl;
if (getMaterial(name))
return NVCV_ERR_SELECTOR;
mtrl.diffuseColor = color;
pimpl->lib.emplace_back(mtrl, name);
return NVCV_SUCCESS;
}
NvCV_Status GLMaterialLibrary::removeMaterial(const char* name) {
unsigned i, n;
for (i = 0, n = unsigned(pimpl->lib.size()); i < n; ++i) {
if (name == pimpl->lib[i].name) {
pimpl->lib.erase(pimpl->lib.begin() + i);
return NVCV_SUCCESS;
}
}
return NVCV_ERR_FEATURENOTFOUND;
}
GLMaterial* GLMaterialLibrary::newMaterial(const char* name) {
if (getMaterial(name))
return nullptr;
size_t z = pimpl->lib.size();
pimpl->lib.resize(z + 1);
GLMaterialName* mtn = &pimpl->lib[z];
mtn->name = name;
return &mtn->mtl;
}
const GLMaterial* GLMaterialLibrary::getMaterial(const char* name) const {
GLMaterialName *mp, *mEnd;
for (mEnd = (mp = pimpl->lib.data()) + pimpl->lib.size(); mp < mEnd; ++mp)
if (name == mp->name)
return &mp->mtl;
return nullptr;
}
const GLMaterial* GLMaterialLibrary::getMaterial(unsigned i, const char** name) const {
if (i < pimpl->lib.size()) {
const GLMaterialName& matn = pimpl->lib[i];
if (name)
*name = matn.name.c_str();
return &matn.mtl;
}
if (name)
name = nullptr;
return nullptr;
}
NvCV_Status GLMaterialLibrary::read(const char* name) {
unsigned lineNum;
std::vector<std::string> tokens;
GLMaterial *mtl = nullptr;
clear();
std::ifstream fd(name);
if (!fd.is_open())
return NVCV_ERR_READ;
std::string line;
for (lineNum = 1; std::getline(fd, line); ++lineNum) {
SplitString(line, tokens);
if (!tokens.size())
continue;
if (tokens[0][0] == '#') {
continue;
}
if (tokens[0] == "newmtl" && 2 == tokens.size()) {
mtl = newMaterial(tokens[1].c_str());
continue;
}
if (tokens[0] == "Ka" && 4 == tokens.size()) {
SetColorFromStringArray(mtl->ambientColor, &tokens[1]);
continue;
}
if (tokens[0] == "Kd" && 4 == tokens.size()) {
SetColorFromStringArray(mtl->diffuseColor, &tokens[1]);
continue;
}
if (tokens[0] == "Ks" && 4 == tokens.size()) {
SetColorFromStringArray(mtl->specularColor, &tokens[1]);
continue;
}
if (tokens[0] == "Tf" && 4 == tokens.size()) {
SetColorFromStringArray(mtl->transmissionColor, &tokens[1]);
continue;
}
if (tokens[0] == "illum" && 2 == tokens.size()) {
mtl->illuminationModel = (unsigned char)strtol(tokens[1].c_str(), nullptr, 10);
continue;
}
if (tokens[0] == "d" && 2 == tokens.size()) {
/* We don't support "_d" */
mtl->opacity = strtof(tokens[1].c_str(), nullptr);
continue;
}
if (tokens[0] == "Ns" && 2 == tokens.size()) { /* We don't support "-d" */
mtl->specularExponent = strtof(tokens[1].c_str(), nullptr);
continue;
}
if (tokens[0] == "sharpness") { /* We don't support sharpness */
continue;
}
if (tokens[0] == "Ni") { /* We don't support index of refraction */
continue;
}
if (tokens[0] == "map_Kd") {
for (unsigned i = 1; i < tokens.size(); ++i) {
if (tokens[i] == "-blendu") {
++i;
}
else if (tokens[i] == "-blendv") {
++i;
}
else if (tokens[i] == "-cc") {
++i;
}
else if (tokens[i] == "-clamp") {
++i;
}
else if (tokens[i] == "-mm") {
++i;
}
else if (tokens[i] == "-o") {
i += 3;
}
else if (tokens[i] == "-s") {
i += 3;
}
else if (tokens[i] == "-t") {
i += 3;
}
else if (tokens[i] == "-texres") {
++i;
}
else if (tokens[i][0] == '-') {
printf("Unknown option: \"%s\"\n", tokens[i].c_str());
}
else {
mtl->diffuseTextureFile = tokens[i];
}
}
if (mtl->diffuseTextureFile.empty())
printf("No diffuse texture given on line %u\n", lineNum);
continue;
}
}
return NVCV_SUCCESS;
}

View File

@@ -0,0 +1,143 @@
/*###############################################################################
#
# Copyright 2016-2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __GLMATERIAL_H
#define __GLMATERIAL_H
#include <string>
#include "GLSpectrum.h"
#include "nvCVStatus.h"
////////////////////////////////////////////////////////////////////////////////
/// Specification for light transport on the surfaces of objects.
/// @todo Store the provenance of the material?
/// @todo Should we store the name, too?
////////////////////////////////////////////////////////////////////////////////
class GLMaterial {
public:
/// Default constructor.
GLMaterial();
/// Copy constructor.
/// @param[in] mtl the material to copy.
/// @note a copy is made of the diffuseTextureFile, if not NULL.
GLMaterial(const GLMaterial& mtl);
/// Destructor.
/// @note the diffuseTextureFile string is disposed.
/// @note the opaque diffuseTexture is *not* disposed.
~GLMaterial();
/// Assignment.
/// This copies the diffuseTextureFile, if not NULL>
/// @param[in] mtl the material to copy (RHS).
/// @return a reference to the LHS of the assignment.
//GLMaterial& operator=(const GLMaterial& mtl); // default implementation
/// Reset as it was in the constructor: 0 materials.
void clear();
/// Use this to set the diffuseTextureFile, by making a copy of the specified string.
/// @param[in] fileName the file name of the texture file. A copy of the string is made.
void setTextureFile(const char* fileName);
GLSpectrum3f ambientColor; ///< The ambient color, in [0,1].
GLSpectrum3f diffuseColor; ///< The diffuse color, in [0,1].
GLSpectrum3f specularColor; ///< The specular color, in [0,1].
GLSpectrum3f transmissionColor; ///< The transmission color, in [0,1].
float specularExponent; ///< The specular exponent, in [1, 10000]
float opacity; ///< The opacity, in [0,1].
std::string diffuseTextureFile; ///< The name of the diffuse texture file. Set through setTextureFile().
void *diffuseTexture; ///< User-defined texture representation -- unmanaged.
unsigned char illuminationModel; ///< The illumination model, in [0,10], or kUnspecifiedIlluminationModel.
static const int kUnspecifiedIlluminationModel = 255; ///< The value to be used for an unspecified illumination model.
};
////////////////////////////////////////////////////////////////////////////////
/// Library of material specifications for surface light transport.
////////////////////////////////////////////////////////////////////////////////
class GLMaterialLibrary {
public:
/// Constructor.
GLMaterialLibrary();
/// Destructor.
~GLMaterialLibrary();
/// Reset as it was in the constructor: 0 materials.
void clear();
/// Read from a file
NvCV_Status read(const char* name);
/// Add a new material to the library. A copy is made both of material and name.
/// @param[in] mtrl the material to be added to the library.
/// @param[in] name the name of the material, for future access.
/// @return keErrNone if the operation was completed successfully.
/// @return keErrDuplicate if a material of the same name is already found in the library.
NvCV_Status addMaterial(const GLMaterial& mtrl, const char* name);
/// Add a new diffuse material to the library. A copy is made both of the name.
/// @param[in] color the diffuse color to be added to the library.
/// @param[in] name the name of the material, for future access.
/// @return keErrNone if the operation was completed successfully.
/// @return keErrDuplicate if a material of the same name is already found in the library.
NvCV_Status addDiffuseMaterial(const GLSpectrum3f& color, const char* name);
/// Remove a material.
/// @param[in] name the name of the material to remove.
/// @return keErrNone if the operation was completed successfully.
NvCV_Status removeMaterial(const char* name);
/// Create a new material with the given name.
/// @param[in] name the name of the material, for future access.
/// @return a pointer to the new material in the database, if the operation was completed successfully.
/// @return NULL, if a material of the same name is already found in the library.
GLMaterial* newMaterial(const char* name);
/// Get the number of materials in the material library.
/// @return the number of materials.
unsigned numMaterials() const;
/// Get the material with the specified name.
/// @param[in] name the name of the material to get.
/// @return the specified material, or NULL if the material was not found.
const GLMaterial* getMaterial(const char* name) const;
/// Get the material with the specified index.
/// @param[in] i the index of the material to get.
/// @param[out] name the name of the material with the specified index (can be NULL).
/// @return the specified material, or NULL if the material was not found.
const GLMaterial* getMaterial(unsigned i, const char** name = nullptr) const;
private:
struct Impl;
Impl *pimpl;
};
#endif /* __GLMATERIAL_H */

View File

@@ -0,0 +1,624 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#include "GLMesh.h"
#include <string.h>
#include <algorithm>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//// ////
//// GLMesh ////
//// ////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Note: we assume that the transformation is affine, i.e. that M[3] = M[7] = M[11] = 0 and M[15] = 1.
static void TransformPoints(const glm::mat4x4& M, unsigned numPts, const glm::vec3 *pts, glm::vec3 *xPts) {
for (; numPts--; ++pts, ++xPts) { // NB it is better to do the dot products in double precision
glm::vec3 q; // Use an intermediate variable to allow transformation in-place.
q.x = M[0][0] * pts->x + M[1][0] * pts->y + M[2][0] * pts->z + M[3][0];
q.y = M[0][1] * pts->x + M[1][1] * pts->y + M[2][1] * pts->z + M[3][1];
q.z = M[0][2] * pts->x + M[1][2] * pts->y + M[2][2] * pts->z + M[3][2];
*xPts = q;
}
}
// Note: We assume here that the transformation is isotropic;
// otherwise we would need to transform by the inverse transpose of the upper left.
static void TransformNormals(const glm::mat4x4& M, unsigned numPts, const glm::vec3 *pts, glm::vec3 *xPts) {
for (; numPts--; ++pts, ++xPts) { // NB it is better to do the dot products in double precision
glm::vec3 q; // Use an intermediate variable to allow transformation in-place.
q.x = M[0][0] * pts->x + M[1][0] * pts->y + M[2][0] * pts->z;
q.y = M[0][1] * pts->x + M[1][1] * pts->y + M[2][1] * pts->z;
q.z = M[0][2] * pts->x + M[1][2] * pts->y + M[2][2] * pts->z;
*xPts = glm::normalize(q);
}
}
////////////////////////////////////////////////////////////////////////////////
// GLMesh API
////////////////////////////////////////////////////////////////////////////////
GLMesh::GLMesh(const GLMesh& mesh) {
m_faceVertexCount = mesh.m_faceVertexCount;
m_vertices = mesh.m_vertices;
m_vertexIndices = mesh.m_vertexIndices;
m_texCoords = mesh.m_texCoords;
m_textureIndices = mesh.m_textureIndices;
m_normals = mesh.m_normals;
m_normalIndices = mesh.m_normalIndices;
m_faceNormals = mesh.m_faceNormals;
}
GLMesh::GLMesh() { }
GLMesh::~GLMesh() { }
void GLMesh::resizeVertices(unsigned n) { m_vertices.resize(n); }
void GLMesh::resizeTexCoords(unsigned n) {
m_texCoords.resize(n);
m_textureIndices.resize(n ? unsigned(m_vertexIndices.size()) : 0);
}
void GLMesh::resizeNormals(unsigned n) {
m_normals.resize(n);
m_normalIndices.resize(n ? unsigned(m_vertexIndices.size()) : 0);
}
void GLMesh::resizeFaces(unsigned n) { m_faceVertexCount.resize(n); }
void GLMesh::resizeTriangles(unsigned n) { m_faceVertexCount.clear(); m_faceVertexCount.resize(n, 3); }
void GLMesh::resizeVertexIndices(unsigned n) {
m_vertexIndices.resize(n);
m_textureIndices.resize(m_texCoords.size() ? n : 0);
m_normalIndices.resize(m_normals.size() ? n : 0);
}
void GLMesh::resizeDualIndices(unsigned n) {
m_dualIndices.resize(n);
m_vertexFaceCount.resize(m_vertices.size());
}
void GLMesh::useFaceNormals(bool yes) { m_faceNormals.resize(yes ? numFaces() : 0); }
unsigned GLMesh::numVertices() const { return unsigned(m_vertices.size()); }
unsigned GLMesh::numTexCoords() const { return unsigned(m_texCoords.size()); }
unsigned GLMesh::numNormals() const { return unsigned(m_normals.size()); }
unsigned GLMesh::numFaces() const { return unsigned(m_faceVertexCount.size()); }
unsigned GLMesh::numIndices() const { return unsigned(m_vertexIndices.size()); }
void GLMesh::initPartitions() {
m_partitions.resize(1);
Partition& pt = m_partitions[0];
pt.faceIndex = 0;
pt.vertexIndex = 0;
pt.name.clear();
pt.materialName.clear();
}
NvCV_Status GLMesh::startPartition(const char *name, const char *material, int smooth) {
if (name)
for (const GLMesh::Partition& p : m_partitions)
if (p.name == name)
return NVCV_ERR_SELECTOR;
unsigned i = unsigned(m_partitions.size());
GLMesh::Partition *pt = &m_partitions[i - 1];
if (m_faceVertexCount.size() != pt->faceIndex) {
m_partitions.resize(i + 1);
pt = &m_partitions[i];
pt->faceIndex = unsigned(m_faceVertexCount.size());
pt->vertexIndex = unsigned(m_vertexIndices.size());
}
if (name) pt->name = name;
if (material) pt->materialName = material;
if (smooth >= 0) pt->smooth = smooth;
return NVCV_SUCCESS;
}
NvCV_Status GLMesh::partitionMesh(unsigned numPartitions, const GLMesh::Partition *srcPartition) {
m_partitions.resize(numPartitions);
for (unsigned i = 0; i < numPartitions; ++i, ++srcPartition) {
if (srcPartition->faceIndex >= m_faceVertexCount.size()) {
initPartitions();
return NVCV_ERR_MISMATCH;
}
GLMesh::Partition& pt = m_partitions[i];
pt.faceIndex = srcPartition->faceIndex;
pt.vertexIndex = srcPartition->vertexIndex;
pt.numFaces = srcPartition->numFaces;
pt.numVertexIndices = srcPartition->numVertexIndices;
pt.name = srcPartition->name;
pt.materialName = srcPartition->materialName;
}
//computeStartingVertexIndices();
return NVCV_SUCCESS;
}
NvCV_Status GLMesh::updatePartition(unsigned i, const GLMesh::Partition& update) {
if (i >= m_partitions.size())
return NVCV_ERR_FEATURENOTFOUND;
GLMesh::Partition& pt = m_partitions[i];
pt.faceIndex = update.faceIndex;
pt.vertexIndex = update.vertexIndex;
if (update.name.empty()) pt.name.clear();
else pt.name = update.name;
if (update.materialName.empty()) pt.materialName.clear();
else pt.materialName = update.materialName;
return NVCV_SUCCESS;
}
void GLMesh::computeStartingVertexIndices() {
unsigned vertIx;
std::sort(m_partitions.begin(), m_partitions.end());
const unsigned short *faceCount = m_faceVertexCount.data(), *lastFace;
GLMesh::Partition *pt = m_partitions.data(), *lastPt = pt + m_partitions.size() - 1;
for (vertIx = 0; pt != lastPt; ++pt) {
pt->vertexIndex = vertIx;
for (lastFace = faceCount + (pt[1].faceIndex - pt[0].faceIndex); faceCount != lastFace; ++faceCount)
vertIx += *faceCount;
}
pt->vertexIndex = vertIx;
}
NvCV_Status GLMesh::getPartition(unsigned i, GLMesh::Partition& pt) const {
if (i > m_partitions.size())
return NVCV_ERR_FEATURENOTFOUND;
pt = m_partitions[i];
return NVCV_SUCCESS;
}
bool GLMesh::indicesMatch(const std::vector<unsigned short>& ivecA, const std::vector<unsigned short>& ivecB) {
size_t n = ivecA.size();
const unsigned short *a = ivecA.data(),
*b = ivecB.data();
if (ivecB.size() != n)
return false;
for (; n--; ++a, ++b)
if (*a != *b)
return false;
return true;
}
void GLMesh::assureConsistency() {
if (m_texCoords.size() && (m_textureIndices.size() != m_vertexIndices.size()))
m_textureIndices.resize(m_vertexIndices.size());
if (m_normals.size() && (m_normalIndices.size() != m_vertexIndices.size()))
m_normalIndices.resize(m_vertexIndices.size());
if (m_faceNormals.size() && (m_faceNormals.size() != (m_vertexIndices.size() / 3)))
m_faceNormals.resize(m_vertexIndices.size() / 3);
}
void GLMesh::clear() {
m_faceVertexCount.resize(0);
m_vertices.resize(0);
m_texCoords.resize(0);
m_normals.resize(0);
m_faceNormals.resize(0);
m_vertexIndices.resize(0);
m_textureIndices.resize(0);
m_normalIndices.resize(0);
initPartitions();
}
glm::vec3* GLMesh::getVertices() {
return m_vertices.data();
}
glm::vec2* GLMesh::getTexCoords() {
assureConsistency();
return m_texCoords.size() ? m_texCoords.data() : nullptr;
}
glm::vec3* GLMesh::getNormals() {
assureConsistency();
return m_normals.size() ? m_normals.data() : nullptr;
}
glm::vec3* GLMesh::getFaceNormals() {
assureConsistency();
return m_faceNormals.size() ? m_faceNormals.data() : nullptr;
}
const glm::vec3* GLMesh::getVertices() const { return const_cast<GLMesh*>(this)->getVertices(); }
const glm::vec2* GLMesh::getTexCoords() const { return const_cast<GLMesh*>(this)->getTexCoords(); }
const glm::vec3* GLMesh::getNormals() const { return const_cast<GLMesh*>(this)->getNormals(); }
const glm::vec3* GLMesh::getFaceNormals() const { return const_cast<GLMesh*>(this)->getFaceNormals(); }
unsigned short* GLMesh::getFaceVertexCounts() { return m_faceVertexCount.data(); }
unsigned short* GLMesh::getVertexIndices() { return m_vertexIndices.data(); }
unsigned short* GLMesh::getTextureIndices() {
return m_textureIndices.size() ? m_textureIndices.data() : nullptr;
}
unsigned short* GLMesh::getNormalIndices() {
return m_normalIndices.size() ? m_normalIndices.data() : nullptr;
}
const unsigned short* GLMesh::getFaceVertexCounts() const { return m_faceVertexCount.data(); }
const unsigned short* GLMesh::getVertexIndices() const { return m_vertexIndices.data(); }
const unsigned short* GLMesh::getTextureIndices() const { return const_cast<GLMesh*>(this)->getTextureIndices(); }
const unsigned short* GLMesh::getNormalIndices() const { return const_cast<GLMesh*>(this)->getNormalIndices(); }
unsigned short* GLMesh::getVertexFaceCounts() { return m_vertexFaceCount.data(); }
unsigned short* GLMesh::getDualIndices() {
return m_dualIndices.size() ? m_dualIndices.data() : nullptr;
}
const unsigned short* GLMesh::getVertexFaceCounts() const { return const_cast<GLMesh*>(this)->getVertexFaceCounts(); }
const unsigned short* GLMesh::getDualIndices() const { return const_cast<GLMesh*>(this)->getDualIndices(); }
void GLMesh::addVertex(float x, float y, float z) { m_vertices.emplace_back(glm::vec3{ x, y, z }); }
void GLMesh::addTexCoord(float u, float v) { m_texCoords.emplace_back(glm::vec2{ u, v }); }
void GLMesh::addNormal(float x, float y, float z) { m_normals.emplace_back(glm::vec3{ x, y, z }); }
void GLMesh::addVertices(unsigned numVertices, const float *vertices) {
size_t preVertices = m_vertices.size();
m_vertices.resize(preVertices + numVertices);
memcpy(m_vertices.data() + preVertices, vertices, numVertices * sizeof(*m_vertices.data()));
}
void GLMesh::addTexCoords(unsigned numTexCoords, const float *texCoords) {
size_t preTexCoords = m_texCoords.size();
m_texCoords.resize(preTexCoords + numTexCoords);
memcpy(m_texCoords.data() + preTexCoords, texCoords, numTexCoords * sizeof(*m_texCoords.data()));
}
void GLMesh::addNormals(unsigned numNormals, const float *normals) {
size_t preNormals = m_normals.size();
m_normals.resize(preNormals + numNormals);
memcpy(m_normals.data() + preNormals, normals, numNormals * sizeof(*m_normals.data()));
}
void GLMesh::addFace(unsigned numVertices, const unsigned short *vertexIndices,
const unsigned short *textureIndices, const unsigned short *normalIndices)
{
size_t n;
m_faceVertexCount.push_back((unsigned short)numVertices);
if (vertexIndices) {
n = m_vertexIndices.size();
m_vertexIndices.resize(n + numVertices);
memcpy(m_vertexIndices.data() + n, vertexIndices, numVertices * sizeof(*vertexIndices));
}
if (textureIndices) {
n = m_textureIndices.size();
m_textureIndices.resize(n + numVertices);
memcpy(m_textureIndices.data() + n, textureIndices, numVertices * sizeof(*textureIndices));
}
if (normalIndices) {
n = m_normalIndices.size();
m_normalIndices.resize(n + numVertices);
memcpy(m_normalIndices.data() + n, normalIndices, numVertices * sizeof(*normalIndices));
}
}
void GLMesh::addFaces(unsigned numFaces, unsigned numVerticesPerFace, const unsigned short *vertexIndices,
const unsigned short *textureIndices, const unsigned short *normalIndices)
{
size_t numIndices = numFaces * numVerticesPerFace,
indexBytes = numIndices * sizeof(*vertexIndices);
size_t n;
n = m_faceVertexCount.size();
m_faceVertexCount.resize(n + numFaces, (unsigned short)numVerticesPerFace);
if (vertexIndices) {
n = m_vertexIndices.size();
m_vertexIndices.resize(n + numIndices);
memcpy(m_vertexIndices.data() + n, vertexIndices, indexBytes);
}
if (textureIndices) {
n = m_textureIndices.size();
m_textureIndices.resize(n + numIndices);
memcpy(m_textureIndices.data() + n, textureIndices, indexBytes);
}
if (normalIndices) {
n = m_normalIndices.size();
m_normalIndices.resize(n + numIndices);
memcpy(m_normalIndices.data() + n, normalIndices, indexBytes);
}
}
bool GLMesh::isTriMesh() const {
unsigned n;
const unsigned short *ix;
for (n = numFaces(), ix = getFaceVertexCounts(); n--; ++ix)
if (*ix != 3)
return false;
return true;
}
bool GLMesh::isQuadMesh() const {
unsigned n;
const unsigned short *ix;
for (n = numFaces(), ix = getFaceVertexCounts(); n--; ++ix)
if (*ix != 4)
return false;
return true;
}
bool GLMesh::isTriQuadMesh() const {
unsigned n;
const unsigned short *ix;
for (n = numFaces(), ix = getFaceVertexCounts(); n--; ++ix)
if (*ix > 4)
return false;
return true;
}
void GLMesh::transform(const glm::mat4x4& M) {
TransformPoints (M, unsigned(m_vertices.size()), m_vertices.data(), m_vertices.data());
TransformNormals(M, unsigned(m_normals.size()), m_normals.data(), m_normals.data());
TransformNormals(M, unsigned(m_faceNormals.size()), m_faceNormals.data(), m_faceNormals.data());
}
unsigned GLMesh::numPartitions() const {
return unsigned(m_partitions.size());
}
void GLMesh::finishPartitioning() {
computeStartingVertexIndices();
}
NvCV_Status GLMesh::setMaterial(const char *name) {
Partition pt{};
pt.materialName = name;
return partitionMesh(1, &pt);
}
void GLMesh::computeFaceNormals(int weighted) {
const glm::vec3 *vertices = m_vertices.data();
const unsigned short *numVertices = m_faceVertexCount.data();
glm::vec3 *nrm, *nrmEnd;
const unsigned short *ix;
const glm::vec3 *p0, *p1, *p2;
glm::vec3 n;
float mag;
useFaceNormals(true);
nrm = getFaceNormals();
nrmEnd = nrm + numFaces();
ix = m_vertexIndices.data();
for (; nrm != nrmEnd; ++nrm, ix += *numVertices++) {
if (3 == *numVertices) {
p0 = &vertices[ix[0]];
p1 = &vertices[ix[1]];
p2 = &vertices[ix[2]];
n = glm::cross((*p1 - *p0), (*p2 - *p0));
}
else {
unsigned numPts = *numVertices;
unsigned i;
p0 = &vertices[ix[numPts - 1]];
n = { 0.f, 0.f, 0.f };
for (i = 0, p0 = &vertices[ix[numPts - 1]]; i < numPts; ++i, p0 = p1) {
p1 = &vertices[ix[i]];
n.x -= (p1->y - p0->y) * (p1->z + p0->z);
n.y -= (p1->z - p0->z) * (p1->x + p0->x);
n.z -= (p1->x - p0->x) * (p1->y + p0->y);
}
}
mag = glm::length(n);
if (weighted == 0) { if (mag) n /= mag; } // Unit vector
else if (weighted > 0) { n *= 0.5f; } // Area-weighted normal
else /* weighted < 0 */ { if (mag) n /= mag * mag * 0.25f; } // Inverse-area-weighted vector
*nrm = n;
}
}
void GLMesh::computeVertexNormals(int weighted) {
glm::vec3 nrm;
computeFaceNormals(weighted);
if (m_normals.size() != m_vertices.size()) {
m_normals.resize(m_vertices.size());
m_normalIndices = m_vertexIndices;
}
if (m_vertexFaceCount.size() == m_vertices.size()) { // We already have the dual topology
glm::vec3 *n, *nEnd;
unsigned short *numPolys, *ix, *ixEnd;
for (nEnd = (n = m_normals.data()) + m_vertexFaceCount.size(), numPolys = m_vertexFaceCount.data(), ix = m_dualIndices.data(); n != nEnd; ++n, ++numPolys) {
for (ixEnd = ix + *numPolys, nrm = { 0.f, 0.f, 0.f }; ix != ixEnd; ++ix)
nrm += m_faceNormals[*ix];
*n = glm::normalize(nrm);
}
}
}
void GLMesh::BoundingBox::unionPoint(const glm::vec3& pt) { /* This works with NaN's */
if (!(_box[0].x < pt.x)) _box[0].x = pt.x; if (!(_box[1].x > pt.x)) _box[1].x = pt.x;
if (!(_box[0].y < pt.y)) _box[0].y = pt.y; if (!(_box[1].y > pt.y)) _box[1].y = pt.y;
if (!(_box[0].z < pt.z)) _box[0].z = pt.z; if (!(_box[1].z > pt.z)) _box[1].z = pt.z;
}
void GLMesh::BoundingBox::set(unsigned numPts, const glm::vec3 *pts) {
_box[0] = pts[0];
_box[1] = pts[0];
for (++pts; --numPts; ++pts)
unionPoint(*pts);
}
void GLMesh::BoundingBox::set(unsigned numPts, const glm::vec3 *pts, const glm::mat4x4& M) {
memset(this, -1, sizeof(*this)); // Set to NaN
for (; numPts--; ++pts) {
glm::vec3 q;
TransformPoints(M, 1, pts, &q);
unionPoint(q);
}
}
void GLMesh::BoundingSphere::set(unsigned numPts, const glm::vec3 *pts) {
/* Ritter algorithm */
float d, d0;
glm::vec3 p0, p1;
const glm::vec3 *pp, *pEnd = pts + numPts;
p0 = p1 = pts[0]; // Choose one point
for (pp = pts + 1, d0 = 0; pp != pEnd; ++pp) {
if (!(d0 > (d = glm::distance(p0, *pp)))) {
d0 = d;
p1 = *pp; // Find the furthest point
}
}
p0 = p1; // Choose that furthest point
for (pp = pts, d0 = 0; pp != pEnd; ++pp) {
if (!(d0 > (d = glm::distance(p0, *pp)))) {
d0 = d;
p1 = *pp; // Find the furthest point from that
}
}
_radius = d0 * .5f; // Make a sphere ...
_center = (p1 - p0) * .5f + p0; // ... from these furthest points
bool done;
// Accommodate every outlier as we encounter them
do {
done = true;
for (pp = pts; pp != pEnd; ++pp) { // Check that all points are in this sphere
glm::vec3 v = *pp - _center;
d0 = glm::length(v);
if (d0 > _radius) { // If not, ...
d = (d0 - _radius) * .5f;
_center += v * (d / d0); // ... adjust the sphere center ...
_radius += d; // ... and radius to accommodate this new point
done = false;
}
}
} while (!done);
}
void GLMesh::BoundingSphere::set(unsigned numPts, const glm::vec3 *pts, const glm::mat4x4& M) {
std::vector<glm::vec3> xPts(numPts);
TransformPoints(M, numPts, pts, xPts.data());
set(numPts, xPts.data());
}
void GLMesh::getBoundingBox(BoundingBox *bbox, const glm::mat4x4 *M) const {
if (M) bbox->set(unsigned(m_vertices.size()), m_vertices.data(), *M);
else bbox->set(unsigned(m_vertices.size()), m_vertices.data());
}
void GLMesh::getBoundingSphere(BoundingSphere *bsph, const glm::mat4x4 *M) const {
if (M) bsph->set(unsigned(m_vertices.size()), m_vertices.data(), *M);
else bsph->set(unsigned(m_vertices.size()), m_vertices.data());
}
unsigned GLMesh::notRenderable(unsigned /*options*/) const {
unsigned result = RENDERABLE;
if (!isTriMesh())
result |= NOT_TRIMESH;
if (0 != m_textureIndices.size() && !indicesMatch(m_vertexIndices, m_textureIndices))
result |= COMPLEX_TOPOLOGY;
if (0 != m_normalIndices.size() && !indicesMatch(m_vertexIndices, m_normalIndices))
result |= COMPLEX_TOPOLOGY;
return result;
}
NvCV_Status GLMesh::append(const GLMesh& other, const glm::mat4x4 *M) {
if ((!numTexCoords() != !other.numTexCoords()) || (!numNormals() != !other.numNormals()))
return NVCV_ERR_MISMATCH;
unsigned indexOffset = numVertices(),
thisCount = numIndices(),
otherCount = other.numIndices(),
i;
// Add vertices
addVertices(other.numVertices(), &other.getVertices()->x);
if (M)
TransformPoints(*M, other.numVertices(), getVertices() + indexOffset, getVertices() + indexOffset);
if (0 != (i = other.numTexCoords()))
addTexCoords(i, &other.getTexCoords()->x);
if (0 != (i = other.numNormals())) {
addNormals(i, &other.getNormals()->x);
if (M)
TransformNormals(*M, other.numNormals(), getNormals() + indexOffset, getNormals() + indexOffset);
}
{ // Add indices
const unsigned short *nvx = other.getFaceVertexCounts(),
*vix = other.getVertexIndices(),
*tix = other.getTextureIndices(),
*nix = other.getNormalIndices();
for (i = other.numFaces(); i--; ++nvx) {
addFace(*nvx, vix, tix, nix);
vix += *nvx;
if (tix) tix += *nvx;
if (nix) nix += *nvx;
}
}
{ // Offset the new indices
unsigned short *ix;
for (i = otherCount, ix = getVertexIndices() + thisCount; i--; ++ix)
*ix += (unsigned short)indexOffset;
if (nullptr != (ix = getTextureIndices()))
for (i = otherCount, ix += thisCount; i--; ++ix)
*ix += (unsigned short)indexOffset;
if (nullptr != (ix = getNormalIndices()))
for (i = otherCount, ix += thisCount; i--; ++ix)
*ix += (unsigned short)indexOffset;
}
return NVCV_SUCCESS;
}

View File

@@ -0,0 +1,280 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __GLMESH_H
#define __GLMESH_H
#include <string>
#include <vector>
#include "glm/glm.hpp"
#include "nvCVStatus.h"
class GLMesh {
public:
struct Partition {
unsigned faceIndex; ///< The index of the first face in the partition.
unsigned numFaces; ///< The number of faces in the partition.
unsigned vertexIndex; ///< The index of the first topological vertex in the partition.
unsigned numVertexIndices; ///< The number of topological vertices in the partition.
std::string name; ///< The name of the partition.
std::string materialName; ///< The name of the material assigned to the partition.
int smooth; ///< The smoothing group > 0; no smoothing == 0; unassigned < 0.
Partition() { smooth = -1; }
bool operator<(const Partition& pt) const { return faceIndex < pt.faceIndex; }
void finishPartitioning();
};
class BoundingBox {
public:
void unionPoint(const glm::vec3& pt);
void set(unsigned numPts, const glm::vec3* pts);
void set(unsigned numPts, const glm::vec3* pts, const glm::mat4x4& M);
glm::vec3& min() { return _box[0]; }
glm::vec3& max() { return _box[1]; }
const glm::vec3& min() const { return _box[0]; }
const glm::vec3& max() const { return _box[1]; }
glm::vec3 center() const { return (_box[0] + _box[1]) * 0.5f; }
private:
glm::vec3 _box[2];
};
class BoundingSphere {
public:
void set(unsigned numPts, const glm::vec3* pts);
void set(unsigned numPts, const glm::vec3* pts, const glm::mat4x4& M);
glm::vec3& center() { return _center; }
const glm::vec3& center() const { return _center; }
float& radius() { return _radius; }
float radius() const { return _radius; }
private:
glm::vec3 _center;
float _radius;
};
enum { BOUNDARY = 0xFFFFu }; ///< An index that indicates the boundary
GLMesh();
GLMesh(const GLMesh& mesh);
~GLMesh();
/// Get the number of faces.
/// @return the number of faces.
unsigned numFaces() const;
/// Get the number of XYZ vertices.
/// @return the number of XYZ vertices.
unsigned numVertices() const;
/// Get the number of UV texture coordinates.
/// @return the number of UV texture coordinates.
unsigned numTexCoords() const;
/// Get the number of XYZ normals.
/// @return the number of XYZ normals.
unsigned numNormals() const;
/// Get the number of vertex indices.
/// @return the number of vertex indices.
unsigned numIndices() const;
/// Evaluate whether the mesh is composed only of triangles.
/// @return true if all faces have 3 vertices; false otherwise.
bool isTriMesh() const;
/// Evaluate whether the mesh is composed only of quadrilaterals.
/// @return true if all faces have 4 vertices; false otherwise.
bool isQuadMesh() const;
/// Evaluate whether the mesh is composed only of triangles and quadrilaterals.
/// @return true if no face has greater than 4 vertices; false otherwise.
bool isTriQuadMesh() const;
void resizeVertices(unsigned numVert);
void resizeTexCoords(unsigned numTexCoord);
void resizeNormals(unsigned numNorm);
void resizeFaces(unsigned numFace);
void resizeTriangles(unsigned numTriangles);
void resizeVertexIndices(unsigned numIndices);
void resizeDualIndices(unsigned numIndices);
void clear();
glm::vec3* getVertices(); ///< Get the vertices. @return a pointer to the vertices.
const glm::vec3* getVertices() const; ///< Get the vertices. @return a pointer to the vertices.
glm::vec2* getTexCoords(); ///< Get the texture coordinates. @return a pointer to the texture coordinates.
const glm::vec2* getTexCoords() const; ///< Get the texture coordinates. @return a pointer to the texture coordinates.
glm::vec3* getNormals(); ///< Get the vertex normals. @return a pointer to the vertex normals.
const glm::vec3* getNormals() const; ///< Get the vertex normals. @return a pointer to the vertex normals.
glm::vec3* getFaceNormals(); ///< Get the face normals, computed with computeFaceNormals(). @return a pointer to the vertex normals.
const glm::vec3* getFaceNormals() const; ///< Get the face normals, computed with computeFaceNormals(). @return a pointer to the vertex normals.
unsigned short* getFaceVertexCounts(); ///< Get the vertex counts for each face, in the primal topology. @return an array of vertex counts, one per face.
const unsigned short* getFaceVertexCounts() const; ///< Get the vertex counts for each face, in the primal topology. @return an array of vertex counts, one per face.
unsigned short* getVertexIndices(); ///< Get the vertex indices for each face: the primal topology. @return a pointer to the vertex indices.
const unsigned short* getVertexIndices() const; ///< Get the vertex indices for each face: the primal topology. @return a pointer to the vertex indices.
unsigned short* getTextureIndices(); ///< Get the texture indices for each face: the primal topology. @return a pointer to the texture indices.
const unsigned short* getTextureIndices() const; ///< Get the texture indices for each face: the primal topology. @return a pointer to the texture indices.
unsigned short* getNormalIndices(); ///< Get the normal indices for each face: the primal topology. @return a pointer to the normal indices.
const unsigned short* getNormalIndices() const; ///< Get the normal indices for each face: the primal topology. @return a pointer to the normal indices.
unsigned short* getVertexFaceCounts(); ///< Get the face counts for each vertex, in the dual topology. @return an array of face counts, one per vertex.
const unsigned short* getVertexFaceCounts() const; ///< Get the face counts for each vertex, in the dual topology. @return an array of face counts, one per vertex.
unsigned short* getDualIndices(); ///< Get the face indices for each vertex: the dual topology. @return a pointer to the dual face indices.
const unsigned short* getDualIndices() const; ///< Get the face indices for each vertex: the dual topology. @return a pointer to the dual face indices.
void addVertex(float x, float y, float z);
void addTexCoord(float u, float v);
void addNormal(float x, float y, float z);
void addVertices(unsigned numVertices, const float* vertices);
void addTexCoords(unsigned numTexCoords, const float* texCoords);
void addNormals(unsigned numNormals, const float* normals);
void addFace(unsigned numVertices, const unsigned short* vertexIndices,
const unsigned short* textureIndices, const unsigned short* normalIndices);
void addFaces(unsigned numFaces, unsigned numVerticesPerFace, const unsigned short* vertexIndices,
const unsigned short* textureIndices, const unsigned short* normalIndices);
/// Compute the normals per face.
/// @param[in] specify the weighing for the normals. In all cases, the zero vector will
/// be returned for faces with zero area.
/// 0: unit vectors.
/// +1: vectors weighted by the area.
/// -1: vectors weighted by the reciprocal of the area.
void computeFaceNormals(int weighted = 0);
/// Compute the vertex normals. The face normals will be computed in the process.
/// @param[in] weighted Determines the weighting used to combine the face normals:
/// 0: all incident faces normals will have the same weight.
/// -1: the normals will be weighted by inverse area of the face.
void computeVertexNormals(int weighted = 0);
void transform(const glm::mat4x4& M);
/// Get the number of partitions.
/// There is always at least one, which may neither have a name nor a material.
/// @return the number of partitions.
unsigned numPartitions() const;
/// The easiest way to partition a mesh: call this after all vertices and attributes
/// are recorded, and before the first face of each partition is recorded.
/// @param[in] name the name of the new partition.
/// @param[in] material the name of the material to be used in the new partition.
/// @param[in] smooth {-1, 0, 1} means {unspecified, not smooth, smooth}.
/// @return NvCV_StatusNone if the partition was retrieved successfully.
/// @return NvCV_StatusDuplicate if a partition with the same name already exists.
NvCV_Status startPartition(const char* name, const char* material, int smooth = -1);
/// Get the specified partition.
/// @param[in] i the index of the partition to retrieve.
/// @param[out] pt a place to store the specified partition.
/// @return NvCV_StatusNone if the partition was retrieved successfully.
/// @return NvCV_StatusTooBig if the face index was >= the number of faces.
NvCV_Status getPartition(unsigned i, Partition& pt) const;
/// Update the specified partition.
/// The function finishPartitioning() should be called
/// after the last updatePartition() has been called.
/// @param[in] i the index of the partition.
/// @param[in] partition the desired value for the specified partition.
/// @return NvCV_StatusNone if the partition was updated successfully.
/// @return NvCV_StatusTooBig if the face index was >= the number of faces.
NvCV_Status updatePartition(unsigned i, const Partition& partition);
/// Partition the mesh.
/// @param[in] numPartitions the number of partitions.
/// @param[in] partitions the array of partitions. Only { faceIndex, name, and
/// materialName need be supplied}; the rest are computed.
/// @return NvCV_StatusNone if the partition was executed successfully.
/// @return NvCV_StatusTooBig if any faceIndex was >= the number of faces.
NvCV_Status partitionMesh(unsigned numPartitions, const Partition* partitions);
/// The last step after partitioning with updatePartition().
/// This is not needed if the partitions were created solely with the use of
/// startPartition() or PartitionMesh().
/// @note The partitions may be reordered (sorted) after calling finishPartitioning().
void finishPartitioning();
/// Set a single material for the whole mesh.
/// @param[in] name the name of the material.
NvCV_Status setMaterial(const char* name);
/// Get the bounding box, optionally with an affine transformation.
/// @param[out] bbox a place to store the bounding box.
/// @param[in] M pointer to a modeling matrix; NULL implies the identity.
void getBoundingBox(BoundingBox* bbox, const glm::mat4x4* M = nullptr) const;
/// Get the bounding box, optionally with an affine transformation.
/// @param[out] bbox a place to store the bounding box.
/// @param[in] M pointer to a modeling matrix; NULL implies the identity.
void getBoundingSphere(BoundingSphere* bsph, const glm::mat4x4* M = nullptr) const;
/// Query whether the PolyMesh is not renderable easily by Open GL.
/// Since the more typical query would be whether it is renderable instead,
/// this seems like negative logic, but this choice was made to return a bit vector
/// indicating the reason that the Polymesh is not renderable.
/// @param[in] options Rendering options; currently ignored.
/// @return RENDERABLE if the PolyMesh is renderable. Otherwise a bit vector of:
/// NOT_TRIMESH if some faces are not triangular;
/// COMPLEX_TOPOLOGY if the vertex attribute topology is inconsistent;
unsigned notRenderable(unsigned options) const;
/// Append another mesh.
/// @param[in] mesh the other mesh.
/// @param[in] M an optional affine transform
NvCV_Status append(const GLMesh& mesh, const glm::mat4x4* M = nullptr);
/// Bit vector components indicating non-renderability.
enum {
RENDERABLE = 0x0, ///< The PolyMesh is renderable.
NOT_TRIMESH = 0x1, ///< Some faces are not triangular.
COMPLEX_TOPOLOGY = 0x2 ///< The vertex topology is not consistent.
};
private:
void initPartitions();
void computeStartingVertexIndices();
static bool indicesMatch(const std::vector<unsigned short>& ivecA, const std::vector<unsigned short>& ivecB);
void assureConsistency();
void useFaceNormals(bool yes);
std::vector<unsigned short> m_faceVertexCount;
std::vector<glm::vec3> m_vertices;
std::vector<unsigned short> m_vertexIndices;
std::vector<glm::vec2> m_texCoords;
std::vector<unsigned short> m_textureIndices;
std::vector<glm::vec3> m_normals;
std::vector<unsigned short> m_normalIndices;
std::vector<glm::vec3> m_faceNormals;
std::vector<Partition> m_partitions;
std::vector<unsigned short> m_vertexFaceCount; // the number of faces surrounding each vertex
std::vector<unsigned short> m_dualIndices; // the face indices for each vertex
};
#endif // __GLMESH_H

View File

@@ -0,0 +1,632 @@
/*###############################################################################
#
# Copyright 2016-2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifdef _MSC_VER
#include "glad/glad.h"
#else
#include <GLES3/gl3.h>
#endif // _MSC_VER
#include <string>
#include <stdint.h>
#include "GLShaders.h"
enum {
myErrNone = 0,
myErrShader = -1,
myErrProgram = -2,
myErrTexture = -3,
};
#define BAIL_IF_ERR(err) do { if ((err)) { goto bail; } } while(0)
#define _STRINGIFY_(token) #token
#define STRINGIFY(token) _STRINGIFY_(token)
#define MAYBE_UNUSED(token) if (token){}
/****************************************************************************//**
* Print Shader Log.
* \param[in] id the ID of the shader.
* \param[in] type either GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
* \param[in] shader the shader source code.
********************************************************************************/
static void PrintShaderLog(GLuint id, GLenum type, const char *shader) {
GLsizei msgLength;
std::string errMsg;
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &msgLength);
errMsg.resize(msgLength);
glGetShaderInfoLog(id, msgLength, &msgLength, &errMsg[0]);
fprintf(stderr, "\nShader Log:\n%sfor %s Shader:\n%s\n", errMsg.c_str(),
((type == GL_VERTEX_SHADER) ? "Vertex" : "Fragment"), shader);
}
/****************************************************************************//**
* Print Program Log.
* \param[in] id the id of the program.
********************************************************************************/
static void PrintProgramLog(GLuint id) {
GLsizei msgLength;
std::string errMsg;
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &msgLength);
errMsg.resize(msgLength);
glGetProgramInfoLog(id, msgLength, &msgLength, &errMsg[0]);
fprintf(stderr, "\nProgram Log:\n%s\n", errMsg.c_str());
}
/****************************************************************************//**
* NewShader
********************************************************************************/
static int NewShader(const char *shaderStr, GLenum type, GLuint *shaderID) {
GLuint id;
GLint result;
*shaderID = 0;
id = glCreateShader(type);
glShaderSource(id, 1, &shaderStr, NULL);
glCompileShader(id);
glGetShaderiv(id, GL_COMPILE_STATUS, &result);
if (result) {
*shaderID = id;
return myErrNone;
}
else {
PrintShaderLog(id, type, shaderStr);
glDeleteShader(id);
return myErrShader;
}
}
/****************************************************************************//**
* NewProgram
********************************************************************************/
static int NewProgram(GLuint vertexShader, GLuint fragmentShader, GLuint *progID) {
GLint result;
GLuint id;
*progID = 0;
id = glCreateProgram();
glAttachShader(id, vertexShader);
glAttachShader(id, fragmentShader);
glLinkProgram(id);
glGetProgramiv(id, GL_LINK_STATUS, &result);
if (result) {
*progID = id;
return myErrNone;
}
else {
PrintProgramLog(id);
glDeleteProgram(id);
return myErrProgram;
}
}
/****************************************************************************//**
* IndexTypeFromSize
********************************************************************************/
static GLenum IndexTypeFromSize(unsigned indexSize) {
return (indexSize < 2) ? GL_UNSIGNED_BYTE
: (indexSize == 2) ? GL_UNSIGNED_SHORT
: GL_UNSIGNED_INT;
}
/********************************************************************************
********************************************************************************
***** SMOOTH RENDERER *****
********************************************************************************
********************************************************************************/
/********************************************************************************
* Shaders
********************************************************************************/
const char SmoothRenderer::_vertexShader[] =
"uniform mat4 MVP;\n"
"attribute vec3 vCol;\n"
"attribute vec3 vPos;\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(vPos, 1.0);\n"
" color = vCol;\n"
"}\n";
const char SmoothRenderer::_fragmentShader[] =
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(color, 1.0);\n"
"}\n";
/********************************************************************************
* startup
********************************************************************************/
int SmoothRenderer::startup() {
int err = myErrNone;
GLuint vertexShader = 0, fragmentShader = 0;
_programID = 0;
BAIL_IF_ERR(err = NewShader(_vertexShader, GL_VERTEX_SHADER, &vertexShader));
BAIL_IF_ERR(err = NewShader(_fragmentShader, GL_FRAGMENT_SHADER, &fragmentShader));
BAIL_IF_ERR(err = NewProgram(vertexShader, fragmentShader, &_programID));
_maxtrixID = glGetUniformLocation(_programID, "MVP");
_vtxPosID = glGetAttribLocation(_programID, "vPos");
_vtxColID = glGetAttribLocation(_programID, "vCol");
err = (-1 == _maxtrixID || -1 == _vtxPosID || -1 == _vtxColID) ? myErrShader : myErrNone;
bail:
if (myErrNone != err) shutdown();
if (fragmentShader) glDeleteShader(fragmentShader);
if (vertexShader) glDeleteShader(vertexShader);
return err;
}
/********************************************************************************
* use
********************************************************************************/
int SmoothRenderer::use() {
if (0 == _programID)
return myErrProgram;
glUseProgram(_programID);
return myErrNone;
}
/********************************************************************************
* drawElements, from user memory
********************************************************************************/
void SmoothRenderer::drawElements(GLsizei numVertices, const GLfloat *positions, const GLfloat *colors,
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid *indices, const GLfloat *M
) {
MAYBE_UNUSED(numVertices);
glUseProgram(_programID);
if (M)
glUniformMatrix4fv(_maxtrixID, 1, GL_FALSE, M);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (colors) { /* Separate array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*positions), positions);
glEnableVertexAttribArray(_vtxColID);
glVertexAttribPointer(_vtxColID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*colors), colors);
}
else { /* One contiguous array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*positions), positions);
glEnableVertexAttribArray(_vtxColID);
glVertexAttribPointer(_vtxColID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*positions), positions + 3);
}
glDrawElements(graphicsMode, indexCount, indexType, indices);
}
/********************************************************************************
* drawElements, from buffer objects
********************************************************************************/
void SmoothRenderer::drawElements(GLuint vtxBuf, unsigned posOff, unsigned colOff,
GLenum graphicsMode, GLsizei numIndices, unsigned indexSize, GLuint topoBuf, const GLfloat *M
) {
GLenum err;
glUseProgram(_programID);
if (M)
glUniformMatrix4fv(_maxtrixID, 1, GL_FALSE, M);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuf);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, topoBuf);
if (!(colOff == 12 || colOff == 0)) { /* Separate array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)posOff);
glEnableVertexAttribArray(_vtxColID);
glVertexAttribPointer(_vtxColID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)colOff);
}
else { /* One contiguous array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(intptr_t)(posOff + 0 * sizeof(float)));
glEnableVertexAttribArray(_vtxColID);
glVertexAttribPointer(_vtxColID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(intptr_t)(posOff + 3 * sizeof(float)));
err = glGetError(); if (err) printf("glVertexAttribPointer returns %d\n", err);
}
glDrawElements(graphicsMode, numIndices, IndexTypeFromSize(indexSize), (void*)0);
}
/********************************************************************************
********************************************************************************
***** TEXTURE RENDERER *****
********************************************************************************
********************************************************************************/
/********************************************************************************
* shaders
********************************************************************************/
const char TextureRenderer::_vertexShader[] =
"uniform mat4 MVP;\n" // Model, view, projection matrices, concatenated.
"attribute vec3 vPos;\n" // Vertex position
"attribute vec2 vTex;\n" // Vertex texture coordinate
"varying vec2 texCoord;\n" // Interpolated texture coordinate
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(vPos, 1.0);\n"
" texCoord = vTex;\n"
"}\n";
const char TextureRenderer::_fragmentShader[] =
"uniform sampler2D tex;\n"
"varying vec2 texCoord;\n" // Interpolated texture coordinate
"void main()\n"
"{\n"
" gl_FragColor = texture2D(tex, texCoord);\n"
"}\n";
/********************************************************************************
* startup
********************************************************************************/
int TextureRenderer::startup() {
int err = myErrNone;
GLuint vertexShader = 0, fragmentShader = 0;
if (_programID)
return myErrNone;
_programID = 0;
BAIL_IF_ERR(err = NewShader(_vertexShader, GL_VERTEX_SHADER, &vertexShader));
BAIL_IF_ERR(err = NewShader(_fragmentShader, GL_FRAGMENT_SHADER, &fragmentShader));
BAIL_IF_ERR(err = NewProgram(vertexShader, fragmentShader, &_programID));
_maxtrixID = _vtxPosID = _vtxTexID = -1;
_maxtrixID = glGetUniformLocation(_programID, "MVP");
_vtxPosID = glGetAttribLocation(_programID, "vPos");
_vtxTexID = glGetAttribLocation(_programID, "vTex");
err = (-1 == _maxtrixID || -1 == _vtxPosID || -1 == _vtxTexID) ? myErrShader : myErrNone;
bail:
if (myErrNone != err) shutdown();
if (fragmentShader) glDeleteShader(fragmentShader);
if (vertexShader) glDeleteShader(vertexShader);
return err;
}
/********************************************************************************
* use
********************************************************************************/
int TextureRenderer::use() {
if (0 == _programID)
return myErrProgram;
glUseProgram(_programID);
return myErrNone;
}
/********************************************************************************
* drawElements, from user buffers
********************************************************************************/
void TextureRenderer::drawElements(GLsizei numVertices, const GLfloat *xyz, const GLfloat *uv,
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid *indices, GLuint texID ,const GLfloat *M
) {
MAYBE_UNUSED(numVertices);
glUseProgram(_programID);
if (M)
glUniformMatrix4fv(_maxtrixID, 1, GL_FALSE, M);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, texID);
if (uv) { /* Separate array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*xyz), xyz);
glEnableVertexAttribArray(_vtxTexID);
glVertexAttribPointer(_vtxTexID, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(*uv), uv);
}
else { /* One contiguous array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(*xyz), xyz);
glEnableVertexAttribArray(_vtxTexID);
glVertexAttribPointer(_vtxTexID, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(*xyz), xyz + 3);
}
glDrawElements(graphicsMode, indexCount, indexType, indices);
}
/********************************************************************************
* drawElements, from buffer objects
********************************************************************************/
void TextureRenderer::drawElements(
GLuint vtxBuf, unsigned xyzOff, unsigned uvOff, GLenum graphicsMode,
GLsizei numIndices, GLenum indexSize, GLuint indexBuf, GLuint texID, const GLfloat *M
) {
GLenum err;
glUseProgram(_programID);
if (M)
glUniformMatrix4fv(_maxtrixID, 1, GL_FALSE, M);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuf);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
glBindTexture(GL_TEXTURE_2D, texID);
if (!(uvOff == 12 || uvOff == 0)) { /* Separate array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)xyzOff);
glEnableVertexAttribArray(_vtxTexID);
glVertexAttribPointer(_vtxTexID, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(intptr_t)uvOff);
}
else { /* One contiguous array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(intptr_t)(xyzOff + 0 * sizeof(float)));
glEnableVertexAttribArray(_vtxTexID);
glVertexAttribPointer(_vtxTexID, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(intptr_t)(xyzOff + 3 * sizeof(float)));
err = glGetError(); if (err) printf("glVertexAttribPointer returns %d\n", err);
}
glDrawElements(graphicsMode, numIndices, IndexTypeFromSize(indexSize), (void*)0);
}
/********************************************************************************
* drawQuad, from user buffers
********************************************************************************/
void TextureRenderer::drawQuad(const float xyz[4*3], const float uv[4*2], GLuint texID, const float *M) {
static const unsigned char indices[4] = { 0, 1, 2, 3 }; // These need to be static, because GL is asynchronous
drawElements(4, xyz, uv, GL_TRIANGLE_FAN, 4, GL_UNSIGNED_BYTE, indices, texID, M);
}
/********************************************************************************
* Mesh shader
********************************************************************************/
class MeshShader {
static const char _vertexShader[], _fragmentShader[];
};
// The ambient and diffuse coefficients are rolled into the ambCol and litCol, respectively.
const char MeshShader::_vertexShader[] =
"uniform mat4 MVP;\n" // Model, view, projection matrices, concatenated.
"uniform mat3 N;\n" // Normal matrix.
"uniform vec3 litDir;\n" // Light direction
"uniform vec3 litCol;\n" // Light color multiplied by the diffuse coefficient
"uniform vec3 ambCol;\n" // Ambient color multiplied by the ambient coefficient
"attribute vec3 vtxPos;\n" // Vertex position
"attribute vec3 vtxNor;\n" // Vertex normal
"attribute vec2 vtxTex;\n" // Vertex texture coordinate
"varying vec2 texCoord;\n" // Interpolated texture coordinate
"varying vec3 illum;\n" // Interpolated illumination
"void main()\n"
"{\n"
" gl_Position = MVP * vec4(vtxPos, 1.0);\n"
" texCoord = vtxTex;\n"
" illum = max(dot(N * vtxNor, litDir) * litCol + ambCol;\n"
"}\n";
/********************************************************************************
* UpdateTexture
********************************************************************************/
GLenum UpdateTexture(GLint texID, GLsizei width, GLsizei height, GLsizei rowBytes, GLenum glFormat, const GLvoid *pixels) {
glBindTexture(GL_TEXTURE_2D, texID);
glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, rowBytes / 4);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, glFormat, GL_UNSIGNED_BYTE, pixels);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); // restore to default
return glGetError();
}
/********************************************************************************
********************************************************************************
***** LAMBERTIAN RENDERER *****
********************************************************************************
********************************************************************************/
/********************************************************************************
* Shaders
********************************************************************************/
const char LambertianRenderer::_vertexShader[] =
"#version 120\n"
"uniform mat4 M;\n"
"uniform mat4 VP;\n"
"uniform vec4 lightLoc[" STRINGIFY(LAMBERTIAN_NUM_LIGHTS) "];\n"
"uniform vec3 lightColor[" STRINGIFY(LAMBERTIAN_NUM_LIGHTS) "];\n"
"uniform vec3 Ka;\n"
"uniform vec3 Kd;\n"
"attribute vec3 vPos;\n"
"attribute vec3 vNrm;\n"
"varying vec3 color;\n"
"void main()\n"
"{\n"
" vec4 loc = M * vec4(vPos, 1.);\n" // Transform points into world space ...
" gl_Position = VP * loc;\n" // ... and screen space
" vec3 N = normalize(mat3(M) * vNrm);\n" // Transform normal into world space, assuming isotropic scaling
" color = Ka;\n" // Initialize color to ambient
" for (int i = 0; i < " STRINGIFY(LAMBERTIAN_NUM_LIGHTS) "; ++i)\n"
" {\n"
" vec3 L = normalize(lightLoc[i].xyz - lightLoc[i].w * loc.xyz);\n" // Compute vector to light: w must be either 1 or 0
" float d = dot(L, N);\n" // Lambertian lighting
" if (d > 0.)\n" // If the light hits the outside surface, ...
" color += d * lightColor[i] * Kd;\n" // ... accumulate color from the light source
" }\n"
"}\n";
const char LambertianRenderer::_fragmentShader[] =
"varying vec3 color;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(color, 1.);\n" // Interpolate the color
"}\n";
/********************************************************************************
* startup
********************************************************************************/
int LambertianRenderer::startup() {
int err = myErrNone;
GLuint vertexShader = 0, fragmentShader = 0;
_programID = 0;
BAIL_IF_ERR(err = NewShader(_vertexShader, GL_VERTEX_SHADER, &vertexShader));
BAIL_IF_ERR(err = NewShader(_fragmentShader, GL_FRAGMENT_SHADER, &fragmentShader));
BAIL_IF_ERR(err = NewProgram(vertexShader, fragmentShader, &_programID));
_lightLoc = glGetUniformLocation(_programID, "lightLoc"); // light locations
_lightColor = glGetUniformLocation(_programID, "lightColor"); // light diffuse colors
_MmatrixID = glGetUniformLocation(_programID, "M"); // M matrix; require UL 3x3 to be orthogonal
_VPmatrixID = glGetUniformLocation(_programID, "VP"); // VP matrix
_ambientColorID = glGetUniformLocation(_programID, "Ka"); // ambient color
_diffuseColorID = glGetUniformLocation(_programID, "Kd"); // diffuse color
_vtxPosID = glGetAttribLocation(_programID, "vPos"); // vertex positions
_vtxNrmID = glGetAttribLocation(_programID, "vNrm"); // vertex normals
err = (-1 == _lightLoc || -1 == _lightColor || -1 == _MmatrixID || -1 == _VPmatrixID || -1 == _ambientColorID
|| -1 == _diffuseColorID || -1 == _vtxPosID || -1 == _vtxNrmID) ? myErrShader : myErrNone;
BAIL_IF_ERR(err);
bail:
if (myErrNone != err) shutdown();
if (fragmentShader) glDeleteShader(fragmentShader);
if (vertexShader) glDeleteShader(vertexShader);
return err;
}
/********************************************************************************
* use
********************************************************************************/
int LambertianRenderer::use() {
if (0 == _programID)
return myErrProgram;
glUseProgram(_programID);
return myErrNone;
}
/********************************************************************************
* set lights
********************************************************************************/
void LambertianRenderer::setLights(const float locXYZW[4*LAMBERTIAN_NUM_LIGHTS], const float colorRGB[3*LAMBERTIAN_NUM_LIGHTS]) {
glUseProgram(_programID);
glUniform4fv(_lightLoc, LAMBERTIAN_NUM_LIGHTS, locXYZW);
glUniform3fv(_lightColor, LAMBERTIAN_NUM_LIGHTS, colorRGB);
}
/********************************************************************************
* drawElements, from user memory
********************************************************************************/
void LambertianRenderer::drawElements(GLsizei numVertices, const GLfloat *positions, const GLfloat *normals,
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid *indices,
const GLfloat M[4*4], const GLfloat VP[4*4], const float Ka[3], const float Kd[3]
) {
MAYBE_UNUSED(numVertices);
glUseProgram(_programID);
if (M) glUniformMatrix4fv(_MmatrixID, 1, GL_FALSE, M);
if (VP) glUniformMatrix4fv(_VPmatrixID, 1, GL_FALSE, VP);
if (Ka) glUniform3fv(_ambientColorID, 1, Ka);
if (Kd) glUniform3fv(_diffuseColorID, 1, Kd);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
if (normals) { /* Separate array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*positions), positions);
glEnableVertexAttribArray(_vtxNrmID);
glVertexAttribPointer(_vtxNrmID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(*normals), normals);
}
else { /* One contiguous array for position and color */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*positions), positions);
glEnableVertexAttribArray(_vtxNrmID);
glVertexAttribPointer(_vtxNrmID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(*normals), normals + 3);
}
glDrawElements(graphicsMode, indexCount, indexType, indices);
}
/********************************************************************************
* drawElements, from buffer objects
********************************************************************************/
void LambertianRenderer::drawElements(GLuint vtxBuf, unsigned posOff, unsigned nrmOff,
GLenum graphicsMode, GLsizei numIndices, unsigned indexSize, GLuint indexBuf,
const GLfloat M[4*4], const GLfloat VP[4*4], const float Ka[3], const float Kd[3]
) {
GLenum err;
glUseProgram(_programID);
if (M) glUniformMatrix4fv(_MmatrixID, 1, GL_FALSE, M);
if (VP) glUniformMatrix4fv(_VPmatrixID, 1, GL_FALSE, VP);
if (Ka) glUniform3fv(_ambientColorID, 1, Ka);
if (Kd) glUniform3fv(_diffuseColorID, 1, Kd);
glBindBuffer(GL_ARRAY_BUFFER, vtxBuf);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuf);
if (!(nrmOff == 12 || nrmOff == 0)) { /* Separate array for position and normal */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)posOff);
glEnableVertexAttribArray(_vtxNrmID);
glVertexAttribPointer(_vtxNrmID, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(intptr_t)nrmOff);
}
else { /* One contiguous array for position and normal */
glEnableVertexAttribArray(_vtxPosID);
glVertexAttribPointer(_vtxPosID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(intptr_t)(posOff + 0 * sizeof(float)));
glEnableVertexAttribArray(_vtxNrmID);
glVertexAttribPointer(_vtxNrmID, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(intptr_t)(posOff + 3 * sizeof(float)));
err = glGetError(); if (err) printf("glVertexAttribPointer returns %d\n", err);
}
glDrawElements(graphicsMode, numIndices, IndexTypeFromSize(indexSize), (void*)0);
}

View File

@@ -0,0 +1,366 @@
/*###############################################################################
#
# Copyright 2016-2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __ARSHADERS_H__
#define __ARSHADERS_H__
#ifdef _MSC_VER
#include "glad/glad.h"
#else
#include <GLES3/gl3.h>
#endif // _MSC_VER
/********************************************************************************
********************************************************************************
***** SMOOTH RENDERER *****
********************************************************************************
********************************************************************************/
class SmoothRenderer {
public:
SmoothRenderer() { _programID = 0; }
~SmoothRenderer() { shutdown(); }
int startup();
void shutdown() { if (_programID) glDeleteProgram(_programID); _programID = 0; }
int use();
int activate() { return startup(); } // DEPRECATED
void deactivate() { shutdown(); } // DEPRECATED
/** These take vertex and topology data in user-space buffers.
* @param[in] numPts The number of points in xyz or rgb.
* @param[in] xyz The vertex locations {x, y, z }.
* @param[in] rgb The vertex colors { r, g, b }, in [0, 1].
* @param[in] numIndices The number of indices.
* @param[in] indices The indices. Note that three versions are given, where indices can be 1, 2, or 4 bytes.
* @param[in] M the matrix.
*/
void drawTriMesh(unsigned numPts, const float* xyz, const float* rgb,
unsigned numIndices, const unsigned char* indices, const float* M = nullptr) {
drawElements(numPts, xyz, rgb, GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, indices, M);
}
void drawTriMesh(unsigned numPts, const float* xyz, const float* rgb,
unsigned numIndices, const unsigned short* indices, const float* M = nullptr) {
drawElements(numPts, xyz, rgb, GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices, M);
}
void drawTriMesh(unsigned numPts, const float* xyz, const float* rgb,
unsigned numIndices, const unsigned int* indices, const float* M = nullptr) {
drawElements(numPts, xyz, rgb, GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, indices, M);
}
/** These take vertex and topology data in GL buffer objects
* @param[in] vtxBuf the vertex buffer object identifier.
* @param[in] xyzOff the offset, in bytes, of the xyz positions in the vertex buffer.
* @param[in] rgbOff the offset, in bytes, of the rgb color in the vertex buffer.
* @param[in] numIndices the number of indices.
* @param[in] indexBuf the index buffer object identifier.
* @param[in] indexSize the byte size of the indices: 1, 2, or 4.
* @param[in] M the matrix.
*/
void drawTriMesh(GLuint vtxBuf, unsigned xyzOff, unsigned rgbOff,
unsigned numIndices, GLuint indexBuf, GLenum indexSize, const float* M) {
drawElements(vtxBuf, xyzOff, rgbOff, GL_TRIANGLES, numIndices, indexSize, indexBuf, M);
}
private:
/** Render geometry from user buffers, pre-shaded at vertices.
* @param[in] numVertices The number of 3D vertices.
* @param[in] positions The array of 3D positions -- one for every vertex.
* @param[in] colors The array of RGB colors -- one for every vertex.
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
* GL_QUADS is not supported.
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
* from the vertices and graphics mode.
* @param[in] indexType The type of index { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }.
* @param[in] indices The array of vertices.
* @param[in] M The modeling-viewing-projection matrix.
*/
void drawElements(GLsizei numVertices, const GLfloat* positions, const GLfloat* colors,
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid* indices, const GLfloat* M);
/** Render geometry from GL buffer objects, pre-shaded at vertices.
* @param[in] vtxBuf The ID of the GL buffer used to store the vertices.
* @param[in] posOff The offset of the positions in the vertex buffer. This is typically 0,
* but is not restricted so.
* @param[in] colOff The offset of the colors in the vertex buffer. Both planar (homogeneous, separate)
* and chunky (nonhomogeneous, interleaved) representations are accommodated.
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
* GL_QUADS is not supported.
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
* from the vertices and graphics mode.
* @param[in] indexType The type of index { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }.
* @param[in] indexBuf The ID of the GL buffer used to store the indices.
* @param[in] M The modeling-viewing-projection matrix.
*/
void drawElements(GLuint vtxBuf, unsigned posOff, unsigned colOff,
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, GLuint indexBuf, const GLfloat* M);
GLuint _programID;
GLint _maxtrixID, _vtxPosID, _vtxColID;
static const char _vertexShader[], _fragmentShader[];
};
/********************************************************************************
********************************************************************************
***** TEXTURE RENDERER *****
********************************************************************************
********************************************************************************/
class TextureRenderer {
public:
TextureRenderer() { _programID = 0; }
~TextureRenderer() { shutdown(); }
int startup();
void shutdown() { if (_programID) glDeleteProgram(_programID); _programID = 0; }
int use();
int activate() { return startup(); } // DEPRECATED
void deactivate() { shutdown(); } // DEPRECATED
/** These take vertex and topology data in user-space buffers.
* @param[in] numPts The number of points in xyz or uv.
* @param[in] xyz The vertex locations {x, y, z }.
* @param[in] uv The vertex texture coordinates { u, v }, in [0, 1].
* @param[in] numIndices The number of indices.
* @param[in] indices The indices. Note that three versions are given, where indices can be 1, 2, or 4 bytes.
* @param[in] texID The texture ID.
* @param[in] M the matrix. NULL keeps the matrix as it was in the last invocation.
*/
void drawTriMesh(unsigned numPts, const float* xyz, const float* uv,
unsigned numIndices, const unsigned char* indices, GLuint texID, const float* M = nullptr) {
drawElements(numPts, xyz, uv, GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, indices, texID, M);
}
void drawTriMesh(unsigned numPts, const float* xyz, const float* uv,
unsigned numIndices, const unsigned short* indices, GLuint texID, const float* M = nullptr) {
drawElements(numPts, xyz, uv, GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices, texID, M);
}
void drawTriMesh(unsigned numPts, const float* xyz, const float* uv,
unsigned numIndices, const unsigned int* indices, GLuint texID, const float* M = nullptr) {
drawElements(numPts, xyz, uv, GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, indices, texID, M);
}
/** Draw a texture-mapped quadrilateral.
* @param[in] xyz The vertex locations {x, y, z }.
* @param[in] uv The vertex texture coordinates { u, v }, in [0, 1].
* @param[in] texID The texture ID.
* @param[in] M the matrix. NULL keeps the matrix as it was in the last invocation.
*/
void drawQuad(const float xyz[4 * 3], const float uv[4 * 2], GLuint texID, const float* M = nullptr);
/** These take vertex and topology data in GL buffer objects
* @param[in] vtxBuf the vertex buffer object identifier.
* @param[in] xyzOff the offset, in bytes, of the xyz positions in the vertex buffer.
* @param[in] uvOff the offset, in bytes, of the texture coordinates in the vertex buffer.
* @param[in] numIndices the number of indices.
* @param[in] indexBuf the index buffer object identifier.
* @param[in] indexSize the byte size of the indices: 1, 2, or 4.
* @param[in] texID The texture ID.
* @param[in] M the matrix. NULL keeps the matrix as it was in the last invocation.
*/
void drawTriMesh(GLuint vtxBuf, unsigned xyzOff, unsigned rgbOff,
unsigned numIndices, GLuint indexBuf, GLenum indexSize, GLuint texID, const float* M) {
drawElements(vtxBuf, xyzOff, rgbOff, GL_TRIANGLES, numIndices, indexSize, indexBuf, texID, M);
}
private:
/** Render geometry from user buffers.
* @param[in] numVertices The number of 3D vertices.
* @param[in] positions The array of 3D positions -- one for every vertex.
* @param[in] uv The array of texture coordinates -- one for every vertex.
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
* GL_QUADS is not supported.
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
* from the vertices and graphics mode.
* @param[in] indexType The type of index { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }.
* @param[in] indices The array of vertices.
* @param[in] texID The ID of the texture to be used.
* @param[in] M The modeling-viewing-projection matrix.
*/
void drawElements(GLsizei numVertices, const GLfloat* positions, const GLfloat* uv, GLenum graphicsMode,
GLsizei indexCount, GLenum indexType, const GLvoid* indices, GLuint texID, const GLfloat* M);
/** Render geometry from GL buffer objects.
* @param[in] vtxBuf The ID of the GL buffer used to store the vertices.
* @param[in] posOff The offset of the positions in the vertex buffer. This is typically 0,
* but is not restricted so.
* @param[in] uvOff The offset of the texture coordinates in the vertex buffer. Both planar
* (homogeneous, separate) and chunky (nonhomogeneous, interleaved)
* representations are accommodated.
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
* GL_QUADS is not supported.
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
* from the vertices and graphics mode.
* @param[in] indexSize The size of index { 1, 2, 4 } in bytes.
* @param[in] indexBuf The ID of the GL buffer used to store the indices.
* @param[in] texID The ID of the texture to be used.
* @param[in] M The modeling-viewing-projection matrix.
*/
void drawElements(GLuint vtxBuf, unsigned posOff, unsigned uvOff, GLenum graphicsMode,
GLsizei indexCount, GLenum indexSize, GLuint indexBuf, GLuint texID, const GLfloat* M);
GLuint _programID;
GLint _maxtrixID, _vtxPosID, _vtxTexID;
static const char _vertexShader[], _fragmentShader[];
};
/** Update the specified texture.
* @param[in] texID The ID of the texture to be updated.
* @param[in] width The width of the source image.
* @param[in] height The height of the source image.
* @param[in] rowBytes The byte stride between pixels vertically in the source image (must be positive).
* @param[in] glFormat The format of the source image. One of { GL_RGBA, GL_BGRA, GL_RGB, GL_BGR, GL_RG, GL_R }.
* @param[in] pixels A pointer to pixel(0,0) of the source image.
* @return GL_NO_ERROR if the update was successful.
*/
GLenum UpdateTexture(GLint texID, GLsizei width, GLsizei height, GLsizei rowBytes, GLenum glFormat,
const GLvoid* pixels);
/********************************************************************************
********************************************************************************
***** LAMBERTIAN SHADER *****
********************************************************************************
********************************************************************************/
/** The camera is assumed to be at the origin. Lights are represented in the camera coordinate system.
* The model coordinates are transformed M * pt;
* the normal transformed by (M{3x3})^(-1)^(T), or simply M{3x3} assuming the scaling is isotropic.
* We further assume that M{3x3} is orthonormal.
*/
class LambertianRenderer {
public:
#define LAMBERTIAN_NUM_LIGHTS 2
LambertianRenderer() { _programID = 0; }
~LambertianRenderer() { shutdown(); }
int startup();
void shutdown() { if (_programID) glDeleteProgram(_programID); _programID = 0; }
int use();
/** Set all lights. We accommodate point lights or directional lights.
* These are specified in camera space, which we assume is fixed while the objects move.
* @param[in] locXYZW The location of the lights -- in camera space.
* The homogeneous coordinate W is used to choose between
* directional lights (W=0) and point lights (W=1).
* The result is undefined for other values of W.
* @param[in] colorRGB the emissive color of the light source, RGB in [0, 1].
* To turn a light off, set its emissive color to (0,0,0).
*/
void setLights(const float locXYZW[4 * LAMBERTIAN_NUM_LIGHTS], const float colorRGB[3 * LAMBERTIAN_NUM_LIGHTS]);
/* These take vertex and topology data in user-space buffers.
* @param[in] numPts The number of points in xyz or normals.
* @param[in] xyz The vertex locations {x, y, z}.
* @param[in] nrm The vertex normals {nx, ny, nz}.
* @param[in] numIndices The number of indices.
* @param[in] indices The indices. Note that three versions are given, where indices can be 1, 2, or 4 bytes.
* @param[in] M The modeling matrix. If NULL, the previous matrix will be used.
* @param[in] VP The viewing+projection matrix. If NULL, the previous matrix will be used.
* @param[in] Ka The ambient color {r, g, b}. If NULL, the previous ambient color will be used.
* @param[in] Kd The diffuse color {r, g, b}. If NULL, the previous diffuse color will be used.
*/
void drawTriMesh(unsigned numPts, const float* xyz, const float* nrm, unsigned numIndices, const unsigned char* indices,
const float* M = nullptr, const float* VP = nullptr, const float* Ka = nullptr, const float* Kd = nullptr) {
drawElements(numPts, xyz, nrm, GL_TRIANGLES, numIndices, GL_UNSIGNED_BYTE, indices, M, VP, Ka, Kd);
}
void drawTriMesh(unsigned numPts, const float* xyz, const float* nrm, unsigned numIndices, const unsigned short* indices,
const float* M = nullptr, const float* VP = nullptr, const float* Ka = nullptr, const float* Kd = nullptr) {
drawElements(numPts, xyz, nrm, GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, indices, M, VP, Ka, Kd);
}
void drawTriMesh(unsigned numPts, const float* xyz, const float* nrm, unsigned numIndices, const unsigned int* indices,
const float* M = nullptr, const float* VP = nullptr, const float* Ka = nullptr, const float* Kd = nullptr) {
drawElements(numPts, xyz, nrm, GL_TRIANGLES, numIndices, GL_UNSIGNED_INT, indices, M, VP, Ka, Kd);
}
/* These take vertex and topology data in GL buffer objects
* @param[in] vtxBuf the vertex buffer object identifier.
* @param[in] xyzOff the offset, in bytes, of the xyz positions in the vertex buffer.
* @param[in] nrmOff the offset, in bytes, of the normals in the vertex buffer.
* @param[in] numIndices the number of indices.
* @param[in] indexBuf the index buffer object identifier.
* @param[in] indexSize the byte size of the indices: 1, 2, or 4.
* @param[in] M The modeling matrix. If NULL, the previous matrix will be used.
* @param[in] VP The viewing+projection matrix. If NULL, the previous matrix will be used.
* @param[in] Ka The ambient color {r, g, b}. If NULL, the previous ambient color will be used.
* @param[in] Kd The diffuse color {r, g, b}. If NULL, the previous diffuse color will be used.
*/
void drawTriMesh(GLuint vtxBuf, unsigned xyzOff, unsigned rgbOff, unsigned numIndices, GLuint indexBuf, GLenum indexSize,
const float* M = nullptr, const float* VP = nullptr, const float* Ka = nullptr, const float* Kd = nullptr) {
drawElements(vtxBuf, xyzOff, rgbOff, GL_TRIANGLES, numIndices, indexSize, indexBuf, M, VP, Ka, Kd);
}
private:
/** Render geometry from user buffers.
* @param[in] numVertices The number of 3D vertices.
* @param[in] positions The array of 3D positions -- one for every vertex.
* @param[in] normals The array of normals -- one for every vertex.
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
* GL_QUADS is not supported.
* @param[in] indexCount The number of 0-based vertex indices that define the geometry
* from the vertices and graphics mode.
* @param[in] indexType The type of index { GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, GL_UNSIGNED_INT }.
* @param[in] indices The array of vertices.
* @param[in] MV The modeling-viewing matrix.
* @param[in] P The projection matrix.
* @param[in] Ka The ambient color.
* @param[in] Kd The diffuse color.
*/
void drawElements(GLsizei numVertices, const GLfloat* positions, const GLfloat* normals,
GLenum graphicsMode, GLsizei indexCount, GLenum indexType, const GLvoid* indices,
const GLfloat M[4 * 4], const GLfloat VP[4 * 4], const float Ka[3], const float Kd[3]);
/** Render geometry from GL buffer objects.
* @param[in] vtxBuf The ID of the GL buffer used to store the vertices.
* @param[in] posOff The offset of the positions in the vertex buffer. This is typically 0,
* but is not restricted so.
* @param[in] nrmOff The offset of the normals in the vertex buffer. Both planar (homogeneous, separate)
* and chunky (nonhomogeneous, interleaved) representations are accommodated.
* @param[in] graphicsMode One of { GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN }.
* GL_QUADS is not supported.
* @param[in] numIndices The number of 0-based vertex indices that define the geometry
* from the vertices and graphics mode.
* @param[in] indexSize The size of index { 1, 2, 4 } in bytes.
* @param[in] indexBuf The ID of the GL buffer used to store the indices.
* @param[in] M The modeling matrix.
* @param[in] VP The viewing+projection matrix.
* @param[in] Ka The ambient color.
* @param[in] Kd The diffuse color.
*/
void drawElements(GLuint vtxBuf, unsigned posOff, unsigned nrmOff,
GLenum graphicsMode, GLsizei numIndices, unsigned indexSize, GLuint indexBuf,
const GLfloat M[4 * 4], const GLfloat VP[4 * 4], const float Ka[3], const float Kd[3]);
GLuint _programID;
GLint _MmatrixID, _VPmatrixID, _lightLoc, _lightColor, _ambientColorID, _diffuseColorID;
GLint _vtxPosID, _vtxNrmID;
static const char _vertexShader[], _fragmentShader[];
};
#endif /* __ARSHADERS_H__ */

View File

@@ -0,0 +1,106 @@
/*###############################################################################
#
# Copyright 2016-2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __GLSPECTRUM_H
#define __GLSPECTRUM_H
////////////////////////////////////////////////////////////////////////////////
/// The representation used for spectral parameters in surface illumination transport.
////////////////////////////////////////////////////////////////////////////////
struct GLSpectrum3f {
float r, g, b; ///< Red, green and blue components of the color spectrum.
/// Default constructor.
GLSpectrum3f() {}
/// Initialization constructor.
/// @param[in] R the red component.
/// @param[in] G the green component.
/// @param[in] B the blue component.
GLSpectrum3f(float R, float G, float B) { set(R, G, B); }
/// Access to the array of spectral components.
/// @return a pointer to the array of spectral components.
const float* data() const { return &r; }
/// Access to the array of spectral components.
/// @return a pointer to the array of spectral components.
float* data() { return &r; }
/// Set the spectral components.
/// @param[in] R the red component.
/// @param[in] G the green component.
/// @param[in] B the blue component.
void set(float R, float G, float B) { r = R; g = G; b = B; };
/// Componentwise scaling of the spectrum.
/// @param[in] the scaling spectrum (RHS).
/// @return The LHS, scaled by the RHS.
GLSpectrum3f& operator*=(const GLSpectrum3f& k) { r *= k.r; g *= k.g; b *= k.b; return *this; }
/// Componentwise augmentation of the spectrum.
/// @param[in] the delta spectrum (RHS).
/// @return The LHS, augmented by the RHS.
GLSpectrum3f& operator+=(const GLSpectrum3f& k) { r += k.r; g += k.g; b += k.b; return *this; }
/// Scalar scaling of the spectrum.
/// @param[in] the scalar (RHS).
/// @return The LHS, scaled by the RHS.
GLSpectrum3f& operator*=(float s) { r *= s; g *= s; b *= s; return *this; }
/// Scalar scaling of the spectrum.
/// @param[in] the scalar (RHS).
/// @return The LHS, scaled by the RHS.
GLSpectrum3f& operator/=(float s) { r /= s; g /= s; b /= s; return *this; }
/// Componentwise scaling of the spectrum.
/// @param[in] k the scaling spectrum (RHS).
/// @return The componentwise product of the LHS and RHS.
GLSpectrum3f operator*(const GLSpectrum3f& k) const { return GLSpectrum3f(r * k.r, g * k.g, b * k.b); }
/// Componentwise augmentation of the spectrum.
/// @param[in] k the scale vector (RHS).
/// @return The componentwise sum of the LHS and RHS.
GLSpectrum3f operator+(const GLSpectrum3f& k) const { return GLSpectrum3f(r + k.r, g + k.g, b + k.b); }
/// Scalar scaling of the spectrum.
/// @param[in] s the scalar (RHS).
/// @return The product of the LHS and the RHS scalar.
GLSpectrum3f operator*(float s) const { return GLSpectrum3f(r * s, g * s, b * s); }
/// Scalar scaling of the spectrum.
/// @param[in] s the scalar (RHS).
/// @return The product of the LHS and the RHS scalar.
GLSpectrum3f operator/(float s) const { return GLSpectrum3f(r / s, g / s, b / s); }
};
/// Scalar scaling of the spectrum.
/// @param[in] s the scalar (LHS).
/// @param[in] k the spectrum to be scaled (RHS).
/// @return The product of the RHS and the scalar LHS.
inline GLSpectrum3f operator*(float s, const GLSpectrum3f& k) { return GLSpectrum3f(s * k.r, s * k.g, s * k.b); }
#endif // __GLSPECTRUM_H

View File

@@ -0,0 +1,645 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#include "OpenGLMeshRenderer.h"
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#ifdef _MSC_VER
#include "glad/glad.h"
#define strcasecmp _stricmp
#else
#include <GLES3/gl3.h>
#endif // _MSC_VER
#include "FaceIO.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtc/quaternion.hpp"
#include "GLMaterial.h"
#include "GLMesh.h"
#include "GLShaders.h"
#include "GLSpectrum.h"
#include "nvAR_defs.h"
#include "nvCVOpenCV.h"
#include "opencv2/highgui/highgui.hpp"
#include "SimpleFaceModel.h"
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///// SUPPORT MACROS AND FUNCTIONS /////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#define BAIL_IF_ERR(err) do { if ((err) != 0) { goto bail; } } while(0)
#define BAIL(err, code) do { err = code; goto bail; } while(0)
#ifndef __BYTE_ORDER__ /* How bytes are packed into a 32 bit word */
#define __ORDER_LITTLE_ENDIAN__ 3210 /* First byte in the least significant position */
#define __ORDER_BIG_ENDIAN__ 0123 /* First byte in the most significant position */
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || _MSC_VER
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
#endif /* _MSC_VER */
#endif /* __BYTE_ORDER__ */
/********************************************************************************
* glfwErrorCallback
********************************************************************************/
static void glfwErrorCallback(int error, const char *description) {
fprintf(stderr, "Error %d: %s\n", error, description);
}
/********************************************************************************
* MakeGLContext
********************************************************************************/
static NvCV_Status MakeGLContext(int width, int height, const char *title, GLFWwindow **pWindow) {
NvCV_Status nvErr = NVCV_SUCCESS;
GLFWwindow *window;
/* Get a context */
glfwSetErrorCallback(glfwErrorCallback);
if (!glfwInit()) {
// Initialization failed
fprintf(stderr, "Unable to initialize glfw\n");
return NVCV_ERR_INITIALIZATION;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
window = glfwCreateWindow(width, height, title, /*GLFWmonitor */NULL, /*GLFWwindow*/NULL);
if (!window) {
// Window or OpenGL context creation failed
fprintf(stderr, "Unable to create glfw window\n");
BAIL(nvErr, NVCV_ERR_INITIALIZATION);
}
int winWidth, winHeight;
glfwGetWindowSize(window, &winWidth, &winHeight);
if (winWidth != width || winHeight != height) {
fprintf(stderr, "getWindowSize(%u x %u) != (%u x %u)\n", winWidth, winHeight, width, height);
}
glfwMakeContextCurrent(window);
#ifdef _MSC_VER
if (!gladLoadGL()) {
fprintf(stderr, "Unable to load GL\n");
BAIL(nvErr, NVCV_ERR_INITIALIZATION);
}
fprintf(stderr, "OpenGL Version %d.%d loaded\n", GLVersion.major, GLVersion.minor);
#endif // _MSC_VER
*pWindow = window;
bail:
return nvErr;
}
/********************************************************************************
* CloseGLContext
********************************************************************************/
static void CloseGLContext(GLFWwindow *window) {
if (window)
glfwDestroyWindow(window);
glfwTerminate();
}
/********************************************************************************
* ComputeDualTopologyFromAdjacencies
********************************************************************************/
static NvCV_Status ComputeDualTopologyFromAdjacencies(const SimpleFaceModelAdapter *fma, GLMesh *mesh) {
union IVF {
unsigned i;
struct VF {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
unsigned short face, vertex; // Vertex in most significant position
#else // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
unsigned short vertex, face; // Vertex in most significant position
#endif // __BYTE_ORDER__
} vf;
bool operator<( const IVF& other) { return i < other.i; }
bool operator==(const IVF& other) { return i == other.i; }
};
std::vector<IVF> topo;
topo.reserve(mesh->numVertices() * 6 * 2); // Assume valence-6, duplicated
const unsigned short *adjVertices = const_cast<SimpleFaceModelAdapter*>(fma)->getAdjacentVertices(0),
*adjFaces = const_cast<SimpleFaceModelAdapter*>(fma)->getAdjacentFaces(0);
unsigned n = fma->getAdjacentVerticesSize();
if (n != fma->getAdjacentFacesSize()) return NVCV_ERR_MISMATCH;
for (unsigned ej = 0; ej < n; ej += 2) { // 2 adjacencies per edge
for (unsigned vx = 0; vx < 2; ++vx) { // for every vertex on the edge
for (unsigned fc = 0; fc < 2; ++fc) { // and every face on the edge
IVF vf;
vf.vf.vertex = adjVertices[ej + vx];
vf.vf.face = adjFaces[ej + fc];
if (vf.vf.vertex && vf.vf.face) { // if a real vertex and a real face
--vf.vf.vertex; // convert from 1-based index ...
--vf.vf.face; // ... to 0-based index
topo.push_back(vf);
}
}
}
}
std::sort(topo.begin(), topo.end());
topo.erase(std::unique(topo.begin(), topo.end()), topo.end());
mesh->resizeDualIndices(unsigned(topo.size()));
unsigned short *dual = mesh->getDualIndices(),
*numFaces = mesh->getVertexFaceCounts();
memset(numFaces, 0, mesh->numVertices() * sizeof(*numFaces));
for (unsigned i = 0; i < topo.size(); ++i) {
numFaces[topo[i].vf.vertex]++;
dual[i] = topo[i].vf.face;
}
return NVCV_SUCCESS;
}
/********************************************************************************
* MakeMesh
********************************************************************************/
NvCV_Status MakeMesh(const SimpleFaceModelAdapter *fma, GLMesh *mesh) {
mesh->clear();
mesh->addVertices(fma->getShapeMeanSize() / 3, const_cast<SimpleFaceModelAdapter*>(fma)->getShapeMean(0));
mesh->addFaces(fma->getTriangleListSize() / 3, 3, const_cast<SimpleFaceModelAdapter*>(fma)->getTriangleList(0), 0, 0);
NvCV_Status err = ComputeDualTopologyFromAdjacencies(fma, mesh); // This make vertex normal computation lightning fast
if (NVCV_SUCCESS != err) return err;
mesh->computeVertexNormals();
if (fma->fm.partitions.size()) {
std::vector<GLMesh::Partition> parts(fma->fm.partitions.size());
for (unsigned i = unsigned(parts.size()); i--;) {
const SimpleFaceModel::Partition& fr = fma->fm.partitions[i];
GLMesh::Partition& to = parts[fr.partitionIndex];
//to.partitionIndex = fr.partitionIndex; // to doesn't have a partitionIndex
to.faceIndex = fr.faceIndex;
to.numFaces = fr.numFaces;
to.vertexIndex = fr.vertexIndex;
to.numVertexIndices = fr.numVertexIndices;
to.name = fr.name;
to.materialName = fr.materialName;
to.smooth = fr.smoothingGroup;
}
mesh->partitionMesh(unsigned(parts.size()), parts.data());
}
return NVCV_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///// RENDER CONTEXT /////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#define LAMBERTIAN_NUM_LIGHTS 2
class RenderContext {
public:
RenderContext() {
m_win = nullptr;
}
~RenderContext() {
if (m_win) CloseGLContext(m_win);
m_lam.shutdown();
m_txr.shutdown();
}
NvCV_Status init() {
if (0 != m_lam.startup())
return NVCV_ERR_OPENGL;
if (0 != m_txr.startup())
return NVCV_ERR_OPENGL;
return NVCV_SUCCESS;
}
void setClearColor(float r, float g, float b, float a = 1.f) { glClearColor(r, g, b, a); }
void setClearColor(unsigned char r, unsigned char g, unsigned char b) {
glClearColor(r * (1.f / 255.f), g * (1.f / 255.f), b * (1.f / 255.f), 1.f);
}
NvCV_Status makeWindowContext(int wd, int ht, const char *title) {
NvCV_Status err = MakeGLContext(wd, ht, title, &m_win);
if (NVCV_SUCCESS == err) {
m_width = wd;
m_height = ht;
glfwMakeContextCurrent(m_win);
glViewport(0, 0, wd, ht);
glEnable(GL_DEPTH_TEST);
glClearColor(0.f, 0.f, 0.f, 1.f);
if (/*FLAG_orientation*/0) {
glEnable(GL_CULL_FACE);
glCullFace((/*FLAG_orientation*/0 > 0) ? GL_BACK : GL_FRONT);
}
else {
glDisable(GL_CULL_FACE);
}
}
return err;
}
void computeInverseViewMatrix() {
#if 0
Vinv = glm::inverse(V);
#else // Inversion is simple because we know that it is a rigid transform
m_Vinv = glm::transpose(m_V);
m_Vinv[3][0] = -(m_Vinv[0][0] * m_V[3][0] + m_Vinv[1][0] * m_V[3][1] + m_Vinv[2][0] * m_V[3][2]);
m_Vinv[3][1] = -(m_Vinv[0][1] * m_V[3][0] + m_Vinv[1][1] * m_V[3][1] + m_Vinv[2][1] * m_V[3][2]);
m_Vinv[3][2] = -(m_Vinv[0][2] * m_V[3][0] + m_Vinv[1][2] * m_V[3][1] + m_Vinv[2][2] * m_V[3][2]);
m_Vinv[0][3] = 0.f; m_Vinv[1][3] = 0.f; m_Vinv[2][3] = 0.f; m_Vinv[3][3] = 1.f;
#endif
}
void setViewMatrix(const glm::mat4x4& viewMatrix) {
m_V = viewMatrix;
computeInverseViewMatrix();
}
void setViewMatrix(const glm::vec3& fromPoint, const glm::vec3& toPoint, const glm::vec3& upVector) {
m_V = glm::lookAt(fromPoint, toPoint, upVector);
computeInverseViewMatrix();
}
void setOrthoCamera(float hither, float yon) {
m_P = glm::orthoLH_NO(m_width * -.5f, m_width * +.5f, m_height * -.5f, m_height * +.5f, hither, yon);
}
void setOrthoCamera(float wd, float ht, float hither, float yon) {
m_P = glm::orthoLH_NO(wd * -.5f, wd * +.5f, ht * -.5f, ht * +.5f, hither, yon);
}
void setLights(const glm::vec4 locs[LAMBERTIAN_NUM_LIGHTS], const GLSpectrum3f colors[LAMBERTIAN_NUM_LIGHTS]) {
memcpy(m_lightLoc, locs, sizeof(m_lightLoc));
memcpy(m_lightColor, colors, sizeof(m_lightColor));
}
void setViewOfBound(const GLMesh::BoundingSphere& bsph, const glm::vec3& lookAt, const glm::vec3& up, float vfov,
float fracFill, float yDir = 1.f) {
float r = bsph.radius() / fracFill,
aspect = (float)m_width / (float)m_height,
signZ = -yDir,
dist;
if (vfov > 0) { // Perspective
dist = r * .5f / tanf(vfov * .5f);
m_P = glm::perspective(vfov, aspect, (dist - r) * 0.2f, (dist + r) * 2.0f);
}
else { // Orthographic
float w = r,
h = r;
if (aspect < 1.f) h /= aspect; // Wide
else w *= aspect; // Tall
dist = r * 2.f;
m_P = glm::orthoLH_NO(-w, +w, -h, +h, (dist - r) * signZ, (dist + r) * signZ);
}
m_V = glm::lookAt(bsph.center() - glm::normalize(lookAt) * dist, bsph.center(), up);
computeInverseViewMatrix();
}
void setViewOfBound(const GLMesh::BoundingBox& bbox, const glm::vec3& lookAt, const glm::vec3& up, float vfov,
float fracFill, float yDir = 1.f, float yOff = 0.f) {
glm::vec3 boxSize = bbox.max() - bbox.min();
glm::vec3 boxCenter = bbox.center();
float borderFrac = ((1.f - fracFill) / fracFill),
dx = boxSize.x * (1.f + borderFrac), // border on left and right
dy = boxSize.y * (1.f + borderFrac) * (1.f - fabsf(yOff)),
r = ((dx > dy) ? dx : dy), // radius of bounding sphere
aspectGeom = dx / dy,
aspectWind = (float)m_width / (float)m_height,
signZ = -yDir,
dist;
if (vfov > 0) { // Perspective
dist = r * .5f / tanf(vfov * .5f);
m_P = glm::perspective(vfov, aspectWind, dist - r, dist + r);
}
else { // Orthographic
if (aspectGeom > aspectWind) dy *= aspectGeom / aspectWind;
else dx *= aspectWind / aspectGeom;
dist = r * 2.f;
dx *= .5f;
dy *= .5f;
m_P = glm::orthoLH_NO(-dx, +dx, -dy, +dy, (dist - r) * signZ, (dist + r) * signZ);
}
boxCenter.y += boxSize.y * yOff;
m_V = glm::lookAt(boxCenter - glm::normalize(lookAt) * dist, boxCenter, up);
computeInverseViewMatrix();
}
NvCV_Status renderPolyMesh(const GLMesh& mesh, const glm::mat4x4& M, const char *materialOverride = nullptr) {
NvCV_Status nvErr = NVCV_SUCCESS;
glm::mat4x4 VP = m_P * m_V;
const GLSpectrum3f defaultDiffuse = { 0.77f, 0.63f, 0.55f },
defaultAmbient = defaultDiffuse * 0.3f;
#ifdef DEBUG_RENDERING
unsigned why = mesh.notRenderable(0);
if (why) {
if (FLAG_debug)
printf("Mesh %p is not renderable: %s: %s\n", &mesh,
((why & GLMesh::NOT_TRIMESH) ? "not a TriMesh" : ""),
((why & GLMesh::COMPLEX_TOPOLOGY) ? "complex topology" : "")
);
return keErrGeometry;
}
#endif // DEBUG_RENDERING
// Set lights for all shaders
m_lam.setLights(&m_lightLoc[0].x, m_lightColor[0].data()); // TODO: set this elsewhere
for (unsigned ix = 0, numPartitions = mesh.numPartitions(); ix < numPartitions; ++ix) {
GLMesh::Partition pt;
nvErr = mesh.getPartition(ix, pt);
BAIL_IF_ERR(nvErr);
const GLMaterial *mtl = m_mtlLib.getMaterial(materialOverride ? materialOverride : pt.materialName.c_str());
if (mesh.numNormals()) { // We should check for textures, too
const GLSpectrum3f *difColor, *ambColor;
if (mtl) {
difColor = &mtl->diffuseColor;
ambColor = &mtl->ambientColor;
}
else {
difColor = &defaultDiffuse;
ambColor = &defaultAmbient;
}
m_lam.drawTriMesh(mesh.numVertices(), &mesh.getVertices()->x, &mesh.getNormals()->x,
pt.numVertexIndices, mesh.getVertexIndices() + pt.vertexIndex, &M[0][0], &VP[0][0],
ambColor->data(), difColor->data());
}
}
bail:
return nvErr;
}
unsigned m_width, m_height; ///< The dimensions of the viewport.
GLFWwindow *m_win; ///< The window context.
GLMaterialLibrary m_mtlLib; ///< The material library.
glm::mat4x4 m_V, m_Vinv; ///< The viewing matrix and its inverse.
glm::mat4x4 m_P; ///< The projection matrix.
glm::vec4 m_lightLoc[LAMBERTIAN_NUM_LIGHTS]; ///< The light locations.
GLSpectrum3f m_lightColor[LAMBERTIAN_NUM_LIGHTS]; ///< The light colors.
LambertianRenderer m_lam; ///< The Lambertian renderer.
TextureRenderer m_txr; ///< The texture renderer.
};
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///// OPENGL MESH RENDERER /////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
class OpenGLMeshRenderer : public MeshRenderer {
public:
~OpenGLMeshRenderer();
static NvCV_Status initDispatch(MeshRenderer::Dispatch *dispatch);
static NvCV_Status unload();
private:
OpenGLMeshRenderer();
SimpleFaceModelAdapter _sfma;
RenderContext _ctx;
GLMesh _mesh;
glm::vec3 _ctrRot;
// C-style object-oriented member functions that are usually loaded from DLL, although in this implementation
// the OpenGLMeshRenderer is compiled directly into the ExpressionApp, and the MeshRendererBroker is
// automatically adding it to its portfolio of renderers without creating a separate DLL.
static NvCV_Status create(MeshRenderer **han);
static void destroy(MeshRenderer *han);
static NvCV_Status name(const char **str);
static NvCV_Status info(const char **str);
static NvCV_Status read(MeshRenderer *han, const char *modelFile);
static NvCV_Status init(MeshRenderer *han, unsigned width, unsigned height, const char *windowName);
static NvCV_Status setCamera(MeshRenderer *han,
const float locPt[3], const float lookVec[3], const float upVec[3], float vfov);
static NvCV_Status render(MeshRenderer *han,
const float exprs[53], const float qrot[4], const float tran[3], NvCVImage *result);
NvCV_Status setFOV(float radians);
};
NvCV_Status OpenGLMeshRenderer_InitDispatch(MeshRenderer::Dispatch *dispatch) {
return OpenGLMeshRenderer::initDispatch(dispatch);
}
NvCV_Status OpenGLMeshRenderer_Unload() {
return OpenGLMeshRenderer::unload();
}
/********************************************************************************
* DeformModel
********************************************************************************/
static NvCV_Status DeformModel(const SimpleFaceModel& model, const float *identCoeffs, const float *exprCoeffs, GLMesh *mesh) {
unsigned size = unsigned(model.shapeMean.size()) * 3, // the number of floats in the mesh vector
numCoeffs, i;
float *const dst0 = &mesh->getVertices()->x, // begin
*const dst1 = dst0 + size; // end
float const *src;
float *dst, c;
memcpy(dst0, model.shapeMean.data(), size * sizeof(*dst0)); // Initialize
if (identCoeffs) {
for (i = 0, numCoeffs = unsigned(model.shapeEigenValues.size()), src = model.shapeModes.data()->vec; i < numCoeffs; ++i, ++identCoeffs) {
if ((c = *identCoeffs) != 0.f) {
for (dst = dst0; dst != dst1;)
*dst++ += *src++ * c;
}
else {
src += size;
}
}
}
for (i = 0, numCoeffs = unsigned(model.blendShapes.size()); i < numCoeffs; ++i, ++exprCoeffs) {
if ((c = *exprCoeffs) != 0.f) {
for (dst = dst0, src = model.blendShapes[i].shape.data()->vec; dst != dst1;)
*dst++ += *src++ * c;
}
}
mesh->computeVertexNormals();
return NVCV_SUCCESS;
}
OpenGLMeshRenderer::OpenGLMeshRenderer() {
/*NvCV_Status err =*/ (void)initDispatch(&this->m_dispatch);
}
OpenGLMeshRenderer::~OpenGLMeshRenderer() {
}
NvCV_Status OpenGLMeshRenderer::name(const char **str) {
static const char name[] = "OpenGL";
*str = name;
return NVCV_SUCCESS;
}
NvCV_Status OpenGLMeshRenderer::info(const char **str) {
static const char info[] = "OpenGL renderer using local illumination";
*str = info;
return NVCV_SUCCESS;
}
NvCV_Status OpenGLMeshRenderer::create(MeshRenderer **han) {
*han = new OpenGLMeshRenderer();
return NVCV_SUCCESS;
}
void OpenGLMeshRenderer::destroy(MeshRenderer* /*han*/) {
}
NvCV_Status OpenGLMeshRenderer::read(MeshRenderer *han, const char *modelFile) {
OpenGLMeshRenderer *ren = static_cast<OpenGLMeshRenderer*>(han);
size_t z = strlen(modelFile);
if (z < 5) return NVCV_ERR_FILE;
if (!strcasecmp(".nvf", modelFile + z - 4)) {
FaceIOErr ioErr = ReadNVFFaceModel(modelFile, &ren->_sfma); // TODO clear _sfma first
if (kIOErrNone != ioErr) {
printf("Error: \"%s\": %s\n", modelFile, FaceIOErrorStringFromCode(ioErr));
return NVCV_ERR_READ;
}
NvCV_Status nvErr;
nvErr = MakeMesh(&ren->_sfma, &ren->_mesh);
if (NVCV_SUCCESS != nvErr) return nvErr;
std::string mtlFile;
mtlFile.assign(modelFile, 0, strlen(modelFile) - 3);
mtlFile += "mtl";
nvErr = ren->_ctx.m_mtlLib.read(mtlFile.c_str());
unsigned why = ren->_mesh.notRenderable(0);
if (why) {
printf("Mesh \"%s\" is not renderable: %s: %s\n", modelFile,
((why & GLMesh::NOT_TRIMESH) ? "not a TriMesh" : ""),
((why & GLMesh::COMPLEX_TOPOLOGY) ? "complex topology" : "")
);
return NVCV_ERR_MISMATCH;
}
return NVCV_SUCCESS;
}
// else if (!strcasecmp(".obj", file + z - 4)) { read obj files }
else {
return NVCV_ERR_FILE;
}
}
NvCV_Status OpenGLMeshRenderer::init(MeshRenderer *han,
unsigned width, unsigned height, const char *windowName) {
OpenGLMeshRenderer *ren = static_cast<OpenGLMeshRenderer*>(han);
static const GLSpectrum3f lightColor[LAMBERTIAN_NUM_LIGHTS] = { { 1.f, 1.f, 1.f }, { .8f, .1f, .1f } };
static const glm::vec4 lightLoc[LAMBERTIAN_NUM_LIGHTS] = { { 0, 0, +1000, 0}, { 100, -200, -500, 0 } };
NvCV_Status nvErr;
nvErr = ren->_ctx.makeWindowContext(width, height, windowName);
nvErr = ren->_ctx.init();
ren->_ctx.setClearColor(0.2f, 0.2f, 0.2f, 1.f);
ren->_ctx.setLights(lightLoc, lightColor);
ren->setFOV(0.f); // Default orthographic
return NVCV_SUCCESS;
}
NvCV_Status OpenGLMeshRenderer::setFOV(float fov) {
if (0 == _mesh.numVertices())
return NVCV_ERR_MODEL;
GLMesh::BoundingBox bbox;
_mesh.getBoundingBox(&bbox);
_ctrRot = bbox.center();
_ctrRot.y = bbox.min().y; // Assume that assets are designed with Y-up.
float vShift = (_mesh.numVertices() > 10000) ? 0.15f : 0.0f; // Heuristic to determine whether there is a neck
_ctx.setViewOfBound(bbox, glm::vec3(0.f, 0.f, -1.f), glm::vec3(0.f, +1.f, 0.f), fov, .9f, +1, vShift);
return NVCV_SUCCESS;
}
NvCV_Status OpenGLMeshRenderer::setCamera(MeshRenderer *han,
const float locPt[3], const float lookVec[3], const float upVec[3], float vfov) {
if (locPt || lookVec || upVec) {} // We don't accommodate these yet
return static_cast<OpenGLMeshRenderer*>(han)->setFOV(vfov);
}
NvCV_Status OpenGLMeshRenderer::render(MeshRenderer *han,
const float exprs[53], const float qrot[4], const float* /*tran*/, NvCVImage *result) {
OpenGLMeshRenderer *ren = static_cast<OpenGLMeshRenderer*>(han);
NvCV_Status nvErr;
glm::mat4x4 M;
glm::quat q; // Convert quaternion from {x,y,z,w} --> GLM's {w,x,y,z}
if (NVCV_RGBA != result->pixelFormat)
return NVCV_ERR_PIXELFORMAT;
if (qrot) { q.x = qrot[0]; q.y = qrot[1]; q.z = qrot[2]; q.w = qrot[3]; }
else { q.x = 0.0f; q.y = 0.0f; q.z = 0.0f; q.w = 1.0f; }
#ifndef TRANSLATE_POSE
M = glm::translate(glm::mat4x4(1.f), -ren->_ctrRot);
M = glm::mat4_cast(q) * M;
M = glm::translate(M, ren->_ctrRot);
#else // TRANSLATE_POSE
M = glm::mat4_cast(q);
if (tran)
M = glm::translate(M, *((const glm::vec3*)(trans)));
#endif // TRANSLATE_POSE
nvErr = DeformModel(ren->_sfma.fm, nullptr, exprs, &ren->_mesh);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nvErr = ren->_ctx.renderPolyMesh(ren->_mesh, M, NULL);
glReadPixels(0, 0, result->width, result->height, GL_RGBA, GL_UNSIGNED_BYTE, result->pixels);
GLenum glErr = glGetError();
if (glErr)
return NVCV_ERR_OPENGL;
// GL returns an image upside-down, but we can use the NvCVImage_FlipY in the caller to flip it with no overhead
return NVCV_SUCCESS;
}
NvCV_Status OpenGLMeshRenderer::initDispatch(MeshRenderer::Dispatch *dispatch) {
dispatch->name = &OpenGLMeshRenderer::name;
dispatch->info = &OpenGLMeshRenderer::info;
dispatch->create = &OpenGLMeshRenderer::create;
dispatch->destroy = &OpenGLMeshRenderer::destroy;
dispatch->read = &OpenGLMeshRenderer::read;
dispatch->init = &OpenGLMeshRenderer::init;
dispatch->setCamera = &OpenGLMeshRenderer::setCamera;
dispatch->render = &OpenGLMeshRenderer::render;
return NVCV_SUCCESS;
}
NvCV_Status OpenGLMeshRenderer::unload() {
return NVCV_SUCCESS;
}

View File

@@ -0,0 +1,41 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __OPENGL_MESH_RENDERER__
#define __OPENGL_MESH_RENDERER__
#include "MeshRenderer.h"
/// Initialize the renderer dispatch table.
/// @param[out] dispatch the dispatch table.
/// @return NVCV_SUCCESS if successful.
NvCV_Status OpenGLMeshRenderer_InitDispatch(MeshRenderer::Dispatch *dispatch);
/// Unload the OpenGL Mesh Renderer from memory.
/// @note Any previously initialized dispatch tables will be invalid.
/// @return NVCV_SUCCESS if successful.
NvCV_Status OpenGLMeshRenderer_Unload();
#endif // __OPENGL_MESH_RENDERER__

View File

@@ -0,0 +1,245 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __SIMPLE_FACE_MODEL__
#define __SIMPLE_FACE_MODEL__
#include <stdint.h>
#include <vector>
#include <string>
#include "FaceIO.h"
#include "nvAR_defs.h"
/********************************************************************************
* SimpleFaceModel
********************************************************************************/
struct SimpleFaceModel {
std::vector<NvAR_Point3f> shapeMean;
std::vector<NvAR_Vector3f> shapeModes; /* shapeMean.size() * numModes */
std::vector<float> shapeEigenValues;
std::vector<NvAR_Vector3u16> triangles;
struct BlendShape {
std::string name;
std::vector<NvAR_Vector3f> shape;
};
std::vector<BlendShape> blendShapes;
struct Partition {
unsigned partitionIndex; ///< The index of the partition.
unsigned faceIndex; ///< The index of the first face in the partition.
unsigned numFaces; ///< The number of faces in the partition.
unsigned vertexIndex; ///< The index of the first topological vertex in the partition.
unsigned numVertexIndices; ///< The number of topological vertices in the partition.
int smoothingGroup; ///< Smoothing group > 0; no smoothing == 0; undefined < 0.
std::string name; ///< The name of the partition.
std::string materialName; ///< The name of the material assigned to the partition.
void set(unsigned partIx, unsigned firstFaceIndex, unsigned lastFaceIndex,
unsigned firstVertexIndex, unsigned lastVertexIndex, int smooth,
const char* partName = nullptr, const char* mtrlName = nullptr) {
partitionIndex = partIx;
smoothingGroup = smooth;
faceIndex = firstFaceIndex;
numFaces = lastFaceIndex - firstFaceIndex + 1;
vertexIndex = firstVertexIndex;
numVertexIndices = lastVertexIndex - firstVertexIndex + 1;
if (partName) name = partName;
if (mtrlName) materialName = mtrlName;
}
Partition(unsigned partIx, unsigned firstFaceIndex, unsigned lastFaceIndex,
unsigned firstVertexIndex, unsigned lastVertexIndex, int smooth,
const char* partName, const char* mtrlName) {
set(partIx, firstFaceIndex, lastFaceIndex, firstVertexIndex, lastVertexIndex, smooth, partName, mtrlName);
}
Partition() { set(0, 0, 0, 0, 0, -1, nullptr, nullptr); }
};
std::vector<Partition> partitions;
std::vector<unsigned short> ibugLandmarkMappings; /* 68 */
const unsigned short ibugRightContour[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
const unsigned short ibugLeftContour[8] = { 10, 11, 12, 13, 14, 15, 16, 17 };
std::vector<unsigned short> modelRightContour;
std::vector<unsigned short> modelLeftContour;
std::vector<unsigned short> adjacentFaces;
std::vector<unsigned short> adjacentVertices;
std::vector<unsigned short> nvlmLandmarks;
std::vector<unsigned short> nvlmRightContour;
std::vector<unsigned short> nvlmLeftContour;
void appendMode(const NvAR_Point3f* pts) {
size_t n = shapeMean.size(),
off = shapeModes.size();
shapeModes.resize(off + n);
float *to = shapeModes[off].vec; // Delta mode vector
const float *fr = &pts->x; // Mode points
const float *mn = &shapeMean[0].x; // Mean points
for (n *= 3; n--;) // 3D points
*to++ = *fr++ - *mn++; // Delta shape
}
void setBlendShape(unsigned i, const std::string& name, const NvAR_Point3f* pts) {
size_t n = shapeMean.size();
blendShapes[i].name = name;
blendShapes[i].shape.resize(n);
float *to = blendShapes[i].shape.data()->vec; // Delta mode vector
const float *fr = &pts->x; // Blendshape points
const float *mn = &shapeMean[0].x; // Mean points
for (n *= 3; n--;) // 3D points
*to++ = *fr++ - *mn++; // Delta shape
}
};
/********************************************************************************
* SimpleFaceModelAdapter
********************************************************************************/
class SimpleFaceModelAdapter : public FaceIOAdapter {
public:
SimpleFaceModel fm;
uint32_t getShapeMeanSize() const override { return unsigned(fm.shapeMean.size()) * 3; }
uint32_t getShapeModesSize() const override { return unsigned(fm.shapeModes.size()) * 3; }
uint32_t getShapeNumModes() const override { return unsigned(fm.shapeModes.size() / fm.shapeMean.size()); }
uint32_t getShapeEigenvaluesSize()const override { return unsigned(fm.shapeEigenValues.size()); }
float* getShapeMean(uint32_t size) override { if (size) fm.shapeMean.resize(size / 3);
return &fm.shapeMean.data()->x; };
float* getShapeModes(uint32_t modeSize, uint32_t numModes) override {
if (modeSize) fm.shapeModes.resize(modeSize / 3 * numModes); return fm.shapeModes.data()->vec; }
float* getShapeEigenvalues(uint32_t numModes) override { if (numModes) fm.shapeEigenValues.resize(numModes);
return fm.shapeEigenValues.data(); }
uint32_t getColorMeanSize() const override { return 0; }
uint32_t getColorModesSize() const override { return 0; }
uint32_t getColorNumModes() const override { return 0; }
uint32_t getColorEigenvaluesSize() const override { return 0; }
float* getColorMean(uint32_t /*size*/) override { return nullptr; }
float* getColorModes(uint32_t /*modeSize*/, uint32_t /*numModes*/) override { return nullptr; }
float* getColorEigenvalues(uint32_t /*numModes*/) override { return nullptr; }
void setTriangleListSize(uint32_t size) override { fm.triangles.resize(size / 3); }
uint32_t getTriangleListSize() const override { return unsigned(fm.triangles.size()) * 3; }
uint16_t* getTriangleList(uint32_t size) override { if (size) fm.triangles.resize(size / 3);
return fm.triangles.data()->vec; }
void setTextureCoordinatesSize(uint32_t /*size*/) override {}
uint32_t getTextureCoordinatesSize() const override { return 0; }
float* getTextureCoordinates(uint32_t /*size*/) override { return nullptr; }
void setNumBlendShapes(uint32_t n) override { fm.blendShapes.resize(n); }
void setBlendShapeName(uint32_t i, const char* name) override { fm.blendShapes[i].name = name; }
uint32_t getNumBlendShapes() const override { return unsigned(fm.blendShapes.size()); }
const char* getBlendShapeName(uint32_t i) const override { return fm.blendShapes[i].name.c_str(); }
uint32_t getBlendShapeSize(uint32_t i) const override { return unsigned((fm.blendShapes[i].shape.size()) * 3); }
float* getBlendShape(uint32_t i, uint32_t size) override { if (size) fm.blendShapes[i].shape.resize(size / 3);
return fm.blendShapes[i].shape.data()->vec; }
void setIbugLandmarkMappingsSize(uint32_t n) override { fm.ibugLandmarkMappings.resize(n); }
uint32_t getIbugLandmarkMappingsSize() const override { return unsigned(fm.ibugLandmarkMappings.size()); }
uint16_t* getIbugLandmarkMappings(uint32_t size) override { if (size) fm.ibugLandmarkMappings.resize(size);
return fm.ibugLandmarkMappings.data(); }
void appendIbugLandmarkMapping(uint16_t i) override { fm.ibugLandmarkMappings.push_back(i); }
void appendIbugLandmarkMapping(uint16_t i, uint16_t j) override { fm.ibugLandmarkMappings.push_back(i);
fm.ibugLandmarkMappings.push_back(j); }
void setIbugRightContourSize(uint32_t /*n*/) override {}
uint32_t getIbugRightContourSize() const override {
return sizeof(fm.ibugRightContour) / sizeof(fm.ibugRightContour[0]); }
uint16_t* getIbugRightContour(uint32_t /*size*/) override { return const_cast<uint16_t*>(fm.ibugRightContour); }
void appendIbugRightContour(uint16_t /*i*/) override {}
void setIbugLeftContourSize(uint32_t /*n*/) override {}
uint32_t getIbugLeftContourSize() const override { return sizeof(fm.ibugLeftContour)/sizeof(fm.ibugLeftContour[0]);}
uint16_t* getIbugLeftContour(uint32_t /*size*/) override { return const_cast<uint16_t*>(fm.ibugLeftContour); }
void appendIbugLeftContour(uint16_t /*i*/) override {}
void setModelRightContourSize(uint32_t n) override { fm.modelRightContour.resize(n); }
uint32_t getModelRightContourSize() const override { return unsigned(fm.modelRightContour.size()); }
uint16_t* getModelRightContour(uint32_t size) override { if (size) fm.modelRightContour.resize(size);
return fm.modelRightContour.data(); }
void appendModelRightContour(uint16_t i) override { fm.modelRightContour.push_back(i); }
void setModelLeftContourSize(uint32_t n) override { fm.modelLeftContour.resize(n); }
uint32_t getModelLeftContourSize() const override { return unsigned(fm.modelLeftContour.size()); }
uint16_t* getModelLeftContour(uint32_t size) override { if (size) fm.modelLeftContour.resize(size);
return fm.modelLeftContour.data(); }
void appendModelLeftContour(uint16_t i) override { fm.modelLeftContour.push_back(i); }
void setAdjacentFacesSize(uint32_t n) override { fm.adjacentFaces.resize(n); }
uint32_t getAdjacentFacesSize() const override { return unsigned(fm.adjacentFaces.size()); }
uint16_t* getAdjacentFaces(uint32_t size) override { if (size) fm.adjacentFaces.resize(size);
return fm.adjacentFaces.data(); }
void appendAdjacentFace(uint16_t i) override { fm.adjacentFaces.push_back(i); }
void appendAdjacentFaces(uint16_t i, uint16_t j) override { fm.adjacentFaces.push_back(i);
fm.adjacentFaces.push_back(j); }
void setAdjacentVerticesSize(uint32_t n) override { fm.adjacentVertices.resize(n); }
uint32_t getAdjacentVerticesSize() const override { return unsigned(fm.adjacentVertices.size()); }
uint16_t* getAdjacentVertices(uint32_t size) override { if (size) fm.adjacentVertices.resize(size);
return fm.adjacentVertices.data(); }
void appendAdjacentVertex(uint16_t i) override { fm.adjacentVertices.push_back(i); }
void appendAdjacentVertices(uint16_t i, uint16_t j) override { fm.adjacentVertices.push_back(i);
fm.adjacentVertices.push_back(j); }
void setNvlmLandmarksSize(uint32_t n) override { fm.nvlmLandmarks.resize(n); }
uint32_t getNvlmLandmarksSize() const override { return (uint32_t)fm.nvlmLandmarks.size(); }
uint16_t* getNvlmLandmarks(uint32_t size) override { if (size) fm.nvlmLandmarks.resize(size);
return fm.nvlmLandmarks.data(); }
void appendNvlmLandmark(uint16_t i) override { fm.nvlmLandmarks.push_back(i); }
void setNvlmRightContourSize(uint32_t n) override { fm.nvlmRightContour.resize(n); }
uint32_t getNvlmRightContourSize() const override { return (uint32_t)fm.nvlmRightContour.size(); }
uint16_t* getNvlmRightContour(uint32_t size) override { if (size) fm.nvlmRightContour.resize(size);
return fm.nvlmRightContour.data(); }
void appendNvlmRightContour(uint16_t i) override { fm.nvlmRightContour.push_back(i); }
void setNvlmLeftContourSize(uint32_t n) override { fm.nvlmLeftContour.resize(n); }
uint32_t getNvlmLeftContourSize() const override { return (uint32_t)fm.nvlmLeftContour.size(); }
uint16_t* getNvlmLeftContour(uint32_t size) override { if (size) fm.nvlmLeftContour.resize(size);
return fm.nvlmLeftContour.data(); }
void appendNvlmLeftContour(uint16_t i) override { fm.nvlmLeftContour.push_back(i); }
void setNumPartitions(uint32_t n) override { fm.partitions.resize(n); }
void setPartitionName(uint32_t i, const char* name) override { fm.partitions.at(i).name = name; }
void setPartitionMaterialName(uint32_t i, const char* name) override { fm.partitions.at(i).materialName = name;}
void setPartition(uint32_t i, uint32_t faceIndex, uint32_t numFaces, uint32_t vertexIndex, uint32_t numVertices,
int32_t smoothingGroup) override {
fm.partitions.at(i).set(i, faceIndex, faceIndex + numFaces - 1, vertexIndex,
vertexIndex + numVertices - 1, smoothingGroup);
}
uint32_t getNumPartitions() const override { return (uint32_t)fm.partitions.size(); }
const char* getPartitionName(uint32_t i) const override { return fm.partitions.at(i).name.c_str(); }
const char* getPartitionMaterialName(uint32_t i) const override { return fm.partitions.at(i).materialName.c_str(); }
int16_t getPartition(uint32_t i, uint32_t* faceIndex, uint32_t* numFaces, uint32_t* vertexIndex,
uint32_t* numVertices, int32_t* smoothingGroup) const override {
const SimpleFaceModel::Partition& pt = fm.partitions.at(i);
if (faceIndex) *faceIndex = pt.faceIndex;
if (numFaces) *numFaces = pt.numFaces;
if (vertexIndex) *vertexIndex = pt.vertexIndex;
if (numVertices) *numVertices = pt.numVertexIndices;
if (smoothingGroup) *smoothingGroup = pt.smoothingGroup;
return (int16_t)pt.partitionIndex;
}
};
#endif // __SIMPLE_FACE_MODEL__

View File

@@ -0,0 +1,97 @@
######################
# The Expression app #
######################
set(APP_SRCS
ExpressionApp.cpp
MeshRenderer.cpp MeshRenderer.h
DirectoryIterator.cpp DirectoryIterator.h
BackEndOpenGL/GLMaterial.cpp BackEndOpenGL/GLMaterial.h
BackEndOpenGL/GLMesh.cpp BackEndOpenGL/GLMesh.h
BackEndOpenGL/GLShaders.cpp BackEndOpenGL/GLShaders.h
BackEndOpenGL/GLSpectrum.h
BackEndOpenGL/SimpleFaceModel.h
BackEndOpenGL/OpenGLMeshRenderer.cpp BackEndOpenGL/OpenGLMeshRenderer.h
BackEndOpenGL/FaceIO.cpp BackEndOpenGL/FaceIO.h
)
if(WIN32)
set(APP_SRCS ${APP_SRCS} nvARProxy.cpp nvCVImageProxy.cpp)
find_package(OpenGL REQUIRED)
endif(WIN32)
option(ENABLE_UI "Enable UI to adjust rigging" OFF) # ON still needs some more link debugging
if (${ENABLE_UI})
set(APP_SRCS ${APP_SRCS}
ExpressionAppUI.h
ExpressionAppUI.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imconfig.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui_internal.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imstb_textedit.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imstb_rectpack.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imstb_truetype.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_glfw.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_opengl3.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_opengl3_loader.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/misc/cpp/imgui_stdlib.h
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui_tables.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui_widgets.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/imgui_draw.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_glfw.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/backends/imgui_impl_opengl3.cpp
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking/misc/cpp/imgui_stdlib.cpp
)
endif (${ENABLE_UI})
add_executable(ExpressionApp ${APP_SRCS})
target_include_directories(ExpressionApp PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/BackEndOpenGL
${CMAKE_CURRENT_SOURCE_DIR}/../utils
${CMAKE_CURRENT_SOURCE_DIR}/../external/glm/include
${SDK_INCLUDES_PATH}
)
if (${ENABLE_UI})
add_definitions("-D_ENABLE_UI")
target_include_directories(ExpressionApp PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../external/Imgui/imgui-docking
${CMAKE_CURRENT_SOURCE_DIR}/../external/nlohmann/json/single_include/nlohmann
)
endif (${ENABLE_UI})
if(WIN32)
target_link_libraries(ExpressionApp PUBLIC
opencv346
glfw3
GLAD
${OPENGL_gl_LIBRARY}
)
target_link_directories(ExpressionApp PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../external/GLAD/lib
${CMAKE_CURRENT_SOURCE_DIR}/../external/GLFW/lib
)
target_include_directories(ExpressionApp PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/../external/GLAD/include
${CMAKE_CURRENT_SOURCE_DIR}/../external/GLFW/include
)
set(OPENCV_PATH_STR ${CMAKE_CURRENT_SOURCE_DIR}/../external/opencv/bin)
set(PATH_STR "PATH=%PATH%" ${OPENCV_PATH_STR})
set_target_properties(ExpressionApp PROPERTIES
FOLDER SampleApps
VS_DEBUGGER_ENVIRONMENT "${PATH_STR}"
VS_DEBUGGER_COMMAND_ARGUMENTS "${CMD_ARG_STR}" )
elseif(UNIX)
#find_package(PNG REQUIRED)
#find_package(JPEG REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread -fpermissive")
target_link_libraries(ExpressionApp PUBLIC
nvARPose
NVCVImage
OpenCV
glfw
OpenGL
dl
)
endif()

View File

@@ -0,0 +1,169 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#include "DirectoryIterator.h"
#ifdef _WIN32
////////////////////////////////////////////////////////////////////////////////
///// WINDOWS /////
////////////////////////////////////////////////////////////////////////////////
#include <Windows.h>
#include <string>
struct DirectoryIterator::Impl {
HANDLE h;
unsigned which;
bool first;
WIN32_FIND_DATAA data;
};
DirectoryIterator::DirectoryIterator() {
m_impl = new DirectoryIterator::Impl;
m_impl->h = nullptr;
}
DirectoryIterator::DirectoryIterator(const char *path, unsigned iterateWhat) : DirectoryIterator() {
init(path, iterateWhat);
}
DirectoryIterator::~DirectoryIterator() {
if (m_impl) {
if (m_impl->h) FindClose(m_impl->h);
delete m_impl;
}
}
int DirectoryIterator::init(const char *path, unsigned iterateWhat) {
std::string pathStar = path;
pathStar += "\\*";
if (nullptr == (m_impl->h = FindFirstFileA(pathStar.c_str(), &m_impl->data))) return -99; /* either dir or file */
m_impl->which = iterateWhat ? iterateWhat : kTypeAll;
m_impl->first = true;
return 0;
}
int DirectoryIterator::next(const char **pName, unsigned *type) {
if (!pName) return -1;
while (1) {
if (m_impl->first) {
m_impl->first = false;
}
else if (!FindNextFileA(m_impl->h, &m_impl->data)) {
*pName = nullptr;
if (type) *type = 0;
return -99;
}
*pName = m_impl->data.cFileName;
if (0 != (m_impl->data.dwFileAttributes & (
FILE_ATTRIBUTE_NORMAL |
FILE_ATTRIBUTE_ARCHIVE |
FILE_ATTRIBUTE_COMPRESSED |
FILE_ATTRIBUTE_ENCRYPTED |
FILE_ATTRIBUTE_HIDDEN |
FILE_ATTRIBUTE_INTEGRITY_STREAM |
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED |
FILE_ATTRIBUTE_NO_SCRUB_DATA |
FILE_ATTRIBUTE_READONLY |
FILE_ATTRIBUTE_REPARSE_POINT |
FILE_ATTRIBUTE_SPARSE_FILE |
FILE_ATTRIBUTE_TEMPORARY
))) {
if (m_impl->which & kTypeFile) {
if (type) *type = kTypeFile;
break;
}
}
else if (0 == (m_impl->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
if (m_impl->which & kTypeDirectory) {
if (type) *type = kTypeDirectory;
break;
}
}
else {
if (m_impl->which & kTypeSpecial) {
if (type) *type = kTypeSpecial;
break;
}
}
}
return 0;
}
#else /* !_WIN32 == UNIX */
////////////////////////////////////////////////////////////////////////////////
///// UNIX /////
////////////////////////////////////////////////////////////////////////////////
#include <dirent.h>
struct DirectoryIterator::Impl {
DIR *dp;
unsigned which;
};
DirectoryIterator::DirectoryIterator() {
m_impl = new DirectoryIterator::Impl;
m_impl->dp = nullptr;
}
DirectoryIterator::DirectoryIterator(const char* path, unsigned iterateWhat) : DirectoryIterator() {
init(path, iterateWhat);
}
DirectoryIterator::~DirectoryIterator() {
if (m_impl) {
if (m_impl->dp) closedir(m_impl->dp);
delete m_impl;
}
}
int DirectoryIterator::init(const char *path, unsigned iterateWhat) {
if (nullptr == (m_impl->dp = opendir(path))) return -1;
m_impl->which = iterateWhat ? iterateWhat : kTypeAll;
return 0;
}
int DirectoryIterator::next(const char **pName, unsigned *type) {
struct dirent *entry;
if (type) *type = 0;
if (!pName) return -1;
while (nullptr != (entry = readdir(m_impl->dp))) {
*pName = entry->d_name;
switch (entry->d_type) {
case DT_REG: if (m_impl->which & kTypeFile) { if (type) *type = kTypeFile; return 0; } break;
case DT_DIR: if (m_impl->which & kTypeDirectory) { if (type) *type = kTypeDirectory; return 0; } break;
default: if (m_impl->which & kTypeSpecial) { if (type) *type = kTypeSpecial; return 0; } break;
}
}
*pName = nullptr;
return -99;
}
#endif /* UNIX */

View File

@@ -0,0 +1,68 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __DIRECTORY_ITERATOR_H
#define __DIRECTORY_ITERATOR_H
class DirectoryIterator {
public:
enum {
kTypeFile = 1,
kTypeDirectory = 2,
kTypeSpecial = 4,
kTypeAll = (kTypeFile | kTypeDirectory | kTypeSpecial)
};
/// Constructor
DirectoryIterator();
/// Constructor
/// @param[in] path The path of the directory to iterate.
/// @param[in] iterateWhat The types of files to list.
DirectoryIterator(const char *path, unsigned iterateWhat);
/// Destructor
~DirectoryIterator();
/// Start looking in a particular directory.
/// @param[in] path The path of the directory to iterate.
/// @param[in] iterateWhat The types of files to list.
/// @return 0 If successful,
/// -1 If path was NULL,
/// -99 If there are no files.
int init(const char *path, unsigned iterateWhat);
/// Get the next file.
/// @param pName[out] a place to store the name of the next file.
/// @param type[out] a place to store the type of the next file.
/// @return 0 If successful,
/// -1 If path was NULL,
/// -99 If there are no more files.
int next(const char **pName, unsigned *type);
private:
struct Impl;
Impl *m_impl;
};
#endif // __DIRECTORY_ITERATOR_H

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,711 @@
/*###############################################################################
#
# Copyright(c) 2020 NVIDIA CORPORATION.All Rights Reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#
###############################################################################*/
#if _ENABLE_UI
#include <map>
#include <fstream>
#include <json.hpp>
#include <imgui_internal.h>
#include "nvAR_defs.h"
#include "ExpressionAppUI.h"
#define CTL(x) ((x) & 0x1F)
static std::map<int, std::string> exprMap = {
{0 ,"browDown_L "},
{1 ,"browDown_R "},
{2 ,"browInnerUp_L "},
{3 ,"browInnerUp_R "},
{4 ,"browOuterUp_L "},
{5 ,"browOuterUp_R "},
{6 ,"cheekPuff_L "},
{7 ,"cheekPuff_R "},
{8 ,"cheekSquint_L "},
{9 ,"cheekSquint_R "},
{10 ,"eyeBlink_L "},
{11 ,"eyeBlink_R "},
{12 ,"eyeLookDown_L "},
{13 ,"eyeLookDown_R "},
{14 ,"eyeLookIn_L "},
{15 ,"eyeLookIn_R "},
{16 ,"eyeLookOut_L "},
{17 ,"eyeLookOut_R "},
{18 ,"eyeLookUp_L "},
{19 ,"eyeLookUp_R "},
{20 ,"eyeSquint_L "},
{21 ,"eyeSquint_R "},
{22 ,"eyeWide_L "},
{23 ,"eyeWide_R "},
{24 ,"jawForward "},
{25 ,"jawLeft "},
{26 ,"jawOpen "},
{27 ,"jawRight "},
{28 ,"mouthClose "},
{29 ,"mouthDimple_L "},
{30 ,"mouthDimple_R "},
{31 ,"mouthFrown_L "},
{32 ,"mouthFrown_R "},
{33 ,"mouthFunnel "},
{34 ,"mouthLeft "},
{35 ,"mouthLowerDown_L"},
{36 ,"mouthLowerDown_R"},
{37 ,"mouthPress_L "},
{38 ,"mouthPress_R "},
{39 ,"mouthPucker "},
{40 ,"mouthRight "},
{41 ,"mouthRollLower "},
{42 ,"mouthRollUpper "},
{43 ,"mouthShrugLower "},
{44 ,"mouthShrugUpper "},
{45 ,"mouthSmile_L "},
{46 ,"mouthSmile_R "},
{47 ,"mouthStretch_L "},
{48 ,"mouthStretch_R "},
{49 ,"mouthUpperUp_L "},
{50 ,"mouthUpperUp_R "},
{51 ,"noseSneer_L "},
{52 ,"noseSneer_R "}
};
static const unsigned int browStartIndex = 0;
static const unsigned int browEndIndex = 5;
static const unsigned int cheekStartIndex = 6;
static const unsigned int cheekEndIndex = 9;
static const unsigned int eyeStartIndex = 10;
static const unsigned int eyeEndIndex = 23;
static const unsigned int jawStartIndex = 24;
static const unsigned int jawEndIndex = 27;
static const unsigned int mouthStartIndex = 28;
static const unsigned int mouthEndIndex = 50;
static const unsigned int noseStartIndex = 51;
static const unsigned int noseEndIndex = 52;
static void glfw_error_callback(int error, const char* description) {
printf("Glfw Error %d: %s\n", error, description);
}
void ExpressionAppUI::init(int numExpr, int filter, int exprMode, int display, int showFPS) {
keyboard_input_ = -1;
filter_face_box_ = (filter & (NVAR_TEMPORAL_FILTER_FACE_BOX)) ? true : false;
filter_face_landmark_ = (filter & (NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS)) ? true : false;
filter_face_rot_pose_ = (filter & (NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE)) ? true : false;
filter_face_expr_ = (filter & (NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS)) ? true : false;
filter_face_gaze_ = (filter & (NVAR_TEMPORAL_FILTER_FACIAL_GAZE)) ? true : false;
filter_enhance_expr_ = (filter & (NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS)) ? true : false;
num_expressions_ = numExpr;
show_expr_ = false;
brow_expr_ = false;
cheek_expr_ = false;
eye_expr_ = false;
jaw_expr_ = false;
mouth_expr_ = false;
nose_expr_ = false;
curr_state_.expr_mode = exprMode;
omniverse_interface_window_ = false;
load_from_file_ = false;
curr_state_.calibrate = false;
curr_state_.uncalibrate = false;
curr_state_.landmark_display = (DISPLAY_LM & display) ? true: false;
curr_state_.mesh_display = (DISPLAY_MESH & display) ? true : false;
curr_state_.image_display = (DISPLAY_IMAGE & display) ? true : false;
curr_state_.bargraph_display = (DISPLAY_PLOT & display) ? true : false;
curr_state_.expr.resize(numExpr, 0.0f);
curr_state_.expr_offset.resize(numExpr, 0.0f);
curr_state_.expr_scale.resize(numExpr, 1.0f);
curr_state_.expr_exponent.resize(numExpr, 1.0f);
curr_state_.global_parameter = 1.0f;
internal_get_state_counter_ = 0;
internal_set_state_counter_ = 0;
curr_state_.input_filter = filter;
curr_state_.show_fps = showFPS;
show_filter_window_ = false;
expr = 0;
ui_state_ = curr_state_;
ui_state_.expr.resize(numExpr, 0.0f);
ui_state_.expr_offset.resize(numExpr, 0.0f);
ui_state_.expr_scale.resize(numExpr, 1.0f);
ui_state_.expr_exponent.resize(numExpr, 1.0f);
file_name_ = "";
ui_keep_running_ = true;
ui_thread_ = std::thread([this]() { uiRenderThread();});
}
void ExpressionAppUI::cleanup() {
ui_keep_running_ = false;
if (ui_thread_.joinable()) {
ui_thread_.join();
}
ui_expression_list_.clear();
}
void ExpressionAppUI::showMLPSetting() {
ImGui::PushItemWidth(100);
ImGui::InputInt("Expression Mode : 1 : Mesh Fitting , 2: MLP", &curr_state_.expr_mode);
if (curr_state_.expr_mode < 1) {
curr_state_.expr_mode = 1;
}
if (curr_state_.expr_mode > 2) {
curr_state_.expr_mode = 2;
}
ImGui::PopItemWidth();
ImGui::NewLine();
ImGui::NewLine();
}
void ExpressionAppUI::showFilterSetting() {
if (!show_filter_window_) {
if (ImGui::Button("Set Filters")) {
show_filter_window_ = true;
}
}
if (show_filter_window_) {
if (ImGui::Button("Close Filter Settings")) {
show_filter_window_ = false;
}
}
if (show_filter_window_) {
ImGui::SetNextWindowPos({ ImGui::GetCursorPosX() + 100 ,ImGui::GetCursorPosY() + 100 }, ImGuiCond_FirstUseEver);
ImGui::SetNextWindowContentSize(ImVec2(400, 400.0f));
ImGui::Begin("Filter");
curr_state_.input_filter = 0;
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACE_BOX", &filter_face_box_); ImGui::SameLine();
ImGui::Text("FILTER_FACE_BOX");
ImGui::NewLine();
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS", &filter_face_landmark_); ImGui::SameLine();
ImGui::Text("FILTER_FACIAL_LANDMARKS");
ImGui::NewLine();
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE", &filter_face_rot_pose_); ImGui::SameLine();
ImGui::Text("FILTER_FACE_ROTATIONAL_POSE");
ImGui::NewLine();
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS", &filter_face_expr_); ImGui::SameLine();
ImGui::Text("FILTER_FACIAL_EXPRESSIONS");
ImGui::NewLine();
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_FACIAL_GAZE", &filter_face_gaze_); ImGui::SameLine();
ImGui::Text("FILTER_FACIAL_GAZE");
ImGui::NewLine();
ImGui::Checkbox("##NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS", &filter_enhance_expr_); ImGui::SameLine();
ImGui::Text("FILTER_ENHANCE_EXPRESSIONS");
ImGui::NewLine();
ImGui::NewLine();
curr_state_.input_filter |= filter_face_box_ ? NVAR_TEMPORAL_FILTER_FACE_BOX : 0;
curr_state_.input_filter |= filter_face_landmark_ ? NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS : 0;
curr_state_.input_filter |= filter_face_rot_pose_ ? NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE : 0;
curr_state_.input_filter |= filter_face_expr_ ? NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS : 0;
curr_state_.input_filter |= filter_face_gaze_ ? NVAR_TEMPORAL_FILTER_FACIAL_GAZE : 0;
curr_state_.input_filter |= filter_enhance_expr_ ? NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS : 0;
if (ImGui::Button("Close")) {
show_filter_window_ = false;
}
ImGui::End();
}
ImGui::NewLine();
ImGui::NewLine();
}
void ExpressionAppUI::showExpressionWindow() {
// Fill the list with curently active expressions
if ((1 << BROW) & expr) {
for (int i = 0; i <= 5; i++) {
ui_expression_list_.insert({ i });
}
}
else {
auto it = ui_expression_list_.find(browStartIndex);
if (it != ui_expression_list_.end()) {
auto begin = it;
std::advance(it, (browEndIndex - browStartIndex + 1));
ui_expression_list_.erase(begin, it);
}
}
if ((1 << CHEEK) & expr) {
for (int i = 6; i <= 9; i++) {
ui_expression_list_.insert({ i });
}
}
else {
auto it = ui_expression_list_.find(cheekStartIndex);
if (it != ui_expression_list_.end()) {
auto begin = it;
std::advance(it, (cheekEndIndex - cheekStartIndex + 1));
ui_expression_list_.erase(begin, it);
}
}
if ((1 << EYE) & expr) {
for (int i = 10; i <= 23; i++) {
ui_expression_list_.insert({ i });
}
}
else {
auto it = ui_expression_list_.find(eyeStartIndex);
if (it != ui_expression_list_.end()) {
auto begin = it;
std::advance(it, (eyeEndIndex - eyeStartIndex + 1));
ui_expression_list_.erase(begin, it);
}
}
if ((1 << JAW) & expr) {
for (int i = 24; i <= 27; i++) {
ui_expression_list_.insert({ i });
}
}
else {
auto it = ui_expression_list_.find(jawStartIndex);
if (it != ui_expression_list_.end()) {
auto begin = it;
std::advance(it, (jawEndIndex - jawStartIndex + 1));
ui_expression_list_.erase(begin, it);
}
}
if ((1 << MOUTH) & expr) {
for (int i = 28; i <= 50; i++) {
ui_expression_list_.insert({ i });
}
}
else {
auto it = ui_expression_list_.find(mouthStartIndex);
if (it != ui_expression_list_.end()) {
auto begin = it;
std::advance(it, (mouthEndIndex - mouthStartIndex + 1));
ui_expression_list_.erase(begin, it);
}
}
if ((1 << NOSE) & expr) {
for (int i = 51; i <= 52; i++) {
ui_expression_list_.insert({ i });
}
}
else {
auto it = ui_expression_list_.find(noseStartIndex);
if (it != ui_expression_list_.end()) {
auto begin = it;
std::advance(it, (noseEndIndex - noseStartIndex + 1));
ui_expression_list_.erase(begin, it);
}
}
ImGui::SetNextWindowContentSize(ImVec2(1080, 400.0f));
ImGui::Begin("Expressions");
ImGui::NewLine();
ImGui::NewLine();
ImGui::SliderFloat("Global Expression Parameter: Filter the effect of scaling and offset", &curr_state_.global_parameter, 0.0f, 1.0f);
ImGui::NewLine();
ImGui::NewLine();
expr = 0;
for (auto it = ui_expression_list_.begin(); it != ui_expression_list_.end(); it++) {
ImGui::PushItemWidth(400);
char overlay_buf[32];
ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf), "%.04f%%", curr_state_.expr[*it]);
ImGui::ProgressBar(curr_state_.expr[*it], ImVec2(0.0f, 0.0f), overlay_buf);
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
int id = *it;
ImGui::Text("%s", exprMap[id].c_str());
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
ImGui::PushItemWidth(100);
ImGui::Text("Scale(0.0-2.0)");
ImGui::SameLine();
std::string scaleLabel = "##Scale:" + exprMap[*it];
ImGui::SliderFloat(scaleLabel.c_str(), &curr_state_.expr_scale[*it], 0.0f, 2.0f);
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);
ImGui::Text("Offset(-1.0 to 1.0)");
ImGui::SameLine();
std::string offsetLabel = "##Offset:" + exprMap[*it];
ImGui::SliderFloat(offsetLabel.c_str(), &curr_state_.expr_offset[*it], -1.0f, 1.0f);
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);
ImGui::Text("Exponent(0.0 to 2.0)");
ImGui::SameLine();
std::string expLabel = "##Exponent:" + exprMap[*it];
ImGui::SliderFloat(expLabel.c_str(), &curr_state_.expr_exponent[*it], 0.0f, 2.0f);
ImGui::PopItemWidth();
}
ImGui::End();
}
void ExpressionAppUI::showExpressionPane() {
ImGui::Text("Expression Graph Options");
ImGui::Checkbox("Brow", &brow_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::Checkbox("Cheek", &cheek_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::Checkbox("Eye", &eye_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::Checkbox("Jaw", &jaw_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::Checkbox("Mouth", &mouth_expr_); ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::Checkbox("Nose", &nose_expr_);
expr |= (brow_expr_) ? (1 << BROW) : 0;
expr |= (cheek_expr_) ? (1 << CHEEK) : 0;
expr |= (eye_expr_) ? (1 << EYE) : 0;
expr |= (jaw_expr_) ? (1 << JAW) : 0;
expr |= (mouth_expr_) ? (1 << MOUTH) : 0;
expr |= (nose_expr_) ? (1 << NOSE) : 0;
if (expr) {
show_expr_ = true;
}
else {
if (ui_expression_list_.empty() == false) {
ui_expression_list_.clear();
}
show_expr_ = false;
}
if (show_expr_) {
showExpressionWindow();
}
ImGui::NewLine();
ImGui::NewLine();
}
void ExpressionAppUI::showCalibrationSetting() {
if (ImGui::Button("Calibrate")) {
curr_state_.calibrate = true;
}
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
if (ImGui::Button("Uncalibrate")) {
curr_state_.uncalibrate = true;
}
ImGui::NewLine();
}
void ExpressionAppUI::showLandmarkOption() {
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
ImGui::Checkbox("Landmark", &curr_state_.landmark_display);
ImGui::SameLine();
ImGui::Checkbox("Mesh", &curr_state_.mesh_display);
ImGui::SameLine();
ImGui::Checkbox("Graph", &curr_state_.bargraph_display);
ImGui::SameLine();
ImGui::Checkbox("Image", &curr_state_.image_display);
}
void ExpressionAppUI::showImageDisplaySettings() {
ImGui::Text("Image Settings");
showLandmarkOption();
ImGui::NewLine();
}
void ExpressionAppUI::showFPSSetting() {
ImGui::Checkbox("Toggle FPS Display", &curr_state_.show_fps);
ImGui::NewLine();
}
void ExpressionAppUI::saveConfigToFile() {
std::ofstream configFile;
std::string fileName = "ExpressionAppSettings.json";
configFile.open(fileName.c_str());
nlohmann::json settings; {
settings["MLP"] = curr_state_.expr_mode;
settings["Filter"] = curr_state_.input_filter;
settings["Expressions"] = curr_state_.expr;
settings["ExpressionsOffset"] = curr_state_.expr_offset;
settings["ExpressionsScale"] = curr_state_.expr_scale;
settings["ExpressionsExponent"] = curr_state_.expr_exponent;
settings["GlobalParameter"] = curr_state_.global_parameter;
}
configFile << settings;
configFile.close();
}
void ExpressionAppUI::loadConfgFromFile(const char* filePath) {
std::ifstream configFile;
std::string fileName;
if (!filePath) {
fileName = "ExpressionAppSettings.json";
}
else {
fileName = filePath;
}
configFile.open(fileName.c_str());
if (configFile) {
auto settings = nlohmann::json::parse(configFile); {
curr_state_.expr_mode = settings["MLP"];
curr_state_.input_filter = settings["Filter"];
curr_state_.expr = settings["Expressions"].get<std::vector<float>>();
curr_state_.expr_offset = settings["ExpressionsOffset"].get<std::vector<float>>();
curr_state_.expr_scale = settings["ExpressionsScale"].get<std::vector<float>>();
curr_state_.expr_exponent = settings["ExpressionsExponent"].get<std::vector<float>>();
curr_state_.global_parameter = settings["GlobalParameter"];
}
}
filter_face_box_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACE_BOX) ? true : false;
filter_face_landmark_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS) ? true : false;
filter_face_rot_pose_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE) ? true : false;
filter_face_expr_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS) ? true : false;
filter_face_gaze_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_FACIAL_GAZE) ? true : false;
filter_enhance_expr_ = (curr_state_.input_filter & NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS) ? true : false;
}
void ExpressionAppUI::openFileLoadSettings() {
if (load_from_file_) {
ImGui::SetNextWindowContentSize(ImVec2(500, 100.0f));
ImGui::Begin("Config Settings");
ImGui::Text("Enter Full File name with path eg : C:\\sample.json (no double quotes)");
ImGui::InputText("##FileName", &file_name_);
ImGui::NewLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 30);
if (ImGui::Button("OK")) {
loadConfgFromFile(file_name_.c_str());
load_from_file_ = false;
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {
load_from_file_ = false;
}
ImGui::End();
}
}
void ExpressionAppUI::showSaveSettingsOption() {
ImGui::NewLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);
if (ImGui::Button("SaveSettings")) {
saveConfigToFile();
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
if (ImGui::Button("LoadSettings")) {
loadConfgFromFile(NULL);
}
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 50);
if (load_from_file_) {
openFileLoadSettings();
if (ImGui::Button("Close Settings Window")) {
load_from_file_ = false;
}
}
else {
if (ImGui::Button("LoadSettingsFromFile")) {
load_from_file_ = true;
}
}
}
void ExpressionAppUI::closeAppSettings() {
ImGui::NewLine();
ImGui::NewLine();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 170);
if (ImGui::Button("App shutdown")) {
curr_state_.kill_app_ = true;
}
}
void ExpressionAppUI::CreateUIElements() {
showMLPSetting();
showFilterSetting();
showExpressionPane();
showCalibrationSetting();
showImageDisplaySettings();
showFPSSetting();
showSaveSettingsOption();
closeAppSettings();
}
void ExpressionAppUI::stateQuerybyCore(unsigned int& displayMode, unsigned int& exprMode, unsigned int& filter, bool& calibrate, bool& uncalibrate, bool& showFPS,
float& globalParam, std::vector<float>& expressionOffset, std::vector<float>& expressionScale, std::vector<float>& expressionExponent, bool& killApp) {
{
std::lock_guard<std::mutex> lock(ui_mutex_);
displayMode = ((ui_state_.landmark_display == true) ? DISPLAY_LM : 0) + ((ui_state_.mesh_display == true) ? DISPLAY_MESH : 0) + ((ui_state_.bargraph_display == true) ? DISPLAY_PLOT : 0) + ((ui_state_.image_display == true) ? DISPLAY_IMAGE : 0);;
filter = ui_state_.input_filter;
calibrate = ui_state_.calibrate;
uncalibrate = ui_state_.uncalibrate;
showFPS = ui_state_.show_fps;
exprMode = ui_state_.expr_mode;
globalParam = ui_state_.global_parameter;
expressionOffset = ui_state_.expr_offset;
expressionScale = ui_state_.expr_scale;
expressionExponent = ui_state_.expr_exponent;
killApp = ui_state_.kill_app_;
}
}
void ExpressionAppUI::stateSetbyCore(std::vector<float> expression,
std::vector<float> expressionOffset, std::vector<float> expressionScale, std::vector<float> expressionExponent, bool isCalibrated, int key) {
{
std::lock_guard<std::mutex> lock(ui_mutex_);
ui_state_.expr = expression;
ui_state_.expr_offset = expressionOffset;
ui_state_.expr_scale = expressionScale;
ui_state_.expr_exponent = expressionExponent;
if ((internal_get_state_counter_ == internal_set_state_counter_) && (isCalibrated)) {
ui_state_.calibrate = false;
ui_state_.uncalibrate = false;
}
if (key >= 0) {
keyboard_input_ = key;
}
}
}
void ExpressionAppUI::checkForKeyInput() {
if (keyboard_input_ >= 0) {
switch (keyboard_input_) {
case 27 /*ESC*/:
case 'q': case 'Q': curr_state_.kill_app_ = true; break; // Quit
case 'i': curr_state_.image_display = !ui_state_.image_display; break;
case 'l': curr_state_.landmark_display = !ui_state_.landmark_display; break;
case 'm': curr_state_.mesh_display = !ui_state_.mesh_display; break;
case 'n': curr_state_.calibrate = true; break;
case 'p': curr_state_.bargraph_display = !ui_state_.bargraph_display; break;
case 'f': curr_state_.show_fps = !ui_state_.show_fps; break;
case '1': curr_state_.expr_mode = 1; break;
case '2': curr_state_.expr_mode = 2; break;
case 'L': case CTL('L'): filter_face_landmark_ = !filter_face_landmark_;
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_FACIAL_LANDMARKS; break;
case 'N': case CTL('N'): curr_state_.uncalibrate = true;; break;
case 'P': case CTL('P'): filter_face_rot_pose_ = !filter_face_rot_pose_;
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_FACE_ROTATIONAL_POSE; break;
case 'E': case CTL('E'): filter_face_expr_ = !filter_face_expr_;
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_FACIAL_EXPRESSIONS; break;
case 'G': case CTL('G'): filter_face_gaze_ = !filter_face_gaze_;
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_FACIAL_GAZE; break;
case 'C': case CTL('C'): filter_enhance_expr_ = !filter_enhance_expr_;
curr_state_.input_filter ^= NVAR_TEMPORAL_FILTER_ENHANCE_EXPRESSIONS; break;
default: // No key
break;
}
keyboard_input_ = -1;
}
}
void ExpressionAppUI::setStateToLocal() {
std::lock_guard<std::mutex> lock(ui_mutex_);
ui_state_ = curr_state_;
ui_state_.expr = curr_state_.expr;
ui_state_.expr_exponent = curr_state_.expr_exponent;
ui_state_.expr_offset = curr_state_.expr_offset;
ui_state_.expr_scale = curr_state_.expr_scale;
ui_state_.kill_app_ = curr_state_.kill_app_;
internal_set_state_counter_ = internal_get_state_counter_;
if (internal_get_state_counter_ > 100000) {
internal_get_state_counter_ = internal_set_state_counter_ = 0;
}
}
void ExpressionAppUI::getStateFromLocal() {
std::lock_guard<std::mutex> lock(ui_mutex_);
curr_state_ = ui_state_;
curr_state_.expr = ui_state_.expr;
curr_state_.expr_exponent = ui_state_.expr_exponent;
curr_state_.expr_offset = ui_state_.expr_offset;
curr_state_.expr_scale = ui_state_.expr_scale;
internal_get_state_counter_++;
}
void ExpressionAppUI::uiRenderThread() {
ImVec4 clear_color_;
glfwSetErrorCallback(glfw_error_callback);
glfwInit();
GLFWwindow* window = glfwCreateWindow(640, 540, "Expression App Interface", NULL, NULL);
if (window == NULL) {
GLenum err = glGetError();
printf("Create window failed : %d", err);
}
glfwMakeContextCurrent(window);
glfwSwapInterval(1); // Enable vsync
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
// Setup Platform/Renderer backends
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 130");
setStateToLocal();
{
std::lock_guard<std::mutex> lock(ui_mutex_);
internal_get_state_counter_ = 0;
internal_set_state_counter_ = 0;
}
while (!glfwWindowShouldClose(window) && ui_keep_running_) {
if (!ui_keep_running_) {
break;
}
glfwPollEvents();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
{
ImGui::SetNextWindowContentSize(ImVec2(500, 500.0f));
ImGui::Begin("Expression: Input Options");
getStateFromLocal();
CreateUIElements();
checkForKeyInput();
setStateToLocal();
ImGui::End();
}
ImGui::Render();
int display_w, display_h;
glfwGetFramebufferSize(window, &display_w, &display_h);
glViewport(0, 0, display_w, display_h);
glClearColor(clear_color_.x * clear_color_.w, clear_color_.y * clear_color_.w, clear_color_.z * clear_color_.w, clear_color_.w);
glClear(GL_COLOR_BUFFER_BIT);
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
GLFWwindow* backup_current_context = glfwGetCurrentContext();
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
glfwMakeContextCurrent(backup_current_context);
}
glfwSwapBuffers(window);
}
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
glfwDestroyWindow(window);
// TODO: call terminate if GL renderer is not being used
// glfwTerminate();
}
#endif

View File

@@ -0,0 +1,145 @@
/*###############################################################################
#
# Copyright(c) 2020 NVIDIA CORPORATION.All Rights Reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto.Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#
###############################################################################*/
#pragma once
#if _ENABLE_UI
#include <set>
#include <atomic>
#include <thread>
#include <mutex>
#include <string>
#include <vector>
#include <GLFW/glfw3.h>
#include <imgui.h>
#include <backends/imgui_impl_glfw.h>
#include <backends/imgui_impl_opengl3.h>
#include <misc/cpp/imgui_stdlib.h>
enum exprType {
BROW = 1,
CHEEK,
EYE,
JAW,
MOUTH,
NOSE
};
enum {
DISPLAY_MESH = (1 << 0),
DISPLAY_IMAGE = (1 << 1),
DISPLAY_PLOT = (1 << 2),
DISPLAY_LM = (1 << 3)
};
struct ExpressionState {
int input_filter;
float global_parameter;
int expr_mode;
unsigned long counter;
bool calibrate;
bool uncalibrate;
bool landmark_display;
bool mesh_display;
bool image_display;
bool bargraph_display;
bool show_fps;
bool kill_app_;
std::vector<float> expr;
std::vector<float> expr_scale;
std::vector<float> expr_offset;
std::vector<float> expr_exponent;
ExpressionState() {
input_filter = -1;
counter = 0;
global_parameter = 1.0f;
expr_mode = 1;
calibrate = false;
uncalibrate = false;
landmark_display = false;
mesh_display = false;
image_display = false;
bargraph_display = false;
show_fps = false;
kill_app_ = false;
}
};
class ExpressionAppUI {
public:
//============= State Management =================
void init(int numExpr, int filter, int exprMode, int display, int showFPS);
void cleanup();
void stateQuerybyCore(unsigned int& displayMode, unsigned int& exprMode, unsigned int& filter, bool& calibrate, bool& uncalibrate, bool& showFPS,
float& globalParam, std::vector<float>& expressionOffset, std::vector<float>& expressionScale, std::vector<float>& expressionExponent, bool& killApp);
void stateSetbyCore(std::vector<float> expression,
std::vector<float> expressionOffset, std::vector<float> expressionScale, std::vector<float> expressionExponent, bool isCalibrated = false, int key = -1);
private:
void uiRenderThread();
void getStateFromLocal();
void setStateToLocal();
//============= UI calls ====================
void CreateUIElements(); // main API to create UI compoenents
void showMLPSetting();
void showStreamingSetting();
void showFilterSetting();
void showExpressionPane();
void showExpressionWindow();
void showCalibrationSetting();
void showImageDisplaySettings();
void showLandmarkOption();
void showFPSSetting();
void showSaveSettingsOption();
void saveConfigToFile();
void loadConfgFromFile(const char* filePath = NULL);
void openFileLoadSettings();
void closeAppSettings();
void checkForKeyInput();
//================= Filter =======================
bool filter_face_box_;
bool filter_face_landmark_;
bool filter_face_rot_pose_;
bool filter_face_expr_;
bool filter_face_gaze_;
bool filter_enhance_expr_;
//================= Expression ===================
bool show_expr_;
bool brow_expr_;
bool cheek_expr_;
bool eye_expr_ ;
bool jaw_expr_ ;
bool mouth_expr_;
bool nose_expr_;
std::set<int> ui_expression_list_;
//=================================================
std::atomic_bool omniverse_interface_window_;
std::atomic_int keyboard_input_;
bool load_from_file_;
bool show_filter_window_;
int expr;
ExpressionState ui_state_;
ExpressionState curr_state_;
std::atomic_bool ui_keep_running_;
std::thread ui_thread_;
std::mutex ui_mutex_;
std::string file_name_;
unsigned long internal_get_state_counter_;
unsigned long internal_set_state_counter_;
int32_t num_expressions_;
};
#endif

View File

@@ -0,0 +1,332 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifdef _WIN32
#define _WINSOCKAPI_
#include <windows.h>
#include <tchar.h>
#else // UNIX
#include <dlfcn.h>
typedef void *HMODULE;
typedef void *HANDLE;
typedef void *HINSTANCE;
#endif // _WIN32 || UNIX
#include "MeshRenderer.h"
#include "DirectoryIterator.h"
#include "OpenGLMeshRenderer.h" // Eventually this will be discoverable
#include <string.h>
#include <string>
#include <vector>
#ifdef _WIN32
#define nvLoadLibrary(library) LoadLibrary(TEXT(library))
#else // UNIX
#define nvLoadLibrary(library) dlopen(library, RTLD_LAZY)
#endif // _WIN32 || UNIX
inline void* nvGetProcAddress(HINSTANCE handle, const char *proc) {
if (nullptr == handle) return nullptr;
#ifdef _WIN32
return GetProcAddress(handle, proc);
#else // UNIX
return dlsym(handle, proc);
#endif // _WIN32 || UNIX
}
inline int nvFreeLibrary(HINSTANCE handle) {
if (nullptr == handle) return -1;
#ifdef _WIN32
return int(!FreeLibrary(handle)); // convert bool true to 0 int and 1 error code
#else // UNIX
return dlclose(handle); // 0 on success, error code otherwise
#endif // _WIN32 || UNIX
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///// Abstract class MeshRenderer /////
///// This merely converts from a C++ to a C object call. /////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#ifdef DEBUG_CAST // We never instantiate MeshRenderer, only ClubMeshRenderer, so we don't need a dynamic cast.
#define static_cast dynamic_cast // But #define this to prove it
#endif // DEBUG_CAST
NvCV_Status MeshRenderer::name(const char **str) const {
return m_dispatch.name(str);
}
NvCV_Status MeshRenderer::info(const char **str) const {
return m_dispatch.info(str);
}
void MeshRenderer::destroy() {
m_dispatch.destroy(this);
}
NvCV_Status MeshRenderer::read(const char *modelFile) {
return m_dispatch.read(this, modelFile);
}
NvCV_Status MeshRenderer::init(unsigned width, unsigned height, const char *windowName) {
return m_dispatch.init(this, width, height, windowName);
}
NvCV_Status MeshRenderer::setCamera(const float locPt[3], const float lookVec[3], const float upVec[3], float vfov) {
return m_dispatch.setCamera(this, locPt, lookVec, upVec, vfov);
}
NvCV_Status MeshRenderer::render(const float exprs[53], const float qrot[4], const float trans[3], NvCVImage *result) {
return m_dispatch.render(this, exprs, qrot, trans, result);
}
MeshRenderer::Dispatch::Dispatch() {
memset(this, 0, sizeof(*this));
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
///// MeshRendererBroker /////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
class RendererInfo {
public:
std::string name, info, file;
HMODULE module;
MeshRenderer::Dispatch dispatch;
RendererInfo() {
memset(&dispatch, 0, sizeof(dispatch));
module = nullptr;
}
};
class MeshRendererBroker::Impl {
public:
static const char nameStr[], infoStr[], createStr[], destroyStr[], readStr[], initStr[], setCameraStr[], renderStr[];
std::string rendererDirectory;
std::vector<RendererInfo> renderers;
NvCV_Status GetRenderers();
NvCV_Status LoadRenderer(const char *name);
NvCV_Status UnloadRenderer(const char *name);
bool AlreadyHave(const char *name);
~Impl() {
for (RendererInfo& ri : renderers)
(void)UnloadRenderer(ri.name.c_str());
}
};
const char MeshRendererBroker::Impl::nameStr[] = "RendererName";
const char MeshRendererBroker::Impl::infoStr[] = "RendererInfo";
const char MeshRendererBroker::Impl::createStr[] = "RendererName";
const char MeshRendererBroker::Impl::destroyStr[] = "RendererDestroy";
const char MeshRendererBroker::Impl::readStr[] = "RendererReadModel";
const char MeshRendererBroker::Impl::initStr[] = "RendererInit";
const char MeshRendererBroker::Impl::setCameraStr[] = "RendererSetCamera";
const char MeshRendererBroker::Impl::renderStr[] = "RendererRender";
static bool HasDLLSuffix(const char *name) {
static const char dllSuffix[] =
#ifdef _WIN32
".dll"
#else // UNIX
".so"
#endif // _WIN32 || UNIX
;
constexpr unsigned suf_len = sizeof(dllSuffix) - 1; // Strings have a NULL terminator, are not part of the string
unsigned name_len = unsigned(strlen(name));
return name_len > suf_len && !strcmp(name + name_len - suf_len, dllSuffix);
}
bool MeshRendererBroker::Impl::AlreadyHave(const char* name) {
for (const RendererInfo& ri : renderers)
if (ri.name == name)
return true;
return false;
}
NvCV_Status MeshRendererBroker::Impl::GetRenderers() {
if (rendererDirectory.empty()) // Or should we pass in the directory as an argument?
return NVCV_ERR_INITIALIZATION; // The renderer directory was not initialized.
DirectoryIterator dit(rendererDirectory.c_str(), DirectoryIterator::kTypeFile);
const char *fileName;
unsigned type;
while (0 == dit.next(&fileName, &type)) {
if (!HasDLLSuffix(fileName))
continue;
std::string path = rendererDirectory + '/' + fileName;
HINSTANCE lib = nvLoadLibrary(path.c_str());
if (!lib)
continue;
typedef NvCV_Status(*GetStringFunc)(const char** str);
GetStringFunc getString;
const char *name = nullptr, *info = nullptr;
if ((nullptr != (getString = reinterpret_cast<GetStringFunc>(nvGetProcAddress(lib, nameStr)))) &&
(NVCV_SUCCESS == (*getString)(&name)) &&
(nullptr != (getString = reinterpret_cast<GetStringFunc>(nvGetProcAddress(lib, infoStr)))) &&
(NVCV_SUCCESS == (*getString)(&info)) &&
!AlreadyHave(name)
) {
unsigned i = unsigned(renderers.size());
renderers.resize(i + 1);
RendererInfo& ri = renderers[i];
ri.name.assign(name);
ri.info.assign(info);
ri.file.assign(path);
}
nvFreeLibrary(lib);
}
return NVCV_SUCCESS;
}
NvCV_Status MeshRendererBroker::Impl::LoadRenderer(const char *name) {
for (RendererInfo& ri : renderers) {
if (name == ri.name) {
if (!ri.module) {
ri.module = nvLoadLibrary(ri.file.c_str());
// BE VERY CAREFUL WHEN CHANGING FUNCTION SIGNATURES, ESPECIALLY FOR WINDOWS!!!! THERE ARE NO CHECKS BELOW!!!!
*((void**)&ri.dispatch.name) = nvGetProcAddress(ri.module, nameStr);
*((void**)&ri.dispatch.info) = nvGetProcAddress(ri.module, infoStr);
*((void**)&ri.dispatch.create) = nvGetProcAddress(ri.module, createStr);
*((void**)&ri.dispatch.destroy) = nvGetProcAddress(ri.module, destroyStr);
*((void**)&ri.dispatch.read) = nvGetProcAddress(ri.module, readStr);
*((void**)&ri.dispatch.init) = nvGetProcAddress(ri.module, initStr);
*((void**)&ri.dispatch.setCamera) = nvGetProcAddress(ri.module, setCameraStr);
*((void**)&ri.dispatch.render) = nvGetProcAddress(ri.module, renderStr);
}
return NVCV_SUCCESS;
}
}
return NVCV_ERR_FEATURENOTFOUND;
}
NvCV_Status MeshRendererBroker::Impl::UnloadRenderer(const char *name) {
NvCV_Status err = NVCV_ERR_FEATURENOTFOUND;
for (RendererInfo& ri : renderers) {
if (name == ri.name) {
err = !ri.module ? NVCV_SUCCESS : nvFreeLibrary(ri.module) ? NVCV_ERR_LIBRARY : NVCV_SUCCESS;
ri.module = nullptr;
memset(&ri.dispatch, 0, sizeof(ri.dispatch));
break;
}
}
return err;
}
MeshRendererBroker::MeshRendererBroker() {
NvCV_Status err;
m_impl = new Impl;
// Automatically register the OpenGL Renderer
MeshRenderer::Dispatch disp;
if (NVCV_SUCCESS == (err = OpenGLMeshRenderer_InitDispatch(&disp)))
MeshRendererBroker::addRenderer(&disp);
}
MeshRendererBroker::~MeshRendererBroker() {
delete m_impl;
}
NvCV_Status MeshRendererBroker::setRendererDirectory(const char *dir) {
// Load more renderers from DLLs in the given directory
m_impl->rendererDirectory = dir;
return m_impl->GetRenderers();
}
NvCV_Status MeshRendererBroker::getMeshRendererList(std::vector<std::string>& list) {
list.clear();
list.resize(m_impl->renderers.size());
for (size_t i = 0; i < list.size(); ++i)
list[i] = m_impl->renderers[i].name;
return list.size() ? NVCV_SUCCESS : NVCV_ERR_FEATURENOTFOUND;
}
NvCV_Status MeshRendererBroker::info(const char *renderer, const char **info) {
if (!info)
return NVCV_ERR_PARAMETER;
for (const RendererInfo& ri : m_impl->renderers) {
if (ri.name == renderer) {
*info = ri.info.c_str();
return NVCV_SUCCESS;
}
}
*info = nullptr;
return NVCV_ERR_FEATURENOTFOUND;
}
NvCV_Status MeshRendererBroker::create(const char *renderer, MeshRenderer **han) {
if (!han)
return NVCV_ERR_PARAMETER;
for (const RendererInfo& ri : m_impl->renderers) {
if (ri.name == renderer) {
if (!ri.dispatch.create) {
NvCV_Status err = m_impl->LoadRenderer(renderer);
if (NVCV_SUCCESS != err)
return err;
}
return ri.dispatch.create(han);
}
}
*han = nullptr;
return NVCV_ERR_FEATURENOTFOUND;
}
void MeshRendererBroker::addRenderer(MeshRenderer::Dispatch *disp) {
unsigned n = unsigned(m_impl->renderers.size());
m_impl->renderers.resize(n + 1);
RendererInfo& ri = m_impl->renderers[n];
ri.dispatch = *disp;
const char *str;
disp->name(&str); ri.name = str;
disp->info(&str); ri.info = str;
}

View File

@@ -0,0 +1,149 @@
/*###############################################################################
#
# Copyright 2021 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#ifndef __MESH_RENDERER__
#define __MESH_RENDERER__
#include "nvCVImage.h"
#include <string>
#include <vector>
/// Abstract class to provide methods and hide the implementation.
class MeshRenderer {
public:
struct Dispatch {
// We get these procs from the DLL
NvCV_Status (*name)(const char **str);
NvCV_Status (*info)(const char **str);
NvCV_Status (*create)(MeshRenderer **han);
void (*destroy)(MeshRenderer *han);
NvCV_Status (*read)(MeshRenderer *han, const char *modelFile);
NvCV_Status (*init)(MeshRenderer *han, unsigned width, unsigned height, const char *windowName);
NvCV_Status (*setCamera)(MeshRenderer *han,
const float locPt[3], const float lookVec[3], const float upVec[3], float vfov);
NvCV_Status (*render)(MeshRenderer *han,
const float exprs[53], const float qrot[4], const float trans[3], NvCVImage *result);
Dispatch();
~Dispatch() {}
};
/// Destructor.
void destroy();
/// Get the name of the renderer associated with the given handle.
/// @param[out] str a place to store a pointer to the name of the mesh renderer.
/// @return NVCV_SUCCESS if the specified mesh renderer was successfully instantiated.
NvCV_Status name(const char **str) const;
/// Get information about the renderer.
/// @param[out] str a place to store a pointer to the name of the mesh renderer.
/// @return NVCV_SUCCESS if the specified mesh renderer was successfully instantiated.
NvCV_Status info(const char **str) const;
/// Read the specified mesh model.
/// If another model was already loaded, it will first be unloaded.
/// If a relative path is specified, several places are searched.
/// @param[in] modelFile the name of the file containing the desired mesh model.
/// @return NVCV_SUCCESS if the model was read successfully.
NvCV_Status read(const char *modelFile);
/// Initialize the rendering resources.
/// @param[in] width The desired width of the rendered image.
/// @param[in] height The desired height of the rendered image.
/// @param[in] windowName The name given to the auxiliary window, if the renderer requires one.
/// @return NVCV_SUCCESS if the renderer was successfully initialized.
NvCV_Status init(unsigned width, unsigned height, const char *windowName);
/// Set the viewing parameters.
/// @param[in] locPt the 3D point location of the camera.
/// NULL implies the default location, derived from the rest pose of the model.
/// @param[in] lookVec the 3D vector indicating the direction of view. This does not need to be normalized.
/// NULL implies the default direction, derived from the rest pose of the model.
/// @param[in] upVec the 3D vector pointing up. This does not need to be normalized.
/// NULL implies the default up direction, derived from the rest pose of the model.
/// @param[in] vfov the vertical field of view of the camera. Zero implies an orthographic camera.
/// @return NVCV_SUCCESS if the camera was initialized successfully.
NvCV_Status setCamera(const float locPt[3], const float lookVec[3], const float upVec[3], float vfov);
/// Render the mesh as deformed by the expression signals.
/// @param[in] exprs the expression signals (53 of them).
/// @param[in] qrot the rotation of the model as an xyzw quaternion.
/// @param[in] trans the translation of the model as an xyz vector.
/// @param[out] result the resultant rendered image.
/// @note: This will appear upside-down.
NvCV_Status render(const float exprs[53], const float qrot[4], const float trans[3], NvCVImage *result);
protected:
MeshRenderer() {} ///< Never create a member of this class
~MeshRenderer() {} ///< Instantiations are always subclasses
Dispatch m_dispatch;
};
class MeshRendererBroker {
public:
/// Constructor.
MeshRendererBroker();
/// Destructor.
~MeshRendererBroker();
/// Set the directory to be searched for additional renderers.
/// @param[in] dir the directory to be searched for additional renderers.
/// @return +NVCV_SUCCESS if the operation was successful.
NvCV_Status setRendererDirectory(const char *dir);
/// Return a list of the available mesh renderers.
/// @param[out] list pointer to a place to store the list of available renderers, separated by newlines.
/// @return NVCV_SUCCESS if a list was successfully returned.
NvCV_Status getMeshRendererList(std::vector<std::string>& list);
/// Retrieve the information about the selected renderer.
/// @param[in] renderer the selected renderer.
/// @param[out] info a place to store a pointer to the information about the selected renderer.
/// @return NVCV_SUCCESS if the information was successfully retrieved;
/// NVCV_ERR_FEATURENOTFOUND if the specified renderer was not found.
/// @note This string is ephemeral. If persistency is desired, a copy must be made. The previous pointer is
/// invalidated when this is called repeatedly
NvCV_Status info(const char *renderer, const char **info);
/// Create an instance of the chosen mesh renderer.
/// @param[in] renderer the desired renderer. NULL chooses the default renderer.
/// @param[out] han a place to store a handle to the desired mesh renderer.
/// @return NVCV_SUCCESS if the specified mesh renderer was successfully instantiated.
/// NVCV_ERR_FEATURENOTFOUND if the specified renderer was not found.
NvCV_Status create(const char *renderer, MeshRenderer **han);
/// Add a new renderer to the broker's portfolio.
/// @param disp the renderer's dispatch table.
void addRenderer(MeshRenderer::Dispatch *disp);
private:
class Impl;
Impl *m_impl;
};
#endif // __MESH_RENDERER__

View File

@@ -0,0 +1,19 @@
ExpressionApp is a sample application using the AR SDK to extract face expression signals from video. These signals are
used to control the expressions, pose and gaze of a 3D morphable face model. The application can either process
real-time video from a webcam or offline videos from files. It illustrates the facial keypoints that are tracked, plots
the expression signals that are derived, and renders an animated 3D avatar mesh.
The application runs either the Face3DReconstruction, or FaceExpression feature, depending on which expression mode is
used. The expression mode is toggled using the '1' and '2' keys on the keyboard
1 - Face3DReconstruction expression estimation
2 - FaceExpression expression estimation (default, and recommended for avatar animation)
The FaceExpression mode is preferred for avatar animation. Note that Face3DReconstruction is demonstrated for its
ability to track the face over time for AR effects. This feature enables identity face shape estimation on top of
expression estimation and is better demonstrated in the FaceTrack sample application. The resulting expression weights
from FaceExpression is more accurate than from Face3DReconstruction.
For details on command line arguments, execute ExpressionApp.exe --help.
For more controls and configurations of the sample app, including expression definition and conversion to ARKit
blendshapes, please read the SDK programming guide. It also contains information about how to control the GUI which can
be enabled by running the application with the --show_ui argument.

View File

@@ -0,0 +1,274 @@
/*###############################################################################
#
# Copyright 2020 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#include <string>
#include "nvAR.h"
#ifdef _WIN32
#define _WINSOCKAPI_
#include <windows.h>
#include <tchar.h>
#else
#include <dlfcn.h>
typedef void* HMODULE;
typedef void* HANDLE;
typedef void* HINSTANCE;
#endif
// Parameter string does not include the file extension
#ifdef _WIN32
#define nvLoadLibrary(library) LoadLibrary(TEXT(library ".dll"))
#else
#define nvLoadLibrary(library) dlopen("lib" library ".so", RTLD_LAZY)
#endif
inline void* nvGetProcAddress(HINSTANCE handle, const char* proc) {
if (nullptr == handle) return nullptr;
#ifdef _WIN32
return GetProcAddress(handle, proc);
#else
return dlsym(handle, proc);
#endif
}
inline int nvFreeLibrary(HINSTANCE handle) {
#ifdef _WIN32
return FreeLibrary(handle);
#else
return dlclose(handle);
#endif
}
HINSTANCE getNvARLib() {
TCHAR path[MAX_PATH], fullPath[MAX_PATH];
bool bSDKPathSet = false;
extern char* g_nvARSDKPath;
if (g_nvARSDKPath && g_nvARSDKPath[0]) {
#ifndef UNICODE
strncpy_s(fullPath, MAX_PATH, g_nvARSDKPath, MAX_PATH);
#else
size_t res = 0;
mbstowcs_s(&res, fullPath, MAX_PATH, g_nvARSDKPath, MAX_PATH);
#endif
SetDllDirectory(fullPath);
bSDKPathSet = true;
}
if (!bSDKPathSet) {
// There can be multiple apps on the system,
// some might include the SDK in the app package and
// others might expect the SDK to be installed in Program Files
GetEnvironmentVariable(TEXT("NV_AR_SDK_PATH"), path, MAX_PATH);
if (_tcscmp(path, TEXT("USE_APP_PATH"))) {
// App has not set environment variable to "USE_APP_PATH"
// So pick up the SDK dll and dependencies from Program Files
GetEnvironmentVariable(TEXT("ProgramFiles"), path, MAX_PATH);
size_t max_len = sizeof(fullPath) / sizeof(TCHAR);
_stprintf_s(fullPath, max_len, TEXT("%s\\NVIDIA Corporation\\NVIDIA AR SDK\\"), path);
SetDllDirectory(fullPath);
}
}
static const HINSTANCE NvArLib = nvLoadLibrary("nvARPose");
return NvArLib;
}
NvCV_Status NvAR_API NvAR_GetVersion(unsigned int* version) {
static const auto funcPtr = (decltype(NvAR_GetVersion)*)nvGetProcAddress(getNvARLib(), "NvAR_GetVersion");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(version);
}
NvCV_Status NvAR_API NvAR_Create(NvAR_FeatureID featureID, NvAR_FeatureHandle* handle) {
static const auto funcPtr = (decltype(NvAR_Create)*)nvGetProcAddress(getNvARLib(), "NvAR_Create");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(featureID, handle);
}
NvCV_Status NvAR_API NvAR_Destroy(NvAR_FeatureHandle handle) {
static const auto funcPtr = (decltype(NvAR_Destroy)*)nvGetProcAddress(getNvARLib(), "NvAR_Destroy");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle);
}
NvCV_Status NvAR_API NvAR_SetU32(NvAR_FeatureHandle handle, const char* name, unsigned int val) {
static const auto funcPtr = (decltype(NvAR_SetU32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetU32");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_SetS32(NvAR_FeatureHandle handle, const char* name, int val) {
static const auto funcPtr = (decltype(NvAR_SetS32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetS32");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_SetF32(NvAR_FeatureHandle handle, const char* name, float val) {
static const auto funcPtr = (decltype(NvAR_SetF32)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF32");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_SetF64(NvAR_FeatureHandle handle, const char* name, double val) {
static const auto funcPtr = (decltype(NvAR_SetF64)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF64");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_SetU64(NvAR_FeatureHandle handle, const char* name, unsigned long long val) {
static const auto funcPtr = (decltype(NvAR_SetU64)*)nvGetProcAddress(getNvARLib(), "NvAR_SetU64");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_SetObject(NvAR_FeatureHandle handle, const char* name, void* ptr, unsigned long typeSize) {
static const auto funcPtr = (decltype(NvAR_SetObject)*)nvGetProcAddress(getNvARLib(), "NvAR_SetObject");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, ptr, typeSize);
}
NvCV_Status NvAR_API NvAR_SetString(NvAR_FeatureHandle handle, const char* name, const char* str) {
static const auto funcPtr = (decltype(NvAR_SetString)*)nvGetProcAddress(getNvARLib(), "NvAR_SetString");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, str);
}
NvCV_Status NvAR_API NvAR_SetCudaStream(NvAR_FeatureHandle handle, const char* name, CUstream stream) {
static const auto funcPtr = (decltype(NvAR_SetCudaStream)*)nvGetProcAddress(getNvARLib(), "NvAR_SetCudaStream");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, stream);
}
NvCV_Status NvAR_API NvAR_SetF32Array(NvAR_FeatureHandle handle, const char* name, float* val, int count) {
static const auto funcPtr = (decltype(NvAR_SetF32Array)*)nvGetProcAddress(getNvARLib(), "NvAR_SetF32Array");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val, count);
}
NvCV_Status NvAR_API NvAR_GetU32(NvAR_FeatureHandle handle, const char* name, unsigned int* val) {
static const auto funcPtr = (decltype(NvAR_GetU32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetU32");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_GetS32(NvAR_FeatureHandle handle, const char* name, int* val) {
static const auto funcPtr = (decltype(NvAR_GetS32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetS32");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_GetF32(NvAR_FeatureHandle handle, const char* name, float* val) {
static const auto funcPtr = (decltype(NvAR_GetF32)*)nvGetProcAddress(getNvARLib(), "NvAR_GetF32");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_GetF64(NvAR_FeatureHandle handle, const char* name, double* val) {
static const auto funcPtr = (decltype(NvAR_GetF64)*)nvGetProcAddress(getNvARLib(), "NvAR_GetF64");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_GetU64(NvAR_FeatureHandle handle, const char* name, unsigned long long* val) {
static const auto funcPtr = (decltype(NvAR_GetU64)*)nvGetProcAddress(getNvARLib(), "NvAR_GetU64");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, val);
}
NvCV_Status NvAR_API NvAR_GetObject(NvAR_FeatureHandle handle, const char* name, const void** ptr, unsigned long typeSize) {
static const auto funcPtr = (decltype(NvAR_GetObject)*)nvGetProcAddress(getNvARLib(), "NvAR_GetObject");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, ptr, typeSize);
}
NvCV_Status NvAR_API NvAR_GetString(NvAR_FeatureHandle handle, const char* name, const char** str) {
static const auto funcPtr = (decltype(NvAR_GetString)*)nvGetProcAddress(getNvARLib(), "NvAR_GetString");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, str);
}
NvCV_Status NvAR_API NvAR_GetCudaStream(NvAR_FeatureHandle handle, const char* name, const CUstream* stream) {
static const auto funcPtr = (decltype(NvAR_GetCudaStream)*)nvGetProcAddress(getNvARLib(), "NvAR_GetCudaStream");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, stream);
}
NvCV_Status NvAR_API NvAR_GetF32Array(NvAR_FeatureHandle handle, const char* name, const float** vals, int* count) {
static const auto funcPtr = (decltype(NvAR_GetF32Array)*)nvGetProcAddress(getNvARLib(), "NvAR_GetF32Array");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle, name, vals, count);
}
NvCV_Status NvAR_API NvAR_Run(NvAR_FeatureHandle handle) {
static const auto funcPtr = (decltype(NvAR_Run)*)nvGetProcAddress(getNvARLib(), "NvAR_Run");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle);
}
NvCV_Status NvAR_API NvAR_Load(NvAR_FeatureHandle handle) {
static const auto funcPtr = (decltype(NvAR_Load)*)nvGetProcAddress(getNvARLib(), "NvAR_Load");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(handle);
}
NvCV_Status NvAR_API NvAR_CudaStreamCreate(CUstream* stream) {
static const auto funcPtr =
(decltype(NvAR_CudaStreamCreate)*)nvGetProcAddress(getNvARLib(), "NvAR_CudaStreamCreate");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(stream);
}
NvCV_Status NvAR_API NvAR_CudaStreamDestroy(CUstream stream) {
static const auto funcPtr =
(decltype(NvAR_CudaStreamDestroy)*)nvGetProcAddress(getNvARLib(), "NvAR_CudaStreamDestroy");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(stream);
}

View File

@@ -0,0 +1,341 @@
#if defined(linux) || defined(unix) || defined(__linux)
#warning nvCVImageProxy.cpp not ported
#else
/*###############################################################################
#
# Copyright 2020 NVIDIA Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
###############################################################################*/
#include <string>
#include "nvCVImage.h"
#ifdef _WIN32
#define _WINSOCKAPI_
#include <windows.h>
#include <tchar.h>
#include "nvTransferD3D.h"
#include "nvTransferD3D11.h"
#else // !_WIN32
#include <dlfcn.h>
typedef void* HMODULE;
typedef void* HANDLE;
typedef void* HINSTANCE;
#endif // _WIN32
// Parameter string does not include the file extension
#ifdef _WIN32
#define nvLoadLibrary(library) LoadLibrary(TEXT(library ".dll"))
#else // !_WIN32
#define nvLoadLibrary(library) dlopen("lib" library ".so", RTLD_LAZY)
#endif // _WIN32
inline void* nvGetProcAddress(HINSTANCE handle, const char* proc) {
if (nullptr == handle) return nullptr;
#ifdef _WIN32
return GetProcAddress(handle, proc);
#else // !_WIN32
return dlsym(handle, proc);
#endif // _WIN32
}
inline int nvFreeLibrary(HINSTANCE handle) {
#ifdef _WIN32
return FreeLibrary(handle);
#else
return dlclose(handle);
#endif
}
HINSTANCE getNvCVImageLib() {
TCHAR path[MAX_PATH], tmpPath[MAX_PATH], fullPath[MAX_PATH];
static HINSTANCE nvCVImageLib = NULL;
static bool bSDKPathSet = false;
if (!bSDKPathSet) {
nvCVImageLib = nvLoadLibrary("NVCVImage");
if (nvCVImageLib) bSDKPathSet = true;
}
if (!bSDKPathSet) {
// There can be multiple apps on the system,
// some might include the SDK in the app package and
// others might expect the SDK to be installed in Program Files
GetEnvironmentVariable(TEXT("NV_VIDEO_EFFECTS_PATH"), path, MAX_PATH);
GetEnvironmentVariable(TEXT("NV_AR_SDK_PATH"), tmpPath, MAX_PATH);
if (_tcscmp(path, TEXT("USE_APP_PATH")) && _tcscmp(tmpPath, TEXT("USE_APP_PATH"))) {
// App has not set environment variable to "USE_APP_PATH"
// So pick up the SDK dll and dependencies from Program Files
GetEnvironmentVariable(TEXT("ProgramFiles"), path, MAX_PATH);
size_t max_len = sizeof(fullPath) / sizeof(TCHAR);
_stprintf_s(fullPath, max_len, TEXT("%s\\NVIDIA Corporation\\NVIDIA Video Effects\\"), path);
SetDllDirectory(fullPath);
nvCVImageLib = nvLoadLibrary("NVCVImage");
if (!nvCVImageLib) {
_stprintf_s(fullPath, max_len, TEXT("%s\\NVIDIA Corporation\\NVIDIA AR SDK\\"), path);
SetDllDirectory(fullPath);
nvCVImageLib = nvLoadLibrary("NVCVImage");
}
}
bSDKPathSet = true;
}
return nvCVImageLib;
}
NvCV_Status NvCV_API NvCVImage_Init(NvCVImage* im, unsigned width, unsigned height, int pitch, void* pixels,
NvCVImage_PixelFormat format, NvCVImage_ComponentType type, unsigned isPlanar,
unsigned onGPU) {
static const auto funcPtr = (decltype(NvCVImage_Init)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Init");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(im, width, height, pitch, pixels, format, type, isPlanar, onGPU);
}
void NvCV_API NvCVImage_InitView(NvCVImage* subImg, NvCVImage* fullImg, int x, int y, unsigned width,
unsigned height) {
static const auto funcPtr = (decltype(NvCVImage_InitView)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_InitView");
if (nullptr != funcPtr) funcPtr(subImg, fullImg, x, y, width, height);
}
NvCV_Status NvCV_API NvCVImage_Alloc(NvCVImage* im, unsigned width, unsigned height, NvCVImage_PixelFormat format,
NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU, unsigned alignment) {
static const auto funcPtr = (decltype(NvCVImage_Alloc)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Alloc");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(im, width, height, format, type, isPlanar, onGPU, alignment);
}
NvCV_Status NvCV_API NvCVImage_Realloc(NvCVImage* im, unsigned width, unsigned height,
NvCVImage_PixelFormat format, NvCVImage_ComponentType type,
unsigned isPlanar, unsigned onGPU, unsigned alignment) {
static const auto funcPtr = (decltype(NvCVImage_Realloc)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Realloc");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(im, width, height, format, type, isPlanar, onGPU, alignment);
}
void NvCV_API NvCVImage_Dealloc(NvCVImage* im) {
static const auto funcPtr = (decltype(NvCVImage_Dealloc)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Dealloc");
if (nullptr != funcPtr) funcPtr(im);
}
void NvCV_API NvCVImage_DeallocAsync(NvCVImage* im, CUstream_st* stream) {
static const auto funcPtr = (decltype(NvCVImage_DeallocAsync)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_DeallocAsync");
if (nullptr != funcPtr) funcPtr(im, stream);
}
NvCV_Status NvCV_API NvCVImage_Create(unsigned width, unsigned height, NvCVImage_PixelFormat format,
NvCVImage_ComponentType type, unsigned isPlanar, unsigned onGPU,
unsigned alignment, NvCVImage** out) {
static const auto funcPtr = (decltype(NvCVImage_Create)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Create");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(width, height, format, type, isPlanar, onGPU, alignment, out);
}
void NvCV_API NvCVImage_Destroy(NvCVImage* im) {
static const auto funcPtr = (decltype(NvCVImage_Destroy)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Destroy");
if (nullptr != funcPtr) funcPtr(im);
}
void NvCV_API NvCVImage_ComponentOffsets(NvCVImage_PixelFormat format, int* rOff, int* gOff, int* bOff, int* aOff,
int* yOff) {
static const auto funcPtr =
(decltype(NvCVImage_ComponentOffsets)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_ComponentOffsets");
if (nullptr != funcPtr) funcPtr(format, rOff, gOff, bOff, aOff, yOff);
}
NvCV_Status NvCV_API NvCVImage_Transfer(const NvCVImage* src, NvCVImage* dst, float scale, CUstream_st* stream,
NvCVImage* tmp) {
static const auto funcPtr = (decltype(NvCVImage_Transfer)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Transfer");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(src, dst, scale, stream, tmp);
}
NvCV_Status NvCV_API NvCVImage_TransferRect(const NvCVImage *src, const NvCVRect2i *srcRect, NvCVImage *dst,
const NvCVPoint2i *dstPt, float scale, struct CUstream_st *stream, NvCVImage *tmp) {
static const auto funcPtr = (decltype(NvCVImage_TransferRect)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_TransferRect");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(src, srcRect, dst, dstPt, scale, stream, tmp);
}
NvCV_Status NvCV_API NvCVImage_TransferFromYUV(const void *y, int yPixBytes, int yPitch, const void *u, const void *v,
int uvPixBytes, int uvPitch, NvCVImage_PixelFormat yuvFormat, NvCVImage_ComponentType yuvType, unsigned yuvColorSpace,
unsigned yuvMemSpace, NvCVImage *dst, const NvCVRect2i *dstRect, float scale, struct CUstream_st *stream, NvCVImage *tmp) {
static const auto funcPtr = (decltype(NvCVImage_TransferFromYUV)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_TransferFromYUV");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(y, yPixBytes, yPitch, u, v, uvPixBytes, uvPitch, yuvFormat, yuvType, yuvColorSpace, yuvMemSpace, dst,
dstRect, scale, stream, tmp);
}
NvCV_Status NvCV_API NvCVImage_TransferToYUV(const NvCVImage *src, const NvCVRect2i *srcRect,
const void *y, int yPixBytes, int yPitch, const void *u, const void *v, int uvPixBytes, int uvPitch,
NvCVImage_PixelFormat yuvFormat, NvCVImage_ComponentType yuvType, unsigned yuvColorSpace, unsigned yuvMemSpace,
float scale, struct CUstream_st *stream, NvCVImage *tmp) {
static const auto funcPtr = (decltype(NvCVImage_TransferToYUV)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_TransferToYUV");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(src, srcRect, y, yPixBytes, yPitch, u, v, uvPixBytes, uvPitch, yuvFormat, yuvType, yuvColorSpace, yuvMemSpace, scale, stream, tmp);
}
NvCV_Status NvCV_API NvCVImage_MapResource(NvCVImage *im, struct CUstream_st *stream) {
static const auto funcPtr = (decltype(NvCVImage_MapResource)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_MapResource");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(im, stream);
}
NvCV_Status NvCV_API NvCVImage_UnmapResource(NvCVImage *im, struct CUstream_st *stream) {
static const auto funcPtr = (decltype(NvCVImage_UnmapResource)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_UnmapResource");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(im, stream);
}
#if RTX_CAMERA_IMAGE == 0
NvCV_Status NvCV_API NvCVImage_Composite(const NvCVImage* fg, const NvCVImage* bg, const NvCVImage* mat, NvCVImage* dst,
struct CUstream_st *stream) {
static const auto funcPtr = (decltype(NvCVImage_Composite)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Composite");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(fg, bg, mat, dst, stream);
}
#else // RTX_CAMERA_IMAGE == 1
NvCV_Status NvCV_API NvCVImage_Composite(const NvCVImage* fg, const NvCVImage* bg, const NvCVImage* mat, NvCVImage* dst) {
static const auto funcPtr = (decltype(NvCVImage_Composite)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Composite");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(fg, bg, mat, dst);
}
#endif // RTX_CAMERA_IMAGE
NvCV_Status NvCV_API NvCVImage_CompositeRect(
const NvCVImage *fg, const NvCVPoint2i *fgOrg,
const NvCVImage *bg, const NvCVPoint2i *bgOrg,
const NvCVImage *mat, unsigned mode,
NvCVImage *dst, const NvCVPoint2i *dstOrg,
struct CUstream_st *stream) {
static const auto funcPtr = (decltype(NvCVImage_CompositeRect)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_CompositeRect");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(fg, fgOrg, bg, bgOrg, mat, mode, dst, dstOrg, stream);
}
#if RTX_CAMERA_IMAGE == 0
NvCV_Status NvCV_API NvCVImage_CompositeOverConstant(const NvCVImage *src, const NvCVImage *mat,
const void *bgColor, NvCVImage *dst, struct CUstream_st *stream) {
static const auto funcPtr =
(decltype(NvCVImage_CompositeOverConstant)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_CompositeOverConstant");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(src, mat, bgColor, dst, stream);
}
#else // RTX_CAMERA_IMAGE == 1
NvCV_Status NvCV_API NvCVImage_CompositeOverConstant(const NvCVImage *src, const NvCVImage *mat,
const unsigned char bgColor[3], NvCVImage *dst) {
static const auto funcPtr =
(decltype(NvCVImage_CompositeOverConstant)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_CompositeOverConstant");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(src, mat, bgColor, dst);
}
#endif // RTX_CAMERA_IMAGE
NvCV_Status NvCV_API NvCVImage_FlipY(const NvCVImage *src, NvCVImage *dst) {
static const auto funcPtr = (decltype(NvCVImage_FlipY)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_FlipY");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(src, dst);
}
NvCV_Status NvCV_API NvCVImage_Sharpen(float sharpness, const NvCVImage *src, NvCVImage *dst,
struct CUstream_st *stream, NvCVImage *tmp) {
static const auto funcPtr = (decltype(NvCVImage_Sharpen)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_Sharpen");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(sharpness, src, dst, stream, tmp);
}
#ifdef _WIN32
__declspec(dllexport) const char* __cdecl
#else
const char*
#endif // _WIN32 or linux
NvCV_GetErrorStringFromCode(NvCV_Status code) {
static const auto funcPtr =
(decltype(NvCV_GetErrorStringFromCode)*)nvGetProcAddress(getNvCVImageLib(), "NvCV_GetErrorStringFromCode");
if (nullptr == funcPtr) return "Cannot find nvCVImage DLL or its dependencies";
return funcPtr(code);
}
#ifdef _WIN32 // Direct 3D
NvCV_Status NvCV_API NvCVImage_InitFromD3D11Texture(NvCVImage *im, struct ID3D11Texture2D *tx) {
static const auto funcPtr = (decltype(NvCVImage_InitFromD3D11Texture)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_InitFromD3D11Texture");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(im, tx);
}
NvCV_Status NvCV_API NvCVImage_ToD3DFormat(NvCVImage_PixelFormat format, NvCVImage_ComponentType type, unsigned layout, DXGI_FORMAT *d3dFormat) {
static const auto funcPtr = (decltype(NvCVImage_ToD3DFormat)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_ToD3DFormat");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(format, type, layout, d3dFormat);
}
NvCV_Status NvCV_API NvCVImage_FromD3DFormat(DXGI_FORMAT d3dFormat, NvCVImage_PixelFormat *format, NvCVImage_ComponentType *type, unsigned char *layout) {
static const auto funcPtr = (decltype(NvCVImage_FromD3DFormat)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_FromD3DFormat");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(d3dFormat, format, type, layout);
}
#ifdef __dxgicommon_h__
NvCV_Status NvCV_API NvCVImage_ToD3DColorSpace(unsigned char nvcvColorSpace, DXGI_COLOR_SPACE_TYPE *pD3dColorSpace) {
static const auto funcPtr = (decltype(NvCVImage_ToD3DColorSpace)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_ToD3DColorSpace");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(nvcvColorSpace, pD3dColorSpace);
}
NvCV_Status NvCV_API NvCVImage_FromD3DColorSpace(DXGI_COLOR_SPACE_TYPE d3dColorSpace, unsigned char *pNvcvColorSpace) {
static const auto funcPtr = (decltype(NvCVImage_FromD3DColorSpace)*)nvGetProcAddress(getNvCVImageLib(), "NvCVImage_FromD3DColorSpace");
if (nullptr == funcPtr) return NVCV_ERR_LIBRARY;
return funcPtr(d3dColorSpace, pNvcvColorSpace);
}
#endif // __dxgicommon_h__
#endif // _WIN32 Direct 3D
#endif // enabling for this file

View File

@@ -0,0 +1,3 @@
SETLOCAL
SET PATH=%PATH%;..\..\samples\external\opencv\bin;..\..\bin;
ExpressionApp.exe