From 86ea086790a677d6de6a836e7562814d3ba30bd1 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Wed, 18 Jul 2012 21:47:47 +0200 Subject: [PATCH] ComputeSphereVisibility function - borrowed implementation of ComputeSphereVisibility from libwine - added -lrt to Linux libs --- src/CMakeLists.txt | 5 ++ src/graphics/common/device.h | 23 +++++++-- src/graphics/opengl/gldevice.cpp | 82 ++++++++++++++++++++++++++++++++ src/graphics/opengl/gldevice.h | 1 + 4 files changed, 108 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fc3cfe39..9430da66 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ # Configure options option(DEBUG "Enable debug output" ON) +set(PLATFORM_LIBS "") + if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(PLATFORM_WINDOWS 1) set(PLATFORM_LINUX 0) @@ -13,6 +15,8 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(PLATFORM_WINDOWS 0) set(PLATFORM_LINUX 1) set(PLATFORM_OTHER 0) + # for clock_gettime + set(PLATFORM_LIBS "-lrt") else() set(PLATFORM_WINDOWS 0) set(PLATFORM_LINUX 0) @@ -154,6 +158,7 @@ ${SDLIMAGE_LIBRARY} ${OPENGL_LIBRARY} ${PNG_LIBRARIES} #CBot -- not yet WinAPI-independent +${PLATFORM_LIBS} ) include_directories(. ${CMAKE_CURRENT_BINARY_DIR} diff --git a/src/graphics/common/device.h b/src/graphics/common/device.h index 6a71a8a5..ceaf67aa 100644 --- a/src/graphics/common/device.h +++ b/src/graphics/common/device.h @@ -181,6 +181,24 @@ enum PrimitiveType PRIMITIVE_TRIANGLE_STRIP }; +/** + \enum IntersectPlane + \brief Intersection plane of projection volume + + These flags can be OR'd together. */ +enum IntersectPlane +{ + INTERSECT_PLANE_LEFT = 0x01, + INTERSECT_PLANE_RIGHT = 0x02, + INTERSECT_PLANE_TOP = 0x04, + INTERSECT_PLANE_BOTTOM = 0x08, + INTERSECT_PLANE_FRONT = 0x10, + INTERSECT_PLANE_BACK = 0x20, + INTERSECT_PLANE_ALL = INTERSECT_PLANE_LEFT | INTERSECT_PLANE_RIGHT | + INTERSECT_PLANE_TOP | INTERSECT_PLANE_BOTTOM | + INTERSECT_PLANE_FRONT | INTERSECT_PLANE_BACK +}; + /* Notes for rewriting DirectX code: @@ -324,9 +342,8 @@ public: //! Renders primitive composed of vertices with multitexturing (2 textures) virtual void DrawPrimitive(Gfx::PrimitiveType type, Gfx::VertexTex2 *vertices, int vertexCount) = 0; - // TODO: - // virtual void ComputeSphereVisibility() = 0; - + //! Tests whether a sphere intersects the 6 clipping planes of projection volume + virtual int ComputeSphereVisibility(Math::Vector center, float radius) = 0; //! Enables/disables the given render state virtual void SetRenderState(Gfx::RenderState state, bool enabled) = 0; diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index b8f3bed1..19a9cffa 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -18,6 +18,7 @@ #include "common/image.h" #include "graphics/opengl/gldevice.h" +#include "math/geometry.h" #define GL_GLEXT_PROTOTYPES @@ -732,6 +733,87 @@ void Gfx::CGLDevice::DrawPrimitive(Gfx::PrimitiveType type, VertexTex2 *vertices glEnd(); } +bool InPlane(Math::Vector normal, float originPlane, Math::Vector center, float radius) +{ + float distance = (originPlane + Math::DotProduct(normal, center)) / normal.Length(); + + if (distance < -radius) + return true; + + return false; +} + +/* + The implementation of ComputeSphereVisibility is taken from libwine's device.c + Copyright of the WINE team, licensed under GNU LGPL v 2.1 + */ + +// TODO: testing +int Gfx::CGLDevice::ComputeSphereVisibility(Math::Vector center, 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); + + Math::Vector vec[6]; + float originPlane[6]; + + // Left plane + 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); + + // 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); + + // 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); + + // 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); + + // 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); + + int result = 0; + + if (InPlane(vec[0], originPlane[0], center, radius)) + result |= Gfx::INTERSECT_PLANE_LEFT; + if (InPlane(vec[1], originPlane[1], center, radius)) + result |= Gfx::INTERSECT_PLANE_RIGHT; + if (InPlane(vec[2], originPlane[2], center, radius)) + result |= Gfx::INTERSECT_PLANE_TOP; + if (InPlane(vec[3], originPlane[3], center, radius)) + result |= Gfx::INTERSECT_PLANE_BOTTOM; + if (InPlane(vec[4], originPlane[4], center, radius)) + result |= Gfx::INTERSECT_PLANE_FRONT; + if (InPlane(vec[5], originPlane[5], center, radius)) + result |= Gfx::INTERSECT_PLANE_BACK; + + return result; +} + void Gfx::CGLDevice::SetRenderState(Gfx::RenderState state, bool enabled) { if (state == RENDER_STATE_DEPTH_WRITE) diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index 2b1b05da..56ea2c01 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -117,6 +117,7 @@ public: virtual void DrawPrimitive(Gfx::PrimitiveType type, Gfx::VertexCol *vertices, int vertexCount); virtual void DrawPrimitive(Gfx::PrimitiveType type, VertexTex2 *vertices, int vertexCount); + virtual int ComputeSphereVisibility(Math::Vector center, float radius); virtual void SetRenderState(Gfx::RenderState state, bool enabled); virtual bool GetRenderState(Gfx::RenderState state);