Implement clipping for DrawableLine.

This commit is contained in:
King_DuckZ 2014-08-23 00:30:47 +02:00
parent 634503bf00
commit 488c31c57e
11 changed files with 309 additions and 8 deletions

View file

@ -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<ushort2>(m_bottomBar.From()), static_cast<ushort2>(m_bottomBar.To()))
, m_bottomBarDrawable(parMain, Colour(250, 5, 1), static_cast<short2>(m_bottomBar.From()), static_cast<short2>(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<ushort2>(m_bottomBar.From()), static_cast<ushort2>(m_bottomBar.To()))
, m_bottomBarDrawable(parMain, Colour(250, 5, 1), static_cast<short2>(m_bottomBar.From()), static_cast<short2>(m_bottomBar.To()))
#endif
{
assert(parMain);

View file

@ -20,15 +20,68 @@
#include "drawableline.hpp"
#include "sdlmain.hpp"
#include "geometry_2d.hpp"
#if !defined(NDEBUG)
# include "line_helpers.hpp"
#endif
#include <SDL2/SDL.h>
#include <algorithm>
#if defined(WITH_DEBUG_VISUALS)
namespace cloonel {
namespace {
///----------------------------------------------------------------------
///----------------------------------------------------------------------
void ClipLine (const SDL_Rect& /*parArea*/, Line<uint16_t, 2>& /*parLine*/) {
void ClipLine (const SDL_Rect& parArea, Line<int16_t, 2>& parLine) {
Line<float, 2> line(static_cast<float2>(parLine[0]), static_cast<float2>(parLine[1]));
const float al = static_cast<float>(parArea.x);
const float at = static_cast<float>(parArea.y);
const float ar = static_cast<float>(parArea.x + parArea.w);
const float ab = static_cast<float>(parArea.y + parArea.h);
{
const Line<float, 2> 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<float, 2> 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<float, 2> 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<float, 2> 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<short2>(line[0]);
parLine[1] = static_cast<short2>(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<ushort2>(parPos);
scaledLine += static_cast<short2>(parPos);
scaledLine *= parScaling;
{
SDL_Rect screen;
screen.x = screen.y = 0;
const ushort2 wh(m_sdlmain->WidthHeight());
const short2 wh(static_cast<short2>(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<int16_t>(m_sdlmain->WidthHeight().y());
if (scaledLine[0] != scaledLine[1]) {
SDL_RenderDrawLine(
m_sdlmain->GetRenderer(),

View file

@ -30,8 +30,8 @@
namespace cloonel {
class SDLMain;
class DrawableLine : public Line<uint16_t, 2> {
typedef Line<uint16_t, 2> LineBase;
class DrawableLine : public Line<int16_t, 2> {
typedef Line<int16_t, 2> LineBase;
public:
explicit DrawableLine ( SDLMain* parMain );
explicit DrawableLine ( SDLMain* parMain, Colour parColour );

25
src/geometry.cpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "geometry.hpp"
namespace cloonel {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
} //namespace cloonel

34
src/geometry.hpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef id3E40B29606D048569E18083DB682280F
#define id3E40B29606D048569E18083DB682280F
#include "vector.hpp"
#include <ciso646>
#include <algorithm>
namespace cloonel {
template <typename T, uint32_t S>
bool IsPointOnSegment ( const Vector<T, S>& parPoint, const Vector<T, S>& parSegA, const Vector<T, S>& parSegB ) __attribute__((pure));
} //namespace cloonel
#include "geometry.inl"
#endif

31
src/geometry.inl Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
namespace cloonel {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T, uint32_t S>
bool IsPointOnSegment (const Vector<T, S>& parPoint, const Vector<T, S>& parSegA, const Vector<T, S>& 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

23
src/geometry_2d.cpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "geometry_2d.hpp"
namespace cloonel {
} //namespace cloonel

43
src/geometry_2d.hpp Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "vector.hpp"
#include "line.hpp"
#include "geometry.hpp"
#include <ciso646>
#include <algorithm>
#include <utility>
#ifndef id2B404E7CFDD3470680E572779CB819F6
#define id2B404E7CFDD3470680E572779CB819F6
namespace cloonel {
template <typename T>
int GetOrientation ( const Vector<T, 2>& parPointA, const Vector<T, 2>& parPointB, const Vector<T, 2>& parPointC ) __attribute__((pure));
template <typename T>
bool Intersection2D ( const Vector<T, 2>& parSegA1, const Vector<T, 2>& parSegA2, const Vector<T, 2>& parSegB1, const Vector<T, 2>& parSegB2 ) __attribute__((pure));
template <typename T>
std::pair<bool, Vector<T, 2>> Intersection ( const Line<T, 2>& parSegA, const Line<T, 2>& parSegB ) __attribute__((pure));
} //namespace cloonel
#include "geometry_2d.inl"
#endif

88
src/geometry_2d.inl Normal file
View file

@ -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 <http://www.gnu.org/licenses/>.
*/
namespace cloonel {
///--------------------------------------------------------------------------
///--------------------------------------------------------------------------
template <typename T>
int GetOrientation (const Vector<T, 2>& parPointA, const Vector<T, 2>& parPointB, const Vector<T, 2>& 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 <typename T>
bool Intersection2D (const Vector<T, 2>& parSegA1, const Vector<T, 2>& parSegA2, const Vector<T, 2>& parSegB1, const Vector<T, 2>& 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 <typename T>
std::pair<bool, Vector<T, 2>> Intersection (const Line<T, 2>& parSegA, const Line<T, 2>& parSegB) {
typedef Line<T, 2> 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

View file

@ -44,6 +44,7 @@ namespace cloonel {
void MoverSine::ApplyMotion (float parDelta) {
const float pitwo = static_cast<float>(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;
}

View file

@ -116,6 +116,9 @@ namespace cloonel {
typedef Vector<float, 2> float2;
typedef Vector<uint16_t, 2> ushort2;
#if !defined(NDEBUG)
typedef Vector<int16_t, 2> short2;
#endif
typedef Vector<int32_t, 2> int2;
#if !defined(NDEBUG)