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 ::