diff --git a/src/Ball.hpp b/src/Ball.hpp index f16ba2d..c0857e6 100644 --- a/src/Ball.hpp +++ b/src/Ball.hpp @@ -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(); } }; diff --git a/src/BatchRenderer.cpp b/src/BatchRenderer.cpp new file mode 100644 index 0000000..f7fea99 --- /dev/null +++ b/src/BatchRenderer.cpp @@ -0,0 +1,85 @@ +#include "BatchRenderer.hpp" + +#include +#include +#include + +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(center.x) - static_cast(pixel.x); + int dy = static_cast(center.y) - static_cast(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(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); +} diff --git a/src/BatchRenderer.hpp b/src/BatchRenderer.hpp new file mode 100644 index 0000000..188f413 --- /dev/null +++ b/src/BatchRenderer.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include +#include +#include + +#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); +}; diff --git a/src/Constants.hpp b/src/Constants.hpp index ab2883c..2af559f 100644 --- a/src/Constants.hpp +++ b/src/Constants.hpp @@ -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 diff --git a/src/DebugOverlay.cpp b/src/DebugOverlay.cpp index ac5d17a..f51c00f 100644 --- a/src/DebugOverlay.cpp +++ b/src/DebugOverlay.cpp @@ -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)); } diff --git a/src/Game.cpp b/src/Game.cpp index d75f891..a73bed8 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -126,9 +126,15 @@ void Game::render() { m_debugLines.clear(); m_drawCallCount = 0; + m_batchRenderer.clear(); + for (const auto &object : m_objects) { - object->draw(m_window); - ++m_drawCallCount; + if (auto *ball = dynamic_cast(object.get())) { + m_batchRenderer.addBall(*ball); + } else { + object->draw(m_window); + ++m_drawCallCount; + } if (!m_toggleDebug) continue; if (auto *ball = dynamic_cast(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); diff --git a/src/Game.hpp b/src/Game.hpp index 991cc48..f65dd7e 100644 --- a/src/Game.hpp +++ b/src/Game.hpp @@ -11,6 +11,7 @@ #include #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> 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);