31
General / Re: need a better collision idea
« on: July 23, 2020, 12:08:54 am »
Framebuffer like everything else in OpenGL is drawn from bottom left position, inverting helped.
Now it works, it seems like slowest part (cca 3 ms on my PC) is rendering sprites into buffer/RenderTexture with shader (without shader it's cca 0.3 ms). I have no experience with them, hard to say. I rewrote it a bit to make more sense (use texture from post above). There are no extra optimalizations, it render all sprites to buffer etc. Anyway, this is probably the slowest way to do it. With some complex scene it can be pretty slow.
glReadPixels(mouse.x, window.getSize().y - mouse.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
Now it works, it seems like slowest part (cca 3 ms on my PC) is rendering sprites into buffer/RenderTexture with shader (without shader it's cca 0.3 ms). I have no experience with them, hard to say. I rewrote it a bit to make more sense (use texture from post above). There are no extra optimalizations, it render all sprites to buffer etc. Anyway, this is probably the slowest way to do it. With some complex scene it can be pretty slow.
#include <string>
#include <iostream>
#include <SFML/OpenGL.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
class Entity
{
public:
size_t objectID;
sf::Sprite sprite;
unsigned int frame;
sf::Vector2f pos;
sf::Vector2f speed;
Entity(const sf::Texture& texture, const unsigned int& frame, const size_t& objectID, const sf::Vector2f& pos, const sf::Vector2u& texture_size, const sf::Vector2u& frame_size) : objectID(objectID), frame(frame), pos(pos)
{
speed = { rand() % 500 / 10 + 50.f, rand() % 500 / 10 + 50.f };
sf::IntRect frameRect;
frameRect.left = (frame % texture_size.x) * frame_size.x;
frameRect.top = (frame / texture_size.x) * frame_size.y;
frameRect.width = frame_size.x;
frameRect.height = frame_size.y;
sprite.setTexture(texture);
sprite.setTextureRect(frameRect);
sprite.setPosition(pos);
}
void OnUpdate(const float& dt, const sf::Vector2u& posLimit)
{
pos.x += speed.x * dt;
pos.y += speed.y * dt;
if ((pos.x > posLimit.x - 64) || (pos.x < 0))
{
speed.x = -speed.x;
}
if ((pos.y > posLimit.y - 64) || (pos.y < 0))
{
speed.y = -speed.y;
}
sprite.setPosition(pos);
}
};
class EntityManager
{
public:
size_t lastID;
bool sorting;
std::vector<Entity> v;
public:
EntityManager() : lastID(0), sorting(false) {};
void Add(const int& number, const sf::Texture& texture, const sf::Vector2u& posLimit, const sf::Vector2u& texture_size, const sf::Vector2u& frame_size )
{
v.reserve(v.size() + number);
for (int i = 0; i < number; i++)
{
v.emplace_back(Entity(texture, rand() % 36, lastID, { rand() % posLimit.x + 50.f, rand() % posLimit.y + 50.f }, texture_size, frame_size));
lastID++;
}
};
void OnUpdate(const float& dt, const sf::Vector2u posLimit, const bool& movingObjects)
{
if (movingObjects)
{
for (Entity& entity : v)
entity.OnUpdate(dt, posLimit);
if (sorting)
Sort();
}
}
void Sort()
{
std::sort(v.begin(), v.end(), [](const Entity& lhs, const Entity& rhs)
{
return lhs.pos.y < rhs.pos.y;
});
}
void Draw(sf::RenderWindow& window)
{
for (Entity& entity : v)
{
window.draw(entity.sprite);
}
}
void PrintOut(const size_t& objectID)
{
for (Entity& entity : v)
{
if (entity.objectID == objectID)
{
std::cout << "-------------------- " << std::endl;
std::cout << "ID: " << entity.objectID << std::endl;
std::cout << "Pos: [" << entity.pos.x << "; " << entity.pos.y << "] " << std::endl;
return;
}
}
std::cout << "Entity with ID: " << objectID << " not found." << std::endl;
}
};
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "Tests");
//window.setVerticalSyncEnabled(true);
window.setFramerateLimit(60);
sf::Clock clock;
sf::Vector2i mouse;
sf::VertexArray vertices;
vertices.setPrimitiveType(sf::Quads);
sf::Texture texture; // 9 x 4 = 36 frames (64x64 pixels)
texture.loadFromFile("texture.png");
sf::Vector2u texture_size = { 9, 4 }; // Rows, cols
sf::Vector2u frame_size = { 64, 64 }; // In pixels
sf::Shader shader;
shader.loadFromFile("shaders/test.frag", sf::Shader::Fragment);
shader.setUniform("texture", texture);
sf::RenderTexture buffer;
buffer.create(window.getSize().x, window.getSize().y);
sf::Sprite rt_buffer_sprite;
sf::Sprite buffer_spr(texture); // Temp
buffer_spr.setTexture(texture);
sf::RenderStates rs;
rs.texture = &texture;
rs.shader = &shader;
EntityManager objectManager;
objectManager.Add(100, texture, { window.getSize().x - 100, window.getSize().y - 100 }, texture_size, frame_size);
objectManager.Sort();
bool drawBuffer = true;
bool drawObjects = false;
bool movingObjects = false;
bool benchmarkOutput = false;
int selected_ID;
while (window.isOpen())
{
// Process events
sf::Event event;
while (window.pollEvent(event))
{
switch (event.type)
{
case sf::Event::Closed:
window.close();
break;
case sf::Event::KeyPressed:
{
if (event.key.code == sf::Keyboard::Num1)
drawBuffer = !drawBuffer;
if (event.key.code == sf::Keyboard::Num2)
drawObjects = !drawObjects;
if (event.key.code == sf::Keyboard::Space)
movingObjects = !movingObjects;
if (event.key.code == sf::Keyboard::S)
objectManager.sorting = !objectManager.sorting;
if (event.key.code == sf::Keyboard::B)
benchmarkOutput = !benchmarkOutput;
}
break;
case sf::Event::MouseButtonPressed:
{
if (event.mouseButton.button == sf::Mouse::Left)
{
if (selected_ID > -1)
{
objectManager.PrintOut(selected_ID);
}
}
}
break;
default: break;
}
}
// Update
mouse = sf::Mouse::getPosition(window);
objectManager.OnUpdate(1 / 60.f, window.getSize(), movingObjects);
// Buffer
clock.restart();
buffer.clear();
for (int i = 0; i < objectManager.v.size(); i++)
{
// Calc ID
size_t ID = objectManager.v[i].objectID + 50;
int r = (ID & 0x000000FF) >> 0;
int g = (ID & 0x0000FF00) >> 8;
int b = (ID & 0x00FF0000) >> 16;
shader.setUniform("color_id", sf::Glsl::Vec4(r / 255.0f, g / 255.0f, b / 255.0f, 255));
sf::IntRect frameRect;
frameRect.left = (objectManager.v[i].frame % texture_size.x) * frame_size.x;
frameRect.top = (objectManager.v[i].frame / texture_size.x) * frame_size.y;
frameRect.width = frame_size.x;
frameRect.height = frame_size.y;
buffer_spr.setTextureRect(frameRect);
buffer_spr.setPosition(objectManager.v[i].pos);
buffer.draw(buffer_spr, rs); // Bit slow ??
//buffer.draw(buffer_spr);
}
buffer.display();
//sf::Texture::bind(&buffer.getTexture(), sf::Texture::CoordinateType::Pixels); // It's not needed?
unsigned char data[4];
//glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(mouse.x, window.getSize().y - mouse.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
// Get ID from color
selected_ID = (data[0] + data[1] * 256 + data[2] * 256 * 256) - 50;
// Benchmark end
sf::Time benchmark = clock.getElapsedTime();
if (benchmarkOutput)
std::cout << (float)benchmark.asMicroseconds() / 1000 << " ms \n";
//std::cout << "RGBA: [" << static_cast<unsigned int>(data[0]) << " " << static_cast<unsigned int>(data[1]) << " " << static_cast<unsigned int>(data[2]) << "] " << static_cast<unsigned int>(data[3]) << "\n";
std::string title = "Mouse: [" + std::to_string(mouse.x) + "; " + std::to_string(mouse.y) + "] " +
"R[" + std::to_string((unsigned char)data[0]) + "] G:[" + std::to_string((unsigned char)data[1]) +
"] B:[" + std::to_string((unsigned char)data[2]) + "] A:[" + std::to_string((unsigned char)data[3]) + "]";
if (objectManager.sorting)
title += +" SORTING";
if (selected_ID > -1)
title += +" ID: " + std::to_string(selected_ID);
window.setTitle(title);
// Draw
window.clear({ 20, 20, 20 });
if (drawBuffer)
{
rt_buffer_sprite.setTexture(buffer.getTexture());
window.draw(rt_buffer_sprite);
}
if (drawObjects)
objectManager.Draw(window);
window.display();
}
return 0;
}
#include <iostream>
#include <SFML/OpenGL.hpp>
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
class Entity
{
public:
size_t objectID;
sf::Sprite sprite;
unsigned int frame;
sf::Vector2f pos;
sf::Vector2f speed;
Entity(const sf::Texture& texture, const unsigned int& frame, const size_t& objectID, const sf::Vector2f& pos, const sf::Vector2u& texture_size, const sf::Vector2u& frame_size) : objectID(objectID), frame(frame), pos(pos)
{
speed = { rand() % 500 / 10 + 50.f, rand() % 500 / 10 + 50.f };
sf::IntRect frameRect;
frameRect.left = (frame % texture_size.x) * frame_size.x;
frameRect.top = (frame / texture_size.x) * frame_size.y;
frameRect.width = frame_size.x;
frameRect.height = frame_size.y;
sprite.setTexture(texture);
sprite.setTextureRect(frameRect);
sprite.setPosition(pos);
}
void OnUpdate(const float& dt, const sf::Vector2u& posLimit)
{
pos.x += speed.x * dt;
pos.y += speed.y * dt;
if ((pos.x > posLimit.x - 64) || (pos.x < 0))
{
speed.x = -speed.x;
}
if ((pos.y > posLimit.y - 64) || (pos.y < 0))
{
speed.y = -speed.y;
}
sprite.setPosition(pos);
}
};
class EntityManager
{
public:
size_t lastID;
bool sorting;
std::vector<Entity> v;
public:
EntityManager() : lastID(0), sorting(false) {};
void Add(const int& number, const sf::Texture& texture, const sf::Vector2u& posLimit, const sf::Vector2u& texture_size, const sf::Vector2u& frame_size )
{
v.reserve(v.size() + number);
for (int i = 0; i < number; i++)
{
v.emplace_back(Entity(texture, rand() % 36, lastID, { rand() % posLimit.x + 50.f, rand() % posLimit.y + 50.f }, texture_size, frame_size));
lastID++;
}
};
void OnUpdate(const float& dt, const sf::Vector2u posLimit, const bool& movingObjects)
{
if (movingObjects)
{
for (Entity& entity : v)
entity.OnUpdate(dt, posLimit);
if (sorting)
Sort();
}
}
void Sort()
{
std::sort(v.begin(), v.end(), [](const Entity& lhs, const Entity& rhs)
{
return lhs.pos.y < rhs.pos.y;
});
}
void Draw(sf::RenderWindow& window)
{
for (Entity& entity : v)
{
window.draw(entity.sprite);
}
}
void PrintOut(const size_t& objectID)
{
for (Entity& entity : v)
{
if (entity.objectID == objectID)
{
std::cout << "-------------------- " << std::endl;
std::cout << "ID: " << entity.objectID << std::endl;
std::cout << "Pos: [" << entity.pos.x << "; " << entity.pos.y << "] " << std::endl;
return;
}
}
std::cout << "Entity with ID: " << objectID << " not found." << std::endl;
}
};
int main() {
sf::RenderWindow window(sf::VideoMode(800, 600), "Tests");
//window.setVerticalSyncEnabled(true);
window.setFramerateLimit(60);
sf::Clock clock;
sf::Vector2i mouse;
sf::VertexArray vertices;
vertices.setPrimitiveType(sf::Quads);
sf::Texture texture; // 9 x 4 = 36 frames (64x64 pixels)
texture.loadFromFile("texture.png");
sf::Vector2u texture_size = { 9, 4 }; // Rows, cols
sf::Vector2u frame_size = { 64, 64 }; // In pixels
sf::Shader shader;
shader.loadFromFile("shaders/test.frag", sf::Shader::Fragment);
shader.setUniform("texture", texture);
sf::RenderTexture buffer;
buffer.create(window.getSize().x, window.getSize().y);
sf::Sprite rt_buffer_sprite;
sf::Sprite buffer_spr(texture); // Temp
buffer_spr.setTexture(texture);
sf::RenderStates rs;
rs.texture = &texture;
rs.shader = &shader;
EntityManager objectManager;
objectManager.Add(100, texture, { window.getSize().x - 100, window.getSize().y - 100 }, texture_size, frame_size);
objectManager.Sort();
bool drawBuffer = true;
bool drawObjects = false;
bool movingObjects = false;
bool benchmarkOutput = false;
int selected_ID;
while (window.isOpen())
{
// Process events
sf::Event event;
while (window.pollEvent(event))
{
switch (event.type)
{
case sf::Event::Closed:
window.close();
break;
case sf::Event::KeyPressed:
{
if (event.key.code == sf::Keyboard::Num1)
drawBuffer = !drawBuffer;
if (event.key.code == sf::Keyboard::Num2)
drawObjects = !drawObjects;
if (event.key.code == sf::Keyboard::Space)
movingObjects = !movingObjects;
if (event.key.code == sf::Keyboard::S)
objectManager.sorting = !objectManager.sorting;
if (event.key.code == sf::Keyboard::B)
benchmarkOutput = !benchmarkOutput;
}
break;
case sf::Event::MouseButtonPressed:
{
if (event.mouseButton.button == sf::Mouse::Left)
{
if (selected_ID > -1)
{
objectManager.PrintOut(selected_ID);
}
}
}
break;
default: break;
}
}
// Update
mouse = sf::Mouse::getPosition(window);
objectManager.OnUpdate(1 / 60.f, window.getSize(), movingObjects);
// Buffer
clock.restart();
buffer.clear();
for (int i = 0; i < objectManager.v.size(); i++)
{
// Calc ID
size_t ID = objectManager.v[i].objectID + 50;
int r = (ID & 0x000000FF) >> 0;
int g = (ID & 0x0000FF00) >> 8;
int b = (ID & 0x00FF0000) >> 16;
shader.setUniform("color_id", sf::Glsl::Vec4(r / 255.0f, g / 255.0f, b / 255.0f, 255));
sf::IntRect frameRect;
frameRect.left = (objectManager.v[i].frame % texture_size.x) * frame_size.x;
frameRect.top = (objectManager.v[i].frame / texture_size.x) * frame_size.y;
frameRect.width = frame_size.x;
frameRect.height = frame_size.y;
buffer_spr.setTextureRect(frameRect);
buffer_spr.setPosition(objectManager.v[i].pos);
buffer.draw(buffer_spr, rs); // Bit slow ??
//buffer.draw(buffer_spr);
}
buffer.display();
//sf::Texture::bind(&buffer.getTexture(), sf::Texture::CoordinateType::Pixels); // It's not needed?
unsigned char data[4];
//glPixelStorei(GL_PACK_ALIGNMENT, 1);
glReadPixels(mouse.x, window.getSize().y - mouse.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
// Get ID from color
selected_ID = (data[0] + data[1] * 256 + data[2] * 256 * 256) - 50;
// Benchmark end
sf::Time benchmark = clock.getElapsedTime();
if (benchmarkOutput)
std::cout << (float)benchmark.asMicroseconds() / 1000 << " ms \n";
//std::cout << "RGBA: [" << static_cast<unsigned int>(data[0]) << " " << static_cast<unsigned int>(data[1]) << " " << static_cast<unsigned int>(data[2]) << "] " << static_cast<unsigned int>(data[3]) << "\n";
std::string title = "Mouse: [" + std::to_string(mouse.x) + "; " + std::to_string(mouse.y) + "] " +
"R[" + std::to_string((unsigned char)data[0]) + "] G:[" + std::to_string((unsigned char)data[1]) +
"] B:[" + std::to_string((unsigned char)data[2]) + "] A:[" + std::to_string((unsigned char)data[3]) + "]";
if (objectManager.sorting)
title += +" SORTING";
if (selected_ID > -1)
title += +" ID: " + std::to_string(selected_ID);
window.setTitle(title);
// Draw
window.clear({ 20, 20, 20 });
if (drawBuffer)
{
rt_buffer_sprite.setTexture(buffer.getTexture());
window.draw(rt_buffer_sprite);
}
if (drawObjects)
objectManager.Draw(window);
window.display();
}
return 0;
}