Implement Shape rendering and Transform math for SDL2 backend
Shape rendering now works: - Shape::draw() generates triangle vertices for fill and outline - RectangleShape, CircleShape, ConvexShape provide getPointCount()/getPoint() - Shapes render with correct fill color, outline color, and outline thickness Transform class fully implemented: - translate(), rotate(), scale() modify the 3x3 affine matrix - transformPoint() applies transform to Vector2f - operator* combines transforms - getInverse() computes inverse transform Transformable::getTransform() now computes proper transform from: - position, rotation, scale, and origin RenderStates now has transform, blendMode, shader members Canvas sizing fixed for Emscripten: - EM_ASM sets canvas size after SDL window creation - SDL_GL_MakeCurrent called after canvas resize Result: RectangleShape UI elements render in correct positions! Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c5cc022aa2
commit
a702d3cab4
2 changed files with 303 additions and 26 deletions
|
|
@ -370,9 +370,16 @@ void SDL2Renderer::setProjection(float left, float right, float bottom, float to
|
||||||
projectionMatrix_[15] = 1.0f;
|
projectionMatrix_[15] = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int clearCount = 0;
|
||||||
void SDL2Renderer::clear(float r, float g, float b, float a) {
|
void SDL2Renderer::clear(float r, float g, float b, float a) {
|
||||||
glClearColor(r, g, b, a);
|
glClearColor(r, g, b, a);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
// Debug: Log first few clears to confirm render loop is running
|
||||||
|
if (clearCount < 5) {
|
||||||
|
std::cout << "SDL2Renderer::clear(" << r << ", " << g << ", " << b << ", " << a << ") #" << clearCount << std::endl;
|
||||||
|
clearCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDL2Renderer::drawTriangles(const float* vertices, size_t vertexCount,
|
void SDL2Renderer::drawTriangles(const float* vertices, size_t vertexCount,
|
||||||
|
|
@ -461,9 +468,14 @@ void RenderWindow::create(VideoMode mode, const std::string& title, uint32_t sty
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
// For Emscripten, we need to set the canvas size explicitly
|
// For Emscripten, tell SDL2 which canvas element to use
|
||||||
// The canvas element with id="canvas" is used by default
|
// SDL_HINT_EMSCRIPTEN_CANVAS_SELECTOR = "SDL_EMSCRIPTEN_CANVAS_SELECTOR"
|
||||||
|
SDL_SetHint("SDL_EMSCRIPTEN_CANVAS_SELECTOR", "#canvas");
|
||||||
|
|
||||||
|
// Set the canvas size explicitly before creating the window
|
||||||
emscripten_set_canvas_element_size("#canvas", mode.width, mode.height);
|
emscripten_set_canvas_element_size("#canvas", mode.width, mode.height);
|
||||||
|
|
||||||
|
std::cout << "Emscripten: Setting canvas to " << mode.width << "x" << mode.height << std::endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create window
|
// Create window
|
||||||
|
|
@ -493,6 +505,28 @@ void RenderWindow::create(VideoMode mode, const std::string& title, uint32_t sty
|
||||||
title_ = title;
|
title_ = title;
|
||||||
open_ = true;
|
open_ = true;
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
// Force canvas size AFTER SDL window creation (SDL may have reset it)
|
||||||
|
emscripten_set_canvas_element_size("#canvas", mode.width, mode.height);
|
||||||
|
|
||||||
|
// Also set the CSS size to match
|
||||||
|
EM_ASM({
|
||||||
|
var canvas = document.getElementById('canvas');
|
||||||
|
if (canvas) {
|
||||||
|
canvas.width = $0;
|
||||||
|
canvas.height = $1;
|
||||||
|
canvas.style.width = $0 + 'px';
|
||||||
|
canvas.style.height = $1 + 'px';
|
||||||
|
console.log('EM_ASM: Set canvas to ' + $0 + 'x' + $1);
|
||||||
|
} else {
|
||||||
|
console.error('EM_ASM: Canvas element not found!');
|
||||||
|
}
|
||||||
|
}, mode.width, mode.height);
|
||||||
|
|
||||||
|
// Re-make context current after canvas resize
|
||||||
|
SDL_GL_MakeCurrent(window, context);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Initialize OpenGL resources now that we have a context
|
// Initialize OpenGL resources now that we have a context
|
||||||
if (!SDL2Renderer::getInstance().initGL()) {
|
if (!SDL2Renderer::getInstance().initGL()) {
|
||||||
std::cerr << "RenderWindow: Failed to initialize OpenGL resources" << std::endl;
|
std::cerr << "RenderWindow: Failed to initialize OpenGL resources" << std::endl;
|
||||||
|
|
@ -504,6 +538,13 @@ void RenderWindow::create(VideoMode mode, const std::string& title, uint32_t sty
|
||||||
|
|
||||||
// Set up OpenGL state
|
// Set up OpenGL state
|
||||||
glViewport(0, 0, mode.width, mode.height);
|
glViewport(0, 0, mode.width, mode.height);
|
||||||
|
std::cout << "GL viewport set to " << mode.width << "x" << mode.height << std::endl;
|
||||||
|
|
||||||
|
GLenum err = glGetError();
|
||||||
|
if (err != GL_NO_ERROR) {
|
||||||
|
std::cerr << "GL error after viewport: " << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
SDL2Renderer::getInstance().setProjection(0, mode.width, mode.height, 0);
|
SDL2Renderer::getInstance().setProjection(0, mode.width, mode.height, 0);
|
||||||
|
|
||||||
// Enable blending for transparency
|
// Enable blending for transparency
|
||||||
|
|
@ -513,9 +554,21 @@ void RenderWindow::create(VideoMode mode, const std::string& title, uint32_t sty
|
||||||
// Initial clear to a visible color to confirm GL is working
|
// Initial clear to a visible color to confirm GL is working
|
||||||
glClearColor(0.2f, 0.3f, 0.4f, 1.0f); // Blue-gray
|
glClearColor(0.2f, 0.3f, 0.4f, 1.0f); // Blue-gray
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
err = glGetError();
|
||||||
|
if (err != GL_NO_ERROR) {
|
||||||
|
std::cerr << "GL error after clear: " << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
|
|
||||||
|
err = glGetError();
|
||||||
|
if (err != GL_NO_ERROR) {
|
||||||
|
std::cerr << "GL error after swap: " << err << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
std::cout << "RenderWindow: Created " << mode.width << "x" << mode.height << " window" << std::endl;
|
std::cout << "RenderWindow: Created " << mode.width << "x" << mode.height << " window" << std::endl;
|
||||||
|
std::cout << "WebGL context should now show blue-gray" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWindow::close() {
|
void RenderWindow::close() {
|
||||||
|
|
@ -1118,7 +1171,125 @@ bool Font::loadFromMemory(const void* data, size_t sizeInBytes) {
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
void Shape::draw(RenderTarget& target, RenderStates states) const {
|
void Shape::draw(RenderTarget& target, RenderStates states) const {
|
||||||
// TODO: Generate vertices and draw using SDL2Renderer
|
size_t pointCount = getPointCount();
|
||||||
|
if (pointCount < 3) return;
|
||||||
|
|
||||||
|
// Get the combined transform
|
||||||
|
Transform combinedTransform = states.transform * getTransform();
|
||||||
|
|
||||||
|
// Build vertex data for fill (triangle fan from center)
|
||||||
|
std::vector<float> vertices;
|
||||||
|
std::vector<float> colors;
|
||||||
|
|
||||||
|
// Calculate center point
|
||||||
|
Vector2f center(0, 0);
|
||||||
|
for (size_t i = 0; i < pointCount; ++i) {
|
||||||
|
center.x += getPoint(i).x;
|
||||||
|
center.y += getPoint(i).y;
|
||||||
|
}
|
||||||
|
center.x /= pointCount;
|
||||||
|
center.y /= pointCount;
|
||||||
|
|
||||||
|
// Transform center
|
||||||
|
Vector2f transformedCenter = combinedTransform.transformPoint(center);
|
||||||
|
|
||||||
|
// Build triangles (fan from center)
|
||||||
|
Color fill = getFillColor();
|
||||||
|
float fr = fill.r / 255.0f;
|
||||||
|
float fg = fill.g / 255.0f;
|
||||||
|
float fb = fill.b / 255.0f;
|
||||||
|
float fa = fill.a / 255.0f;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pointCount; ++i) {
|
||||||
|
size_t next = (i + 1) % pointCount;
|
||||||
|
|
||||||
|
Vector2f p1 = combinedTransform.transformPoint(getPoint(i));
|
||||||
|
Vector2f p2 = combinedTransform.transformPoint(getPoint(next));
|
||||||
|
|
||||||
|
// Triangle: center, p1, p2
|
||||||
|
vertices.push_back(transformedCenter.x);
|
||||||
|
vertices.push_back(transformedCenter.y);
|
||||||
|
vertices.push_back(p1.x);
|
||||||
|
vertices.push_back(p1.y);
|
||||||
|
vertices.push_back(p2.x);
|
||||||
|
vertices.push_back(p2.y);
|
||||||
|
|
||||||
|
// Colors for each vertex
|
||||||
|
for (int v = 0; v < 3; ++v) {
|
||||||
|
colors.push_back(fr);
|
||||||
|
colors.push_back(fg);
|
||||||
|
colors.push_back(fb);
|
||||||
|
colors.push_back(fa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw fill
|
||||||
|
if (fill.a > 0 && !vertices.empty()) {
|
||||||
|
SDL2Renderer::getInstance().drawTriangles(
|
||||||
|
vertices.data(), vertices.size() / 2,
|
||||||
|
colors.data(), nullptr, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw outline if thickness > 0
|
||||||
|
float outlineThickness = getOutlineThickness();
|
||||||
|
if (outlineThickness > 0) {
|
||||||
|
Color outline = getOutlineColor();
|
||||||
|
if (outline.a > 0) {
|
||||||
|
float or_ = outline.r / 255.0f;
|
||||||
|
float og = outline.g / 255.0f;
|
||||||
|
float ob = outline.b / 255.0f;
|
||||||
|
float oa = outline.a / 255.0f;
|
||||||
|
|
||||||
|
// Build outline as quads (two triangles per edge)
|
||||||
|
vertices.clear();
|
||||||
|
colors.clear();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pointCount; ++i) {
|
||||||
|
size_t next = (i + 1) % pointCount;
|
||||||
|
|
||||||
|
Vector2f p1 = combinedTransform.transformPoint(getPoint(i));
|
||||||
|
Vector2f p2 = combinedTransform.transformPoint(getPoint(next));
|
||||||
|
|
||||||
|
// Calculate normal direction
|
||||||
|
Vector2f dir(p2.x - p1.x, p2.y - p1.y);
|
||||||
|
float len = std::sqrt(dir.x * dir.x + dir.y * dir.y);
|
||||||
|
if (len > 0) {
|
||||||
|
dir.x /= len;
|
||||||
|
dir.y /= len;
|
||||||
|
}
|
||||||
|
Vector2f normal(-dir.y * outlineThickness, dir.x * outlineThickness);
|
||||||
|
|
||||||
|
// Outer points
|
||||||
|
Vector2f p1o(p1.x + normal.x, p1.y + normal.y);
|
||||||
|
Vector2f p2o(p2.x + normal.x, p2.y + normal.y);
|
||||||
|
|
||||||
|
// Two triangles for quad
|
||||||
|
// Triangle 1: p1, p2, p1o
|
||||||
|
vertices.push_back(p1.x); vertices.push_back(p1.y);
|
||||||
|
vertices.push_back(p2.x); vertices.push_back(p2.y);
|
||||||
|
vertices.push_back(p1o.x); vertices.push_back(p1o.y);
|
||||||
|
// Triangle 2: p2, p2o, p1o
|
||||||
|
vertices.push_back(p2.x); vertices.push_back(p2.y);
|
||||||
|
vertices.push_back(p2o.x); vertices.push_back(p2o.y);
|
||||||
|
vertices.push_back(p1o.x); vertices.push_back(p1o.y);
|
||||||
|
|
||||||
|
for (int v = 0; v < 6; ++v) {
|
||||||
|
colors.push_back(or_);
|
||||||
|
colors.push_back(og);
|
||||||
|
colors.push_back(ob);
|
||||||
|
colors.push_back(oa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vertices.empty()) {
|
||||||
|
SDL2Renderer::getInstance().drawTriangles(
|
||||||
|
vertices.data(), vertices.size() / 2,
|
||||||
|
colors.data(), nullptr, 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexArray::draw(RenderTarget& target, RenderStates states) const {
|
void VertexArray::draw(RenderTarget& target, RenderStates states) const {
|
||||||
|
|
|
||||||
|
|
@ -216,29 +216,101 @@ public:
|
||||||
// For now, stub implementation matching headless
|
// For now, stub implementation matching headless
|
||||||
|
|
||||||
class Transform {
|
class Transform {
|
||||||
// 3x3 matrix stored as 4x4 for OpenGL compatibility
|
// 3x3 matrix stored as column-major for OpenGL
|
||||||
// [ m00 m01 m02 ] [ m[0] m[4] m[12] ]
|
// [ a c tx ] [ m[0] m[3] m[6] ]
|
||||||
// [ m10 m11 m12 ] -> [ m[1] m[5] m[13] ]
|
// [ b d ty ] -> [ m[1] m[4] m[7] ]
|
||||||
// [ 0 0 1 ] [ 0 0 1 ]
|
// [ 0 0 1 ] [ m[2] m[5] m[8] ]
|
||||||
float m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
|
float m[9] = {1,0,0, 0,1,0, 0,0,1};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Transform() = default;
|
Transform() = default;
|
||||||
Transform& translate(float x, float y) { return *this; } // TODO: Implement
|
|
||||||
|
Transform& translate(float x, float y) {
|
||||||
|
// Combine with translation matrix
|
||||||
|
m[6] += m[0] * x + m[3] * y;
|
||||||
|
m[7] += m[1] * x + m[4] * y;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
Transform& translate(const Vector2f& offset) { return translate(offset.x, offset.y); }
|
Transform& translate(const Vector2f& offset) { return translate(offset.x, offset.y); }
|
||||||
Transform& rotate(float angle) { return *this; } // TODO: Implement
|
|
||||||
Transform& rotate(float angle, const Vector2f& center) { return *this; } // TODO: Implement
|
Transform& rotate(float angle) {
|
||||||
Transform& scale(float factorX, float factorY) { return *this; } // TODO: Implement
|
float rad = angle * 3.14159265f / 180.0f;
|
||||||
|
float cos_a = std::cos(rad);
|
||||||
|
float sin_a = std::sin(rad);
|
||||||
|
|
||||||
|
float new_m0 = m[0] * cos_a + m[3] * sin_a;
|
||||||
|
float new_m1 = m[1] * cos_a + m[4] * sin_a;
|
||||||
|
float new_m3 = m[0] * -sin_a + m[3] * cos_a;
|
||||||
|
float new_m4 = m[1] * -sin_a + m[4] * cos_a;
|
||||||
|
|
||||||
|
m[0] = new_m0; m[1] = new_m1;
|
||||||
|
m[3] = new_m3; m[4] = new_m4;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
Transform& rotate(float angle, const Vector2f& center) {
|
||||||
|
translate(center.x, center.y);
|
||||||
|
rotate(angle);
|
||||||
|
translate(-center.x, -center.y);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform& scale(float factorX, float factorY) {
|
||||||
|
m[0] *= factorX; m[1] *= factorX;
|
||||||
|
m[3] *= factorY; m[4] *= factorY;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
Transform& scale(const Vector2f& factors) { return scale(factors.x, factors.y); }
|
Transform& scale(const Vector2f& factors) { return scale(factors.x, factors.y); }
|
||||||
|
|
||||||
Vector2f transformPoint(float x, float y) const { return Vector2f(x, y); } // TODO: Implement
|
Vector2f transformPoint(float x, float y) const {
|
||||||
Vector2f transformPoint(const Vector2f& point) const { return point; }
|
return Vector2f(m[0] * x + m[3] * y + m[6],
|
||||||
FloatRect transformRect(const FloatRect& rect) const { return rect; } // TODO: Implement
|
m[1] * x + m[4] * y + m[7]);
|
||||||
|
}
|
||||||
|
Vector2f transformPoint(const Vector2f& point) const {
|
||||||
|
return transformPoint(point.x, point.y);
|
||||||
|
}
|
||||||
|
|
||||||
Transform getInverse() const { return Transform(); } // TODO: Implement
|
FloatRect transformRect(const FloatRect& rect) const {
|
||||||
|
// Transform all four corners and compute bounding box
|
||||||
|
Vector2f p1 = transformPoint(rect.left, rect.top);
|
||||||
|
Vector2f p2 = transformPoint(rect.left + rect.width, rect.top);
|
||||||
|
Vector2f p3 = transformPoint(rect.left, rect.top + rect.height);
|
||||||
|
Vector2f p4 = transformPoint(rect.left + rect.width, rect.top + rect.height);
|
||||||
|
|
||||||
Transform operator*(const Transform& rhs) const { return Transform(); } // TODO: Implement
|
float minX = std::min({p1.x, p2.x, p3.x, p4.x});
|
||||||
Vector2f operator*(const Vector2f& point) const { return point; }
|
float maxX = std::max({p1.x, p2.x, p3.x, p4.x});
|
||||||
|
float minY = std::min({p1.y, p2.y, p3.y, p4.y});
|
||||||
|
float maxY = std::max({p1.y, p2.y, p3.y, p4.y});
|
||||||
|
|
||||||
|
return FloatRect(minX, minY, maxX - minX, maxY - minY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform getInverse() const {
|
||||||
|
// Compute inverse of 3x3 affine matrix
|
||||||
|
float det = m[0] * m[4] - m[1] * m[3];
|
||||||
|
if (std::abs(det) < 1e-7f) return Transform();
|
||||||
|
|
||||||
|
float invDet = 1.0f / det;
|
||||||
|
Transform inv;
|
||||||
|
inv.m[0] = m[4] * invDet;
|
||||||
|
inv.m[1] = -m[1] * invDet;
|
||||||
|
inv.m[3] = -m[3] * invDet;
|
||||||
|
inv.m[4] = m[0] * invDet;
|
||||||
|
inv.m[6] = (m[3] * m[7] - m[4] * m[6]) * invDet;
|
||||||
|
inv.m[7] = (m[1] * m[6] - m[0] * m[7]) * invDet;
|
||||||
|
return inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform operator*(const Transform& rhs) const {
|
||||||
|
Transform result;
|
||||||
|
result.m[0] = m[0] * rhs.m[0] + m[3] * rhs.m[1];
|
||||||
|
result.m[1] = m[1] * rhs.m[0] + m[4] * rhs.m[1];
|
||||||
|
result.m[3] = m[0] * rhs.m[3] + m[3] * rhs.m[4];
|
||||||
|
result.m[4] = m[1] * rhs.m[3] + m[4] * rhs.m[4];
|
||||||
|
result.m[6] = m[0] * rhs.m[6] + m[3] * rhs.m[7] + m[6];
|
||||||
|
result.m[7] = m[1] * rhs.m[6] + m[4] * rhs.m[7] + m[7];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Vector2f operator*(const Vector2f& point) const { return transformPoint(point); }
|
||||||
|
|
||||||
static const Transform Identity;
|
static const Transform Identity;
|
||||||
|
|
||||||
|
|
@ -331,10 +403,14 @@ class Shader;
|
||||||
|
|
||||||
class RenderStates {
|
class RenderStates {
|
||||||
public:
|
public:
|
||||||
|
Transform transform;
|
||||||
|
BlendMode blendMode;
|
||||||
|
const Shader* shader = nullptr;
|
||||||
|
|
||||||
RenderStates() = default;
|
RenderStates() = default;
|
||||||
RenderStates(const Transform& transform) {} // Implicit conversion from Transform
|
RenderStates(const Transform& t) : transform(t) {}
|
||||||
RenderStates(const BlendMode& mode) {}
|
RenderStates(const BlendMode& mode) : blendMode(mode) {}
|
||||||
RenderStates(const Shader* shader) {} // Implicit conversion from Shader pointer
|
RenderStates(const Shader* s) : shader(s) {}
|
||||||
static const RenderStates Default;
|
static const RenderStates Default;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -386,8 +462,18 @@ public:
|
||||||
void scale(float factorX, float factorY) { scale_.x *= factorX; scale_.y *= factorY; }
|
void scale(float factorX, float factorY) { scale_.x *= factorX; scale_.y *= factorY; }
|
||||||
void scale(const Vector2f& factor) { scale_.x *= factor.x; scale_.y *= factor.y; }
|
void scale(const Vector2f& factor) { scale_.x *= factor.x; scale_.y *= factor.y; }
|
||||||
|
|
||||||
Transform getTransform() const { return Transform::Identity; } // TODO: Implement
|
Transform getTransform() const {
|
||||||
Transform getInverseTransform() const { return Transform::Identity; } // TODO: Implement
|
Transform transform;
|
||||||
|
// Apply transformations: translate to position, rotate, scale, translate by -origin
|
||||||
|
transform.translate(position_.x, position_.y);
|
||||||
|
transform.rotate(rotation_);
|
||||||
|
transform.scale(scale_.x, scale_.y);
|
||||||
|
transform.translate(-origin_.x, -origin_.y);
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
Transform getInverseTransform() const {
|
||||||
|
return getTransform().getInverse();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -411,6 +497,10 @@ public:
|
||||||
virtual FloatRect getLocalBounds() const { return FloatRect(); }
|
virtual FloatRect getLocalBounds() const { return FloatRect(); }
|
||||||
virtual FloatRect getGlobalBounds() const { return FloatRect(); }
|
virtual FloatRect getGlobalBounds() const { return FloatRect(); }
|
||||||
|
|
||||||
|
// Virtual methods for shape points (implemented by derived classes)
|
||||||
|
virtual size_t getPointCount() const = 0;
|
||||||
|
virtual Vector2f getPoint(size_t index) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void draw(RenderTarget& target, RenderStates states) const override; // Implemented in SDL2Renderer.cpp
|
void draw(RenderTarget& target, RenderStates states) const override; // Implemented in SDL2Renderer.cpp
|
||||||
};
|
};
|
||||||
|
|
@ -423,6 +513,17 @@ public:
|
||||||
const Vector2f& getSize() const { return size_; }
|
const Vector2f& getSize() const { return size_; }
|
||||||
FloatRect getLocalBounds() const override { return FloatRect(0, 0, size_.x, size_.y); }
|
FloatRect getLocalBounds() const override { return FloatRect(0, 0, size_.x, size_.y); }
|
||||||
FloatRect getGlobalBounds() const override { return FloatRect(position_.x, position_.y, size_.x, size_.y); }
|
FloatRect getGlobalBounds() const override { return FloatRect(position_.x, position_.y, size_.x, size_.y); }
|
||||||
|
|
||||||
|
size_t getPointCount() const override { return 4; }
|
||||||
|
Vector2f getPoint(size_t index) const override {
|
||||||
|
switch (index) {
|
||||||
|
case 0: return Vector2f(0, 0);
|
||||||
|
case 1: return Vector2f(size_.x, 0);
|
||||||
|
case 2: return Vector2f(size_.x, size_.y);
|
||||||
|
case 3: return Vector2f(0, size_.y);
|
||||||
|
default: return Vector2f();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CircleShape : public Shape {
|
class CircleShape : public Shape {
|
||||||
|
|
@ -433,8 +534,13 @@ public:
|
||||||
void setRadius(float radius) { radius_ = radius; }
|
void setRadius(float radius) { radius_ = radius; }
|
||||||
float getRadius() const { return radius_; }
|
float getRadius() const { return radius_; }
|
||||||
void setPointCount(size_t count) { pointCount_ = count; }
|
void setPointCount(size_t count) { pointCount_ = count; }
|
||||||
size_t getPointCount() const { return pointCount_; }
|
size_t getPointCount() const override { return pointCount_; }
|
||||||
FloatRect getLocalBounds() const override { return FloatRect(0, 0, radius_ * 2, radius_ * 2); }
|
FloatRect getLocalBounds() const override { return FloatRect(0, 0, radius_ * 2, radius_ * 2); }
|
||||||
|
|
||||||
|
Vector2f getPoint(size_t index) const override {
|
||||||
|
float angle = static_cast<float>(index) / pointCount_ * 2.0f * 3.14159265f;
|
||||||
|
return Vector2f(radius_ + radius_ * std::cos(angle), radius_ + radius_ * std::sin(angle));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConvexShape : public Shape {
|
class ConvexShape : public Shape {
|
||||||
|
|
@ -442,9 +548,9 @@ class ConvexShape : public Shape {
|
||||||
public:
|
public:
|
||||||
ConvexShape(size_t pointCount = 0) : points_(pointCount) {}
|
ConvexShape(size_t pointCount = 0) : points_(pointCount) {}
|
||||||
void setPointCount(size_t count) { points_.resize(count); }
|
void setPointCount(size_t count) { points_.resize(count); }
|
||||||
size_t getPointCount() const { return points_.size(); }
|
size_t getPointCount() const override { return points_.size(); }
|
||||||
void setPoint(size_t index, const Vector2f& point) { if (index < points_.size()) points_[index] = point; }
|
void setPoint(size_t index, const Vector2f& point) { if (index < points_.size()) points_[index] = point; }
|
||||||
Vector2f getPoint(size_t index) const { return index < points_.size() ? points_[index] : Vector2f(); }
|
Vector2f getPoint(size_t index) const override { return index < points_.size() ? points_[index] : Vector2f(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue