draw graph edges much faster (using raw vertex array)
This commit is contained in:
@ -35,9 +35,10 @@ set(SOURCES
|
|||||||
# Libraries
|
# Libraries
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
find_package(raylib REQUIRED)
|
find_package(raylib REQUIRED)
|
||||||
|
find_package(GLEW REQUIRED)
|
||||||
find_package(libmorton REQUIRED)
|
find_package(libmorton REQUIRED)
|
||||||
find_package(Boost COMPONENTS program_options REQUIRED)
|
find_package(Boost COMPONENTS program_options REQUIRED)
|
||||||
set(LIBS raylib Boost::headers Boost::program_options)
|
set(LIBS raylib GLEW::GLEW Boost::headers Boost::program_options)
|
||||||
set(FLAGS "")
|
set(FLAGS "")
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
|
|||||||
@ -250,6 +250,7 @@ rec {
|
|||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
# C/C++:
|
# C/C++:
|
||||||
raylib
|
raylib
|
||||||
|
glew
|
||||||
raygui
|
raygui
|
||||||
thread-pool
|
thread-pool
|
||||||
libmorton
|
libmorton
|
||||||
|
|||||||
@ -75,8 +75,9 @@ constexpr float SOFTENING = 0.05; // Barnes-Hut [0.01, 1.0]
|
|||||||
|
|
||||||
// Graph Drawing
|
// Graph Drawing
|
||||||
static const Color EDGE_COLOR = Fade(BLUE, 0.3);
|
static const Color EDGE_COLOR = Fade(BLUE, 0.3);
|
||||||
|
constexpr int DRAW_EDGES_LIMIT = 5'000'000;
|
||||||
constexpr float VERTEX_SIZE = 0.75;
|
constexpr float VERTEX_SIZE = 0.75;
|
||||||
constexpr int DRAW_VERTICES_LIMIT = 1000000;
|
constexpr int DRAW_VERTICES_LIMIT = 1'000'000;
|
||||||
static const Color VERTEX_COLOR = Fade(BLUE, 0.8);
|
static const Color VERTEX_COLOR = Fade(BLUE, 0.8);
|
||||||
constexpr Color VERTEX_VISITED_COLOR = ORANGE;
|
constexpr Color VERTEX_VISITED_COLOR = ORANGE;
|
||||||
constexpr Color VERTEX_START_COLOR = ORANGE;
|
constexpr Color VERTEX_START_COLOR = ORANGE;
|
||||||
|
|||||||
@ -24,10 +24,15 @@ private:
|
|||||||
RenderTexture klotski_target = LoadRenderTexture(GetScreenWidth() / 2, GetScreenHeight() - MENU_HEIGHT);
|
RenderTexture klotski_target = LoadRenderTexture(GetScreenWidth() / 2, GetScreenHeight() - MENU_HEIGHT);
|
||||||
RenderTexture menu_target = LoadRenderTexture(GetScreenWidth(), MENU_HEIGHT);
|
RenderTexture menu_target = LoadRenderTexture(GetScreenWidth(), MENU_HEIGHT);
|
||||||
|
|
||||||
// Batching
|
// Edges
|
||||||
|
unsigned int edge_vao_id = 0;
|
||||||
|
unsigned int edge_vbo_id = 0;
|
||||||
|
std::vector<Vector3> edge_vertices;
|
||||||
|
Shader edge_shader = LoadShader("shader/edge_vertex.glsl", "shader/edge_fragment.glsl");
|
||||||
|
int edge_color_loc = -1;
|
||||||
std::vector<std::pair<Vector3, Vector3>> connections;
|
std::vector<std::pair<Vector3, Vector3>> connections;
|
||||||
|
|
||||||
// Instancing
|
// Vertex instancing
|
||||||
static constexpr int INSTANCE_COLOR_ATTR = 5;
|
static constexpr int INSTANCE_COLOR_ATTR = 5;
|
||||||
std::vector<Matrix> transforms;
|
std::vector<Matrix> transforms;
|
||||||
std::vector<Color> colors;
|
std::vector<Color> colors;
|
||||||
@ -37,30 +42,45 @@ private:
|
|||||||
unsigned int color_vbo_id = 0;
|
unsigned int color_vbo_id = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
renderer(const orbit_camera& _camera,
|
// TODO: I am allocating HUGE vertex buffers instead of resizing dynamically...
|
||||||
const state_manager& _state,
|
// Edges: 5'000'000 * 2 * 12 Byte ~= 115 MB
|
||||||
input_handler& _input,
|
// Verts: 1'000'000 * 16 Byte ~= 15 MB
|
||||||
user_interface& _gui)
|
// This is also allocated on the CPU by the vectors
|
||||||
|
renderer(const orbit_camera& _camera, const state_manager& _state, input_handler& _input, user_interface& _gui)
|
||||||
: state(_state), input(_input), gui(_gui), camera(_camera)
|
: state(_state), input(_input), gui(_gui), camera(_camera)
|
||||||
{
|
{
|
||||||
|
// Edges
|
||||||
|
edge_shader.locs[SHADER_LOC_VERTEX_POSITION] = GetShaderLocationAttrib(edge_shader, "vertexPosition");
|
||||||
|
edge_shader.locs[SHADER_LOC_MATRIX_MVP] = GetShaderLocation(edge_shader, "mvp");
|
||||||
|
edge_shader.locs[SHADER_LOC_COLOR_DIFFUSE] = GetShaderLocation(edge_shader, "colDiffuse");
|
||||||
|
edge_color_loc = GetShaderLocation(edge_shader, "colDiffuse");
|
||||||
|
|
||||||
|
edge_vertices.reserve(DRAW_EDGES_LIMIT * 2);
|
||||||
|
|
||||||
|
edge_vao_id = rlLoadVertexArray();
|
||||||
|
edge_vbo_id = rlLoadVertexBuffer(nullptr, DRAW_EDGES_LIMIT * 2 * sizeof(Vector3), true);
|
||||||
|
|
||||||
|
rlEnableVertexArray(edge_vao_id);
|
||||||
|
rlEnableVertexBuffer(edge_vbo_id);
|
||||||
|
|
||||||
|
rlSetVertexAttribute(0, 3, RL_FLOAT, false, sizeof(Vector3), 0);
|
||||||
|
rlEnableVertexAttribute(0);
|
||||||
|
|
||||||
|
rlDisableVertexBuffer();
|
||||||
|
rlDisableVertexArray();
|
||||||
|
|
||||||
|
// Vertex instancing
|
||||||
instancing_shader.locs[SHADER_LOC_MATRIX_MVP] = GetShaderLocation(instancing_shader, "mvp");
|
instancing_shader.locs[SHADER_LOC_MATRIX_MVP] = GetShaderLocation(instancing_shader, "mvp");
|
||||||
instancing_shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocationAttrib(
|
instancing_shader.locs[SHADER_LOC_MATRIX_MODEL] = GetShaderLocationAttrib(
|
||||||
instancing_shader,
|
instancing_shader,
|
||||||
"instanceTransform");
|
"instanceTransform");
|
||||||
instancing_shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(instancing_shader, "viewPos");
|
instancing_shader.locs[SHADER_LOC_VECTOR_VIEW] = GetShaderLocation(instancing_shader, "viewPos");
|
||||||
|
|
||||||
// infoln("LOC vertexPosition: {}",
|
|
||||||
// rlGetLocationAttrib(instancing_shader.id, "vertexPosition"));
|
|
||||||
// infoln("LOC instanceTransform: {}",
|
|
||||||
// rlGetLocationAttrib(instancing_shader.id, "instanceTransform"));
|
|
||||||
// infoln("LOC instanceColor: {}", rlGetLocationAttrib(instancing_shader.id, "instanceColor"));
|
|
||||||
|
|
||||||
// vertex_mat.maps[MATERIAL_MAP_DIFFUSE].color = VERTEX_COLOR;
|
|
||||||
vertex_mat.shader = instancing_shader;
|
vertex_mat.shader = instancing_shader;
|
||||||
|
|
||||||
transforms.reserve(DRAW_VERTICES_LIMIT);
|
transforms.reserve(DRAW_VERTICES_LIMIT);
|
||||||
colors.reserve(DRAW_VERTICES_LIMIT);
|
colors.reserve(DRAW_VERTICES_LIMIT);
|
||||||
color_vbo_id = rlLoadVertexBuffer(colors.data(), DRAW_VERTICES_LIMIT * sizeof(Color), true);
|
color_vbo_id = rlLoadVertexBuffer(nullptr, DRAW_VERTICES_LIMIT * sizeof(Color), true);
|
||||||
|
|
||||||
rlEnableVertexArray(cube_instance.vaoId);
|
rlEnableVertexArray(cube_instance.vaoId);
|
||||||
rlEnableVertexBuffer(color_vbo_id);
|
rlEnableVertexBuffer(color_vbo_id);
|
||||||
@ -83,12 +103,19 @@ public:
|
|||||||
UnloadRenderTexture(klotski_target);
|
UnloadRenderTexture(klotski_target);
|
||||||
UnloadRenderTexture(menu_target);
|
UnloadRenderTexture(menu_target);
|
||||||
|
|
||||||
|
// Edges
|
||||||
|
rlUnloadVertexArray(edge_vao_id);
|
||||||
|
rlUnloadVertexBuffer(edge_vbo_id);
|
||||||
|
UnloadShader(edge_shader);
|
||||||
|
|
||||||
// Instancing
|
// Instancing
|
||||||
UnloadMaterial(vertex_mat);
|
UnloadMaterial(vertex_mat);
|
||||||
UnloadMesh(cube_instance);
|
UnloadMesh(cube_instance);
|
||||||
|
|
||||||
// I think the shader already gets unloaded with the material?
|
// I think the shader already gets unloaded with the material?
|
||||||
// UnloadShader(instancing_shader);
|
// UnloadShader(instancing_shader);
|
||||||
|
|
||||||
|
rlUnloadVertexBuffer(color_vbo_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
9
shader/edge_fragment.glsl
Normal file
9
shader/edge_fragment.glsl
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
uniform vec4 colDiffuse;
|
||||||
|
out vec4 finalColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
finalColor = colDiffuse;
|
||||||
|
}
|
||||||
9
shader/edge_vertex.glsl
Normal file
9
shader/edge_vertex.glsl
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#version 330
|
||||||
|
|
||||||
|
in vec3 vertexPosition;
|
||||||
|
uniform mat4 mvp;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = mvp * vec4(vertexPosition, 1.0);
|
||||||
|
}
|
||||||
15
src/main.cpp
15
src/main.cpp
@ -1,7 +1,3 @@
|
|||||||
#include <chrono>
|
|
||||||
#include <mutex>
|
|
||||||
#include <raylib.h>
|
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "input_handler.hpp"
|
#include "input_handler.hpp"
|
||||||
#include "cpu_layout_engine.hpp"
|
#include "cpu_layout_engine.hpp"
|
||||||
@ -9,6 +5,10 @@
|
|||||||
#include "state_manager.hpp"
|
#include "state_manager.hpp"
|
||||||
#include "user_interface.hpp"
|
#include "user_interface.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <raylib.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#if not defined(_WIN32)
|
#if not defined(_WIN32)
|
||||||
@ -65,6 +65,13 @@ auto ui_mode() -> int
|
|||||||
SetConfigFlags(FLAG_WINDOW_ALWAYS_RUN);
|
SetConfigFlags(FLAG_WINDOW_ALWAYS_RUN);
|
||||||
InitWindow(INITIAL_WIDTH * 2, INITIAL_HEIGHT + MENU_HEIGHT, "MassSprings");
|
InitWindow(INITIAL_WIDTH * 2, INITIAL_HEIGHT + MENU_HEIGHT, "MassSprings");
|
||||||
|
|
||||||
|
// GLEW setup
|
||||||
|
glewExperimental = GL_TRUE;
|
||||||
|
const GLenum glew_err = glewInit();
|
||||||
|
if (glew_err != GLEW_OK) {
|
||||||
|
TraceLog(LOG_FATAL, "Failed to initialize GLEW: %s", glewGetErrorString(glew_err));
|
||||||
|
}
|
||||||
|
|
||||||
// Game setup
|
// Game setup
|
||||||
cpu_layout_engine physics(thread_pool);
|
cpu_layout_engine physics(thread_pool);
|
||||||
state_manager state(physics, preset_file);
|
state_manager state(physics, preset_file);
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include <raymath.h>
|
#include <raymath.h>
|
||||||
#include <rlgl.h>
|
#include <rlgl.h>
|
||||||
|
#include <GL/glew.h>
|
||||||
|
|
||||||
auto renderer::update_texture_sizes() -> void
|
auto renderer::update_texture_sizes() -> void
|
||||||
{
|
{
|
||||||
@ -34,10 +35,24 @@ auto renderer::draw_mass_springs(const std::vector<Vector3>& masses) -> void
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare connection batching
|
// Prepare edge buffer
|
||||||
{
|
{
|
||||||
#ifdef TRACY
|
#ifdef TRACY
|
||||||
ZoneNamedN(prepare_connections, "PrepareConnectionsBatching", true);
|
ZoneNamedN(prepare_edge_buffers, "PrepareEdgeBuffers", true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
edge_vertices.clear();
|
||||||
|
for (const auto& [from, to] : state.get_links()) {
|
||||||
|
edge_vertices.push_back(masses[from]);
|
||||||
|
edge_vertices.push_back(masses[to]);
|
||||||
|
}
|
||||||
|
rlUpdateVertexBuffer(edge_vbo_id, edge_vertices.data(), edge_vertices.size() * sizeof(Vector3), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare connection drawing
|
||||||
|
{
|
||||||
|
#ifdef TRACY
|
||||||
|
ZoneNamedN(prepare_connections, "PrepareConnectionsDrawing", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
connections.clear();
|
connections.clear();
|
||||||
@ -47,7 +62,6 @@ auto renderer::draw_mass_springs(const std::vector<Vector3>& masses) -> void
|
|||||||
const Vector3& current_mass = masses[state.get_current_index()];
|
const Vector3& current_mass = masses[state.get_current_index()];
|
||||||
const Vector3& winning_mass = masses[_state];
|
const Vector3& winning_mass = masses[_state];
|
||||||
connections.emplace_back(current_mass, winning_mass);
|
connections.emplace_back(current_mass, winning_mass);
|
||||||
DrawLine3D(current_mass, winning_mass, Fade(TARGET_BLOCK_COLOR, 0.5));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,12 +87,14 @@ auto renderer::draw_mass_springs(const std::vector<Vector3>& masses) -> void
|
|||||||
#endif
|
#endif
|
||||||
const Ray ray = GetScreenToWorldRayEx(
|
const Ray ray = GetScreenToWorldRayEx(
|
||||||
GetMousePosition() - Vector2(GetScreenWidth() / 2.0f, MENU_HEIGHT),
|
GetMousePosition() - Vector2(GetScreenWidth() / 2.0f, MENU_HEIGHT),
|
||||||
camera.camera, graph_target.texture.width, graph_target.texture.height);
|
camera.camera,
|
||||||
RayCollision collision; // Ray collision hit info
|
graph_target.texture.width,
|
||||||
|
graph_target.texture.height);
|
||||||
|
// Ray collision hit info
|
||||||
|
|
||||||
size_t mass = 0;
|
size_t mass = 0;
|
||||||
for (const auto& [x, y, z] : masses) {
|
for (const auto& [x, y, z] : masses) {
|
||||||
collision = GetRayCollisionBox(ray,
|
const RayCollision collision = GetRayCollisionBox(ray,
|
||||||
BoundingBox{
|
BoundingBox{
|
||||||
{
|
{
|
||||||
x - VERTEX_SIZE / 2.0f,
|
x - VERTEX_SIZE / 2.0f,
|
||||||
@ -160,23 +176,53 @@ auto renderer::draw_mass_springs(const std::vector<Vector3>& masses) -> void
|
|||||||
ClearBackground(RAYWHITE);
|
ClearBackground(RAYWHITE);
|
||||||
BeginMode3D(camera.camera);
|
BeginMode3D(camera.camera);
|
||||||
|
|
||||||
// Draw springs (batched)
|
rlDrawRenderBatchActive();
|
||||||
|
|
||||||
|
// Draw edges
|
||||||
{
|
{
|
||||||
#ifdef TRACY
|
#ifdef TRACY
|
||||||
ZoneNamedN(draw_springs, "DrawSprings", true);
|
ZoneNamedN(draw_springs, "DrawSprings", true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
rlBegin(RL_LINES);
|
rlEnableShader(edge_shader.id);
|
||||||
for (const auto& [from, to] : state.get_links()) {
|
|
||||||
if (masses.size() > from && masses.size() > to) {
|
Matrix modelview = rlGetMatrixModelview();
|
||||||
const auto& [ax, ay, az] = masses[from];
|
Matrix projection = rlGetMatrixProjection();
|
||||||
const auto& [bx, by, bz] = masses[to];
|
Matrix mvp = MatrixMultiply(modelview, projection);
|
||||||
rlColor4ub(EDGE_COLOR.r, EDGE_COLOR.g, EDGE_COLOR.b, EDGE_COLOR.a);
|
rlSetUniformMatrix(edge_shader.locs[SHADER_LOC_MATRIX_MVP], mvp);
|
||||||
rlVertex3f(ax, ay, az);
|
|
||||||
rlVertex3f(bx, by, bz);
|
const std::array<float, 4> edge_color = {
|
||||||
}
|
EDGE_COLOR.r / 255.0f,
|
||||||
}
|
EDGE_COLOR.g / 255.0f,
|
||||||
rlEnd();
|
EDGE_COLOR.b / 255.0f,
|
||||||
|
EDGE_COLOR.a / 255.0f
|
||||||
|
};
|
||||||
|
rlSetUniform(edge_color_loc, edge_color.data(), SHADER_UNIFORM_VEC4, 1);
|
||||||
|
|
||||||
|
glBindVertexArray(edge_vao_id);
|
||||||
|
glDrawArrays(GL_LINES, 0, edge_vertices.size());
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
rlDisableShader();
|
||||||
|
|
||||||
|
// This draws triangles:
|
||||||
|
// rlEnableVertexArray(edge_vao_id);
|
||||||
|
// rlColor4ub(EDGE_COLOR.r, EDGE_COLOR.g, EDGE_COLOR.b, EDGE_COLOR.a);
|
||||||
|
// rlDrawVertexArray(0, edge_vertices.size());
|
||||||
|
// rlDisableVertexArray();
|
||||||
|
|
||||||
|
// This is fucking slow:
|
||||||
|
// rlBegin(RL_LINES);
|
||||||
|
// for (const auto& [from, to] : state.get_links()) {
|
||||||
|
// if (masses.size() > from && masses.size() > to) {
|
||||||
|
// const auto& [ax, ay, az] = masses[from];
|
||||||
|
// const auto& [bx, by, bz] = masses[to];
|
||||||
|
// rlColor4ub(EDGE_COLOR.r, EDGE_COLOR.g, EDGE_COLOR.b, EDGE_COLOR.a);
|
||||||
|
// rlVertex3f(ax, ay, az);
|
||||||
|
// rlVertex3f(bx, by, bz);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// rlEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw masses (instanced)
|
// Draw masses (instanced)
|
||||||
|
|||||||
Reference in New Issue
Block a user