v0.8.1.0 Release
v0.8.1.0 Release
This commit is contained in:
2378
samples/ExpressionApp/BackEndOpenGL/FaceIO.cpp
Normal file
2378
samples/ExpressionApp/BackEndOpenGL/FaceIO.cpp
Normal file
File diff suppressed because it is too large
Load Diff
231
samples/ExpressionApp/BackEndOpenGL/FaceIO.h
Normal file
231
samples/ExpressionApp/BackEndOpenGL/FaceIO.h
Normal 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__ */
|
||||
314
samples/ExpressionApp/BackEndOpenGL/GLMaterial.cpp
Normal file
314
samples/ExpressionApp/BackEndOpenGL/GLMaterial.cpp
Normal 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;
|
||||
}
|
||||
143
samples/ExpressionApp/BackEndOpenGL/GLMaterial.h
Normal file
143
samples/ExpressionApp/BackEndOpenGL/GLMaterial.h
Normal 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 */
|
||||
624
samples/ExpressionApp/BackEndOpenGL/GLMesh.cpp
Normal file
624
samples/ExpressionApp/BackEndOpenGL/GLMesh.cpp
Normal 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;
|
||||
}
|
||||
280
samples/ExpressionApp/BackEndOpenGL/GLMesh.h
Normal file
280
samples/ExpressionApp/BackEndOpenGL/GLMesh.h
Normal 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
|
||||
632
samples/ExpressionApp/BackEndOpenGL/GLShaders.cpp
Normal file
632
samples/ExpressionApp/BackEndOpenGL/GLShaders.cpp
Normal 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);
|
||||
}
|
||||
366
samples/ExpressionApp/BackEndOpenGL/GLShaders.h
Normal file
366
samples/ExpressionApp/BackEndOpenGL/GLShaders.h
Normal 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__ */
|
||||
106
samples/ExpressionApp/BackEndOpenGL/GLSpectrum.h
Normal file
106
samples/ExpressionApp/BackEndOpenGL/GLSpectrum.h
Normal 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
|
||||
645
samples/ExpressionApp/BackEndOpenGL/OpenGLMeshRenderer.cpp
Normal file
645
samples/ExpressionApp/BackEndOpenGL/OpenGLMeshRenderer.cpp
Normal 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;
|
||||
}
|
||||
41
samples/ExpressionApp/BackEndOpenGL/OpenGLMeshRenderer.h
Normal file
41
samples/ExpressionApp/BackEndOpenGL/OpenGLMeshRenderer.h
Normal 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__
|
||||
245
samples/ExpressionApp/BackEndOpenGL/SimpleFaceModel.h
Normal file
245
samples/ExpressionApp/BackEndOpenGL/SimpleFaceModel.h
Normal 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__
|
||||
97
samples/ExpressionApp/CMakeLists.txt
Normal file
97
samples/ExpressionApp/CMakeLists.txt
Normal 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()
|
||||
169
samples/ExpressionApp/DirectoryIterator.cpp
Normal file
169
samples/ExpressionApp/DirectoryIterator.cpp
Normal 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 */
|
||||
68
samples/ExpressionApp/DirectoryIterator.h
Normal file
68
samples/ExpressionApp/DirectoryIterator.h
Normal 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
|
||||
1288
samples/ExpressionApp/ExpressionApp.cpp
Normal file
1288
samples/ExpressionApp/ExpressionApp.cpp
Normal file
File diff suppressed because it is too large
Load Diff
BIN
samples/ExpressionApp/ExpressionApp.exe
Normal file
BIN
samples/ExpressionApp/ExpressionApp.exe
Normal file
Binary file not shown.
711
samples/ExpressionApp/ExpressionAppUI.cpp
Normal file
711
samples/ExpressionApp/ExpressionAppUI.cpp
Normal 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
|
||||
|
||||
145
samples/ExpressionApp/ExpressionAppUI.h
Normal file
145
samples/ExpressionApp/ExpressionAppUI.h
Normal 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
|
||||
332
samples/ExpressionApp/MeshRenderer.cpp
Normal file
332
samples/ExpressionApp/MeshRenderer.cpp
Normal 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;
|
||||
}
|
||||
149
samples/ExpressionApp/MeshRenderer.h
Normal file
149
samples/ExpressionApp/MeshRenderer.h
Normal 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__
|
||||
|
||||
19
samples/ExpressionApp/Readme.txt
Normal file
19
samples/ExpressionApp/Readme.txt
Normal 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.
|
||||
274
samples/ExpressionApp/nvARProxy.cpp
Normal file
274
samples/ExpressionApp/nvARProxy.cpp
Normal 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);
|
||||
}
|
||||
341
samples/ExpressionApp/nvCVImageProxy.cpp
Normal file
341
samples/ExpressionApp/nvCVImageProxy.cpp
Normal 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
|
||||
3
samples/ExpressionApp/run.bat
Normal file
3
samples/ExpressionApp/run.bat
Normal file
@@ -0,0 +1,3 @@
|
||||
SETLOCAL
|
||||
SET PATH=%PATH%;..\..\samples\external\opencv\bin;..\..\bin;
|
||||
ExpressionApp.exe
|
||||
Reference in New Issue
Block a user