SFML logo
  • Main Page
  • Namespaces
  • Classes
  • Files
  • File List

Shape.cpp

00001 
00002 //
00003 // SFML - Simple and Fast Multimedia Library
00004 // Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
00005 //
00006 // This software is provided 'as-is', without any express or implied warranty.
00007 // In no event will the authors be held liable for any damages arising from the use of this software.
00008 //
00009 // Permission is granted to anyone to use this software for any purpose,
00010 // including commercial applications, and to alter it and redistribute it freely,
00011 // subject to the following restrictions:
00012 //
00013 // 1. The origin of this software must not be misrepresented;
00014 //    you must not claim that you wrote the original software.
00015 //    If you use this software in a product, an acknowledgment
00016 //    in the product documentation would be appreciated but is not required.
00017 //
00018 // 2. Altered source versions must be plainly marked as such,
00019 //    and must not be misrepresented as being the original software.
00020 //
00021 // 3. This notice may not be removed or altered from any source distribution.
00022 //
00024 
00026 // Headers
00028 #include <SFML/Graphics/Shape.hpp>
00029 #include <SFML/Graphics/Renderer.hpp>
00030 #include <math.h>
00031 
00032 
00033 namespace sf
00034 {
00038 Shape::Shape() :
00039 myOutline         (0.f),
00040 myIsFillEnabled   (true),
00041 myIsOutlineEnabled(true),
00042 myIsCompiled      (false)
00043 {
00044     // Put a placeholder for the center of the shape
00045     myPoints.push_back(Point());
00046 }
00047 
00048 
00052 void Shape::AddPoint(float x, float y, const Color& color, const Color& outlineColor)
00053 {
00054     AddPoint(Vector2f(x, y), color, outlineColor);
00055 }
00056 
00057 
00061 void Shape::AddPoint(const Vector2f& position, const Color& color, const Color& outlineColor)
00062 {
00063     myPoints.push_back(Point(position, color, outlineColor));
00064     myIsCompiled = false;
00065 }
00066 
00067 
00071 unsigned int Shape::GetPointsCount() const
00072 {
00073     return static_cast<unsigned int>(myPoints.size() - 1);
00074 }
00075 
00076 
00081 void Shape::EnableFill(bool enable)
00082 {
00083     myIsFillEnabled = enable;
00084 }
00085 
00086 
00091 void Shape::EnableOutline(bool enable)
00092 {
00093     myIsOutlineEnabled = enable;
00094 }
00095 
00096 
00100 void Shape::SetPointPosition(unsigned int index, const Vector2f& position)
00101 {
00102     myPoints[index + 1].Position = position;
00103     myIsCompiled = false;
00104 }
00105 
00106 
00110 void Shape::SetPointPosition(unsigned int index, float x, float y)
00111 {
00112     SetPointPosition(index, Vector2f(x, y));
00113 }
00114 
00115 
00119 void Shape::SetPointColor(unsigned int index, const Color& color)
00120 {
00121     myPoints[index + 1].Col = color;
00122     myIsCompiled = false;
00123 }
00124 
00125 
00129 void Shape::SetPointOutlineColor(unsigned int index, const Color& outlineColor)
00130 {
00131     myPoints[index + 1].OutlineCol = outlineColor;
00132     myIsCompiled = false;
00133 }
00134 
00135 
00139 void Shape::SetOutlineWidth(float width)
00140 {
00141     myOutline = width;
00142 }
00143 
00144 
00148 const Vector2f& Shape::GetPointPosition(unsigned int index) const
00149 {
00150     return myPoints[index + 1].Position;
00151 }
00152 
00153 
00157 const Color& Shape::GetPointColor(unsigned int index) const
00158 {
00159     return myPoints[index + 1].Col;
00160 }
00161 
00162 
00166 const Color& Shape::GetPointOutlineColor(unsigned int index) const
00167 {
00168     return myPoints[index + 1].OutlineCol;
00169 }
00170 
00171 
00175 float Shape::GetOutlineWidth() const
00176 {
00177     return myOutline;
00178 }
00179 
00180 
00184 Shape Shape::Line(float p1x, float p1y, float p2x, float p2y, float thickness, const Color& color, float outline, const Color& outlineColor)
00185 {
00186     Vector2f p1(p1x, p1y);
00187     Vector2f p2(p2x, p2y);
00188 
00189     return Shape::Line(p1, p2, thickness, color, outline, outlineColor);
00190 }
00191 
00192 
00196 Shape Shape::Line(const Vector2f& p1, const Vector2f& p2, float thickness, const Color& color, float outline, const Color& outlineColor)
00197 {
00198     // Compute the extrusion direction
00199     Vector2f normal;
00200     ComputeNormal(p1, p2, normal);
00201     normal *= thickness / 2;
00202 
00203     // Create the shape's points
00204     Shape shape;
00205     shape.AddPoint(p1 - normal, color, outlineColor);
00206     shape.AddPoint(p2 - normal, color, outlineColor);
00207     shape.AddPoint(p2 + normal, color, outlineColor);
00208     shape.AddPoint(p1 + normal, color, outlineColor);
00209     shape.SetOutlineWidth(outline);
00210 
00211     // Compile it
00212     shape.Compile();
00213 
00214     return shape;
00215 }
00216 
00217 
00221 Shape Shape::Rectangle(float p1x, float p1y, float p2x, float p2y, const Color& color, float outline, const Color& outlineColor)
00222 {
00223     // Create the shape's points
00224     Shape shape;
00225     shape.AddPoint(Vector2f(p1x, p1y), color, outlineColor);
00226     shape.AddPoint(Vector2f(p2x, p1y), color, outlineColor);
00227     shape.AddPoint(Vector2f(p2x, p2y), color, outlineColor);
00228     shape.AddPoint(Vector2f(p1x, p2y), color, outlineColor);
00229     shape.SetOutlineWidth(outline);
00230 
00231     // Compile it
00232     shape.Compile();
00233 
00234     return shape;
00235 }
00236 
00237 
00241 Shape Shape::Rectangle(const Vector2f& p1, const Vector2f& p2, const Color& color, float outline, const Color& outlineColor)
00242 {
00243     return Shape::Rectangle(p1.x, p1.y, p2.x, p2.y, color, outline, outlineColor);
00244 }
00245 
00246 
00250 Shape Shape::Circle(float x, float y, float radius, const Color& color, float outline, const Color& outlineColor)
00251 {
00252     return Shape::Circle(Vector2f(x, y), radius, color, outline, outlineColor);
00253 }
00254 
00255 
00259 Shape Shape::Circle(const Vector2f& center, float radius, const Color& color, float outline, const Color& outlineColor)
00260 {
00261     static const int nbSegments = 40;
00262 
00263     // Create the points set
00264     Shape shape;
00265     for (int i = 0; i < nbSegments; ++i)
00266     {
00267         float angle = i * 2 * 3.141592654f / nbSegments;
00268         Vector2f offset(cos(angle), sin(angle));
00269 
00270         shape.AddPoint(center + offset * radius, color, outlineColor);
00271     }
00272 
00273     // Compile it
00274     shape.SetOutlineWidth(outline);
00275     shape.Compile();
00276 
00277     return shape;
00278 }
00279 
00280 
00284 void Shape::Render(RenderTarget&, Renderer& renderer) const
00285 {
00286     // Make sure the shape has at least 3 points (4 if we count the center)
00287     if (myPoints.size() < 4)
00288         return;
00289 
00290     // Make sure the shape is compiled
00291     if (!myIsCompiled)
00292         const_cast<Shape*>(this)->Compile();
00293 
00294     // Shapes only use color, no texture
00295     renderer.SetTexture(NULL);
00296 
00297     // Draw the shape
00298     if (myIsFillEnabled)
00299     {
00300         if (myPoints.size() == 4)
00301         {
00302             // Special case of a triangle
00303             renderer.Begin(Renderer::TriangleList);
00304                 renderer.AddVertex(myPoints[1].Position.x, myPoints[1].Position.y, myPoints[1].Col);
00305                 renderer.AddVertex(myPoints[2].Position.x, myPoints[2].Position.y, myPoints[2].Col);
00306                 renderer.AddVertex(myPoints[3].Position.x, myPoints[3].Position.y, myPoints[3].Col);
00307             renderer.End();
00308         }
00309         else if (myPoints.size() == 5)
00310         {
00311             // Special case of a quad
00312             renderer.Begin(Renderer::TriangleStrip);
00313                 renderer.AddVertex(myPoints[1].Position.x, myPoints[1].Position.y, myPoints[1].Col);
00314                 renderer.AddVertex(myPoints[2].Position.x, myPoints[2].Position.y, myPoints[2].Col);
00315                 renderer.AddVertex(myPoints[4].Position.x, myPoints[4].Position.y, myPoints[4].Col);
00316                 renderer.AddVertex(myPoints[3].Position.x, myPoints[3].Position.y, myPoints[3].Col);
00317             renderer.End();
00318         }
00319         else
00320         {
00321             renderer.Begin(Renderer::TriangleFan);
00322 
00323             // General case of a convex polygon
00324             for (std::vector<Point>::const_iterator i = myPoints.begin(); i != myPoints.end(); ++i)
00325                 renderer.AddVertex(i->Position.x, i->Position.y, i->Col);
00326 
00327             // Close the shape by duplicating the first point at the end
00328             const Point& first = myPoints[1];
00329             renderer.AddVertex(first.Position.x, first.Position.y, first.Col);
00330 
00331             renderer.End();
00332         }
00333     }
00334 
00335     // Draw the outline
00336     if (myIsOutlineEnabled && (myOutline != 0))
00337     {
00338         renderer.Begin(Renderer::TriangleStrip);
00339 
00340         for (std::vector<Point>::const_iterator i = myPoints.begin() + 1; i != myPoints.end(); ++i)
00341         {
00342             Vector2f point1 = i->Position;
00343             Vector2f point2 = i->Position + i->Normal * myOutline;
00344             renderer.AddVertex(point1.x, point1.y, i->OutlineCol);
00345             renderer.AddVertex(point2.x, point2.y, i->OutlineCol);
00346         }
00347 
00348         // Close the shape by duplicating the first point at the end
00349         const Point& first = myPoints[1];
00350         Vector2f point1 = first.Position;
00351         Vector2f point2 = first.Position + first.Normal * myOutline;
00352         renderer.AddVertex(point1.x, point1.y, first.OutlineCol);
00353         renderer.AddVertex(point2.x, point2.y, first.OutlineCol);
00354 
00355         renderer.End();
00356     }
00357 }
00358 
00359 
00363 void Shape::Compile()
00364 {
00365     // Compute the center
00366     float nbPoints = static_cast<float>(myPoints.size() - 1);
00367     float r = 0, g = 0, b = 0, a = 0;
00368     Point center(Vector2f(0, 0), Color(0, 0, 0, 0));
00369     for (std::size_t i = 1; i < myPoints.size(); ++i)
00370     {
00371         center.Position += myPoints[i].Position;
00372         r += myPoints[i].Col.r;
00373         g += myPoints[i].Col.g;
00374         b += myPoints[i].Col.b;
00375         a += myPoints[i].Col.a;
00376     }
00377     center.Position /= nbPoints;
00378     center.Col.r = static_cast<Uint8>(r / nbPoints);
00379     center.Col.g = static_cast<Uint8>(g / nbPoints);
00380     center.Col.b = static_cast<Uint8>(b / nbPoints);
00381     center.Col.a = static_cast<Uint8>(a / nbPoints);
00382     myPoints[0] = center;
00383 
00384     // Compute the outline
00385     for (std::size_t i = 1; i < myPoints.size(); ++i)
00386     {
00387         // Get the two segments shared by the current point
00388         Point& p0 = (i == 1) ? myPoints[myPoints.size() - 1] : myPoints[i - 1];
00389         Point& p1 = myPoints[i];
00390         Point& p2 = (i == myPoints.size() - 1) ? myPoints[1] : myPoints[i + 1];
00391 
00392         // Compute their normal
00393         Vector2f normal1, normal2;
00394         if (!ComputeNormal(p0.Position, p1.Position, normal1) || !ComputeNormal(p1.Position, p2.Position, normal2))
00395             continue;
00396 
00397         // Add them to get the extrusion direction
00398         float factor = 1.f + (normal1.x * normal2.x + normal1.y * normal2.y);
00399         p1.Normal = (normal1 + normal2) / factor;
00400 
00401         // Make sure it points towards the outside of the shape
00402         float dot = (p1.Position.x - center.Position.x) * p1.Normal.x + (p1.Position.y - center.Position.y) * p1.Normal.y;
00403         if (dot < 0)
00404             p1.Normal = -p1.Normal;
00405     }
00406 
00407     myIsCompiled = true;
00408 }
00409 
00410 
00414 bool Shape::ComputeNormal(const Vector2f& p1, const Vector2f& p2, Vector2f& normal)
00415 {
00416     normal.x = p1.y - p2.y;
00417     normal.y = p2.x - p1.x;
00418 
00419     float len = sqrt(normal.x * normal.x + normal.y * normal.y);
00420     if (len == 0.f)
00421         return false;
00422 
00423     normal.x /= len;
00424     normal.y /= len;
00425 
00426     return true;
00427 }
00428 
00429 
00433 Shape::Point::Point(const Vector2f& position, const Color& color, const Color& outlineColor) :
00434 Position  (position),
00435 Normal    (0.f, 0.f),
00436 Col       (color),
00437 OutlineCol(outlineColor)
00438 {
00439 
00440 }
00441 
00442 } // namespace sf

 ::  Copyright © 2007-2008 Laurent Gomila, all rights reserved  ::  Documentation generated by doxygen 1.5.2  ::