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;
|
||||
bool isAtRest() const;
|
||||
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
|
||||
|
||||
namespace Constants {
|
||||
constexpr unsigned WIDTH = 1280;
|
||||
constexpr unsigned HEIGHT = 720;
|
||||
constexpr float GRAVITY = 8000.f;
|
||||
constexpr unsigned WIDTH = 1920;
|
||||
constexpr unsigned HEIGHT = 1080;
|
||||
constexpr float GRAVITY = 781.f;
|
||||
constexpr float RESTITUTION = 0.8f;
|
||||
constexpr float FRICTION = 0.9f;
|
||||
constexpr float BALL_RADIUS = 20.f;
|
||||
constexpr float IMPULSE = 2500.f;
|
||||
constexpr float IMPULSE = 2000.f;
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
DebugOverlay::DebugOverlay(const std::string& fontPath)
|
||||
: m_font(fontPath), m_text(m_font) {
|
||||
m_text.setCharacterSize(16);
|
||||
m_text.setCharacterSize(18);
|
||||
m_text.setFillColor(sf::Color::White);
|
||||
m_text.setPosition(sf::Vector2f(5.f, 5.f));
|
||||
}
|
||||
|
||||
@@ -126,9 +126,15 @@ void Game::render() {
|
||||
m_debugLines.clear();
|
||||
m_drawCallCount = 0;
|
||||
|
||||
m_batchRenderer.clear();
|
||||
|
||||
for (const auto &object : m_objects) {
|
||||
if (auto *ball = dynamic_cast<Ball *>(object.get())) {
|
||||
m_batchRenderer.addBall(*ball);
|
||||
} else {
|
||||
object->draw(m_window);
|
||||
++m_drawCallCount;
|
||||
}
|
||||
|
||||
if (!m_toggleDebug) continue;
|
||||
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) {
|
||||
DebugDraw::drawBatchedLines(m_window, m_debugLines);
|
||||
m_debugOverlay.update(m_drawCallCount + 2, m_timeScale, m_window);
|
||||
|
||||
+4
-2
@@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Ball.hpp"
|
||||
#include "BatchRenderer.hpp"
|
||||
#include "DebugOverlay.hpp"
|
||||
#include "InputManager.hpp"
|
||||
#include "PhysicalObject.hpp"
|
||||
@@ -20,7 +21,7 @@ class PhysicalObject;
|
||||
|
||||
class Game {
|
||||
private:
|
||||
float m_timeScale = 1.0f;
|
||||
float m_timeScale = 1.f;
|
||||
sf::RenderWindow m_window;
|
||||
sf::Vector2f m_windowSize;
|
||||
std::vector<std::unique_ptr<PhysicalObject>> m_objects;
|
||||
@@ -29,7 +30,8 @@ class Game {
|
||||
sf::VertexArray m_debugLines;
|
||||
int m_drawCallCount = 0;
|
||||
DebugOverlay m_debugOverlay;
|
||||
bool m_toggleDebug = false;
|
||||
bool m_toggleDebug = true;
|
||||
BatchRenderer m_batchRenderer;
|
||||
|
||||
void processKeyPressed(const sf::Event::KeyPressed& keyPressed);
|
||||
void processMousePressed(const sf::Event::MouseButtonPressed& mousePressed);
|
||||
|
||||
Reference in New Issue
Block a user