Merge pull request #61425 from clayjohn/GLES3-2D
This commit is contained in:
commit
20a1b85589
|
@ -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 *¤t_clip, Light *p_lights, uint32_t &r_index) {
|
void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_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::CanvasItemTextureFilter current_filter = state.default_filter;
|
||||||
RS::CanvasItemTextureRepeat current_repeat = state.default_repeat;
|
RS::CanvasItemTextureRepeat current_repeat = state.default_repeat;
|
||||||
|
|
||||||
|
@ -474,7 +477,10 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
_update_transform_2d_to_mat2x3(base_transform * draw_transform, state.instance_data_array[r_index].world);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
state.instance_data_array[r_index].modulation[i] = 0.0;
|
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;
|
state.instance_data_array[r_index].ninepatch_margins[j] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the previous operation is not done yet, allocate a new buffer
|
_bind_instance_data_buffer(1);
|
||||||
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
|
|
||||||
glBindVertexArray(pb->vertex_array);
|
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) {
|
if (pb->index_buffer != 0) {
|
||||||
glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr);
|
glDrawElements(prim[polygon->primitive], pb->count, GL_UNSIGNED_INT, nullptr);
|
||||||
} else {
|
} 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_MESH:
|
||||||
case Item::Command::TYPE_MULTIMESH:
|
case Item::Command::TYPE_MULTIMESH:
|
||||||
case Item::Command::TYPE_PARTICLES: {
|
case Item::Command::TYPE_PARTICLES: {
|
||||||
/*
|
GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
|
||||||
RID mesh;
|
RID mesh;
|
||||||
RID mesh_instance;
|
RID mesh_instance;
|
||||||
RID texture;
|
RID texture;
|
||||||
Color modulate(1, 1, 1, 1);
|
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) {
|
if (c->type == Item::Command::TYPE_MESH) {
|
||||||
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
|
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) {
|
} else if (c->type == Item::Command::TYPE_MULTIMESH) {
|
||||||
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
|
const Item::CommandMultiMesh *mm = static_cast<const Item::CommandMultiMesh *>(c);
|
||||||
RID multimesh = mm->multimesh;
|
RID multimesh = mm->multimesh;
|
||||||
mesh = storage->multimesh_get_mesh(multimesh);
|
mesh = mesh_storage->multimesh_get_mesh(multimesh);
|
||||||
texture = mm->texture;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance_count = storage->multimesh_get_instances_to_draw(multimesh);
|
instance_count = mesh_storage->multimesh_get_instances_to_draw(multimesh);
|
||||||
|
|
||||||
if (instance_count == 0) {
|
if (instance_count == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.instance_data_array[r_index].flags |= 1; //multimesh, trails disabled
|
multimesh_buffer = mesh_storage->multimesh_get_gl_buffer(multimesh);
|
||||||
if (storage->multimesh_uses_colors(multimesh)) {
|
multimesh_stride = mesh_storage->multimesh_get_stride(multimesh);
|
||||||
state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_COLORS;
|
multimesh_color_offset = mesh_storage->multimesh_get_color_offset(multimesh);
|
||||||
}
|
multimesh_custom_data_offset = mesh_storage->multimesh_get_custom_data_offset(multimesh);
|
||||||
if (storage->multimesh_uses_custom_data(multimesh)) {
|
multimesh_uses_color = mesh_storage->multimesh_uses_colors(multimesh);
|
||||||
state.instance_data_array[r_index].flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
|
multimesh_uses_custom_data = mesh_storage->multimesh_uses_custom_data(multimesh);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: implement particles here
|
// 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);
|
_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[0] = base_color.r * modulate.r;
|
||||||
state.instance_data_array[r_index].modulation[1] = base_color.g * modulate.g;
|
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].dst_rect[j] = 0;
|
||||||
state.instance_data_array[r_index].ninepatch_margins[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++) {
|
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);
|
ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
|
||||||
|
|
||||||
glBindVertexArray(surface->vertex_array);
|
GLuint vertex_array_gl = 0;
|
||||||
static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
|
GLuint index_array_gl = 0;
|
||||||
|
|
||||||
// Draw directly, no need to batch
|
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);
|
||||||
|
|
||||||
|
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;
|
} break;
|
||||||
case Item::Command::TYPE_TRANSFORM: {
|
case Item::Command::TYPE_TRANSFORM: {
|
||||||
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
|
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) {
|
void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
|
||||||
if (r_index > 0) {
|
if (r_index > 0) {
|
||||||
// If the previous operation is not done yet, allocate a new buffer
|
_bind_instance_data_buffer(r_index);
|
||||||
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
|
|
||||||
glBindVertexArray(data.canvas_quad_array);
|
glBindVertexArray(data.canvas_quad_array);
|
||||||
if (state.current_primitive_points == 0) {
|
if (state.current_primitive_points == 0) {
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, r_index);
|
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() {
|
RID RasterizerCanvasGLES3::light_create() {
|
||||||
return RID();
|
return RID();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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 *¤t_clip, Light *p_lights, uint32_t &r_index);
|
void _render_item(RID p_render_target, const Item *p_item, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, uint32_t &r_index);
|
||||||
void _render_batch(uint32_t &p_max_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 _allocate_instance_data_buffer();
|
||||||
|
|
||||||
void set_time(double p_time);
|
void set_time(double p_time);
|
||||||
|
|
|
@ -5,6 +5,7 @@ mode_quad =
|
||||||
mode_ninepatch = #define USE_NINEPATCH
|
mode_ninepatch = #define USE_NINEPATCH
|
||||||
mode_primitive = #define USE_PRIMITIVE
|
mode_primitive = #define USE_PRIMITIVE
|
||||||
mode_attributes = #define USE_ATTRIBUTES
|
mode_attributes = #define USE_ATTRIBUTES
|
||||||
|
mode_instanced = #define USE_ATTRIBUTES \n#define USE_INSTANCING
|
||||||
|
|
||||||
#[specializations]
|
#[specializations]
|
||||||
|
|
||||||
|
@ -20,6 +21,15 @@ layout(location = 4) in vec2 uv_attrib;
|
||||||
layout(location = 10) in uvec4 bone_attrib;
|
layout(location = 10) in uvec4 bone_attrib;
|
||||||
layout(location = 11) in vec4 weight_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
|
#endif
|
||||||
|
|
||||||
// This needs to be outside clang-format so the ubo comment is in the right place
|
// 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);
|
vec4 bone_weights = vec4(0.0);
|
||||||
|
|
||||||
#elif defined(USE_ATTRIBUTES)
|
#elif defined(USE_ATTRIBUTES)
|
||||||
|
#ifdef USE_INSTANCING
|
||||||
|
draw_data_instance = 0;
|
||||||
|
#endif
|
||||||
vec2 vertex = vertex_attrib;
|
vec2 vertex = vertex_attrib;
|
||||||
vec4 color = color_attrib * draw_data[draw_data_instance].modulation;
|
vec4 color = color_attrib * draw_data[draw_data_instance].modulation;
|
||||||
vec2 uv = uv_attrib;
|
vec2 uv = uv_attrib;
|
||||||
|
|
||||||
uvec4 bones = bone_attrib;
|
uvec4 bones = bone_attrib;
|
||||||
vec4 bone_weights = weight_attrib;
|
vec4 bone_weights = weight_attrib;
|
||||||
|
|
||||||
|
#ifdef USE_INSTANCING
|
||||||
|
color *= instance_color;
|
||||||
|
instance_custom = instance_custom_data;
|
||||||
|
#endif
|
||||||
|
|
||||||
#else
|
#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));
|
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));
|
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]
|
#ifdef USE_INSTANCING
|
||||||
uint instancing = draw_data[0].flags & FLAGS_INSTANCING_MASK;
|
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 !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE)
|
||||||
if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) {
|
if (bool(draw_data[draw_data_instance].flags & FLAGS_USING_PARTICLES)) {
|
||||||
//scale by texture size
|
//scale by texture size
|
||||||
|
|
|
@ -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++) {
|
for (int i = 0; i < RS::ARRAY_INDEX; i++) {
|
||||||
if (!attribs[i].enabled) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
if (i <= RS::ARRAY_TANGENT) {
|
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->stride_cache = multimesh->custom_data_offset_cache + (p_use_custom_data ? 4 : 0);
|
||||||
multimesh->buffer_set = false;
|
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->data_cache = Vector<float>();
|
||||||
multimesh->aabb = AABB();
|
multimesh->aabb = AABB();
|
||||||
multimesh->aabb_dirty = false;
|
multimesh->aabb_dirty = false;
|
||||||
|
|
|
@ -493,6 +493,26 @@ public:
|
||||||
return multimesh->instances;
|
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 API */
|
||||||
|
|
||||||
Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };
|
Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };
|
||||||
|
|
|
@ -29,3 +29,102 @@
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
#include "renderer_canvas_render.h"
|
#include "renderer_canvas_render.h"
|
||||||
|
#include "servers/rendering/rendering_server_globals.h"
|
||||||
|
|
||||||
|
const Rect2 &RendererCanvasRender::Item::get_rect() const {
|
||||||
|
if (custom_rect || (!rect_dirty && !update_when_visible)) {
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
//must update rect
|
||||||
|
|
||||||
|
if (commands == nullptr) {
|
||||||
|
rect = Rect2();
|
||||||
|
rect_dirty = false;
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform2D xf;
|
||||||
|
bool found_xform = false;
|
||||||
|
bool first = true;
|
||||||
|
|
||||||
|
const Item::Command *c = commands;
|
||||||
|
|
||||||
|
while (c) {
|
||||||
|
Rect2 r;
|
||||||
|
|
||||||
|
switch (c->type) {
|
||||||
|
case Item::Command::TYPE_RECT: {
|
||||||
|
const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c);
|
||||||
|
r = crect->rect;
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Item::Command::TYPE_NINEPATCH: {
|
||||||
|
const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c);
|
||||||
|
r = style->rect;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Item::Command::TYPE_POLYGON: {
|
||||||
|
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
|
||||||
|
r = polygon->polygon.rect_cache;
|
||||||
|
} break;
|
||||||
|
case Item::Command::TYPE_PRIMITIVE: {
|
||||||
|
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
|
||||||
|
for (uint32_t j = 0; j < primitive->point_count; j++) {
|
||||||
|
if (j == 0) {
|
||||||
|
r.position = primitive->points[0];
|
||||||
|
} else {
|
||||||
|
r.expand_to(primitive->points[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Item::Command::TYPE_MESH: {
|
||||||
|
const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c);
|
||||||
|
AABB aabb = RSG::mesh_storage->mesh_get_aabb(mesh->mesh, RID());
|
||||||
|
|
||||||
|
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Item::Command::TYPE_MULTIMESH: {
|
||||||
|
const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c);
|
||||||
|
AABB aabb = RSG::mesh_storage->multimesh_get_aabb(multimesh->multimesh);
|
||||||
|
|
||||||
|
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Item::Command::TYPE_PARTICLES: {
|
||||||
|
const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c);
|
||||||
|
if (particles_cmd->particles.is_valid()) {
|
||||||
|
AABB aabb = RendererRD::ParticlesStorage::get_singleton()->particles_get_aabb(particles_cmd->particles);
|
||||||
|
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Item::Command::TYPE_TRANSFORM: {
|
||||||
|
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
|
||||||
|
xf = transform->xform;
|
||||||
|
found_xform = true;
|
||||||
|
[[fallthrough]];
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
c = c->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_xform) {
|
||||||
|
r = xf.xform(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
rect = r;
|
||||||
|
first = false;
|
||||||
|
} else {
|
||||||
|
rect = rect.merge(r);
|
||||||
|
}
|
||||||
|
c = c->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
rect_dirty = false;
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
|
@ -356,103 +356,7 @@ public:
|
||||||
|
|
||||||
Rect2 global_rect_cache;
|
Rect2 global_rect_cache;
|
||||||
|
|
||||||
const Rect2 &get_rect() const {
|
const Rect2 &get_rect() const;
|
||||||
if (custom_rect || (!rect_dirty && !update_when_visible)) {
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
//must update rect
|
|
||||||
|
|
||||||
if (commands == nullptr) {
|
|
||||||
rect = Rect2();
|
|
||||||
rect_dirty = false;
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform2D xf;
|
|
||||||
bool found_xform = false;
|
|
||||||
bool first = true;
|
|
||||||
|
|
||||||
const Item::Command *c = commands;
|
|
||||||
|
|
||||||
while (c) {
|
|
||||||
Rect2 r;
|
|
||||||
|
|
||||||
switch (c->type) {
|
|
||||||
case Item::Command::TYPE_RECT: {
|
|
||||||
const Item::CommandRect *crect = static_cast<const Item::CommandRect *>(c);
|
|
||||||
r = crect->rect;
|
|
||||||
|
|
||||||
} break;
|
|
||||||
case Item::Command::TYPE_NINEPATCH: {
|
|
||||||
const Item::CommandNinePatch *style = static_cast<const Item::CommandNinePatch *>(c);
|
|
||||||
r = style->rect;
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case Item::Command::TYPE_POLYGON: {
|
|
||||||
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(c);
|
|
||||||
r = polygon->polygon.rect_cache;
|
|
||||||
} break;
|
|
||||||
case Item::Command::TYPE_PRIMITIVE: {
|
|
||||||
const Item::CommandPrimitive *primitive = static_cast<const Item::CommandPrimitive *>(c);
|
|
||||||
for (uint32_t j = 0; j < primitive->point_count; j++) {
|
|
||||||
if (j == 0) {
|
|
||||||
r.position = primitive->points[0];
|
|
||||||
} else {
|
|
||||||
r.expand_to(primitive->points[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
case Item::Command::TYPE_MESH: {
|
|
||||||
const Item::CommandMesh *mesh = static_cast<const Item::CommandMesh *>(c);
|
|
||||||
AABB aabb = RendererRD::MeshStorage::get_singleton()->mesh_get_aabb(mesh->mesh, RID());
|
|
||||||
|
|
||||||
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
|
||||||
|
|
||||||
} break;
|
|
||||||
case Item::Command::TYPE_MULTIMESH: {
|
|
||||||
const Item::CommandMultiMesh *multimesh = static_cast<const Item::CommandMultiMesh *>(c);
|
|
||||||
AABB aabb = RendererRD::MeshStorage::get_singleton()->multimesh_get_aabb(multimesh->multimesh);
|
|
||||||
|
|
||||||
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
|
||||||
|
|
||||||
} break;
|
|
||||||
case Item::Command::TYPE_PARTICLES: {
|
|
||||||
const Item::CommandParticles *particles_cmd = static_cast<const Item::CommandParticles *>(c);
|
|
||||||
if (particles_cmd->particles.is_valid()) {
|
|
||||||
AABB aabb = RendererRD::ParticlesStorage::get_singleton()->particles_get_aabb(particles_cmd->particles);
|
|
||||||
r = Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
} break;
|
|
||||||
case Item::Command::TYPE_TRANSFORM: {
|
|
||||||
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
|
|
||||||
xf = transform->xform;
|
|
||||||
found_xform = true;
|
|
||||||
[[fallthrough]];
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
c = c->next;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found_xform) {
|
|
||||||
r = xf.xform(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
rect = r;
|
|
||||||
first = false;
|
|
||||||
} else {
|
|
||||||
rect = rect.merge(r);
|
|
||||||
}
|
|
||||||
c = c->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
rect_dirty = false;
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
Command *commands = nullptr;
|
Command *commands = nullptr;
|
||||||
Command *last_command = nullptr;
|
Command *last_command = nullptr;
|
||||||
|
|
Loading…
Reference in New Issue