Fixes missng 2D engine bits

-Mesh2D now works
-MultiMesh2D now works
-Polygon2D now works
-Added hooks for processing 2D particles
-Skeleton2D now works

2D particles still not working, but stuff needed for it is now implemented.
This commit is contained in:
reduz 2021-05-10 13:12:44 -03:00
parent a1cc6b45dc
commit 479391ef54
18 changed files with 395 additions and 308 deletions

View file

@ -705,286 +705,128 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, const Item
case Item::Command::TYPE_MESH:
case Item::Command::TYPE_MULTIMESH:
case Item::Command::TYPE_PARTICLES: {
ERR_PRINT("FIXME: Mesh, MultiMesh and Particles render commands are unimplemented currently, they need to be ported to the 4.0 rendering architecture.");
#ifndef _MSC_VER
#warning Item::Command types for Mesh, MultiMesh and Particles need to be implemented.
#endif
// See #if 0'ed code below to port from GLES3.
} break;
RID mesh;
RID mesh_instance;
RID texture;
Color modulate(1, 1, 1, 1);
float world_backup[6];
int instance_count = 1;
#if 0
case Item::Command::TYPE_MESH: {
Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(c);
_set_texture_rect_mode(false);
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map);
if (texture) {
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
for (int j = 0; j < 6; j++) {
world_backup[j] = push_constant.world[j];
}
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform);
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *m = static_cast<const Item::CommandMesh *>(c);
mesh = m->mesh;
mesh_instance = m->mesh_instance;
texture = m->texture;
modulate = m->modulate;
_update_transform_2d_to_mat2x3(base_transform * m->transform, push_constant.world);
} 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);
texture = mm->texture;
RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh);
if (mesh_data) {
for (int j = 0; j < mesh_data->surfaces.size(); j++) {
RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
// materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
glBindVertexArray(s->array_id);
glVertexAttrib4f(RS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a);
if (s->index_array_len) {
glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0);
} else {
glDrawArrays(gl_primitive[s->primitive], 0, s->array_len);
}
glBindVertexArray(0);
if (storage->multimesh_get_transform_format(multimesh) != RS::MULTIMESH_TRANSFORM_2D) {
break;
}
instance_count = storage->multimesh_get_instances_to_draw(multimesh);
RID uniform_set = storage->multimesh_get_2d_uniform_set(multimesh, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
push_constant.flags |= 1; //multimesh, trails disabled
if (storage->multimesh_uses_colors(multimesh)) {
push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS;
}
if (storage->multimesh_uses_custom_data(multimesh)) {
push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
}
} else if (c->type == Item::Command::TYPE_PARTICLES) {
const Item::CommandParticles *pt = static_cast<const Item::CommandParticles *>(c);
ERR_BREAK(storage->particles_get_mode(pt->particles) != RS::PARTICLES_MODE_2D);
if (storage->particles_is_inactive(pt->particles)) {
break;
}
int dpc = storage->particles_get_draw_passes(pt->particles);
if (dpc == 0) {
break; //nothing to draw
}
uint32_t divisor = 1;
instance_count = storage->particles_get_amount(pt->particles, divisor);
RID uniform_set = storage->particles_get_instance_buffer_uniform_set(pt->particles, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET);
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET);
push_constant.flags |= divisor;
instance_count /= divisor;
push_constant.flags |= FLAGS_INSTANCING_HAS_COLORS;
push_constant.flags |= FLAGS_INSTANCING_HAS_CUSTOM_DATA;
mesh = storage->particles_get_draw_pass_mesh(pt->particles, 0); //higher ones are ignored
texture = pt->texture;
}
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform);
} break;
case Item::Command::TYPE_MULTIMESH: {
Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c);
RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh);
if (!multi_mesh)
if (mesh.is_null()) {
break;
RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh);
if (!mesh_data)
break;
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != RS::MULTIMESH_CUSTOM_DATA_NONE);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
//reset shader and force rebind
state.using_texture_rect = true;
_set_texture_rect_mode(false);
if (texture) {
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
}
int amount = MIN(multi_mesh->size, multi_mesh->visible_instances);
_bind_canvas_texture(p_draw_list, texture, current_filter, current_repeat, last_texture, push_constant, texpixel_size);
if (amount == -1) {
amount = multi_mesh->size;
uint32_t surf_count = storage->mesh_get_surface_count(mesh);
static const PipelineVariant variant[RS::PRIMITIVE_MAX] = { PIPELINE_VARIANT_ATTRIBUTE_POINTS, PIPELINE_VARIANT_ATTRIBUTE_LINES, PIPELINE_VARIANT_ATTRIBUTE_LINES_STRIP, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLES, PIPELINE_VARIANT_ATTRIBUTE_TRIANGLE_STRIP };
push_constant.modulation[0] = base_color.r * modulate.r;
push_constant.modulation[1] = base_color.g * modulate.g;
push_constant.modulation[2] = base_color.b * modulate.b;
push_constant.modulation[3] = base_color.a * modulate.a;
for (int j = 0; j < 4; j++) {
push_constant.src_rect[j] = 0;
push_constant.dst_rect[j] = 0;
push_constant.ninepatch_margins[j] = 0;
}
for (int j = 0; j < mesh_data->surfaces.size(); j++) {
RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
// materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
glBindVertexArray(s->instancing_array_id);
for (uint32_t j = 0; j < surf_count; j++) {
void *surface = storage->mesh_get_surface(mesh, j);
glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer
RS::PrimitiveType primitive = storage->mesh_surface_get_primitive(surface);
ERR_CONTINUE(primitive < 0 || primitive >= RS::PRIMITIVE_MAX);
int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4;
glEnableVertexAttribArray(8);
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0));
glVertexAttribDivisor(8, 1);
glEnableVertexAttribArray(9);
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4));
glVertexAttribDivisor(9, 1);
uint32_t input_mask = pipeline_variants->variants[light_mode][variant[primitive]].get_vertex_input_mask();
int color_ofs;
RID vertex_array;
RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
if (multi_mesh->transform_format == RS::MULTIMESH_TRANSFORM_3D) {
glEnableVertexAttribArray(10);
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4));
glVertexAttribDivisor(10, 1);
color_ofs = 12 * 4;
if (mesh_instance.is_valid()) {
storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array, vertex_format);
} else {
glDisableVertexAttribArray(10);
glVertexAttrib4f(10, 0, 0, 1, 0);
color_ofs = 8 * 4;
storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array, vertex_format);
}
int custom_data_ofs = color_ofs;
RID pipeline = pipeline_variants->variants[light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
switch (multi_mesh->color_format) {
case RS::MULTIMESH_COLOR_NONE: {
glDisableVertexAttribArray(11);
glVertexAttrib4f(11, 1, 1, 1, 1);
} break;
case RS::MULTIMESH_COLOR_8BIT: {
glEnableVertexAttribArray(11);
glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs));
glVertexAttribDivisor(11, 1);
custom_data_ofs += 4;
RID index_array = storage->mesh_surface_get_index_array(surface, 0);
} break;
case RS::MULTIMESH_COLOR_FLOAT: {
glEnableVertexAttribArray(11);
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs));
glVertexAttribDivisor(11, 1);
custom_data_ofs += 4 * 4;
} break;
if (index_array.is_valid()) {
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, index_array);
}
switch (multi_mesh->custom_data_format) {
case RS::MULTIMESH_CUSTOM_DATA_NONE: {
glDisableVertexAttribArray(12);
glVertexAttrib4f(12, 1, 1, 1, 1);
} break;
case RS::MULTIMESH_CUSTOM_DATA_8BIT: {
glEnableVertexAttribArray(12);
glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs));
glVertexAttribDivisor(12, 1);
RD::get_singleton()->draw_list_bind_vertex_array(p_draw_list, vertex_array);
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
} break;
case RS::MULTIMESH_CUSTOM_DATA_FLOAT: {
glEnableVertexAttribArray(12);
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs));
glVertexAttribDivisor(12, 1);
} break;
}
if (s->index_array_len) {
glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount);
} else {
glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount);
}
glBindVertexArray(0);
RD::get_singleton()->draw_list_draw(p_draw_list, index_array.is_valid(), instance_count);
}
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
state.using_texture_rect = true;
_set_texture_rect_mode(false);
for (int j = 0; j < 6; j++) {
push_constant.world[j] = world_backup[j];
}
} break;
case Item::Command::TYPE_PARTICLES: {
Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c);
RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getornull(particles_cmd->particles);
if (!particles)
break;
if (particles->inactive && !particles->emitting)
break;
glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
RenderingServerDefault::redraw_request();
storage->particles_request_process(particles_cmd->particles);
//enable instancing
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, true);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, true);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
//reset shader and force rebind
state.using_texture_rect = true;
_set_texture_rect_mode(false);
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map);
if (texture) {
Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
} else {
state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0));
}
if (!particles->use_local_coords) {
Transform2D inv_xf;
inv_xf.set_axis(0, Vector2(particles->emission_transform.basis.get_axis(0).x, particles->emission_transform.basis.get_axis(0).y));
inv_xf.set_axis(1, Vector2(particles->emission_transform.basis.get_axis(1).x, particles->emission_transform.basis.get_axis(1).y));
inv_xf.set_origin(Vector2(particles->emission_transform.get_origin().x, particles->emission_transform.get_origin().y));
inv_xf.affine_invert();
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf);
}
glBindVertexArray(data.particle_quad_array); //use particle quad array
glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer
int stride = sizeof(float) * 4 * 6;
int amount = particles->amount;
if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_LIFETIME) {
glEnableVertexAttribArray(8); //xform x
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3));
glVertexAttribDivisor(8, 1);
glEnableVertexAttribArray(9); //xform y
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4));
glVertexAttribDivisor(9, 1);
glEnableVertexAttribArray(10); //xform z
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5));
glVertexAttribDivisor(10, 1);
glEnableVertexAttribArray(11); //color
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
glVertexAttribDivisor(11, 1);
glEnableVertexAttribArray(12); //custom
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2));
glVertexAttribDivisor(12, 1);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount);
} else {
//split
int split = int(Math::ceil(particles->phase * particles->amount));
if (amount - split > 0) {
glEnableVertexAttribArray(8); //xform x
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3));
glVertexAttribDivisor(8, 1);
glEnableVertexAttribArray(9); //xform y
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4));
glVertexAttribDivisor(9, 1);
glEnableVertexAttribArray(10); //xform z
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5));
glVertexAttribDivisor(10, 1);
glEnableVertexAttribArray(11); //color
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0));
glVertexAttribDivisor(11, 1);
glEnableVertexAttribArray(12); //custom
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2));
glVertexAttribDivisor(12, 1);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split);
}
if (split > 0) {
glEnableVertexAttribArray(8); //xform x
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3));
glVertexAttribDivisor(8, 1);
glEnableVertexAttribArray(9); //xform y
glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4));
glVertexAttribDivisor(9, 1);
glEnableVertexAttribArray(10); //xform z
glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5));
glVertexAttribDivisor(10, 1);
glEnableVertexAttribArray(11); //color
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, nullptr);
glVertexAttribDivisor(11, 1);
glEnableVertexAttribArray(12); //custom
glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2));
glVertexAttribDivisor(12, 1);
glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split);
}
}
glBindVertexArray(0);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false);
state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
state.using_texture_rect = true;
_set_texture_rect_mode(false);
} break;
#endif
case Item::Command::TYPE_TRANSFORM: {
const Item::CommandTransform *transform = static_cast<const Item::CommandTransform *>(c);
_update_transform_2d_to_mat2x3(base_transform * transform->xform, push_constant.world);
@ -1437,6 +1279,8 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
Item *canvas_group_owner = nullptr;
bool update_skeletons = false;
while (ci) {
if (ci->copy_back_buffer && canvas_group_owner == nullptr) {
backbuffer_copy = true;
@ -1472,9 +1316,27 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
}
}
if (ci->skeleton.is_valid()) {
const Item::Command *c = ci->commands;
while (c) {
if (c->type == Item::Command::TYPE_MESH) {
const Item::CommandMesh *cm = static_cast<const Item::CommandMesh *>(c);
if (cm->mesh_instance.is_valid()) {
storage->mesh_instance_check_for_update(cm->mesh_instance);
update_skeletons = true;
}
}
}
}
if (ci->canvas_group_owner != nullptr) {
if (canvas_group_owner == nullptr) {
//Canvas group begins here, render until before this item
if (update_skeletons) {
storage->update_mesh_instances();
update_skeletons = false;
}
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
item_count = 0;
@ -1494,6 +1356,11 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
}
if (ci == canvas_group_owner) {
if (update_skeletons) {
storage->update_mesh_instances();
update_skeletons = false;
}
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list, true);
item_count = 0;
@ -1506,6 +1373,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
if (backbuffer_copy) {
//render anything pending, including clearing if no items
if (update_skeletons) {
storage->update_mesh_instances();
update_skeletons = false;
}
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
item_count = 0;
@ -1518,6 +1389,11 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
items[item_count++] = ci;
if (!ci->next || item_count == MAX_RENDER_ITEMS - 1) {
if (update_skeletons) {
storage->update_mesh_instances();
update_skeletons = false;
}
_render_items(p_to_render_target, item_count, canvas_transform_inverse, p_light_list);
//then reset
item_count = 0;