From bae6f86257ffb9bed915bcd0d6fa41e1da39894a Mon Sep 17 00:00:00 2001 From: Dominic Date: Fri, 1 Dec 2023 13:26:03 -0500 Subject: [PATCH] Add wireframe for compatibility mode --- drivers/gles3/rasterizer_scene_gles3.cpp | 34 +++++++++--- drivers/gles3/storage/config.h | 3 +- drivers/gles3/storage/mesh_storage.cpp | 69 ++++++++++++++++++++++++ drivers/gles3/storage/mesh_storage.h | 18 +++++++ drivers/gles3/storage/utilities.cpp | 2 + 5 files changed, 118 insertions(+), 8 deletions(-) diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 205f9a552ef..8cacb511ac2 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -2758,6 +2758,15 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, prev_index_array_gl = 0; } + bool use_wireframe = false; + if (p_params->force_wireframe) { + GLuint wireframe_index_array_gl = mesh_storage->mesh_surface_get_index_buffer_wireframe(mesh_surface); + if (wireframe_index_array_gl) { + index_array_gl = wireframe_index_array_gl; + use_wireframe = true; + } + } + bool use_index_buffer = index_array_gl != 0; if (prev_index_array_gl != index_array_gl) { if (index_array_gl != 0) { @@ -2946,6 +2955,11 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, count = mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface); } + if (use_wireframe) { + // In this case we are using index count, and we need double the indices for the wireframe mesh. + count = count * 2; + } + if constexpr (p_pass_mode != PASS_MODE_DEPTH) { // Don't count draw calls during depth pre-pass to match the RD renderers. if (p_render_data->render_info) { @@ -3000,17 +3014,25 @@ void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, glVertexAttribI4ui(15, default_color, default_color, default_custom, default_custom); } - if (use_index_buffer) { - glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count); + if (use_wireframe) { + glDrawElementsInstanced(GL_LINES, count, GL_UNSIGNED_INT, 0, inst->instance_count); } else { - glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count); + if (use_index_buffer) { + glDrawElementsInstanced(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0, inst->instance_count); + } else { + glDrawArraysInstanced(primitive_gl, 0, count, inst->instance_count); + } } } else { // Using regular Mesh. - if (use_index_buffer) { - glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0); + if (use_wireframe) { + glDrawElements(GL_LINES, count, GL_UNSIGNED_INT, 0); } else { - glDrawArrays(primitive_gl, 0, count); + if (use_index_buffer) { + glDrawElements(primitive_gl, count, mesh_storage->mesh_surface_get_index_type(mesh_surface), 0); + } else { + glDrawArrays(primitive_gl, 0, count); + } } } diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index b2dd98f0258..3b097f8e662 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -63,8 +63,7 @@ public: int64_t max_renderable_lights = 0; int64_t max_lights_per_object = 0; - // TODO implement wireframe in OpenGL - // bool generate_wireframes; + bool generate_wireframes = false; HashSet extensions; diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp index 88ee749ed66..7d1742baea6 100644 --- a/drivers/gles3/storage/mesh_storage.cpp +++ b/drivers/gles3/storage/mesh_storage.cpp @@ -31,6 +31,7 @@ #ifdef GLES3_ENABLED #include "mesh_storage.h" +#include "config.h" #include "material_storage.h" #include "utilities.h" @@ -285,6 +286,69 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) ERR_FAIL_COND_MSG(!new_surface.index_count && !new_surface.vertex_count, "Meshes must contain a vertex array, an index array, or both"); + if (GLES3::Config::get_singleton()->generate_wireframes && s->primitive == RS::PRIMITIVE_TRIANGLES) { + // Generate wireframes. This is mostly used by the editor. + s->wireframe = memnew(Mesh::Surface::Wireframe); + Vector wf_indices; + uint32_t &wf_index_count = s->wireframe->index_count; + uint32_t *wr = nullptr; + + if (new_surface.format & RS::ARRAY_FORMAT_INDEX) { + wf_index_count = s->index_count * 2; + wf_indices.resize(wf_index_count); + + Vector ir = new_surface.index_data; + wr = wf_indices.ptrw(); + + if (new_surface.vertex_count < (1 << 16)) { + // Read 16 bit indices. + const uint16_t *src_idx = (const uint16_t *)ir.ptr(); + for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) { + // We use GL_LINES instead of GL_TRIANGLES for drawing these primitives later, + // so we need double the indices for each triangle. + wr[i + 0] = src_idx[i / 2]; + wr[i + 1] = src_idx[i / 2 + 1]; + wr[i + 2] = src_idx[i / 2 + 1]; + wr[i + 3] = src_idx[i / 2 + 2]; + wr[i + 4] = src_idx[i / 2 + 2]; + wr[i + 5] = src_idx[i / 2]; + } + + } else { + // Read 32 bit indices. + const uint32_t *src_idx = (const uint32_t *)ir.ptr(); + for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) { + wr[i + 0] = src_idx[i / 2]; + wr[i + 1] = src_idx[i / 2 + 1]; + wr[i + 2] = src_idx[i / 2 + 1]; + wr[i + 3] = src_idx[i / 2 + 2]; + wr[i + 4] = src_idx[i / 2 + 2]; + wr[i + 5] = src_idx[i / 2]; + } + } + } else { + // Not using indices. + wf_index_count = s->vertex_count * 2; + wf_indices.resize(wf_index_count); + wr = wf_indices.ptrw(); + + for (uint32_t i = 0; i + 5 < wf_index_count; i += 6) { + wr[i + 0] = i / 2; + wr[i + 1] = i / 2 + 1; + wr[i + 2] = i / 2 + 1; + wr[i + 3] = i / 2 + 2; + wr[i + 4] = i / 2 + 2; + wr[i + 5] = i / 2; + } + } + + s->wireframe->index_buffer_size = wf_index_count * sizeof(uint32_t); + glGenBuffers(1, &s->wireframe->index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->wireframe->index_buffer); + GLES3::Utilities::get_singleton()->buffer_allocate_data(GL_ELEMENT_ARRAY_BUFFER, s->wireframe->index_buffer, s->wireframe->index_buffer_size, wr, GL_STATIC_DRAW, "Mesh wireframe index buffer"); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // unbind + } + s->aabb = new_surface.aabb; s->bone_aabbs = new_surface.bone_aabbs; //only really useful for returning them. @@ -712,6 +776,11 @@ void MeshStorage::mesh_clear(RID p_mesh) { memfree(s.versions); //reallocs, so free with memfree. } + if (s.wireframe) { + GLES3::Utilities::get_singleton()->buffer_free_data(s.wireframe->index_buffer); + memdelete(s.wireframe); + } + if (s.lod_count) { for (uint32_t j = 0; j < s.lod_count; j++) { if (s.lods[j].index_buffer != 0) { diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h index 25b15ab6a68..f52a60d067a 100644 --- a/drivers/gles3/storage/mesh_storage.h +++ b/drivers/gles3/storage/mesh_storage.h @@ -84,6 +84,14 @@ struct Mesh { uint32_t index_count = 0; uint32_t index_buffer_size = 0; + struct Wireframe { + GLuint index_buffer = 0; + uint32_t index_count = 0; + uint32_t index_buffer_size = 0; + }; + + Wireframe *wireframe = nullptr; + struct LOD { float edge_length = 0.0; uint32_t index_count = 0; @@ -376,6 +384,16 @@ public: } } + _FORCE_INLINE_ GLuint mesh_surface_get_index_buffer_wireframe(void *p_surface) const { + Mesh::Surface *s = reinterpret_cast(p_surface); + + if (s->wireframe) { + return s->wireframe->index_buffer; + } + + return 0; + } + _FORCE_INLINE_ GLenum mesh_surface_get_index_type(void *p_surface) const { Mesh::Surface *s = reinterpret_cast(p_surface); diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp index 72bcbe879c7..29b265e3271 100644 --- a/drivers/gles3/storage/utilities.cpp +++ b/drivers/gles3/storage/utilities.cpp @@ -327,6 +327,8 @@ void Utilities::update_dirty_resources() { } void Utilities::set_debug_generate_wireframes(bool p_generate) { + Config *config = Config::get_singleton(); + config->generate_wireframes = p_generate; } bool Utilities::has_os_feature(const String &p_feature) const {