summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp190
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h1
-rw-r--r--drivers/gles3/shaders/canvas.glsl97
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp13
-rw-r--r--drivers/gles3/storage/mesh_storage.h20
5 files changed, 182 insertions, 139 deletions
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 5d06224bfd..cdd5217383 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -445,6 +445,9 @@ void RasterizerCanvasGLES3::_render_items(RID p_to_render_target, int p_item_cou
}
void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index) {
+ // Used by Polygon and Mesh.
+ static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+
RS::CanvasItemTextureFilter current_filter = state.default_filter;
RS::CanvasItemTextureRepeat current_repeat = state.default_repeat;
@@ -474,7 +477,10 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
continue;
}
- _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
+ if (c->type != Item::Command::TYPE_MESH) {
+ // For Meshes, this gets updated below.
+ _update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
+ }
for (int i = 0; i < 4; i++) {
state.instance_data_array[r_index].modulation[i] = 0.0;
@@ -680,30 +686,9 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].ninepatch_margins[j] = 0;
}
- // If the previous operation is not done yet, allocate a new buffer
- if (state.fences[state.current_buffer] != GLsync()) {
- GLint syncStatus;
- glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
- if (syncStatus == GL_UNSIGNALED) {
- _allocate_instance_data_buffer();
- } else {
- glDeleteSync(state.fences[state.current_buffer]);
- }
- }
-
- glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
-#ifdef JAVASCRIPT_ENABLED
- //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
- glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData), &state.instance_data_array[0], GL_DYNAMIC_DRAW);
-#else
- void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
- memcpy(ubo, &state.instance_data_array[0], sizeof(InstanceData));
- glUnmapBuffer(GL_UNIFORM_BUFFER);
-#endif
+ _bind_instance_data_buffer(1);
glBindVertexArray(pb->vertex_array);
- static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
-
if (pb->index_buffer != 0) {
glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr);
} else {
@@ -764,12 +749,18 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
case Item::Command::TYPE_MESH:
case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: {
- /*
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
RID mesh;
RID mesh_instance;
RID texture;
Color modulate(1, 1, 1, 1);
- int instance_count = 1;
+ uint32_t instance_count = 1;
+ GLuint multimesh_buffer = 0;
+ uint32_t multimesh_stride = 0;
+ uint32_t multimesh_color_offset = 0;
+ uint32_t multimesh_custom_data_offset = 0;
+ bool multimesh_uses_color = false;
+ bool multimesh_uses_custom_data = false;
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
@@ -781,26 +772,25 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
RID multimesh = mm->multimesh;
- mesh = storage->multimesh_get_mesh(multimesh);
+ mesh = mesh_storage->multimesh_get_mesh(multimesh);
texture = mm->texture;
- if (storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
+ if (mesh_storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
break;
}
- instance_count = storage->multimesh_get_instances_to_draw(multimesh);
+ instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
if (instance_count == 0) {
break;
}
- state.instance_data_array[r_index].flags |= 1; //multimesh, trails disabled
- if (storage->multimesh_uses_colors(multimesh)) {
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
- }
- if (storage->multimesh_uses_custom_data(multimesh)) {
- state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
- }
+ multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
+ multimesh_stride = mesh_storage->multimesh_get_stride(multimesh);
+ multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
+ multimesh_custom_data_offset = mesh_storage->multimesh_get_custom_data_offset(multimesh);
+ multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
+ multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
}
// TODO: implement particles here
@@ -816,8 +806,15 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
}
_bind_canvas_texture(texture, current_filter, current_repeat, r_index);
+ if (instance_count == 1) {
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_ATTRIBUTES);
+ } else if (instance_count > 1) {
+ GLES3::MaterialStorage::get_singleton()->shaders.canvas_shader.version_bind_shader(state.current_shader_version, CanvasShaderGLES3::MODE_INSTANCED);
+ } else {
+ ERR_PRINT("Must have at least one mesh instance to draw mesh");
+ }
- uint32_t surf_count = storage->mesh_get_surface_count(mesh);
+ uint32_t surf_count = mesh_storage->mesh_get_surface_count(mesh);
state.instance_data_array[r_index].modulation[0] = base_color.r * modulate.r;
state.instance_data_array[r_index].modulation[1] = base_color.g * modulate.g;
@@ -829,19 +826,79 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
state.instance_data_array[r_index].dst_rect[j] = 0;
state.instance_data_array[r_index].ninepatch_margins[j] = 0;
}
-
+ _bind_instance_data_buffer(1);
for (uint32_t j = 0; j < surf_count; j++) {
- RS::SurfaceData *surface = storage->mesh_get_surface(mesh, j);
+ void *surface = mesh_storage->mesh_get_surface(mesh, j);
- RS::PrimitiveType primitive = storage->mesh_surface_get_primitive(surface);
+ RS::PrimitiveType primitive = mesh_storage->mesh_surface_get_primitive(surface);
ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
- glBindVertexArray(surface->vertex_array);
- static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+ GLuint vertex_array_gl = 0;
+ GLuint index_array_gl = 0;
+
+ uint32_t input_mask = 0; // 2D meshes always use the same vertex format
+ if (mesh_instance.is_valid()) {
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array_gl);
+ } else {
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array_gl);
+ }
+
+ index_array_gl = mesh_storage->mesh_surface_get_index_buffer(surface, 0);
+ bool use_index_buffer = false;
+ glBindVertexArray(vertex_array_gl);
+ if (index_array_gl != 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
+ use_index_buffer = true;
+ }
+
+ if (instance_count > 1) {
+ // Bind instance buffers.
+ glBindBuffer(GL_ARRAY_BUFFER, multimesh_buffer);
+ glEnableVertexAttribArray(5);
+ glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(0));
+ glVertexAttribDivisor(5, 1);
+ glEnableVertexAttribArray(6);
+ glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(4 * 4));
+ glVertexAttribDivisor(6, 1);
+
+ if (multimesh_uses_color) {
+ glEnableVertexAttribArray(7);
+ glVertexAttribPointer(7, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_color_offset * sizeof(float)));
+ glVertexAttribDivisor(7, 1);
+ }
+ if (multimesh_uses_custom_data) {
+ glEnableVertexAttribArray(8);
+ glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, multimesh_stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(multimesh_custom_data_offset * sizeof(float)));
+ glVertexAttribDivisor(8, 1);
+ }
+ }
+
+ GLenum primitive_gl = prim[int(primitive)];
+ if (instance_count == 1) {
+ if (use_index_buffer) {
+ glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0);
+ } else {
+ glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface));
+ }
+ } else if (instance_count > 1) {
+ if (use_index_buffer) {
+ glDrawElementsInstanced(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), mesh_storage->mesh_surface_get_index_type(surface), 0, instance_count);
+ } else {
+ glDrawArraysInstanced(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(surface), instance_count);
+ }
+ }
+
+ state.fences[state.current_buffer] = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- // Draw directly, no need to batch
+ state.current_buffer = (state.current_buffer + 1) % state.canvas_instance_data_buffers.size();
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ if (instance_count > 1) {
+ glDisableVertexAttribArray(5);
+ glDisableVertexAttribArray(6);
+ glDisableVertexAttribArray(7);
+ glDisableVertexAttribArray(8);
+ }
}
- */
} break;
case Item::Command::TYPE_TRANSFORM: {
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
@@ -886,26 +943,7 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
if (r_index > 0) {
- // If the previous operation is not done yet, allocate a new buffer
- if (state.fences[state.current_buffer] != GLsync()) {
- GLint syncStatus;
- glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
- if (syncStatus == GL_UNSIGNALED) {
- _allocate_instance_data_buffer();
- } else {
- glDeleteSync(state.fences[state.current_buffer]);
- }
- }
-
- glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
-#ifdef JAVASCRIPT_ENABLED
- //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
- glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * r_index, state.instance_data_array, GL_DYNAMIC_DRAW);
-#else
- void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * r_index, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
- memcpy(ubo, state.instance_data_array, sizeof(InstanceData) * r_index);
- glUnmapBuffer(GL_UNIFORM_BUFFER);
-#endif
+ _bind_instance_data_buffer(r_index);
glBindVertexArray(data.canvas_quad_array);
if (state.current_primitive_points == 0) {
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, r_index);
@@ -939,6 +977,32 @@ void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
}
}
+void RasterizerCanvasGLES3::_bind_instance_data_buffer(uint32_t p_max_index) {
+ if (p_max_index == 0) {
+ return;
+ }
+ // If the previous operation is not done yet, allocate a new buffer
+ if (state.fences[state.current_buffer] != GLsync()) {
+ GLint syncStatus;
+ glGetSynciv(state.fences[state.current_buffer], GL_SYNC_STATUS, sizeof(GLint), nullptr, &syncStatus);
+ if (syncStatus == GL_UNSIGNALED) {
+ _allocate_instance_data_buffer();
+ } else {
+ glDeleteSync(state.fences[state.current_buffer]);
+ }
+ }
+
+ glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
+#ifdef JAVASCRIPT_ENABLED
+ //WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * p_max_index, state.instance_data_array, GL_DYNAMIC_DRAW);
+#else
+ void *ubo = glMapBufferRange(GL_UNIFORM_BUFFER, 0, sizeof(InstanceData) * p_max_index, GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT);
+ memcpy(ubo, state.instance_data_array, sizeof(InstanceData) * p_max_index);
+ glUnmapBuffer(GL_UNIFORM_BUFFER);
+#endif
+}
+
RID RasterizerCanvasGLES3::light_create() {
return RID();
}
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index 7fb77f432c..31e82401f9 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -252,6 +252,7 @@ public:
void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool p_to_backbuffer = false);
void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *&current_clip, Light *p_lights, uint32_t &r_index);
void _render_batch(uint32_t &p_max_index);
+ void _bind_instance_data_buffer(uint32_t p_max_index);
void _allocate_instance_data_buffer();
void set_time(double p_time);
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 381a0e8a73..9c426dd3ef 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -5,6 +5,7 @@ mode_quad =
mode_ninepatch = #define USE_NINEPATCH
mode_primitive = #define USE_PRIMITIVE
mode_attributes = #define USE_ATTRIBUTES
+mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
#[specializations]
@@ -20,6 +21,15 @@ layout(location = 4) in vec2 uv_attrib;
layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
+#ifdef USE_INSTANCING
+
+layout(location = 5) in highp vec4 instance_xform0;
+layout(location = 6) in highp vec4 instance_xform1;
+layout(location = 7) in lowp vec4 instance_color;
+layout(location = 8) in highp vec4 instance_custom_data;
+
+#endif
+
#endif
// This needs to be outside clang-format so the ubo comment is in the right place
@@ -77,13 +87,21 @@ void main() {
vec4 bone_weights = vec4(0.0);
#elif defined(USE_ATTRIBUTES)
-
+#ifdef USE_INSTANCING
+ draw_data_instance = 0;
+#endif
vec2 vertex = vertex_attrib;
vec4 color = color_attrib * draw_data[draw_data_instance].modulation;
vec2 uv = uv_attrib;
uvec4 bones = bone_attrib;
vec4 bone_weights = weight_attrib;
+
+#ifdef USE_INSTANCING
+ color *= instance_color;
+ instance_custom = instance_custom_data;
+#endif
+
#else
vec2 vertex_base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
@@ -98,81 +116,10 @@ void main() {
mat4 model_matrix = mat4(vec4(draw_data[draw_data_instance].world_x, 0.0, 0.0), vec4(draw_data[draw_data_instance].world_y, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(draw_data[draw_data_instance].world_ofs, 0.0, 1.0));
- // MultiMeshes don't batch, so always read from draw_data[0]
- uint instancing = draw_data[0].flags & FLAGS_INSTANCING_MASK;
+#ifdef USE_INSTANCING
+ model_matrix = model_matrix * transpose(mat4(instance_xform0, instance_xform1, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)));
+#endif // USE_INSTANCING
-#ifdef USE_ATTRIBUTES
-/*
- if (instancing > 1) {
- // trails
-
- uint stride = 2 + 1 + 1; //particles always uses this format
-
- uint trail_size = instancing;
-
- uint offset = trail_size * stride * gl_InstanceID;
-
- vec4 pcolor;
- vec2 new_vertex;
- {
- uint boffset = offset + bone_attrib.x * stride;
- new_vertex = (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.x;
- pcolor = transforms.data[boffset + 2] * weight_attrib.x;
- }
- if (weight_attrib.y > 0.001) {
- uint boffset = offset + bone_attrib.y * stride;
- new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.y;
- pcolor += transforms.data[boffset + 2] * weight_attrib.y;
- }
- if (weight_attrib.z > 0.001) {
- uint boffset = offset + bone_attrib.z * stride;
- new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.z;
- pcolor += transforms.data[boffset + 2] * weight_attrib.z;
- }
- if (weight_attrib.w > 0.001) {
- uint boffset = offset + bone_attrib.w * stride;
- new_vertex += (vec4(vertex, 0.0, 1.0) * mat4(transforms.data[boffset + 0], transforms.data[boffset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))).xy * weight_attrib.w;
- pcolor += transforms.data[boffset + 2] * weight_attrib.w;
- }
-
- instance_custom = transforms.data[offset + 3];
-
- vertex = new_vertex;
- color *= pcolor;
- } else*/
-#endif // USE_ATTRIBUTES
-/*
- {
- if (instancing == 1) {
- uint stride = 2;
- {
- if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_COLORS)) {
- stride += 1;
- }
- if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
- stride += 1;
- }
- }
-
- uint offset = stride * gl_InstanceID;
-
- mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
- offset += 2;
-
- if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_COLORS)) {
- color *= transforms.data[offset];
- offset += 1;
- }
-
- if (bool(draw_data[0].flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) {
- instance_custom = transforms.data[offset];
- }
-
- matrix = transpose(matrix);
- model_matrix = model_matrix * matrix;
- }
- }
-*/
#if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) {
//scale by texture size
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 3be1792868..822be25337 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -722,6 +722,18 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
for (int i = 0; i < RS::ARRAY_INDEX; i++) {
if (!attribs[i].enabled) {
+ glDisableVertexAttribArray(i);
+ if (s->format & RS::ARRAY_FLAG_USE_2D_VERTICES) {
+ if (i == RS::ARRAY_COLOR) {
+ glVertexAttrib4f(i, 1, 1, 1, 1);
+ } else if (i == RS::ARRAY_TEX_UV) {
+ glVertexAttrib2f(i, 1, 1);
+ } else if (i == RS::ARRAY_BONES) {
+ glVertexAttrib4f(i, 1, 1, 1, 1);
+ } else if (i == RS::ARRAY_WEIGHTS) {
+ glVertexAttrib4f(i, 1, 1, 1, 1);
+ }
+ }
continue;
}
if (i <= RS::ARRAY_TANGENT) {
@@ -941,7 +953,6 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
multimesh->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0);
multimesh->buffer_set = false;
- //print_line("allocate, elements: " + itos(p_instances) + " 2D: " + itos(p_transform_format == RS::MULTIMESH_TRANSFORM_2D) + " colors " + itos(multimesh->uses_colors) + " data " + itos(multimesh->uses_custom_data) + " stride " + itos(multimesh->stride_cache) + " total size " + itos(multimesh->stride_cache * multimesh->instances));
multimesh->data_cache = Vector<float>();
multimesh->aabb = AABB();
multimesh->aabb_dirty = false;
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index 991777842f..068aa2fe40 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -493,6 +493,26 @@ public:
return multimesh->instances;
}
+ _FORCE_INLINE_ GLuint multimesh_get_gl_buffer(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->buffer;
+ }
+
+ _FORCE_INLINE_ uint32_t multimesh_get_stride(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->stride_cache;
+ }
+
+ _FORCE_INLINE_ uint32_t multimesh_get_color_offset(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->color_offset_cache;
+ }
+
+ _FORCE_INLINE_ uint32_t multimesh_get_custom_data_offset(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ return multimesh->custom_data_offset_cache;
+ }
+
/* SKELETON API */
Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };