diff options
Diffstat (limited to 'src/graphics/opengl/gldevice.cpp')
-rw-r--r-- | src/graphics/opengl/gldevice.cpp | 383 |
1 files changed, 348 insertions, 35 deletions
diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index 94b0dbc..9460e07 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -73,6 +73,8 @@ CGLDevice::CGLDevice(const GLDeviceConfig &config) { m_config = config; m_lighting = false; + m_lastVboId = 0; + m_useVbo = false; } @@ -109,6 +111,16 @@ bool CGLDevice::Create() GetLogger()->Error("GLEW reports required extensions not supported\n"); return false; } + + if (GLEW_ARB_vertex_buffer_object) + { + GetLogger()->Info("Detected ARB_vertex_buffer_object extension - using VBOs\n"); + m_useVbo = true; + } + else + { + GetLogger()->Info("No ARB_vertex_buffer_object extension present - using display lists\n"); + } } #endif @@ -174,6 +186,16 @@ void CGLDevice::ConfigChanged(const GLDeviceConfig& newConfig) Create(); } +void CGLDevice::SetUseVbo(bool useVbo) +{ + m_useVbo = useVbo; +} + +bool CGLDevice::GetUseVbo() +{ + return m_useVbo; +} + void CGLDevice::BeginScene() { Clear(); @@ -927,29 +949,308 @@ void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int glDisableClientState(GL_COLOR_ARRAY); } +unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +{ + unsigned int id = 0; + if (m_useVbo) + { + id = ++m_lastVboId; + + VboObjectInfo info; + info.primitiveType = primitiveType; + info.vertexType = VERTEX_TYPE_NORMAL; + info.vertexCount = vertexCount; + info.bufferId = 0; + + glGenBuffers(1, &info.bufferId); + glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + m_vboObjects[id] = info; + } + else + { + id = glGenLists(1); + + glNewList(id, GL_COMPILE); + + DrawPrimitive(primitiveType, vertices, vertexCount); + + glEndList(); + } + + return id; +} + +unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) +{ + unsigned int id = 0; + if (m_useVbo) + { + id = ++m_lastVboId; + + VboObjectInfo info; + info.primitiveType = primitiveType; + info.vertexType = VERTEX_TYPE_TEX2; + info.vertexCount = vertexCount; + info.bufferId = 0; + + glGenBuffers(1, &info.bufferId); + glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + m_vboObjects[id] = info; + } + else + { + id = glGenLists(1); + + glNewList(id, GL_COMPILE); + + DrawPrimitive(primitiveType, vertices, vertexCount); + + glEndList(); + } + + return id; +} + +unsigned int CGLDevice::CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) +{ + unsigned int id = 0; + if (m_useVbo) + { + id = ++m_lastVboId; + + VboObjectInfo info; + info.primitiveType = primitiveType; + info.vertexType = VERTEX_TYPE_COL; + info.vertexCount = vertexCount; + info.bufferId = 0; + + glGenBuffers(1, &info.bufferId); + glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + m_vboObjects[id] = info; + } + else + { + id = glGenLists(1); + + glNewList(id, GL_COMPILE); + + DrawPrimitive(primitiveType, vertices, vertexCount); + + glEndList(); + } + + return id; +} + +void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) +{ + if (m_useVbo) + { + auto it = m_vboObjects.find(bufferId); + if (it == m_vboObjects.end()) + return; + + VboObjectInfo& info = (*it).second; + info.primitiveType = primitiveType; + info.vertexType = VERTEX_TYPE_NORMAL; + info.vertexCount = vertexCount; + + glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + else + { + glNewList(bufferId, GL_COMPILE); + + DrawPrimitive(primitiveType, vertices, vertexCount); + + glEndList(); + } +} + +void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) +{ + if (m_useVbo) + { + auto it = m_vboObjects.find(bufferId); + if (it == m_vboObjects.end()) + return; + + VboObjectInfo& info = (*it).second; + info.primitiveType = primitiveType; + info.vertexType = VERTEX_TYPE_TEX2; + info.vertexCount = vertexCount; + + glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexTex2), vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + else + { + glNewList(bufferId, GL_COMPILE); + + DrawPrimitive(primitiveType, vertices, vertexCount); + + glEndList(); + } +} + +void CGLDevice::UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) +{ + if (m_useVbo) + { + auto it = m_vboObjects.find(bufferId); + if (it == m_vboObjects.end()) + return; + + VboObjectInfo& info = (*it).second; + info.primitiveType = primitiveType; + info.vertexType = VERTEX_TYPE_COL; + info.vertexCount = vertexCount; + + glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); + glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(VertexCol), vertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + } + else + { + glNewList(bufferId, GL_COMPILE); + + DrawPrimitive(primitiveType, vertices, vertexCount); + + glEndList(); + } +} + +void CGLDevice::DrawStaticBuffer(unsigned int bufferId) +{ + if (m_useVbo) + { + auto it = m_vboObjects.find(bufferId); + if (it == m_vboObjects.end()) + return; + + glEnable(GL_VERTEX_ARRAY); + glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId); + + if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, coord)); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, normal)); + + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, texCoord)); + } + else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, coord)); + + glEnableClientState(GL_NORMAL_ARRAY); + glNormalPointer(GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, normal)); + + glClientActiveTexture(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, texCoord)); + + glClientActiveTexture(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, texCoord2)); + } + else if ((*it).second.vertexType == VERTEX_TYPE_COL) + { + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), static_cast<char*>(nullptr) + offsetof(VertexCol, coord)); + + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_FLOAT, sizeof(VertexCol), static_cast<char*>(nullptr) + offsetof(VertexCol, color)); + } + + GLenum mode = TranslateGfxPrimitive((*it).second.primitiveType); + glDrawArrays(mode, 0, (*it).second.vertexCount); + + if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) + { + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE0 + } + else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) + { + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 + glClientActiveTexture(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + else if ((*it).second.vertexType == VERTEX_TYPE_COL) + { + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDisable(GL_VERTEX_ARRAY); + } + else + { + glCallList(bufferId); + } +} + +void CGLDevice::DestroyStaticBuffer(unsigned int bufferId) +{ + if (m_useVbo) + { + auto it = m_vboObjects.find(bufferId); + if (it == m_vboObjects.end()) + return; + + glDeleteBuffers(1, &(*it).second.bufferId); + + m_vboObjects.erase(it); + } + else + { + glDeleteLists(bufferId, 1); + } +} + bool InPlane(Math::Vector normal, float originPlane, Math::Vector center, float radius) { - float distance = (originPlane + Math::DotProduct(normal, center)) / normal.Length(); + float distance = originPlane + Math::DotProduct(normal, center); if (distance < -radius) - return true; + return false; - return false; + return true; } -/* - The implementation of ComputeSphereVisibility is taken from libwine's device.c - Copyright of the WINE team, licensed under GNU LGPL v 2.1 - */ +/* Based on libwine's implementation */ -// TODO: testing int CGLDevice::ComputeSphereVisibility(const Math::Vector ¢er, float radius) { Math::Matrix m; - m.LoadIdentity(); - m = Math::MultiplyMatrices(m, m_worldMat); - m = Math::MultiplyMatrices(m, m_viewMat); - m = Math::MultiplyMatrices(m, m_projectionMat); + m = Math::MultiplyMatrices(m_worldMat, m); + m = Math::MultiplyMatrices(m_viewMat, m); + Math::Matrix sc; + Math::LoadScaleMatrix(sc, Math::Vector(1.0f, 1.0f, -1.0f)); + m = Math::MultiplyMatrices(sc, m); + m = Math::MultiplyMatrices(m_projectionMat, m); Math::Vector vec[6]; float originPlane[6]; @@ -958,52 +1259,64 @@ int CGLDevice::ComputeSphereVisibility(const Math::Vector ¢er, float radius) vec[0].x = m.Get(4, 1) + m.Get(1, 1); vec[0].y = m.Get(4, 2) + m.Get(1, 2); vec[0].z = m.Get(4, 3) + m.Get(1, 3); - originPlane[0] = m.Get(4, 4) + m.Get(1, 4); + float l1 = vec[0].Length(); + vec[0].Normalize(); + originPlane[0] = (m.Get(4, 4) + m.Get(1, 4)) / l1; // Right plane vec[1].x = m.Get(4, 1) - m.Get(1, 1); vec[1].y = m.Get(4, 2) - m.Get(1, 2); vec[1].z = m.Get(4, 3) - m.Get(1, 3); - originPlane[1] = m.Get(4, 4) - m.Get(1, 4); - - // Top plane - vec[2].x = m.Get(4, 1) - m.Get(2, 1); - vec[2].y = m.Get(4, 2) - m.Get(2, 2); - vec[2].z = m.Get(4, 3) - m.Get(2, 3); - originPlane[2] = m.Get(4, 4) - m.Get(2, 4); + float l2 = vec[1].Length(); + vec[1].Normalize(); + originPlane[1] = (m.Get(4, 4) - m.Get(1, 4)) / l2; // Bottom plane - vec[3].x = m.Get(4, 1) + m.Get(2, 1); - vec[3].y = m.Get(4, 2) + m.Get(2, 2); - vec[3].z = m.Get(4, 3) + m.Get(2, 3); - originPlane[3] = m.Get(4, 4) + m.Get(2, 4); + vec[2].x = m.Get(4, 1) + m.Get(2, 1); + vec[2].y = m.Get(4, 2) + m.Get(2, 2); + vec[2].z = m.Get(4, 3) + m.Get(2, 3); + float l3 = vec[2].Length(); + vec[2].Normalize(); + originPlane[2] = (m.Get(4, 4) + m.Get(2, 4)) / l3; + + // Top plane + vec[3].x = m.Get(4, 1) - m.Get(2, 1); + vec[3].y = m.Get(4, 2) - m.Get(2, 2); + vec[3].z = m.Get(4, 3) - m.Get(2, 3); + float l4 = vec[3].Length(); + vec[3].Normalize(); + originPlane[3] = (m.Get(4, 4) - m.Get(2, 4)) / l4; // Front plane - vec[4].x = m.Get(3, 1); - vec[4].y = m.Get(3, 2); - vec[4].z = m.Get(3, 3); - originPlane[4] = m.Get(3, 4); + vec[4].x = m.Get(4, 1) + m.Get(3, 1); + vec[4].y = m.Get(4, 2) + m.Get(3, 2); + vec[4].z = m.Get(4, 3) + m.Get(3, 3); + float l5 = vec[4].Length(); + vec[4].Normalize(); + originPlane[4] = (m.Get(4, 4) + m.Get(3, 4)) / l5; // Back plane vec[5].x = m.Get(4, 1) - m.Get(3, 1); vec[5].y = m.Get(4, 2) - m.Get(3, 2); vec[5].z = m.Get(4, 3) - m.Get(3, 3); - originPlane[5] = m.Get(4, 4) - m.Get(3, 4); + float l6 = vec[5].Length(); + vec[5].Normalize(); + originPlane[5] = (m.Get(4, 4) - m.Get(3, 4)) / l6; int result = 0; if (InPlane(vec[0], originPlane[0], center, radius)) - result |= INTERSECT_PLANE_LEFT; + result |= FRUSTUM_PLANE_LEFT; if (InPlane(vec[1], originPlane[1], center, radius)) - result |= INTERSECT_PLANE_RIGHT; + result |= FRUSTUM_PLANE_RIGHT; if (InPlane(vec[2], originPlane[2], center, radius)) - result |= INTERSECT_PLANE_TOP; + result |= FRUSTUM_PLANE_BOTTOM; if (InPlane(vec[3], originPlane[3], center, radius)) - result |= INTERSECT_PLANE_BOTTOM; + result |= FRUSTUM_PLANE_TOP; if (InPlane(vec[4], originPlane[4], center, radius)) - result |= INTERSECT_PLANE_FRONT; + result |= FRUSTUM_PLANE_FRONT; if (InPlane(vec[5], originPlane[5], center, radius)) - result |= INTERSECT_PLANE_BACK; + result |= FRUSTUM_PLANE_BACK; return result; } |