mirror of
https://github.com/Floriansylvain/SFMLplayground.git
synced 2026-08-19 11:43:24 +02:00
feat: BatchRenderer for optimized ball rendering
This commit is contained in:
@@ -28,4 +28,6 @@ class Ball : public PhysicalObject {
|
|||||||
sf::Vector2f getVelocity() const;
|
sf::Vector2f getVelocity() const;
|
||||||
bool isAtRest() const;
|
bool isAtRest() const;
|
||||||
sf::Vector2f getPixelVelocity() const { return m_pixelVelocity; }
|
sf::Vector2f getPixelVelocity() const { return m_pixelVelocity; }
|
||||||
|
float getRadius() const { return m_radius; }
|
||||||
|
sf::Color getColor() const { return m_shape.getFillColor(); }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#include "BatchRenderer.hpp"
|
||||||
|
|
||||||
|
#include <SFML/Graphics/Image.hpp>
|
||||||
|
#include <SFML/OpenGL.hpp>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
BatchRenderer::BatchRenderer() : m_vertices(sf::PrimitiveType::Triangles) {
|
||||||
|
const unsigned int size = 64;
|
||||||
|
sf::Image image(sf::Vector2u(size, size), sf::Color::Transparent);
|
||||||
|
|
||||||
|
unsigned int radius = size / 2;
|
||||||
|
sf::Vector2u center(radius, radius);
|
||||||
|
|
||||||
|
for (unsigned int y = 0; y < size; ++y) {
|
||||||
|
for (unsigned int x = 0; x < size; ++x) {
|
||||||
|
sf::Vector2u pixel(x, y);
|
||||||
|
int dx = static_cast<int>(center.x) - static_cast<int>(pixel.x);
|
||||||
|
int dy = static_cast<int>(center.y) - static_cast<int>(pixel.y);
|
||||||
|
float distance = std::sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
if (distance <= radius) {
|
||||||
|
float alpha = 255.0f;
|
||||||
|
if (distance > radius - 2.0f) {
|
||||||
|
alpha =
|
||||||
|
255.0f * (1.0f - (distance - (radius - 2.0f)) / 2.0f);
|
||||||
|
}
|
||||||
|
image.setPixel(
|
||||||
|
sf::Vector2u(x, y),
|
||||||
|
sf::Color(255, 255, 255, static_cast<std::uint8_t>(alpha)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_circleTexture.loadFromImage(image)) {
|
||||||
|
throw std::runtime_error("Failed to load circle texture from image");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchRenderer::clear() { m_vertices.clear(); }
|
||||||
|
|
||||||
|
void BatchRenderer::addBall(const Ball& ball) {
|
||||||
|
sf::Vector2f position = ball.getPosition();
|
||||||
|
float radius = ball.getRadius();
|
||||||
|
sf::Color color = ball.getColor();
|
||||||
|
|
||||||
|
sf::Vertex topLeft;
|
||||||
|
sf::Vertex topRight;
|
||||||
|
sf::Vertex bottomRight;
|
||||||
|
sf::Vertex bottomLeft;
|
||||||
|
|
||||||
|
topLeft.position = sf::Vector2f(position.x - radius, position.y - radius);
|
||||||
|
topRight.position = sf::Vector2f(position.x + radius, position.y - radius);
|
||||||
|
bottomRight.position =
|
||||||
|
sf::Vector2f(position.x + radius, position.y + radius);
|
||||||
|
bottomLeft.position =
|
||||||
|
sf::Vector2f(position.x - radius, position.y + radius);
|
||||||
|
|
||||||
|
topLeft.texCoords = sf::Vector2f(0, 0);
|
||||||
|
topRight.texCoords = sf::Vector2f(m_circleTexture.getSize().x, 0);
|
||||||
|
bottomRight.texCoords =
|
||||||
|
sf::Vector2f(m_circleTexture.getSize().x, m_circleTexture.getSize().y);
|
||||||
|
bottomLeft.texCoords = sf::Vector2f(0, m_circleTexture.getSize().y);
|
||||||
|
|
||||||
|
topLeft.color = color;
|
||||||
|
topRight.color = color;
|
||||||
|
bottomRight.color = color;
|
||||||
|
bottomLeft.color = color;
|
||||||
|
|
||||||
|
m_vertices.append(topLeft);
|
||||||
|
m_vertices.append(topRight);
|
||||||
|
m_vertices.append(bottomRight);
|
||||||
|
|
||||||
|
m_vertices.append(topLeft);
|
||||||
|
m_vertices.append(bottomRight);
|
||||||
|
m_vertices.append(bottomLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchRenderer::draw(sf::RenderWindow& window) {
|
||||||
|
if (m_vertices.getVertexCount() == 0) return;
|
||||||
|
|
||||||
|
sf::RenderStates states;
|
||||||
|
states.texture = &m_circleTexture;
|
||||||
|
|
||||||
|
window.draw(m_vertices, states);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <SFML/Graphics/RenderWindow.hpp>
|
||||||
|
#include <SFML/Graphics/Texture.hpp>
|
||||||
|
#include <SFML/Graphics/VertexArray.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Ball.hpp"
|
||||||
|
|
||||||
|
class BatchRenderer {
|
||||||
|
private:
|
||||||
|
sf::VertexArray m_vertices;
|
||||||
|
sf::Texture m_circleTexture;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BatchRenderer();
|
||||||
|
void clear();
|
||||||
|
void addBall(const Ball& ball);
|
||||||
|
void draw(sf::RenderWindow& window);
|
||||||
|
};
|
||||||
+6
-6
@@ -1,13 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
namespace Constants {
|
namespace Constants {
|
||||||
constexpr unsigned WIDTH = 1280;
|
constexpr unsigned WIDTH = 1920;
|
||||||
constexpr unsigned HEIGHT = 720;
|
constexpr unsigned HEIGHT = 1080;
|
||||||
constexpr float GRAVITY = 8000.f;
|
constexpr float GRAVITY = 781.f;
|
||||||
constexpr float RESTITUTION = 0.8f;
|
constexpr float RESTITUTION = 0.8f;
|
||||||
constexpr float FRICTION = 0.9f;
|
constexpr float FRICTION = 0.9f;
|
||||||
constexpr float BALL_RADIUS = 20.f;
|
constexpr float IMPULSE = 2000.f;
|
||||||
constexpr float IMPULSE = 2500.f;
|
|
||||||
constexpr float REST_PIXEL_VELOCITY = 2.0f;
|
constexpr float REST_PIXEL_VELOCITY = 2.0f;
|
||||||
constexpr unsigned BALL_QUANTITY = 100;
|
constexpr float BALL_RADIUS = 15.f;
|
||||||
|
constexpr unsigned BALL_QUANTITY = 500;
|
||||||
} // namespace Constants
|
} // namespace Constants
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
DebugOverlay::DebugOverlay(const std::string& fontPath)
|
DebugOverlay::DebugOverlay(const std::string& fontPath)
|
||||||
: m_font(fontPath), m_text(m_font) {
|
: m_font(fontPath), m_text(m_font) {
|
||||||
m_text.setCharacterSize(16);
|
m_text.setCharacterSize(18);
|
||||||
m_text.setFillColor(sf::Color::White);
|
m_text.setFillColor(sf::Color::White);
|
||||||
m_text.setPosition(sf::Vector2f(5.f, 5.f));
|
m_text.setPosition(sf::Vector2f(5.f, 5.f));
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -126,9 +126,15 @@ void Game::render() {
|
|||||||
m_debugLines.clear();
|
m_debugLines.clear();
|
||||||
m_drawCallCount = 0;
|
m_drawCallCount = 0;
|
||||||
|
|
||||||
|
m_batchRenderer.clear();
|
||||||
|
|
||||||
for (const auto &object : m_objects) {
|
for (const auto &object : m_objects) {
|
||||||
object->draw(m_window);
|
if (auto *ball = dynamic_cast<Ball *>(object.get())) {
|
||||||
++m_drawCallCount;
|
m_batchRenderer.addBall(*ball);
|
||||||
|
} else {
|
||||||
|
object->draw(m_window);
|
||||||
|
++m_drawCallCount;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_toggleDebug) continue;
|
if (!m_toggleDebug) continue;
|
||||||
if (auto *ball = dynamic_cast<Ball *>(object.get())) {
|
if (auto *ball = dynamic_cast<Ball *>(object.get())) {
|
||||||
@@ -137,6 +143,9 @@ void Game::render() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_batchRenderer.draw(m_window);
|
||||||
|
++m_drawCallCount;
|
||||||
|
|
||||||
if (m_toggleDebug) {
|
if (m_toggleDebug) {
|
||||||
DebugDraw::drawBatchedLines(m_window, m_debugLines);
|
DebugDraw::drawBatchedLines(m_window, m_debugLines);
|
||||||
m_debugOverlay.update(m_drawCallCount + 2, m_timeScale, m_window);
|
m_debugOverlay.update(m_drawCallCount + 2, m_timeScale, m_window);
|
||||||
|
|||||||
+4
-2
@@ -11,6 +11,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Ball.hpp"
|
#include "Ball.hpp"
|
||||||
|
#include "BatchRenderer.hpp"
|
||||||
#include "DebugOverlay.hpp"
|
#include "DebugOverlay.hpp"
|
||||||
#include "InputManager.hpp"
|
#include "InputManager.hpp"
|
||||||
#include "PhysicalObject.hpp"
|
#include "PhysicalObject.hpp"
|
||||||
@@ -20,7 +21,7 @@ class PhysicalObject;
|
|||||||
|
|
||||||
class Game {
|
class Game {
|
||||||
private:
|
private:
|
||||||
float m_timeScale = 1.0f;
|
float m_timeScale = 1.f;
|
||||||
sf::RenderWindow m_window;
|
sf::RenderWindow m_window;
|
||||||
sf::Vector2f m_windowSize;
|
sf::Vector2f m_windowSize;
|
||||||
std::vector<std::unique_ptr<PhysicalObject>> m_objects;
|
std::vector<std::unique_ptr<PhysicalObject>> m_objects;
|
||||||
@@ -29,7 +30,8 @@ class Game {
|
|||||||
sf::VertexArray m_debugLines;
|
sf::VertexArray m_debugLines;
|
||||||
int m_drawCallCount = 0;
|
int m_drawCallCount = 0;
|
||||||
DebugOverlay m_debugOverlay;
|
DebugOverlay m_debugOverlay;
|
||||||
bool m_toggleDebug = false;
|
bool m_toggleDebug = true;
|
||||||
|
BatchRenderer m_batchRenderer;
|
||||||
|
|
||||||
void processKeyPressed(const sf::Event::KeyPressed& keyPressed);
|
void processKeyPressed(const sf::Event::KeyPressed& keyPressed);
|
||||||
void processMousePressed(const sf::Event::MouseButtonPressed& mousePressed);
|
void processMousePressed(const sf::Event::MouseButtonPressed& mousePressed);
|
||||||
|
|||||||
Reference in New Issue
Block a user