void apply_material(const aiMaterial *mtl) { float c[4]; GLenum fill_mode; int ret1, ret2; aiColor4D diffuse; aiColor4D specular; aiColor4D ambient; aiColor4D emission; float shininess, strength; int two_sided; int wireframe; unsigned int max; set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) color4_to_float4(&diffuse, c); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular)) color4_to_float4(&specular, c); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c); set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient)) color4_to_float4(&ambient, c); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) color4_to_float4(&emission, c); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c); max = 1; ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max); max = 1; ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max); if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS)) glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength); else { glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f); set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c); } max = 1; if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max)) fill_mode = wireframe ? GL_LINE : GL_FILL; else fill_mode = GL_FILL; glPolygonMode(GL_FRONT_AND_BACK, fill_mode); max = 1; if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); }
void apply_material(const struct aiMaterial *mtl) { float c[4]; GLenum fill_mode; int ret1, ret2; struct aiColor4D diffuse; struct aiColor4D specular; struct aiColor4D ambient; struct aiColor4D emission; float shininess, strength; int two_sided; int wireframe; int max; int texIndex = 0; aiString texPath; //contains filename of texture if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)) { //bind texture unsigned int texId = *textureIdMap[texPath.data]; glBindTexture(GL_TEXTURE_2D, texId); } set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) color4_to_float4(&diffuse, c); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular)) color4_to_float4(&specular, c); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c); set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient)) color4_to_float4(&ambient, c); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) color4_to_float4(&emission, c); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c); max = 1; ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, (unsigned int *)&max); max = 1; ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, (unsigned int *)&max); if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS)) glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength); else { glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f); set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c); } max = 1; if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, (unsigned int *)&max)) fill_mode = wireframe ? GL_LINE : GL_FILL; else fill_mode = GL_FILL; glPolygonMode(GL_FRONT_AND_BACK, fill_mode); max = 1; if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, (unsigned int *)&max)) && two_sided) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); }
void VSResModelLib::genVAOsAndUniformBuffer(const struct aiScene *sc) { struct MyMesh aMesh; struct Material aMat; GLuint buffer; int totalTris = 0; unsigned int *adjFaceArray; VSLOG(mLogInfo, "Number of Meshes: %d",sc->mNumMeshes); // For each mesh for (unsigned int n = 0; n < sc->mNumMeshes; ++n) { const struct aiMesh* mesh = sc->mMeshes[n]; if (mesh->mPrimitiveTypes != 4) { aMesh.numIndices = 0; pMyMeshesAux.push_back(aMesh); continue; } VSLOG(mLogInfo, "Mesh[%d] Triangles %d",n, mesh->mNumFaces); totalTris += mesh->mNumFaces; // create array with faces // have to convert from Assimp format to array unsigned int *faceArray; faceArray = (unsigned int *)malloc( sizeof(unsigned int) * mesh->mNumFaces * 3); unsigned int faceIndex = 0; for (unsigned int t = 0; t < mesh->mNumFaces; ++t) { const struct aiFace* face = &mesh->mFaces[t]; memcpy(&faceArray[faceIndex], face->mIndices, 3 * sizeof(unsigned int)); faceIndex += 3; } if (pUseAdjacency) { // Create the half edge structure std::map<std::pair<unsigned int,unsigned int>, struct HalfEdge *> myEdges; struct HalfEdge *edge; // fill it up with edges. twin info will be added latter edge = (struct HalfEdge *)malloc(sizeof(struct HalfEdge) * mesh->mNumFaces * 3); for (unsigned int i = 0; i < mesh->mNumFaces; ++i) { edge[i*3].vertex = faceArray[i*3+1]; edge[i*3+1].vertex = faceArray[i*3+2]; edge[i*3+2].vertex = faceArray[i*3]; edge[i*3].next = &edge[i*3+1]; edge[i*3+1].next = &edge[i*3+2]; edge[i*3+2].next = &edge[i*3]; myEdges[std::pair<unsigned int,unsigned int>(faceArray[i*3+2],faceArray[i*3])] = &edge[i*3]; myEdges[std::pair<unsigned int,unsigned int>(faceArray[i*3],faceArray[i*3+1])] = &edge[i*3+1]; myEdges[std::pair<unsigned int,unsigned int>(faceArray[i*3+1],faceArray[i*3+2])] = &edge[i*3+2]; } // add twin info std::map<std::pair<unsigned int,unsigned int>, struct HalfEdge *>::iterator iter; std::pair<unsigned int,unsigned int> edgeIndex, twinIndex; iter = myEdges.begin(); for (; iter != myEdges.end(); ++iter) { edgeIndex = iter->first; twinIndex = std::pair<unsigned int, unsigned int>(edgeIndex.second, edgeIndex.first); if (myEdges.count(twinIndex)) iter->second->twin = myEdges[twinIndex]; else iter->second->twin = NULL; } adjFaceArray = (unsigned int *)malloc(sizeof(unsigned int) * mesh->mNumFaces * 6); for (unsigned int i = 0; i < mesh->mNumFaces; i++) { // NOTE: twin may be null adjFaceArray[i*6] = edge[3*i + 0].next->vertex; adjFaceArray[i*6+1] = edge[3*i + 0].twin?edge[3*i + 0].twin->vertex:edge[3*i + 0].next->vertex; adjFaceArray[i*6+2] = edge[3*i + 1].next->vertex; adjFaceArray[i*6+3] = edge[3*i + 1].twin?edge[3*i + 1].twin->vertex:edge[3*i + 1].next->vertex; adjFaceArray[i*6+4] = edge[3*i + 2].next->vertex; adjFaceArray[i*6+5] = edge[3*i + 2].twin?edge[3*i + 2].twin->vertex:edge[3*i + 2].next->vertex; } } //printf("\n"); //for (int i = 0; i < mesh->mNumFaces * 3; ++i) // printf("%d ", faceArray[i]); //printf("\n"); //for (int i = 0; i < mesh->mNumFaces * 6; ++i) // printf("%d ", adjFaceArray[i]); //printf("\n"); aMesh.numIndices = sc->mMeshes[n]->mNumFaces * 3; // generate Vertex Array for mesh glGenVertexArrays(1,&(aMesh.vao)); glBindVertexArray(aMesh.vao); // buffer for faces glGenBuffers(1, &buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); if (pUseAdjacency) { glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * mesh->mNumFaces * 6, adjFaceArray, GL_STATIC_DRAW); free(adjFaceArray); } else glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * mesh->mNumFaces * 3, faceArray, GL_STATIC_DRAW); free(faceArray); // buffer for vertex positions if (mesh->HasPositions()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mVertices, GL_STATIC_DRAW); glEnableVertexAttribArray( VSShaderLib::VERTEX_COORD_ATTRIB); glVertexAttribPointer(VSShaderLib::VERTEX_COORD_ATTRIB, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex normals if (mesh->HasNormals()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mNormals, GL_STATIC_DRAW); glEnableVertexAttribArray(VSShaderLib::NORMAL_ATTRIB); glVertexAttribPointer(VSShaderLib::NORMAL_ATTRIB, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex normals if (mesh->HasTangentsAndBitangents()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mTangents, GL_STATIC_DRAW); glEnableVertexAttribArray(VSShaderLib::TANGENT_ATTRIB); glVertexAttribPointer(VSShaderLib::TANGENT_ATTRIB, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex normals if (mesh->HasTangentsAndBitangents()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mBitangents, GL_STATIC_DRAW); glEnableVertexAttribArray(VSShaderLib::BITANGENT_ATTRIB); glVertexAttribPointer(VSShaderLib::BITANGENT_ATTRIB, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex texture coordinates if (mesh->HasTextureCoords(0)) { float *texCoords = (float *)malloc( sizeof(float)*2*mesh->mNumVertices); for (unsigned int k = 0; k < mesh->mNumVertices; ++k) { texCoords[k*2] = mesh->mTextureCoords[0][k].x; texCoords[k*2+1] = mesh->mTextureCoords[0][k].y; } glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->mNumVertices, texCoords, GL_STATIC_DRAW); glEnableVertexAttribArray( VSShaderLib::TEXTURE_COORD_ATTRIB); glVertexAttribPointer( VSShaderLib::TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, 0, 0, 0); free(texCoords); } // unbind buffers glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER,0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); // create material uniform buffer struct aiMaterial *mtl = sc->mMaterials[mesh->mMaterialIndex]; aiString texPath; //contains filename of texture for (int j = 0; j < VSResourceLib::MAX_TEXTURES; ++j) aMesh.texUnits[j] = 0; if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, 0, &texPath)) { //bind texture aMesh.texUnits[0] = pTextureIdMap[texPath.data]; aMesh.texTypes[0] = GL_TEXTURE_2D; aMat.texCount = 1; } else { aMesh.texUnits[0] = 0; aMat.texCount = 0; } float c[4]; set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f); aiColor4D diffuse; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) color4_to_float4(&diffuse, c); memcpy(aMat.diffuse, c, sizeof(c)); set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f); aiColor4D ambient; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient)) color4_to_float4(&ambient, c); memcpy(aMat.ambient, c, sizeof(c)); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); aiColor4D specular; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular)) color4_to_float4(&specular, c); memcpy(aMat.specular, c, sizeof(c)); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); aiColor4D emission; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) color4_to_float4(&emission, c); memcpy(aMat.emissive, c, sizeof(c)); float shininess = 0.0; unsigned int max; aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max); aMat.shininess = shininess; aMesh.mat = aMat; pMyMeshesAux.push_back(aMesh); } mVSML->loadIdentity(VSMathLib::AUX0); recursive_walk_for_matrices(sc, sc->mRootNode); pMyMeshesAux.clear(); VSLOG(mLogInfo, "Total Meshes: %d | Faces: %d", sc->mNumMeshes, totalTris); }
void Model::genVAOsAndUniformBuffer(const aiScene *sc) { checkForErrors(); struct MyMesh aMesh; struct MyMaterial aMat; GLuint buffer; // For each mesh for (unsigned int n = 0; n < sc->mNumMeshes; ++n) { const aiMesh* mesh = sc->mMeshes[n]; // create array with faces // have to convert from Assimp format to array unsigned int *faceArray; faceArray = (unsigned int *)malloc(sizeof(unsigned int) * mesh->mNumFaces * 3); unsigned int faceIndex = 0; for (unsigned int t = 0; t < mesh->mNumFaces; ++t) { const aiFace* face = &mesh->mFaces[t]; memcpy(&faceArray[faceIndex], face->mIndices,3 * sizeof(unsigned int)); faceIndex += 3; } aMesh.numFaces = sc->mMeshes[n]->mNumFaces; // generate Vertex Array for mesh glGenVertexArrays(1,&(aMesh.vao)); glBindVertexArray(aMesh.vao); // buffer for faces glGenBuffers(1, &buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * mesh->mNumFaces * 3, faceArray, GL_STATIC_DRAW); free(faceArray); // buffer for vertex positions if (mesh->HasPositions()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mVertices, GL_STATIC_DRAW); glEnableVertexAttribArray(vertexLoc); glVertexAttribPointer(vertexLoc, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex normals if (mesh->HasNormals()) { glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*3*mesh->mNumVertices, mesh->mNormals, GL_STATIC_DRAW); glEnableVertexAttribArray(normalLoc); glVertexAttribPointer(normalLoc, 3, GL_FLOAT, 0, 0, 0); } // buffer for vertex texture coordinates if (mesh->HasTextureCoords(0)) { float *texCoords = (float *)malloc(sizeof(float)*2*mesh->mNumVertices); for (unsigned int k = 0; k < mesh->mNumVertices; ++k) { texCoords[k*2] = mesh->mTextureCoords[0][k].x; texCoords[k*2+1] = mesh->mTextureCoords[0][k].y; } glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, sizeof(float)*2*mesh->mNumVertices, texCoords, GL_STATIC_DRAW); glEnableVertexAttribArray(texCoordLoc); glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, 0, 0, 0); } // unbind buffers glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER,0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); // create material uniform buffer aiMaterial *mtl = sc->mMaterials[mesh->mMaterialIndex]; aiString texPath; //contains filename of texture if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, 0, &texPath)){ //bind texture unsigned int texId = textureIdMap[texPath.data]; aMesh.texIndex = texId; aMat.texCount = 1; } else aMat.texCount = 0; float c[4]; set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f); aiColor4D diffuse; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) color4_to_float4(&diffuse, c); memcpy(aMat.diffuse, c, sizeof(c)); set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f); aiColor4D ambient; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient)) color4_to_float4(&ambient, c); memcpy(aMat.ambient, c, sizeof(c)); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); aiColor4D specular; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular)) color4_to_float4(&specular, c); memcpy(aMat.specular, c, sizeof(c)); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); aiColor4D emission; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) color4_to_float4(&emission, c); memcpy(aMat.emissive, c, sizeof(c)); float shininess = 0.0; unsigned int max; aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max); aMat.shininess = shininess; glGenBuffers(1,&(aMesh.uniformBlockIndex)); glBindBuffer(GL_UNIFORM_BUFFER,aMesh.uniformBlockIndex); glBufferData(GL_UNIFORM_BUFFER, sizeof(aMat), (void *)(&aMat), GL_STATIC_DRAW); myMeshes.push_back(aMesh); } }
void AssimpModel::applyMaterial(const aiMaterial *mtl) { int texIndex = 0; aiString texPath; //contains filename of texture if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)) { GLuint& texId = m_textures[texPath.data]; glBindTexture(GL_TEXTURE_2D, texId); } float color[4]; set_float4(color, 0.8f, 0.8f, 0.8f, 1.0f); aiColor4D diffuse; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) color4_to_float4(&diffuse, color); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color); set_float4(color, 0.0f, 0.0f, 0.0f, 1.0f); aiColor4D specular; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular)) color4_to_float4(&specular, color); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); set_float4(color, 0.2f, 0.2f, 0.2f, 1.0f); aiColor4D ambient; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient)) color4_to_float4(&ambient, color); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); set_float4(color, 0.0f, 0.0f, 0.0f, 1.0f); aiColor4D emission; if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) color4_to_float4(&emission, color); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); float shininess, strength; unsigned int max = 1; if( aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max) == AI_SUCCESS && aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max) == AI_SUCCESS) glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength); else { glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f); set_float4(color, 0.0f, 0.0f, 0.0f, 0.0f); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); } max = 1; GLenum fill_mode; int wireframe; if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max)) { fill_mode = wireframe ? GL_LINE : GL_FILL; } else { fill_mode = GL_FILL; } glPolygonMode(GL_FRONT_AND_BACK, fill_mode); max = 1; int two_sided; if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided) { glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); } }