Commit 5f20f377 authored by Christopher Tenter's avatar Christopher Tenter

support face colors + smooth shading refs #2387

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@20227 383ad7c9-94d9-4d36-a494-682f7c89f535
parent c2045f73
...@@ -227,19 +227,20 @@ public: ...@@ -227,19 +227,20 @@ public:
/** \brief binds index and vertex buffer and executes draw calls /** \brief binds index and vertex buffer and executes draw calls
* *
* @param _textureMap maps from internally texture-id to OpenGL texture id * @param _textureMap maps from internally texture-id to OpenGL texture id, may be null to disable textured rendering
* may be null to disable textured rendering * @param _nonindexed use unoptimized non-indexed vbo for rendering, not as efficient in terms of memory usage and performance as an indexed draw call.
*/ */
void draw(std::map< int, GLuint>* _textureMap); void draw(std::map< int, GLuint>* _textureMap, bool _nonindexed = false);
/** \brief adds RenderObjects to a deferred draw call renderer /** \brief adds RenderObjects to a deferred draw call renderer
* *
* @param _renderer renderobjects are added to this renderer * @param _renderer renderobjects are added to this renderer
* @param _baseObj address of the base renderobject with information about shader generation, gl states, matrices .. * @param _baseObj address of the base renderobject with information about shader generation, gl states, matrices ..
* @param _textureMap maps from internally texture-id to OpenGL texture id * @param _textureMap maps from internally texture-id to OpenGL texture id
* @param _nonindexed use non-indexed vbo instead of optimized indexed vbo (should be avoided if possible)
* may be null to disable textured rendering * may be null to disable textured rendering
*/ */
void addTriRenderObjects(IRenderer* _renderer, const RenderObject* _baseObj, std::map< int, GLuint>* _textureMap); void addTriRenderObjects(IRenderer* _renderer, const RenderObject* _baseObj, std::map< int, GLuint>* _textureMap, bool _nonindexed = false);
/** \brief render the mesh in wireframe mode /** \brief render the mesh in wireframe mode
*/ */
...@@ -936,6 +937,46 @@ private: ...@@ -936,6 +937,46 @@ private:
void writeVertexProperty(unsigned int _vertex, const VertexElement* _elementDesc, const ACG::Vec4d& _propd); void writeVertexProperty(unsigned int _vertex, const VertexElement* _elementDesc, const ACG::Vec4d& _propd);
/** \brief Read one vertex from the rendering vbo.
*
* @param _vertex vertex id from the rendering vbo (not the original input id from openmesh!)
* @param _dst [out] pointer to address that will store the vertex. Must have enough space allocated, see vertex declaration stride to get the number of bytes
*/
void readVertexFromVBO(unsigned int _vertex, void* _dst);
public:
//===========================================================================
// fully expanded vbo
//===========================================================================
/** \brief the mesh has been changed
*
* call this function if you changed anything of the mesh.
*/
void invalidateFullVBO();
/** \brief update the full mesh vbo
*
* the full vbo is the non-indexed version for drawing.
* it's not optimized for rendering at all and it uses lots of memory, so should only be used as last resort.
*/
void updateFullVBO();
private:
// fully expanded mesh vbo (not indexed)
// this is only used for drawmodes with incompatible combinations of interpolation modes (ex. smooth gouraud lighting with flat face colors)
GeometryBuffer vboFull_;
// full vbo has been invalidated
bool updateFullVBO_;
public: public:
//======================================================================== //========================================================================
// per edge buffers // per edge buffers
......
...@@ -82,6 +82,7 @@ DrawMeshT<Mesh>::DrawMeshT(Mesh& _mesh) ...@@ -82,6 +82,7 @@ DrawMeshT<Mesh>::DrawMeshT(Mesh& _mesh)
halfedgeNormalMode_(0), bVBOinHalfedgeNormalMode_(0), halfedgeNormalMode_(0), bVBOinHalfedgeNormalMode_(0),
invVertexMap_(0), invVertexMap_(0),
offsetPos_(0), offsetNormal_(20), offsetTexc_(12), offsetColor_(32), offsetPos_(0), offsetNormal_(20), offsetTexc_(12), offsetColor_(32),
updateFullVBO_(true),
textureIndexPropertyName_("Not Set"), textureIndexPropertyName_("Not Set"),
perFaceTextureCoordinatePropertyName_("Not Set"), perFaceTextureCoordinatePropertyName_("Not Set"),
updatePerEdgeBuffers_(1), updatePerEdgeBuffers_(1),
...@@ -455,6 +456,7 @@ DrawMeshT<Mesh>::rebuild() ...@@ -455,6 +456,7 @@ DrawMeshT<Mesh>::rebuild()
return; return;
} }
invalidateFullVBO();
unsigned int maxFaceVertCount = 0; unsigned int maxFaceVertCount = 0;
...@@ -1088,6 +1090,9 @@ DrawMeshT<Mesh>::createVBO() ...@@ -1088,6 +1090,9 @@ DrawMeshT<Mesh>::createVBO()
fillVertexBuffer(); fillVertexBuffer();
ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, 0); ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
// non indexed vbo needs updating now
invalidateFullVBO();
} }
template <class Mesh> template <class Mesh>
...@@ -1117,7 +1122,7 @@ DrawMeshT<Mesh>::createIBO() ...@@ -1117,7 +1122,7 @@ DrawMeshT<Mesh>::createIBO()
// line index buffer: // line index buffer:
if (mesh_.n_edges()) if (mesh_.n_edges())
{ {
unsigned int* pLineBuffer = new unsigned int[mesh_.n_edges() * 2]; std::vector<unsigned int> lineBuffer(mesh_.n_edges() * 2);
for (unsigned int i = 0; i < mesh_.n_edges(); ++i) for (unsigned int i = 0; i < mesh_.n_edges(); ++i)
{ {
...@@ -1125,22 +1130,20 @@ DrawMeshT<Mesh>::createIBO() ...@@ -1125,22 +1130,20 @@ DrawMeshT<Mesh>::createIBO()
if (indexType_ == GL_UNSIGNED_SHORT) if (indexType_ == GL_UNSIGNED_SHORT)
{ {
((unsigned short*)pLineBuffer)[2*i] = (unsigned short)invVertexMap_[mesh_.from_vertex_handle(hh).idx()]; // put two words in a dword
((unsigned short*)pLineBuffer)[2*i+1] = (unsigned short)invVertexMap_[mesh_.to_vertex_handle(hh).idx()]; unsigned int combinedIdx = invVertexMap_[mesh_.from_vertex_handle(hh).idx()] | (invVertexMap_[mesh_.to_vertex_handle(hh).idx()] << 16);
lineBuffer[i] = combinedIdx;
} }
else else
{ {
pLineBuffer[2*i] = invVertexMap_[mesh_.from_vertex_handle(hh).idx()]; lineBuffer[2 * i] = invVertexMap_[mesh_.from_vertex_handle(hh).idx()];
pLineBuffer[2*i+1] = invVertexMap_[mesh_.to_vertex_handle(hh).idx()]; lineBuffer[2 * i + 1] = invVertexMap_[mesh_.to_vertex_handle(hh).idx()];
} }
} }
bindLineIbo(); bindLineIbo();
fillLineBuffer(mesh_.n_edges(), pLineBuffer); fillLineBuffer(mesh_.n_edges(), &lineBuffer[0]);
// FIXME: This is not exception safe and may lead to memory leaks.
delete [] pLineBuffer;
} }
ACG::GLState::bindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); ACG::GLState::bindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
...@@ -1346,9 +1349,16 @@ void DrawMeshT<Mesh>::unbindBuffers() ...@@ -1346,9 +1349,16 @@ void DrawMeshT<Mesh>::unbindBuffers()
} }
template <class Mesh> template <class Mesh>
void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap) void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap, bool _nonindexed)
{ {
bindBuffers(); if (!_nonindexed)
bindBuffers();
else
{
updateFullVBO();
vboFull_.bind();
vertexDecl_->activateFixedFunction();
}
#ifdef DEBUG_MEM_USAGE #ifdef DEBUG_MEM_USAGE
getMemoryUsage(true); getMemoryUsage(true);
...@@ -1371,12 +1381,20 @@ void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap) ...@@ -1371,12 +1381,20 @@ void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap)
else else
ACG::GLState::bindTexture(GL_TEXTURE_2D, (*_textureMap)[sub->id]); ACG::GLState::bindTexture(GL_TEXTURE_2D, (*_textureMap)[sub->id]);
glDrawElements(GL_TRIANGLES, sub->numTris * 3, indexType_, if (!_nonindexed)
(GLvoid*)( (size_t)sub->startIndex * (indexType_ == GL_UNSIGNED_INT ? 4 : 2))); // offset in bytes glDrawElements(GL_TRIANGLES, sub->numTris * 3, indexType_,
(GLvoid*)( (size_t)sub->startIndex * (indexType_ == GL_UNSIGNED_INT ? 4 : 2))); // offset in bytes
else
glDrawArrays(GL_TRIANGLES, sub->startIndex, sub->numTris * 3);
} }
} }
else else
glDrawElements(GL_TRIANGLES, numTris_ * 3, indexType_, 0); {
if (!_nonindexed)
glDrawElements(GL_TRIANGLES, numTris_ * 3, indexType_, 0);
else
glDrawArrays(GL_TRIANGLES, 0, numTris_ * 3);
}
} }
unbindBuffers(); unbindBuffers();
...@@ -1384,12 +1402,20 @@ void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap) ...@@ -1384,12 +1402,20 @@ void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap)
template <class Mesh> template <class Mesh>
void ACG::DrawMeshT<Mesh>::addTriRenderObjects(IRenderer* _renderer, const RenderObject* _baseObj, std::map< int, GLuint>* _textureMap) void ACG::DrawMeshT<Mesh>::addTriRenderObjects(IRenderer* _renderer, const RenderObject* _baseObj, std::map< int, GLuint>* _textureMap, bool _nonindexed)
{ {
if (numTris_) if (numTris_)
{ {
RenderObject ro = *_baseObj; RenderObject ro = *_baseObj;
bindBuffersToRenderObject(&ro); if (!_nonindexed)
bindBuffersToRenderObject(&ro);
else
{
updateFullVBO();
ro.vertexBuffer = vboFull_.id();
ro.vertexDecl = vertexDecl_;
}
if (_baseObj->shaderDesc.textured()) if (_baseObj->shaderDesc.textured())
{ {
...@@ -1426,15 +1452,21 @@ void ACG::DrawMeshT<Mesh>::addTriRenderObjects(IRenderer* _renderer, const Rende ...@@ -1426,15 +1452,21 @@ void ACG::DrawMeshT<Mesh>::addTriRenderObjects(IRenderer* _renderer, const Rende
ro.glDrawElements(GL_TRIANGLES, sub->numTris * 3, indexType_, if (!_nonindexed)
(GLvoid*)( (size_t)sub->startIndex * (indexType_ == GL_UNSIGNED_INT ? 4 : 2))); // offset in bytes ro.glDrawElements(GL_TRIANGLES, sub->numTris * 3, indexType_,
(GLvoid*)((size_t)sub->startIndex * (indexType_ == GL_UNSIGNED_INT ? 4 : 2))); // offset in bytes
else
ro.glDrawArrays(GL_TRIANGLES, sub->startIndex, sub->numTris * 3);
_renderer->addRenderObject(&ro); _renderer->addRenderObject(&ro);
} }
} }
else else
{ {
ro.glDrawElements(GL_TRIANGLES, numTris_ * 3, indexType_, 0); if (!_nonindexed)
ro.glDrawElements(GL_TRIANGLES, numTris_ * 3, indexType_, 0);
else
ro.glDrawArrays(GL_TRIANGLES,0, numTris_ * 3);
_renderer->addRenderObject(&ro); _renderer->addRenderObject(&ro);
} }
} }
...@@ -2681,4 +2713,84 @@ void DrawMeshT<Mesh>::dumpObj(const char* _filename) const ...@@ -2681,4 +2713,84 @@ void DrawMeshT<Mesh>::dumpObj(const char* _filename) const
template <class Mesh>
void ACG::DrawMeshT<Mesh>::readVertexFromVBO(unsigned int _vertex, void* _dst)
{
assert(_dst != 0);
unsigned int stride = vertexDecl_->getVertexStride();
// byte offset
unsigned int offset = _vertex * stride;
// copy
memcpy(_dst, &vertices_[offset], stride);
}
template <class Mesh>
void ACG::DrawMeshT<Mesh>::invalidateFullVBO()
{
updateFullVBO_ = true;
}
template <class Mesh>
void ACG::DrawMeshT<Mesh>::updateFullVBO()
{
// update indexed vbo first, in the next step this vbo is resolved into non-indexed
updateGPUBuffers();
if (updateFullVBO_)
{
MeshCompiler* mc = getMeshCompiler();
if (mc)
{
int numTris = mc->getNumTriangles();
// alloc buffer
int numVerts = 3 * numTris;
int stride = mc->getVertexDeclaration()->getVertexStride();
std::vector<char> fullBuf(numVerts * stride);
// fill buffer
for (int i = 0; i < numTris; ++i)
{
for (int k = 0; k < 3; ++k)
{
int idx = i * 3 + k;
int vertexID = mc->getIndex(idx);
readVertexFromVBO(vertexID, &fullBuf[idx * stride]);
if (colorMode_ == 2)
{
// read face color
int faceId = meshComp_->mapToOriginalFaceID(i);
unsigned int fcolor = getFaceColor(mesh_.face_handle(faceId));
// store face color
writeVertexElement(&fullBuf[0], idx, vertexDecl_->getVertexStride(), offsetColor_, 4, &fcolor);
}
}
}
if (!fullBuf.empty())
vboFull_.upload(fullBuf.size(), &fullBuf[0], GL_STATIC_DRAW);
// clean update flag
updateFullVBO_ = false;
}
}
}
} }
...@@ -266,7 +266,7 @@ GLSL::Program* ACG::ShaderCache::getProgram( const ShaderGenDesc* _desc, const s ...@@ -266,7 +266,7 @@ GLSL::Program* ACG::ShaderCache::getProgram( const ShaderGenDesc* _desc, const s
if (oldCache != cache_.end()) if (oldCache != cache_.end())
{ {
if (!prog || !prog->isLinked()) if (!prog->isLinked())
{ {
delete prog; delete prog;
return oldCache->second; return oldCache->second;
...@@ -574,18 +574,6 @@ int ACG::ShaderCache::compareShaderGenDescs( const CacheEntry* _a, const CacheEn ...@@ -574,18 +574,6 @@ int ACG::ShaderCache::compareShaderGenDescs( const CacheEntry* _a, const CacheEn
const ShaderGenDesc* a = &_a->desc; const ShaderGenDesc* a = &_a->desc;
const ShaderGenDesc* b = &_b->desc; const ShaderGenDesc* b = &_b->desc;
if (a->numLights != b->numLights)
return -1;
if (a->shadeMode != b->shadeMode)
return -1;
if (a->vertexColors != b->vertexColors)
return -1;
if (a->textured() != b->textured())
return -1;
if (_a->strFragmentTemplate != _b->strFragmentTemplate) if (_a->strFragmentTemplate != _b->strFragmentTemplate)
return -1; return -1;
...@@ -605,10 +593,7 @@ int ACG::ShaderCache::compareShaderGenDescs( const CacheEntry* _a, const CacheEn ...@@ -605,10 +593,7 @@ int ACG::ShaderCache::compareShaderGenDescs( const CacheEntry* _a, const CacheEn
return -1; return -1;
if (a->numLights) return *a == *b ? 0 : -1;
return memcmp(a->lightTypes, b->lightTypes, a->numLights * sizeof(ShaderGenLightType));
return 0; // false
} }
......
...@@ -154,23 +154,29 @@ void ShaderGenerator::initVertexShaderIO(const ShaderGenDesc* _desc, const Defau ...@@ -154,23 +154,29 @@ void ShaderGenerator::initVertexShaderIO(const ShaderGenDesc* _desc, const Defau
std::string strColorOut = ""; // vertex color output
if (_desc->vertexColorsInterpolator.isEmpty())
if (_desc->shadeMode == SG_SHADE_FLAT) {
if (!_desc->geometryTemplateFile.isEmpty()) std::string strColorOut = "";
strColorOut = "vec4 outVertexColor"; if (_desc->shadeMode == SG_SHADE_FLAT)
if (!_desc->geometryTemplateFile.isEmpty())
strColorOut = "vec4 outVertexColor";
else {
// Bypass the output setter, as we have to set that directly with the flat.
addStringToList("vec4 outVertexColor", &outputs_, "flat out ", ";");
}
else { else {
// Bypass the output setter, as we have to set that directly with the flat. if (_desc->shadeMode == SG_SHADE_GOURAUD || _desc->vertexColors || _iodesc->inputColor_)
addStringToList("vec4 outVertexColor", &outputs_, "flat out ", ";"); strColorOut = "vec4 outVertexColor";
} }
else {
if (_desc->shadeMode == SG_SHADE_GOURAUD || _desc->vertexColors || _iodesc->inputColor_) if (strColorOut.size())
strColorOut = "vec4 outVertexColor"; addOutput(strColorOut.c_str());
} }
else
addStringToList("vec4 outVertexColor", &outputs_, _desc->vertexColorsInterpolator + " out ", ";");
if (strColorOut.size())
addOutput(strColorOut.c_str());
// handle other requests: normals, positions, texcoords // handle other requests: normals, positions, texcoords
...@@ -311,7 +317,7 @@ void ShaderGenerator::defineIOAbstraction( const DefaultIODesc* _iodesc, bool _v ...@@ -311,7 +317,7 @@ void ShaderGenerator::defineIOAbstraction( const DefaultIODesc* _iodesc, bool _v
addDefine(SG_INPUT_NORMALOS " inNormal"); addDefine(SG_INPUT_NORMALOS " inNormal");
if (_iodesc->inputColor_) if (_iodesc->inputColor_)
addDefine(SG_INPUT_VERTEXCOLOR "inColor"); addDefine(SG_INPUT_VERTEXCOLOR " inColor");
...@@ -1156,8 +1162,8 @@ void ShaderProgGenerator::addVertexBeginCode(QStringList* _code) ...@@ -1156,8 +1162,8 @@ void ShaderProgGenerator::addVertexBeginCode(QStringList* _code)
_code->push_back("sg_vNormalOS = normalize(inNormal);"); _code->push_back("sg_vNormalOS = normalize(inNormal);");
} }
if (ioDesc_.inputColor_) if (ioDesc_.inputColor_ && (desc_.shadeMode == SG_SHADE_UNLIT || desc_.colorMaterialMode == GL_EMISSION))
_code->push_back("sg_cColor = inColor;"); _code->push_back("sg_cColor = " SG_INPUT_VERTEXCOLOR ";");
// apply modifiers // apply modifiers
...@@ -1761,12 +1767,9 @@ void ShaderProgGenerator::addFragmentBeginCode(QStringList* _code) ...@@ -1761,12 +1767,9 @@ void ShaderProgGenerator::addFragmentBeginCode(QStringList* _code)
_code->push_back("vec4 sg_cColor = vec4(g_cEmissive, SG_ALPHA);"); _code->push_back("vec4 sg_cColor = vec4(g_cEmissive, SG_ALPHA);");
if (desc_.shadeMode == SG_SHADE_GOURAUD || if (desc_.shadeMode == SG_SHADE_GOURAUD ||
desc_.shadeMode == SG_SHADE_FLAT || desc_.shadeMode == SG_SHADE_FLAT ||
desc_.vertexColors) (ioDesc_.passColor_ && (desc_.shadeMode == SG_SHADE_UNLIT || desc_.colorMaterialMode == GL_EMISSION)))
{ _code->push_back("sg_cColor = " SG_INPUT_VERTEXCOLOR ";");
_code->push_back("sg_cColor = out" + inputShader + "Color;");
}
if (desc_.shadeMode == SG_SHADE_PHONG) if (desc_.shadeMode == SG_SHADE_PHONG)
addLightingCode(_code); addLightingCode(_code);
...@@ -1823,6 +1826,11 @@ void ShaderProgGenerator::addLightingCode(QStringList* _code) ...@@ -1823,6 +1826,11 @@ void ShaderProgGenerator::addLightingCode(QStringList* _code)
QString buf; QString buf;
const char* vertexColorString = (ioDesc_.inputColor_ && ioDesc_.passColor_) ? SG_INPUT_VERTEXCOLOR ".xyz * " : "";
const char* diffuseVertexColor = (desc_.colorMaterialMode == GL_DIFFUSE || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE) ? vertexColorString : "";
const char* ambientVertexColor = (desc_.colorMaterialMode == GL_AMBIENT || desc_.colorMaterialMode == GL_AMBIENT_AND_DIFFUSE) ? vertexColorString : "";
const char* specularVertexColor = (desc_.colorMaterialMode == GL_SPECULAR) ? vertexColorString : "";
for (int i = 0; i < desc_.numLights; ++i) for (int i = 0; i < desc_.numLights; ++i)
{ {
ShaderGenLightType lgt = desc_.lightTypes[i]; ShaderGenLightType lgt = desc_.lightTypes[i];
...@@ -1830,15 +1838,15 @@ void ShaderProgGenerator::addLightingCode(QStringList* _code) ...@@ -1830,15 +1838,15 @@ void ShaderProgGenerator::addLightingCode(QStringList* _code)
switch (lgt) switch (lgt)
{ {
case SG_LIGHT_DIRECTIONAL: case SG_LIGHT_DIRECTIONAL:
buf.sprintf("sg_cColor.xyz += LitDirLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightDir_%d, g_cLightAmbient_%d, g_cLightDiffuse_%d, g_cLightSpecular_%d);", i, i, i, i); buf.sprintf("sg_cColor.xyz += LitDirLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightDir_%d, %s g_cLightAmbient_%d, %s g_cLightDiffuse_%d, %s g_cLightSpecular_%d);", i, ambientVertexColor, i, diffuseVertexColor, i, specularVertexColor, i);
break; break;
case SG_LIGHT_POINT: case SG_LIGHT_POINT:
buf.sprintf("sg_cColor.xyz += LitPointLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%d, g_cLightAmbient_%d, g_cLightDiffuse_%d, g_cLightSpecular_%d, g_vLightAtten_%d);", i, i, i, i, i); buf.sprintf("sg_cColor.xyz += LitPointLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%d, %s g_cLightAmbient_%d, %s g_cLightDiffuse_%d, %s g_cLightSpecular_%d, g_vLightAtten_%d);", i, ambientVertexColor, i, diffuseVertexColor, i, specularVertexColor, i, i);
break; break;
case SG_LIGHT_SPOT: case SG_LIGHT_SPOT:
buf.sprintf("sg_cColor.xyz += LitSpotLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%d, g_vLightDir_%d, g_cLightAmbient_%d, g_cLightDiffuse_%d, g_cLightSpecular_%d, g_vLightAtten_%d, g_vLightAngleExp_%d);", i, i, i, i, i, i, i); buf.sprintf("sg_cColor.xyz += LitSpotLight(sg_vPosVS.xyz, sg_vNormalVS, g_vLightPos_%d, g_vLightDir_%d, %s g_cLightAmbient_%d, %s g_cLightDiffuse_%d, %s g_cLightSpecular_%d, g_vLightAtten_%d, g_vLightAngleExp_%d);", i, i, ambientVertexColor, i, diffuseVertexColor, i, specularVertexColor, i, i, i);
break; break;
default: break; default: break;
......
...@@ -94,6 +94,7 @@ public: ...@@ -94,6 +94,7 @@ public:
geometryTemplateFile(""), geometryTemplateFile(""),
fragmentTemplateFile(""), fragmentTemplateFile(""),
normalizeTexColors(true), normalizeTexColors(true),
colorMaterialMode(GL_AMBIENT_AND_DIFFUSE),
textureTypes_() textureTypes_()
{ {
for ( unsigned int i = 0 ; i < SG_MAX_SHADER_LIGHTS ; ++i) for ( unsigned int i = 0 ; i < SG_MAX_SHADER_LIGHTS ; ++i)
...@@ -150,7 +151,13 @@ public: ...@@ -150,7 +151,13 @@ public:
/// Defines if the textureVariable is normalized or not, if multiple textures are used /// Defines if the textureVariable is normalized or not, if multiple textures are used
bool normalizeTexColors; bool normalizeTexColors;
/// interpolation qualifier for input vertex colors: "flat", "smooth", "noperspective"
QString vertexColorsInterpolator;
// color material for input vertex colors: GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR, GL_AMBIENT_AND_DIFFUSE
// Usage of vertex colors in lighting function, as diffuse, emission, ambient color .. see glColorMaterial()
// default: GL_AMBIENT_AND_DIFFUSE
GLenum colorMaterialMode;
struct TextureType struct TextureType
{ {
...@@ -158,6 +165,7 @@ public: ...@@ -158,6 +165,7 @@ public:
bool shadow; bool shadow;
}; };
private: private: