diff options
Diffstat (limited to 'src/graphics/opengl')
-rw-r--r-- | src/graphics/opengl/gldevice.cpp | 383 | ||||
-rw-r--r-- | src/graphics/opengl/gldevice.h | 39 | ||||
-rw-r--r-- | src/graphics/opengl/test/light_test.cpp | 27 | ||||
-rw-r--r-- | src/graphics/opengl/test/texture_test.cpp | 1 |
4 files changed, 411 insertions, 39 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; } diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index 87c1247..dd43f2c 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -27,6 +27,7 @@ #include <string> #include <vector> #include <set> +#include <map> // Graphics module namespace @@ -84,6 +85,9 @@ public: void ConfigChanged(const GLDeviceConfig &newConfig); + void SetUseVbo(bool useVbo); + bool GetUseVbo(); + virtual void BeginScene(); virtual void EndScene(); @@ -119,14 +123,21 @@ public: virtual void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT); - //! Renders primitive composed of vertices with single texture virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)); - //! Renders primitive composed of vertices with multitexturing (2 textures) virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)); virtual void DrawPrimitive(PrimitiveType type, const VertexCol *vertices , int vertexCount); + virtual unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); + virtual unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount); + virtual unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount); + virtual void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); + virtual void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount); + virtual void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount); + virtual void DrawStaticBuffer(unsigned int bufferId); + virtual void DestroyStaticBuffer(unsigned int bufferId); + virtual int ComputeSphereVisibility(const Math::Vector ¢er, float radius); virtual void SetRenderState(RenderState state, bool enabled); @@ -200,6 +211,30 @@ private: //! Set of all created textures std::set<Texture> m_allTextures; + + //! Type of vertex structure + enum VertexType + { + VERTEX_TYPE_NORMAL, + VERTEX_TYPE_TEX2, + VERTEX_TYPE_COL, + }; + + //! Info about static VBO buffers + struct VboObjectInfo + { + PrimitiveType primitiveType; + unsigned int bufferId; + VertexType vertexType; + int vertexCount; + }; + + //! Whether to use VBOs or display lists + bool m_useVbo; + //! Map of saved VBO objects + std::map<unsigned int, VboObjectInfo> m_vboObjects; + //! Last ID of VBO object + unsigned int m_lastVboId; }; diff --git a/src/graphics/opengl/test/light_test.cpp b/src/graphics/opengl/test/light_test.cpp index 6ff3b1c..b19ba4b 100644 --- a/src/graphics/opengl/test/light_test.cpp +++ b/src/graphics/opengl/test/light_test.cpp @@ -51,7 +51,7 @@ void Render(Gfx::CGLDevice *device) device->SetRenderState(Gfx::RENDER_STATE_CULLING, false); // Double-sided drawing Math::Matrix persp; - Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 100.0f); + Math::LoadProjectionMatrix(persp, Math::PI / 4.0f, (800.0f) / (600.0f), 0.1f, 50.0f); device->SetTransform(Gfx::TRANSFORM_PROJECTION, persp); @@ -121,6 +121,31 @@ void Render(Gfx::CGLDevice *device) Math::LoadTranslationMatrix(worldMat, Math::Vector(-40.0f, 2.0f, -40.0f)); device->SetTransform(Gfx::TRANSFORM_WORLD, worldMat); + int planes = device->ComputeSphereVisibility(Math::Vector(0.0f, 0.0f, 0.0f), 1.0f); + printf("Planes:"); + if (planes == 0) + printf(" (none)"); + + if (planes & Gfx::FRUSTUM_PLANE_LEFT) + printf(" LEFT"); + + if (planes & Gfx::FRUSTUM_PLANE_RIGHT) + printf(" RIGHT"); + + if (planes & Gfx::FRUSTUM_PLANE_BOTTOM) + printf(" BOTTOM"); + + if (planes & Gfx::FRUSTUM_PLANE_TOP) + printf(" TOP"); + + if (planes & Gfx::FRUSTUM_PLANE_FRONT) + printf(" FRONT"); + + if (planes & Gfx::FRUSTUM_PLANE_BACK) + printf(" BACK"); + + printf("\n"); + device->DrawPrimitive(Gfx::PRIMITIVE_TRIANGLE_STRIP, quad, 4); for (int i = 0; i < 6; ++i) diff --git a/src/graphics/opengl/test/texture_test.cpp b/src/graphics/opengl/test/texture_test.cpp index 534a5c0..d771927 100644 --- a/src/graphics/opengl/test/texture_test.cpp +++ b/src/graphics/opengl/test/texture_test.cpp @@ -13,7 +13,6 @@ void Init(Gfx::CGLDevice *device) device->SetShadeModel(Gfx::SHADE_SMOOTH); device->SetRenderState(Gfx::RENDER_STATE_DEPTH_TEST, false); - device->SetRenderState(Gfx::RENDER_STATE_TEXTURING, true); device->SetTextureEnabled(0, true); device->SetTextureEnabled(1, true); |