Browse Source

Add wireframe for compatibility mode

Dominic 1 year ago
parent
commit
bae6f86257

+ 28 - 6
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);
+					}
 				}
 			}
 

+ 1 - 2
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<String> extensions;
 

+ 69 - 0
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<uint32_t> 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<uint8_t> 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) {

+ 18 - 0
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<Mesh::Surface *>(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<Mesh::Surface *>(p_surface);
 

+ 2 - 0
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 {