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:
/** \brief binds index and vertex buffer and executes draw calls
*
* @param _textureMap maps from internally texture-id to OpenGL texture id
* may be null to disable textured rendering
* @param _textureMap maps from internally texture-id to OpenGL texture id, 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
*
* @param _renderer renderobjects are added to this renderer
* @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 _nonindexed use non-indexed vbo instead of optimized indexed vbo (should be avoided if possible)
* 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
*/
......@@ -936,6 +937,46 @@ private:
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:
//========================================================================
// per edge buffers
......
......@@ -82,6 +82,7 @@ DrawMeshT<Mesh>::DrawMeshT(Mesh& _mesh)
halfedgeNormalMode_(0), bVBOinHalfedgeNormalMode_(0),
invVertexMap_(0),
offsetPos_(0), offsetNormal_(20), offsetTexc_(12), offsetColor_(32),
updateFullVBO_(true),
textureIndexPropertyName_("Not Set"),
perFaceTextureCoordinatePropertyName_("Not Set"),
updatePerEdgeBuffers_(1),
......@@ -455,6 +456,7 @@ DrawMeshT<Mesh>::rebuild()
return;
}
invalidateFullVBO();
unsigned int maxFaceVertCount = 0;
......@@ -1088,6 +1090,9 @@ DrawMeshT<Mesh>::createVBO()
fillVertexBuffer();
ACG::GLState::bindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
// non indexed vbo needs updating now
invalidateFullVBO();
}
template <class Mesh>
......@@ -1117,7 +1122,7 @@ DrawMeshT<Mesh>::createIBO()
// line index buffer:
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)
{
......@@ -1125,22 +1130,20 @@ DrawMeshT<Mesh>::createIBO()
if (indexType_ == GL_UNSIGNED_SHORT)
{
((unsigned short*)pLineBuffer)[2*i] = (unsigned short)invVertexMap_[mesh_.from_vertex_handle(hh).idx()];
((unsigned short*)pLineBuffer)[2*i+1] = (unsigned short)invVertexMap_[mesh_.to_vertex_handle(hh).idx()];
// put two words in a dword
unsigned int combinedIdx = invVertexMap_[mesh_.from_vertex_handle(hh).idx()] | (invVertexMap_[mesh_.to_vertex_handle(hh).idx()] << 16);
lineBuffer[i] = combinedIdx;
}
else
{
pLineBuffer[2*i] = invVertexMap_[mesh_.from_vertex_handle(hh).idx()];
pLineBuffer[2*i+1] = invVertexMap_[mesh_.to_vertex_handle(hh).idx()];
lineBuffer[2 * i] = invVertexMap_[mesh_.from_vertex_handle(hh).idx()];
lineBuffer[2 * i + 1] = invVertexMap_[mesh_.to_vertex_handle(hh).idx()];
}
}
bindLineIbo();
fillLineBuffer(mesh_.n_edges(), pLineBuffer);
// FIXME: This is not exception safe and may lead to memory leaks.
delete [] pLineBuffer;
fillLineBuffer(mesh_.n_edges(), &lineBuffer[0]);
}
ACG::GLState::bindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
......@@ -1346,9 +1349,16 @@ void DrawMeshT<Mesh>::unbindBuffers()
}
template <class Mesh>
void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap)
void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap, bool _nonindexed)
{
if (!_nonindexed)
bindBuffers();
else
{
updateFullVBO();
vboFull_.bind();
vertexDecl_->activateFixedFunction();
}
#ifdef DEBUG_MEM_USAGE
getMemoryUsage(true);
......@@ -1371,12 +1381,20 @@ void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap)
else
ACG::GLState::bindTexture(GL_TEXTURE_2D, (*_textureMap)[sub->id]);
if (!_nonindexed)
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
{
if (!_nonindexed)
glDrawElements(GL_TRIANGLES, numTris_ * 3, indexType_, 0);
else
glDrawArrays(GL_TRIANGLES, 0, numTris_ * 3);
}
}
unbindBuffers();
......@@ -1384,12 +1402,20 @@ void DrawMeshT<Mesh>::draw(std::map< int, GLuint>* _textureMap)
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_)
{
RenderObject ro = *_baseObj;
if (!_nonindexed)
bindBuffersToRenderObject(&ro);
else
{
updateFullVBO();
ro.vertexBuffer = vboFull_.id();
ro.vertexDecl = vertexDecl_;
}
if (_baseObj->shaderDesc.textured())
{
......@@ -1426,15 +1452,21 @@ void ACG::DrawMeshT<Mesh>::addTriRenderObjects(IRenderer* _renderer, const Rende
if (!_nonindexed)
ro.glDrawElements(GL_TRIANGLES, sub->numTris * 3, indexType_,
(GLvoid*)( (size_t)sub->startIndex * (indexType_ == GL_UNSIGNED_INT ? 4 : 2))); // offset in bytes
(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);
}
}
else
{
if (!_nonindexed)
ro.glDrawElements(GL_TRIANGLES, numTris_ * 3, indexType_, 0);
else
ro.glDrawArrays(GL_TRIANGLES,0, numTris_ * 3);
_renderer->addRenderObject(&ro);
}
}
......@@ -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
if (oldCache != cache_.end())
{
if (!prog || !prog->isLinked())
if (!prog->isLinked())
{
delete prog;
return oldCache->second;
......@@ -574,18 +574,6 @@ int ACG::ShaderCache::compareShaderGenDescs( const CacheEntry* _a, const CacheEn
const ShaderGenDesc* a = &_a->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)
return -1;
......@@ -605,10 +593,7 @@ int ACG::ShaderCache::compareShaderGenDescs( const CacheEntry* _a, const CacheEn
return -1;
if (a->numLights)
return memcmp(a->lightTypes, b->lightTypes, a->numLights * sizeof(ShaderGenLightType));
return 0; // false
return *a == *b ? 0 : -1;
}
......
......@@ -154,9 +154,11 @@ void ShaderGenerator::initVertexShaderIO(const ShaderGenDesc* _desc, const Defau
std::string strColorOut = "";
// vertex color output
if (_desc->vertexColorsInterpolator.isEmpty())
{
std::string strColorOut = "";
if (_desc->shadeMode == SG_SHADE_FLAT)
if (!_desc->geometryTemplateFile.isEmpty())
strColorOut = "vec4 outVertexColor";
......@@ -171,6 +173,10 @@ void ShaderGenerator::initVertexShaderIO(const ShaderGenDesc* _desc, const Defau
if (strColorOut.size())
addOutput(strColorOut.c_str());
}
else
addStringToList("vec4 outVertexColor", &outputs_, _desc->vertexColorsInterpolator + " out ", ";");
// handle other requests: normals, positions, texcoords
......@@ -311,7 +317,7 @@ void ShaderGenerator::defineIOAbstraction( const DefaultIODesc* _iodesc, bool _v
addDefine(SG_INPUT_NORMALOS " inNormal");
if (_iodesc->inputColor_)
addDefine(SG_INPUT_VERTEXCOLOR "inColor");
addDefine(SG_INPUT_VERTEXCOLOR " inColor");
......@@ -1156,8 +1162,8 @@ void ShaderProgGenerator::addVertexBeginCode(QStringList* _code)
_code->push_back("sg_vNormalOS = normalize(inNormal);");
}
if (ioDesc_.inputColor_)
_code->push_back("sg_cColor = inColor;");
if (ioDesc_.inputColor_ && (desc_.shadeMode == SG_SHADE_UNLIT || desc_.colorMaterialMode == GL_EMISSION))
_code->push_back("sg_cColor = " SG_INPUT_VERTEXCOLOR ";");
// apply modifiers
......@@ -1762,11 +1768,8 @@ void ShaderProgGenerator::addFragmentBeginCode(QStringList* _code)
if (desc_.shadeMode == SG_SHADE_GOURAUD ||
desc_.shadeMode == SG_SHADE_FLAT ||
desc_.vertexColors)
{
_code->push_back("sg_cColor = out" + inputShader + "Color;");
}
(ioDesc_.passColor_ && (desc_.shadeMode == SG_SHADE_UNLIT || desc_.colorMaterialMode == GL_EMISSION)))
_code->push_back("sg_cColor = " SG_INPUT_VERTEXCOLOR ";");
if (desc_.shadeMode == SG_SHADE_PHONG)
addLightingCode(_code);
......@@ -1823,6 +1826,11 @@ void ShaderProgGenerator::addLightingCode(QStringList* _code)
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)
{
ShaderGenLightType lgt = desc_.lightTypes[i];
......@@ -1830,15 +1838,15 @@ void ShaderProgGenerator::addLightingCode(QStringList* _code)
switch (lgt)
{
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;
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;
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;
default: break;
......
......@@ -94,6 +94,7 @@ public:
geometryTemplateFile(""),
fragmentTemplateFile(""),
normalizeTexColors(true),
colorMaterialMode(GL_AMBIENT_AND_DIFFUSE),
textureTypes_()
{
for ( unsigned int i = 0 ; i < SG_MAX_SHADER_LIGHTS ; ++i)
......@@ -150,7 +151,13 @@ public:
/// Defines if the textureVariable is normalized or not, if multiple textures are used
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
{
......@@ -158,6 +165,7 @@ public:
bool shadow;
};
private:
// TODO: remove this, multitexturing always requires some customization! should be done via custom shader templates or mods. only allow one diffuse texture, as this is something commonly used and intentions are clear
/// holds the texture types (second) and the stage id (first). if empty, shader does not support textures
std::map<size_t,TextureType> textureTypes_;
......@@ -180,6 +188,52 @@ public:
bool textured()const {return !textureTypes_.empty();}
// comparison operator
bool operator == (const ShaderGenDesc& _rhs) const
{
if (numLights != _rhs.numLights)
return false;
if (shadeMode != _rhs.shadeMode)
return false;
if (vertexColors != _rhs.vertexColors)
return false;
if (textured() != _rhs.textured())
return false;
if (vertexColors)
{
if (vertexColorsInterpolator != _rhs.vertexColorsInterpolator)
return false;
if (colorMaterialMode != _rhs.colorMaterialMode)
return false;
}
if (fragmentTemplateFile != _rhs.fragmentTemplateFile)
return false;
if (geometryTemplateFile != _rhs.geometryTemplateFile)
return false;
if (vertexTemplateFile != _rhs.vertexTemplateFile)
return false;
if (tessControlTemplateFile != _rhs.tessControlTemplateFile)
return false;
if (_rhs.tessEvaluationTemplateFile != _rhs.tessEvaluationTemplateFile)
return false;
if (numLights)
return memcmp(lightTypes, _rhs.lightTypes, numLights * sizeof(ShaderGenLightType)) == 0;
return true;
}
};
......
......@@ -503,7 +503,8 @@ draw(GLState& _state, const DrawModes::DrawMode& _drawMode) {
drawMesh_->usePerVertexNormals();
drawMesh_->usePerFaceColors();
draw_faces();
drawMesh_->draw(textureMap_, true);
ACG::GLState::depthRange(0.0, 1.0);
_state.set_base_color(base_color_backup);
......@@ -640,6 +641,8 @@ void ACG::SceneGraph::MeshNodeT<Mesh>::getRenderObjects( IRenderer* _renderer, G
ro.shaderDesc.geometryTemplateFile = ""; //QString(props->geometryShader().c_str());
ro.shaderDesc.fragmentTemplateFile = ""; //QString(props->fragmentShader().c_str());
ro.shaderDesc.vertexColorsInterpolator = "";
// ------------------------
// 1. setup drawMesh based on property source
......@@ -854,7 +857,13 @@ void ACG::SceneGraph::MeshNodeT<Mesh>::getRenderObjects( IRenderer* _renderer, G
if (!ro.shaderDesc.vertexTemplateFile.isEmpty())
drawMesh_->scanVertexShaderForInput(ro.shaderDesc.vertexTemplateFile.toStdString());
add_face_RenderObjects(_renderer, &ro);
bool useNonIndexed = (props->colorSource() == DrawModes::COLOR_PER_FACE) && (props->lightStage() == DrawModes::LIGHTSTAGE_SMOOTH) && !props->flatShaded();
if (!useNonIndexed && props->colorSource() == DrawModes::COLOR_PER_FACE)
ro.shaderDesc.vertexColorsInterpolator = "flat";
add_face_RenderObjects(_renderer, &ro, useNonIndexed);
ro.shaderDesc.vertexColorsInterpolator = "";
} break;
default: break;
}
......@@ -927,8 +936,8 @@ draw_faces() {
template<class Mesh>
void
MeshNodeT<Mesh>::
add_face_RenderObjects(IRenderer* _renderer, const RenderObject* _baseObj) {
drawMesh_->addTriRenderObjects(_renderer, _baseObj, textureMap_);
add_face_RenderObjects(IRenderer* _renderer, const RenderObject* _baseObj, bool _nonindexed) {
drawMesh_->addTriRenderObjects(_renderer, _baseObj, textureMap_, _nonindexed);
}
template<class Mesh>
......@@ -1228,7 +1237,7 @@ pick_edges(GLState& _state, bool _front)
enable_arrays(0);
}
if (_state.color_picking () ) {
if (_state.color_picking () && drawMesh_ ) {
// picking implementations:
// 0 -> render mesh with picking color buffer (compatibility mode, add. mem alloc: 32 bytes per openmesh edge)
......@@ -1411,7 +1420,7 @@ pick_any(GLState& _state)
return;
}
if (_state.color_picking()) {
if (_state.color_picking() && drawMesh_) {
// picking implementations:
// 0 -> render mesh with picking color buffer (compatibility mode, add. mem alloc: 48 bytes per triangle + 32 bytes per edge + 16 bytes per vertex)
......@@ -1513,6 +1522,7 @@ update_geometry() {
drawMesh_->updateGeometry();
drawMesh_->invalidateFullVBO();
// First of all, we update the bounding box:
bbMin_ = Vec3d(FLT_MAX, FLT_MAX, FLT_MAX);
......@@ -1616,6 +1626,8 @@ MeshNodeT<Mesh>::getDrawMesh()
}
//=============================================================================
} // namespace SceneGraph
} // namespace ACG
......
......@@ -185,17 +185,16 @@ private:
/** @} */
//===========================================================================
/** @name Strip generation and handling
/** @name Draw-mesh handling
* @{ */
//===========================================================================
public:
// void update_strips();
private:
DrawMeshT<Mesh>* drawMesh_;
/** @} */
//===========================================================================
/** @name Bounding Box
* @{ */
......@@ -342,7 +341,7 @@ private:
*/
void draw_faces();
void add_face_RenderObjects(IRenderer* _renderer, const RenderObject* _baseObj);
void add_face_RenderObjects(IRenderer* _renderer, const RenderObject* _baseObj, bool _nonindexed = false);
private:
......
Markdown is supported
0% or .