/*! The SLRefGroup::shapeInit checks the validity of the referenced node. To avoid endless loops a refShape node is not allowed to refShape its ancestors. An ancestor of a refShape node is group node followed along the previous pointers with lower depth than the depth of the refShape node. */ void SLRefGroup::shapeInit(SLSceneView* sv) { // cummulate wm with referenced wm SLShape* ref = (SLShape*)_refGroup; _wm *= ref->m(); _wmI.setMatrix(_wm.inverse()); _wmN.setMatrix(_wmI.mat3()); _wmN.transpose(); // check circular references SLNode* parent = this->parent(); while (parent) { if (parent==_refGroup) SL_EXIT_MSG("Reference node produces a never ending loop."); parent = parent->parent(); } // set transparency flag _aabb.hasAlpha(((SLShape*)_refGroup)->aabb()->hasAlpha()); // delete all child references if (_first) deleteAll(); // loop through the referenced group and add a SLRefShape or SLRefGroup SLNode* current = ((SLGroup*)_refGroup)->first(); while (current) { if (typeid(*current)==typeid(SLGroup)) addNode(new SLRefGroup((SLGroup*)current, name()+"_"+current->name())); else addNode(new SLRefShape((SLShape*)current, name()+"_"+current->name())); ((SLShape*)_last)->wm(_wm); ((SLShape*)_last)->depth(depth()+1); ((SLShape*)_last)->shapeInit(sv); current = current->next(); } }
//----------------------------------------------------------------------------- //! SLGLShader::createAndCompile creates & compiles the OpenGL shader object SLbool SLGLShader::createAndCompile() { // delete if object already exits if (_objectGL) glDeleteShader(_objectGL); if (_code!="") { switch (_type) { case VertexShader: _objectGL = glCreateShader(GL_VERTEX_SHADER); break; case FragmentShader: _objectGL = glCreateShader(GL_FRAGMENT_SHADER); break; default: SL_EXIT_MSG("SLGLShader::load: Unknown shader type."); } //SLstring verGLSL = SLGLState::getInstance()->glSLVersionNO(); //SLstring srcVersion = "#version " + verGLSL + "\n"; //if (verGLSL > "120") //{ if (_type == VertexShader) // { SLUtils::replaceString(_code, "attribute", "in"); // SLUtils::replaceString(_code, "varying", "out"); // } // if (_type == FragmentShader) // { SLUtils::replaceString(_code, "varying", "in"); // } //} //SLstring scrComplete = srcVersion + _code; SLstring scrComplete = _code; const char* src = scrComplete.c_str(); glShaderSource(_objectGL, 1, &src, 0); glCompileShader(_objectGL); // Check compiler log SLint compileSuccess = 0; glGetShaderiv(_objectGL, GL_COMPILE_STATUS, &compileSuccess); if (compileSuccess == GL_FALSE) { GLchar log[256]; glGetShaderInfoLog(_objectGL, sizeof(log), 0, &log[0]); SL_LOG("*** COMPILER ERROR ***\n"); SL_LOG("Source file: %s\n", _file.c_str()); SL_LOG("%s\n\n", log); return false; } return true; } else SL_WARN_MSG("SLGLShader::createAndCompile: Nothing to compile!"); return false; }
/*! SLGroup::shapeInit loops over all child nodes and calls their init method with an incremented depth. While looping it must be checked that all child nodes have a depth equal the groups depth + 1. */ void SLGroup::shapeInit(SLSceneView* sv) { SLNode* current = _first; while (current) { if (current->depth() && current->depth() != depth()+1) { SL_EXIT_MSG("Scenegraph is not directed acyclic. There is a loop."); } current->init(sv, depth()+1); // Set transparent flags of the group if (!_aabb.hasAlpha() && ((SLShape*)current)->aabb()->hasAlpha()) _aabb.hasAlpha(true); current = current->next(); } }
/*! The SLRefShape::shapeInit checks the validity of the referenced node. To avoid endless loops a refShape node is not allowed to refShape its ancestors. An ancestor of a refShape node is group node followed along the previous pointers with lower depth than the depth of the refShape node. Do not initialize the referenced shape twice. */ void SLRefShape::shapeInit(SLSceneView* sv) { (void)sv; // avoid unused parameter warning // cummulate my wm with referenced object transform (m) SLShape* ref = (SLShape*)_refShape; _wm *= ref->m(); _wmI.setMatrix(_wm.inverse()); _wmN.setMatrix(_wmI.mat3()); _wmN.transpose(); // set transparency flag _aabb.hasAlpha(((SLShape*)_refShape)->aabb()->hasAlpha()); // check circular references SLNode* parent = this->parent(); while (parent) { if (parent==_refShape) SL_EXIT_MSG("Reference node produces a never ending loop."); parent = parent->parent(); } }
/*! SLLightRect::init sets the light id, the light states & creates an emissive mat. @todo properly remove this function and find a clean way to init lights in a scene */ void SLLightRect::init() { // Check if OpenGL lights are available if (SLScene::current->lights().size() >= SL_MAX_LIGHTS) SL_EXIT_MSG("Max. NO. of lights is exceeded!"); // Add the light to the lights array of the scene if (_id==-1) { _id = (SLint)SLScene::current->lights().size(); SLScene::current->lights().push_back(this); } // Set the OpenGL light states setState(); _stateGL->numLightsUsed = (SLint)SLScene::current->lights().size(); // Set emissive light material to the lights diffuse color if (_meshes.size() > 0) if (_meshes[0]->mat) _meshes[0]->mat->emission(_on ? diffuse() : SLCol4f::BLACK); }
/*! SLMesh::shapeDraw does the OpenGL rendering of the mesh. The triangle primitives are rendered per material (SLMatFaces) with the vertex array P, the normal array N, the array Tc and the face vertex index array F. Optionally you can draw the normals and/or the uniform grid voxels. */ void SLMesh::shapeDraw(SLSceneView* sv) { if (P && N) { //////////////////////// // 1: Check drawing bits //////////////////////// // Return if hidden if (sv->drawBits()->get(SL_DB_HIDDEN) || _drawBits.get(SL_DB_HIDDEN)) return; // Set polygon mode SLPrimitive primitiveType = SL_TRIANGLES; if (sv->drawBits()->get(SL_DB_POLYGONLINE) || _drawBits.get(SL_DB_POLYGONLINE)) primitiveType = SL_LINE_LOOP; // Set face culling stateGL->cullFace(!(sv->drawBits()->get(SL_DB_CULLOFF) || _drawBits.get(SL_DB_CULLOFF))); // check if texture exists SLbool useTexture = Tc && !(sv->drawBits()->get(SL_DB_TEXOFF) || _drawBits.get(SL_DB_TEXOFF)); // enable polygonoffset if voxels are drawn to avoid stitching if (sv->drawBits()->get(SL_DB_VOXELS) || _drawBits.get(SL_DB_VOXELS)) { stateGL->polygonOffset(true, 1.0f, 1.0f); } ////////////////////// // 2: Build VBO's once ////////////////////// if (!_bufP.id()) _bufP.generate(P, numV, 3); if (!_bufN.id()) _bufN.generate(N, numV, 3); if (!_bufTc.id() && Tc) _bufTc.generate(Tc, numV, 2); if (!_bufT.id() && T) _bufT.generate(T, numV, 4); if (!_bufF.id() && F) _bufF.generate(F, numF, 3, SL_UNSIGNED_SHORT, SL_ELEMENT_ARRAY_BUFFER); //////////////////////////////// // 3: Draw elements per material //////////////////////////////// for (SLuint m = 0; m < numM; ++m) { // Opaque materials only in 1st non-blended pass // Transparent materials only in 2nd blended pass if ((!stateGL->blend() && !M[m].mat->hasAlpha()) || ( stateGL->blend() && M[m].mat->hasAlpha())) { // 3.a: Apply mesh material if exists & differs from current if (M[m].mat != SLMaterial::current || SLMaterial::current->shaderProg()==0) M[m].mat->activate(stateGL, this); // 3.b: Pass the matrices to the shader program SLGLShaderProg* sp = SLMaterial::current->shaderProg(); sp->uniformMatrix4fv("u_mvMatrix", 1, (SLfloat*)&stateGL->modelViewMatrix); sp->uniformMatrix4fv("u_mvpMatrix", 1, (SLfloat*)stateGL->mvpMatrix()); sp->uniformMatrix3fv("u_nMatrix", 1, (SLfloat*)stateGL->normalMatrix()); sp->uniformMatrix4fv("u_invMvMatrix", 1, (SLfloat*)stateGL->invModelViewMatrix()); // 3.c: Enable attribute pointers _bufP.bindAndEnableAttrib(sp->getAttribLocation("a_position")); _bufN.bindAndEnableAttrib(sp->getAttribLocation("a_normal")); if (_bufTc.id() && useTexture) _bufTc.bindAndEnableAttrib(sp->getAttribLocation("a_texCoord")); if (_bufT.id()) _bufT.bindAndEnableAttrib(sp->getAttribLocation("a_tangent")); // 3.d: Finally draw elements _bufF.bindAndDrawElementsAs(primitiveType, M[m].numF*3, M[m].startF*3*sizeof(SLushort)); // 3.e: Disable attribute pointers _bufP.disableAttribArray(); _bufN.disableAttribArray(); if (_bufTc.id()) _bufTc.disableAttribArray(); if (_bufT.id()) _bufT.disableAttribArray(); } } ////////////////////////////////////// // 4: Draw optional normals & tangents ////////////////////////////////////// if (sv->drawBits()->get(SL_DB_NORMALS) || _drawBits.get(SL_DB_NORMALS)) { // scale the normals to 5% of the surounding sphere float r = _aabb.radiusOS() * 0.05f; SLVec3f* V2; if (!_bufN2.id()) { // scalefactor r from scaled radius for normals & tangents // build array between vertex and normal target point V2 = new SLVec3f[numV*2]; for (SLuint i=0; i < numV; ++i) { V2[i<<1] = P[i]; V2[(i<<1)+1].set(P[i] + N[i]*r); } // Create buffer object for normals _bufN2.generate(V2, numV*2, 3); if (T) { if (!_bufT2.id()) { for (SLuint i=0; i < numV; ++i) { V2[(i<<1)+1].set(P[i].x+T[i].x*r, P[i].y+T[i].y*r, P[i].z+T[i].z*r); } // Create buffer object for tangents _bufT2.generate(V2, numV*2, 3); } } delete[] V2; } _bufN2.drawArrayAsConstantColorLines(SLCol3f::BLUE); if (T) _bufT2.drawArrayAsConstantColorLines(SLCol3f::RED); } else { // release buffer objects for normal & tangent rendering if (_bufN2.id()) _bufN2.dispose(); if (_bufT2.id()) _bufT2.dispose(); } ////////////////////////////////////////// // 5: Draw optional acceleration structure ////////////////////////////////////////// if (_accelStruct) { if (sv->drawBits()->get(SL_DB_VOXELS) || _drawBits.get(SL_DB_VOXELS)) { _accelStruct->draw(sv); stateGL->polygonOffset(false); } else { // Delete the visualization VBO if not rendered anymore _accelStruct->disposeBuffers(); } } GET_GL_ERROR; } else { SL_EXIT_MSG("SLMesh::shapeDraw: Arrays P or/and N empty"); } }
//----------------------------------------------------------------------------- //! SLRectangle::buildMesh fills in the underlying arrays from the SLMesh object void SLRectangle::buildMesh(SLMaterial* material) { deleteData(); // Check max. allowed no. of verts SLuint uIntNumV64 = (_resX+1) * (_resY+1); if (uIntNumV64 > UINT_MAX) SL_EXIT_MSG("SLMesh supports max. 2^32 vertices."); // allocate new arrays of SLMesh numV = (_resX+1) * (_resY+1); numI = _resX * _resY * 2 * 3; P = new SLVec3f[numV]; N = new SLVec3f[numV]; Tc = new SLVec2f[numV]; if (uIntNumV64 < 65535) I16 = new SLushort[numI]; else I32 = new SLuint[numI]; // Calculate normal from the first 3 corners SLVec3f maxmin(_max.x, _min.y, 0); SLVec3f minmax(_min.x, _max.y, 0); SLVec3f e1(maxmin - _min); SLVec3f e2(minmax - _min); SLVec3f curN(e1^e2); curN.normalize(); //Set one default material index mat = material; // define delta vectors dX & dY and deltas for texCoord dS,dT SLVec3f dX = e1 / (SLfloat)_resX; SLVec3f dY = e2 / (SLfloat)_resY; SLfloat dS = (_tmax.x - _tmin.x) / (SLfloat)_resX; SLfloat dT = (_tmax.y - _tmin.y) / (SLfloat)_resY; // Build vertex data SLuint i = 0; for (SLuint y=0; y<=_resY; ++y) { SLVec3f curV = _min; SLVec2f curT = _tmin; curV += (SLfloat)y*dY; curT.y += (SLfloat)y*dT; for (SLuint x=0; x<=_resX; ++x, ++i) { P[i] = curV; Tc[i] = curT; N[i] = curN; curV += dX; curT.x += dS; } } // Build face vertex indexes if (I16) { SLuint v = 0, i = 0; //index for vertices and indexes for (SLuint y=0; y<_resY; ++y) { for (SLuint x=0; x<_resX; ++x, ++v) { // triangle 1 I16[i++] = v; I16[i++] = v+_resX+2; I16[i++] = v+_resX+1; // triangle 2 I16[i++] = v; I16[i++] = v+1; I16[i++] = v+_resX+2; } v++; } } else { SLuint v = 0, i = 0; //index for vertices and indexes for (SLuint y=0; y<_resY; ++y) { for (SLuint x=0; x<_resX; ++x, ++v) { // triangle 1 I32[i++] = v; I32[i++] = v+_resX+2; I32[i++] = v+_resX+1; // triangle 2 I32[i++] = v; I32[i++] = v+1; I32[i++] = v+_resX+2; } v++; } } }
/*! SLGLShaderProg::init creates the OpenGL shaderprogram object, compiles all shader objects and attaches them to the shaderprogram. At the end all shaders are linked. If a shader fails to compile a simple texture only shader is compiled that shows an error message in the texture. */ void SLGLShaderProg::init() { // create program object if it doesn't exist if(!_programObjectGL) _programObjectGL = glCreateProgram(); // if already linked, detach, recreate and compile shaders if (_isLinked) { for (SLuint i=0; i<_shaderList.size(); i++) { if (_isLinked) { glDetachShader(_programObjectGL, _shaderList[i]->_shaderObjectGL); GET_GL_ERROR; } } _isLinked = false; } // compile all shader objects SLbool allSuccuessfullyCompiled = true; for (SLuint i=0; i<_shaderList.size(); i++) { if (!_shaderList[i]->createAndCompile()) { allSuccuessfullyCompiled = false; break; } GET_GL_ERROR; } // try to compile alternative per vertex lighting shaders if (!allSuccuessfullyCompiled) { // delete all shaders and uniforms that where attached for (SLuint i=0; i<_shaderList.size(); i++) delete _shaderList[i]; for (SLuint i=0; i<_uniform1fList.size(); ++i) delete _uniform1fList[i]; for (SLuint i=0; i<_uniform1iList.size(); ++i) delete _uniform1iList[i]; _shaderList.clear(); _uniform1fList.clear(); _uniform1iList.clear(); addShader(new SLGLShader(defaultPath+"ErrorTex.vert", SLVertexShader)); addShader(new SLGLShader(defaultPath+"ErrorTex.frag", SLFragmentShader)); allSuccuessfullyCompiled = true; for (SLuint i=0; i<_shaderList.size(); i++) { if (!_shaderList[i]->createAndCompile()) { allSuccuessfullyCompiled = false; break; } GET_GL_ERROR; } } // attach all shader objects if (allSuccuessfullyCompiled) { for (SLuint i=0; i<_shaderList.size(); i++) { glAttachShader(_programObjectGL, _shaderList[i]->_shaderObjectGL); GET_GL_ERROR; } } else SL_EXIT_MSG("No successufully compiled shaders attached!"); int linked; glLinkProgram(_programObjectGL); GET_GL_ERROR; glGetProgramiv(_programObjectGL, GL_LINK_STATUS, &linked); GET_GL_ERROR; if (linked) { _isLinked = true; for (SLuint i=0; i<_shaderList.size(); i++) _name += "+"+_shaderList[i]->name(); //SL_LOG("Linked: %s", _name.c_str()); } else { SLchar log[256]; glGetProgramInfoLog(_programObjectGL, sizeof(log), 0, &log[0]); SL_LOG("*** LINKER ERROR ***\n"); SL_LOG("Source files: \n"); for (SLuint i=0; i<_shaderList.size(); i++) SL_LOG("%s\n", _shaderList[i]->name().c_str()); SL_LOG("%s\n", log); SL_EXIT_MSG("GLSL linker error"); } }