Back to index

libsfml  1.6+dfsg2
Shape.cpp
Go to the documentation of this file.
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/GraphicsContext.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& Col, const Color& OutlineCol)
00053 {
00054     AddPoint(Vector2f(X, Y), Col, OutlineCol);
00055 }
00056 
00057 
00061 void Shape::AddPoint(const Vector2f& Position, const Color& Col, const Color& OutlineCol)
00062 {
00063     myPoints.push_back(Point(Position, Col, OutlineCol));
00064     myIsCompiled = false;
00065 }
00066 
00067 
00071 unsigned int Shape::GetNbPoints() 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& Col)
00120 {
00121     myPoints[Index + 1].Col = Col;
00122     myIsCompiled = false;
00123 }
00124 
00125 
00129 void Shape::SetPointOutlineColor(unsigned int Index, const Color& OutlineCol)
00130 {
00131     myPoints[Index + 1].OutlineCol = OutlineCol;
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& Col, float Outline, const Color& OutlineCol)
00185 {
00186     Vector2f P1(P1X, P1Y);
00187     Vector2f P2(P2X, P2Y);
00188 
00189     // Compute the extrusion direction
00190     Vector2f Normal;
00191     ComputeNormal(P1, P2, Normal);
00192     Normal *= Thickness / 2;
00193 
00194     // Create the shape's points
00195     Shape S;
00196     S.AddPoint(P1 - Normal, Col, OutlineCol);
00197     S.AddPoint(P2 - Normal, Col, OutlineCol);
00198     S.AddPoint(P2 + Normal, Col, OutlineCol);
00199     S.AddPoint(P1 + Normal, Col, OutlineCol);
00200     S.SetOutlineWidth(Outline);
00201 
00202     // Compile it
00203     S.Compile();
00204 
00205     return S;
00206 }
00207 
00208 
00212 Shape Shape::Line(const Vector2f& P1, const Vector2f& P2, float Thickness, const Color& Col, float Outline, const Color& OutlineCol)
00213 {
00214     return Shape::Line(P1.x, P1.y, P2.x, P2.y, Thickness, Col, Outline, OutlineCol);
00215 }
00216 
00217 
00221 Shape Shape::Rectangle(float P1X, float P1Y, float P2X, float P2Y, const Color& Col, float Outline, const Color& OutlineCol)
00222 {
00223     // Create the shape's points
00224     Shape S;
00225     S.AddPoint(Vector2f(P1X, P1Y), Col, OutlineCol);
00226     S.AddPoint(Vector2f(P2X, P1Y), Col, OutlineCol);
00227     S.AddPoint(Vector2f(P2X, P2Y), Col, OutlineCol);
00228     S.AddPoint(Vector2f(P1X, P2Y), Col, OutlineCol);
00229     S.SetOutlineWidth(Outline);
00230 
00231     // Compile it
00232     S.Compile();
00233 
00234     return S;
00235 }
00236 
00237 
00241 Shape Shape::Rectangle(const Vector2f& P1, const Vector2f& P2, const Color& Col, float Outline, const Color& OutlineCol)
00242 {
00243     return Shape::Rectangle(P1.x, P1.y, P2.x, P2.y, Col, Outline, OutlineCol);
00244 }
00245 
00246 
00250 Shape Shape::Circle(float X, float Y, float Radius, const Color& Col, float Outline, const Color& OutlineCol)
00251 {
00252     static const int NbSegments = 40;
00253 
00254     // Create the points set
00255     Shape S;
00256     Vector2f Center(X, Y);
00257     for (int i = 0; i < NbSegments; ++i)
00258     {
00259         float Angle = i * 2 * 3.141592654f / NbSegments;
00260         Vector2f Offset(cos(Angle), sin(Angle));
00261 
00262         S.AddPoint(Center + Offset * Radius, Col, OutlineCol);
00263     }
00264 
00265     // Compile it
00266     S.SetOutlineWidth(Outline);
00267     S.Compile();
00268 
00269     return S;
00270 }
00271 
00272 
00276 Shape Shape::Circle(const Vector2f& Center, float Radius, const Color& Col, float Outline, const Color& OutlineCol)
00277 {
00278     return Shape::Circle(Center.x, Center.y, Radius, Col, Outline, OutlineCol);
00279 }
00280 
00281 
00285 void Shape::Render(RenderTarget&) const
00286 {
00287     // Make sure the shape has at least 3 points (4 if we count the center)
00288     if (myPoints.size() < 4)
00289         return;
00290 
00291     // Make sure the shape is compiled
00292     if (!myIsCompiled)
00293         const_cast<Shape*>(this)->Compile();
00294 
00295     // Shapes only use color, no texture
00296     GLCheck(glDisable(GL_TEXTURE_2D));
00297 
00298     // Draw the shape
00299     if (myIsFillEnabled)
00300     {
00301         glBegin(GL_TRIANGLE_FAN);
00302         {
00303             for (std::vector<Point>::const_iterator i = myPoints.begin(); i != myPoints.end(); ++i)
00304             {
00305                 Color PointColor = i->Col * GetColor();
00306                 glColor4f(PointColor.r / 255.f, PointColor.g / 255.f, PointColor.b / 255.f, PointColor.a / 255.f);
00307                 glVertex2f(i->Position.x, i->Position.y);
00308             }
00309 
00310             // Close the shape by duplicating the first point at the end
00311             Color PointColor = myPoints[1].Col * GetColor();
00312             glColor4f(PointColor.r / 255.f, PointColor.g / 255.f, PointColor.b / 255.f, PointColor.a / 255.f);
00313             glVertex2f(myPoints[1].Position.x, myPoints[1].Position.y);
00314         }
00315         glEnd();
00316     }
00317 
00318     // Draw the outline
00319     if (myIsOutlineEnabled)
00320     {
00321         glBegin(GL_TRIANGLE_STRIP);
00322         {
00323             for (std::size_t i = 1; i < myPoints.size(); ++i)
00324             {
00325                 Color PointColor = myPoints[i].OutlineCol * GetColor();
00326                 glColor4f(PointColor.r / 255.f, PointColor.g / 255.f, PointColor.b / 255.f, PointColor.a / 255.f);
00327                 glVertex2f(myPoints[i].Position.x, myPoints[i].Position.y);
00328                 glColor4f(PointColor.r / 255.f, PointColor.g / 255.f, PointColor.b / 255.f, PointColor.a / 255.f);
00329                 glVertex2f(myPoints[i].Position.x + myPoints[i].Normal.x * myOutline, myPoints[i].Position.y + myPoints[i].Normal.y * myOutline);
00330             }
00331 
00332             // Close the shape by duplicating the first point at the end
00333             Color PointColor = myPoints[1].OutlineCol * GetColor();
00334             glColor4f(PointColor.r / 255.f, PointColor.g / 255.f, PointColor.b / 255.f, PointColor.a / 255.f);
00335             glVertex2f(myPoints[1].Position.x, myPoints[1].Position.y);
00336             glColor4f(PointColor.r / 255.f, PointColor.g / 255.f, PointColor.b / 255.f, PointColor.a / 255.f);
00337             glVertex2f(myPoints[1].Position.x + myPoints[1].Normal.x * myOutline, myPoints[1].Position.y + myPoints[1].Normal.y * myOutline);
00338         }
00339         glEnd();
00340     }
00341 }
00342 
00343 
00347 void Shape::Compile()
00348 {
00349     // Compute the center
00350     float NbPoints = static_cast<float>(myPoints.size() - 1);
00351     float R = 0, G = 0, B = 0, A = 0;
00352     Point Center(Vector2f(0, 0), Color(0, 0, 0, 0));
00353     for (std::size_t i = 1; i < myPoints.size(); ++i)
00354     {
00355         Center.Position += myPoints[i].Position / NbPoints;
00356         R += myPoints[i].Col.r / NbPoints;
00357         G += myPoints[i].Col.g / NbPoints;
00358         B += myPoints[i].Col.b / NbPoints;
00359         A += myPoints[i].Col.a / NbPoints;
00360     }
00361     Center.Col.r = static_cast<Uint8>(R);
00362     Center.Col.g = static_cast<Uint8>(G);
00363     Center.Col.b = static_cast<Uint8>(B);
00364     Center.Col.a = static_cast<Uint8>(A);
00365     myPoints[0] = Center;
00366 
00367     // Compute the outline
00368     for (std::size_t i = 1; i < myPoints.size(); ++i)
00369     {
00370         // Get the two segments shared by the current point
00371         Point& P0 = (i == 1) ? myPoints[myPoints.size() - 1] : myPoints[i - 1];
00372         Point& P1 = myPoints[i];
00373         Point& P2 = (i == myPoints.size() - 1) ? myPoints[1] : myPoints[i + 1];
00374 
00375         // Compute their normal
00376         Vector2f Normal1, Normal2;
00377         if (!ComputeNormal(P0.Position, P1.Position, Normal1) || !ComputeNormal(P1.Position, P2.Position, Normal2))
00378             continue;
00379 
00380         // Add them to get the extrusion direction
00381         float Factor = 1.f + (Normal1.x * Normal2.x + Normal1.y * Normal2.y);
00382         P1.Normal = (Normal1 + Normal2) / Factor;
00383 
00384         // Make sure it points towards the outside of the shape
00385         float Dot = (P1.Position.x - Center.Position.x) * P1.Normal.x + (P1.Position.y - Center.Position.y) * P1.Normal.y;
00386         if (Dot < 0)
00387             P1.Normal = -P1.Normal;
00388     }
00389 
00390     myIsCompiled = true;
00391 }
00392 
00393 
00397 bool Shape::ComputeNormal(const Vector2f& P1, const Vector2f& P2, Vector2f& Normal)
00398 {
00399     Normal.x = P1.y - P2.y;
00400     Normal.y = P2.x - P1.x;
00401 
00402     float Len = sqrt(Normal.x * Normal.x + Normal.y * Normal.y);
00403     if (Len == 0.f)
00404         return false;
00405 
00406     Normal.x /= Len;
00407     Normal.y /= Len;
00408 
00409     return true;
00410 }
00411 
00412 
00416 Shape::Point::Point(const Vector2f& Pos, const Color& C, const Color& OutlineC) :
00417 Position  (Pos),
00418 Normal    (0.f, 0.f),
00419 Col       (C),
00420 OutlineCol(OutlineC)
00421 {
00422 
00423 }
00424 
00425 } // namespace sf