From 488c31c57e33fd5609a51b7cfafaa7d7807419c5 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Sat, 23 Aug 2014 00:30:47 +0200 Subject: [PATCH] Implement clipping for DrawableLine. --- src/character.cpp | 4 +- src/drawableline.cpp | 61 ++++++++++++++++++++++++++-- src/drawableline.hpp | 4 +- src/geometry.cpp | 25 ++++++++++++ src/geometry.hpp | 34 ++++++++++++++++ src/geometry.inl | 31 ++++++++++++++ src/geometry_2d.cpp | 23 +++++++++++ src/geometry_2d.hpp | 43 ++++++++++++++++++++ src/geometry_2d.inl | 88 ++++++++++++++++++++++++++++++++++++++++ src/movers/moversine.cpp | 1 + src/vector.hpp | 3 ++ 11 files changed, 309 insertions(+), 8 deletions(-) create mode 100644 src/geometry.cpp create mode 100644 src/geometry.hpp create mode 100644 src/geometry.inl create mode 100644 src/geometry_2d.cpp create mode 100644 src/geometry_2d.hpp create mode 100644 src/geometry_2d.inl diff --git a/src/character.cpp b/src/character.cpp index 1d4757d..2b69044 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -40,7 +40,7 @@ namespace cloonel { m_bounceCallback(&DoNothing), m_texture(new Texture(parPath, parMain, false)) #if defined(WITH_DEBUG_VISUALS) - , m_bottomBarDrawable(parMain, Colour(250, 5, 1), static_cast(m_bottomBar.From()), static_cast(m_bottomBar.To())) + , m_bottomBarDrawable(parMain, Colour(250, 5, 1), static_cast(m_bottomBar.From()), static_cast(m_bottomBar.To())) #endif { assert(parMain); @@ -57,7 +57,7 @@ namespace cloonel { m_bounceCallback(&DoNothing), m_texture(new Texture(parPath, parMain, false)) #if defined(WITH_DEBUG_VISUALS) - , m_bottomBarDrawable(parMain, Colour(250, 5, 1), static_cast(m_bottomBar.From()), static_cast(m_bottomBar.To())) + , m_bottomBarDrawable(parMain, Colour(250, 5, 1), static_cast(m_bottomBar.From()), static_cast(m_bottomBar.To())) #endif { assert(parMain); diff --git a/src/drawableline.cpp b/src/drawableline.cpp index 6411193..006bb06 100644 --- a/src/drawableline.cpp +++ b/src/drawableline.cpp @@ -20,15 +20,68 @@ #include "drawableline.hpp" #include "sdlmain.hpp" +#include "geometry_2d.hpp" +#if !defined(NDEBUG) +# include "line_helpers.hpp" +#endif #include +#include #if defined(WITH_DEBUG_VISUALS) namespace cloonel { namespace { ///---------------------------------------------------------------------- ///---------------------------------------------------------------------- - void ClipLine (const SDL_Rect& /*parArea*/, Line& /*parLine*/) { + void ClipLine (const SDL_Rect& parArea, Line& parLine) { + Line line(static_cast(parLine[0]), static_cast(parLine[1])); + const float al = static_cast(parArea.x); + const float at = static_cast(parArea.y); + const float ar = static_cast(parArea.x + parArea.w); + const float ab = static_cast(parArea.y + parArea.h); + { + const Line leftLine(al, at, al, ab); + const auto intersection(Intersection(line, leftLine)); + if (intersection.first) { + if (line[0] < leftLine) + line[0] = intersection.second; + if (line[1] < leftLine) + line[1] = intersection.second; + } + } + { + const Line rightLine(ar, at, ar, ab); + const auto intersection(Intersection(line, rightLine)); + if (intersection.first) { + if (line[0] > rightLine) + line[0] = intersection.second; + if (line[1] > rightLine) + line[1] = intersection.second; + } + } + { + const Line topLine(al, at, ar, at); + const auto intersection(Intersection(line, topLine)); + if (intersection.first) { + if (line[0] < topLine) + line[0] = intersection.second; + if (line[1] < topLine) + line[1] = intersection.second; + } + } + { + const Line bottomLine(al, ab, ar, ab); + const auto intersection(Intersection(line, bottomLine)); + if (intersection.first) { + if (line[0] > bottomLine) + line[0] = intersection.second; + if (line[1] > bottomLine) + line[1] = intersection.second; + } + } + + parLine[0] = static_cast(line[0]); + parLine[1] = static_cast(line[1]); } } //unnamed namespace @@ -56,18 +109,18 @@ namespace cloonel { SDL_SetRenderDrawColor(m_sdlmain->GetRenderer(), m_colour.r, m_colour.g, m_colour.b, m_colour.a); LineBase scaledLine(*this); - scaledLine += static_cast(parPos); + scaledLine += static_cast(parPos); scaledLine *= parScaling; { SDL_Rect screen; screen.x = screen.y = 0; - const ushort2 wh(m_sdlmain->WidthHeight()); + const short2 wh(static_cast(m_sdlmain->WidthHeight())); screen.w = wh.x(); screen.h = wh.y(); ClipLine(screen, scaledLine); } - const uint16_t h = m_sdlmain->WidthHeight().y(); + const int16_t h = static_cast(m_sdlmain->WidthHeight().y()); if (scaledLine[0] != scaledLine[1]) { SDL_RenderDrawLine( m_sdlmain->GetRenderer(), diff --git a/src/drawableline.hpp b/src/drawableline.hpp index c4626ee..e0cc3a2 100644 --- a/src/drawableline.hpp +++ b/src/drawableline.hpp @@ -30,8 +30,8 @@ namespace cloonel { class SDLMain; - class DrawableLine : public Line { - typedef Line LineBase; + class DrawableLine : public Line { + typedef Line LineBase; public: explicit DrawableLine ( SDLMain* parMain ); explicit DrawableLine ( SDLMain* parMain, Colour parColour ); diff --git a/src/geometry.cpp b/src/geometry.cpp new file mode 100644 index 0000000..4894c29 --- /dev/null +++ b/src/geometry.cpp @@ -0,0 +1,25 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#include "geometry.hpp" + +namespace cloonel { + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- +} //namespace cloonel diff --git a/src/geometry.hpp b/src/geometry.hpp new file mode 100644 index 0000000..eb253b5 --- /dev/null +++ b/src/geometry.hpp @@ -0,0 +1,34 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#ifndef id3E40B29606D048569E18083DB682280F +#define id3E40B29606D048569E18083DB682280F + +#include "vector.hpp" +#include +#include + +namespace cloonel { + template + bool IsPointOnSegment ( const Vector& parPoint, const Vector& parSegA, const Vector& parSegB ) __attribute__((pure)); +} //namespace cloonel + +#include "geometry.inl" + +#endif diff --git a/src/geometry.inl b/src/geometry.inl new file mode 100644 index 0000000..429415c --- /dev/null +++ b/src/geometry.inl @@ -0,0 +1,31 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +namespace cloonel { + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + bool IsPointOnSegment (const Vector& parPoint, const Vector& parSegA, const Vector& parSegB) { + for (uint32_t z = 0; z < S; ++z) { + if (parPoint[z] <= std::max(parSegA[z], parSegB[z]) and parPoint[z] >= std::min(parSegA[z], parSegB[z])) + return false; + } + return true; + } +} //namespace cloonel diff --git a/src/geometry_2d.cpp b/src/geometry_2d.cpp new file mode 100644 index 0000000..a778376 --- /dev/null +++ b/src/geometry_2d.cpp @@ -0,0 +1,23 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#include "geometry_2d.hpp" + +namespace cloonel { +} //namespace cloonel diff --git a/src/geometry_2d.hpp b/src/geometry_2d.hpp new file mode 100644 index 0000000..7b2f08d --- /dev/null +++ b/src/geometry_2d.hpp @@ -0,0 +1,43 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +#include "vector.hpp" +#include "line.hpp" +#include "geometry.hpp" +#include +#include +#include + +#ifndef id2B404E7CFDD3470680E572779CB819F6 +#define id2B404E7CFDD3470680E572779CB819F6 + +namespace cloonel { + template + int GetOrientation ( const Vector& parPointA, const Vector& parPointB, const Vector& parPointC ) __attribute__((pure)); + + template + bool Intersection2D ( const Vector& parSegA1, const Vector& parSegA2, const Vector& parSegB1, const Vector& parSegB2 ) __attribute__((pure)); + + template + std::pair> Intersection ( const Line& parSegA, const Line& parSegB ) __attribute__((pure)); +} //namespace cloonel + +#include "geometry_2d.inl" + +#endif diff --git a/src/geometry_2d.inl b/src/geometry_2d.inl new file mode 100644 index 0000000..f059d5a --- /dev/null +++ b/src/geometry_2d.inl @@ -0,0 +1,88 @@ +/* + Copyright 2014 Michele "King_DuckZ" Santullo + + This file is part of CloonelJump. + + CloonelJump is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + CloonelJump is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with CloonelJump. If not, see . +*/ + +namespace cloonel { + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + int GetOrientation (const Vector& parPointA, const Vector& parPointB, const Vector& parPointC) { + const auto ret = + (parPointB.y() - parPointA.y()) * (parPointC.x() - parPointB.x()) - + (parPointB.x() - parPointA.x()) * (parPointC.y() - parPointB.y()); + const T zero(0); + if (ret == zero) + return 0; + else if (ret < zero) + return -1; + else + return 1; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + template + bool Intersection2D (const Vector& parSegA1, const Vector& parSegA2, const Vector& parSegB1, const Vector& parSegB2) { + const int o1 = GetOrientation(parSegA1, parSegA2, parSegB1); + const int o2 = GetOrientation(parSegA1, parSegA2, parSegB2); + const int o3 = GetOrientation(parSegB1, parSegB2, parSegA1); + const int o4 = GetOrientation(parSegB1, parSegB2, parSegA2); + + if (o1 != o2 and o3 != o4) + return true; + + if (0 == o1 and IsPointOnSegment(parSegA1, parSegB1, parSegA2)) + return true; + if (0 == o2 and IsPointOnSegment(parSegA1, parSegB2, parSegA2)) + return true; + if (0 == o3 and IsPointOnSegment(parSegB1, parSegA1, parSegB2)) + return true; + if (0 == o4 and IsPointOnSegment(parSegB1, parSegA2, parSegB2)) + return true; + + return false; + } + + ///-------------------------------------------------------------------------- + ///http://www.gidforums.com/t-20866.html + ///-------------------------------------------------------------------------- + template + std::pair> Intersection (const Line& parSegA, const Line& parSegB) { + typedef Line LineType; + + const typename LineType::Point& startA = parSegA[0]; + const typename LineType::Point& endA = parSegA[1]; + const typename LineType::Point& startB = parSegB[0]; + const typename LineType::Point& endB = parSegB[1]; + + const T A1(endA.y() - startA.y()); + const T A2(endB.y() - startB.y()); + const T B1(startA.x() - endA.x()); + const T B2(startB.x() - endB.x()); + const T det(A1 * B2 - A2 * B1); + + if (det == 0) { + return std::make_pair(false, typename LineType::Point(0)); + } + else { + const T C1(A1 * startA.x() + B1 * startA.y()); + const T C2(A2 * startB.x() + B2 * startB.y()); + return std::make_pair(true, typename LineType::Point((B2 * C1 - B1 * C2) / det, (A1 * C2 - A2 * C1) / det)); + } + } +} //namespace cloonel diff --git a/src/movers/moversine.cpp b/src/movers/moversine.cpp index cf86823..87a0e39 100644 --- a/src/movers/moversine.cpp +++ b/src/movers/moversine.cpp @@ -44,6 +44,7 @@ namespace cloonel { void MoverSine::ApplyMotion (float parDelta) { const float pitwo = static_cast(M_PI) * 2.0f; m_alpha += parDelta * 2.6f; + //TODO: optimize - see https://groups.google.com/forum/#!topic/comp.graphics.api.opengl/FFl3djAYERs while (m_alpha >= pitwo) m_alpha -= pitwo; } diff --git a/src/vector.hpp b/src/vector.hpp index 3cf4863..5ac995e 100644 --- a/src/vector.hpp +++ b/src/vector.hpp @@ -116,6 +116,9 @@ namespace cloonel { typedef Vector float2; typedef Vector ushort2; +#if !defined(NDEBUG) + typedef Vector short2; +#endif typedef Vector int2; #if !defined(NDEBUG)