godot/servers/visual/rasterizer/rasterizer_canvas_rd.cpp

1265 lines
44 KiB
C++
Raw Normal View History

#include "rasterizer_canvas_rd.h"
void RasterizerCanvasRD::_update_transform_2d_to_mat4(const Transform2D &p_transform, float *p_mat4) {
p_mat4[0] = p_transform.elements[0][0];
p_mat4[1] = p_transform.elements[0][1];
p_mat4[2] = 0;
p_mat4[3] = 0;
p_mat4[4] = p_transform.elements[1][0];
p_mat4[5] = p_transform.elements[1][1];
p_mat4[6] = 0;
p_mat4[7] = 0;
p_mat4[8] = 0;
p_mat4[9] = 0;
p_mat4[10] = 1;
p_mat4[11] = 0;
p_mat4[12] = p_transform.elements[2][0];
p_mat4[13] = p_transform.elements[2][1];
p_mat4[14] = 0;
p_mat4[15] = 1;
}
void RasterizerCanvasRD::_update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4) {
p_mat2x4[0] = p_transform.elements[0][0];
p_mat2x4[1] = p_transform.elements[1][0];
p_mat2x4[2] = 0;
p_mat2x4[3] = p_transform.elements[2][0];
p_mat2x4[4] = p_transform.elements[0][1];
p_mat2x4[5] = p_transform.elements[1][1];
p_mat2x4[6] = 0;
p_mat2x4[7] = p_transform.elements[2][1];
}
void RasterizerCanvasRD::_update_transform_to_mat4(const Transform &p_transform, float *p_mat4) {
p_mat4[0] = p_transform.basis.elements[0][0];
p_mat4[1] = p_transform.basis.elements[1][0];
p_mat4[2] = p_transform.basis.elements[2][0];
p_mat4[3] = 0;
p_mat4[4] = p_transform.basis.elements[0][1];
p_mat4[5] = p_transform.basis.elements[1][1];
p_mat4[6] = p_transform.basis.elements[2][1];
p_mat4[7] = 0;
p_mat4[8] = p_transform.basis.elements[0][2];
p_mat4[9] = p_transform.basis.elements[1][2];
p_mat4[10] = p_transform.basis.elements[2][2];
p_mat4[11] = 0;
p_mat4[12] = p_transform.origin.x;
p_mat4[13] = p_transform.origin.y;
p_mat4[14] = p_transform.origin.z;
p_mat4[15] = 1;
}
RasterizerCanvas::TextureBindingID RasterizerCanvasRD::request_texture_binding(RID p_texture, RID p_normalmap, RID p_specular, VisualServer::CanvasItemTextureFilter p_filter, VisualServer::CanvasItemTextureRepeat p_repeat, RID p_multimesh) {
if (p_filter == VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) {
p_filter = default_samplers.default_filter;
}
if (p_repeat == VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) {
p_repeat = default_samplers.default_repeat;
}
TextureBindingKey key;
key.texture = p_texture;
key.normalmap = p_normalmap;
key.specular = p_specular;
key.multimesh = p_multimesh;
key.texture_filter = p_filter;
key.texture_repeat = p_repeat;
TextureBinding *binding;
TextureBindingID id;
{
TextureBindingID *idptr = bindings.texture_key_bindings.getptr(key);
if (!idptr) {
id = bindings.id_generator++;
bindings.texture_key_bindings[key] = id;
binding = memnew(TextureBinding);
binding->key = key;
binding->id = id;
bindings.texture_bindings[id] = binding;
} else {
id = *idptr;
binding = bindings.texture_bindings[id];
}
}
binding->reference_count++;
if (binding->to_dispose.in_list()) {
//was queued for disposal previously, but ended up reused.
bindings.to_dispose_list.remove(&binding->to_dispose);
}
if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) {
//needs to be re-created
/* from GLSL:
layout(set = 0, binding = 1) uniform texture2D color_texture;
layout(set = 0, binding = 2) uniform texture2D normal_texture;
layout(set = 0, binding = 3) uniform texture2D specular_texture;
layout(set = 0, binding = 4) uniform sampler texture_sampler;
layout(set = 0, binding = 5) uniform textureBuffer instancing_buffer;
*/
Vector<RD::Uniform> uniform_set;
{ // COLOR TEXTURE
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 1;
RID texture = storage->texture_get_rd_texture(p_texture);
if (!texture.is_valid()) {
//use default white texture
texture = default_textures.white_texture;
}
u.ids.push_back(texture);
uniform_set.push_back(u);
}
{ // NORMAL TEXTURE
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 2;
RID texture = storage->texture_get_rd_texture(p_normalmap);
if (!texture.is_valid()) {
//use default normal texture
texture = default_textures.normal_texture;
}
u.ids.push_back(texture);
uniform_set.push_back(u);
}
{ // SPECULAR TEXTURE
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE;
u.binding = 3;
RID texture = storage->texture_get_rd_texture(p_specular);
if (!texture.is_valid()) {
//use default white texture
texture = default_textures.white_texture;
}
u.ids.push_back(texture);
uniform_set.push_back(u);
}
{ // SAMPLER
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_SAMPLER;
u.binding = 4;
RID sampler = default_samplers.samplers[p_filter][p_repeat];
ERR_FAIL_COND_V(sampler.is_null(), 0);
u.ids.push_back(sampler);
uniform_set.push_back(u);
}
{ // MULTIMESH TEXTURE BUFFER
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
u.binding = 5;
u.ids.push_back(default_textures.default_multimesh_tb);
uniform_set.push_back(u);
}
binding->uniform_set = RD::get_singleton()->uniform_set_create(uniform_set, shader.default_version_rd_shader, 0);
}
return id;
}
void RasterizerCanvasRD::free_texture_binding(TextureBindingID p_binding) {
TextureBinding **binding_ptr = bindings.texture_bindings.getptr(p_binding);
ERR_FAIL_COND(!binding_ptr);
TextureBinding *binding = *binding_ptr;
ERR_FAIL_COND(binding->reference_count == 0);
binding->reference_count--;
if (binding->reference_count == 0) {
bindings.to_dispose_list.add(&binding->to_dispose);
}
}
void RasterizerCanvasRD::_dispose_bindings() {
while (bindings.to_dispose_list.first()) {
TextureBinding *binding = bindings.to_dispose_list.first()->self();
if (binding->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(binding->uniform_set)) {
RD::get_singleton()->free(binding->uniform_set);
}
bindings.texture_key_bindings.erase(binding->key);
bindings.texture_bindings.erase(binding->id);
bindings.to_dispose_list.remove(&binding->to_dispose);
memdelete(binding);
}
}
void RasterizerCanvasRD::_render_item(RD::DrawListID p_draw_list, const Item *p_item, RenderTargetFormat p_render_target_format, RD::TextureSamples p_samples, const Color &p_modulate, const Transform2D &p_canvas_transform_inverse) {
int cc = p_item->commands.size();
const Item::Command *const *commands = p_item->commands.ptr();
//create an empty push constant
PushConstant push_constant;
_update_transform_2d_to_mat2x4(p_canvas_transform_inverse * p_item->final_transform, push_constant.world);
for (int i = 0; i < 4; i++) {
push_constant.modulation[i] = 0;
push_constant.ninepatch_margins[i] = 0;
push_constant.src_rect[i] = 0;
push_constant.dst_rect[i] = 0;
}
push_constant.flags = 0;
push_constant.specular_shininess = 0xFFFFFFFF;
push_constant.color_texture_pixel_size[0] = 0;
push_constant.color_texture_pixel_size[1] = 0;
push_constant.pad[0] = 0;
push_constant.pad[1] = 0;
push_constant.pad[2] = 0;
PipelineVariants *pipeline_variants = &shader.pipeline_variants;
for (int i = 0; i < cc; i++) {
const Item::Command *c = commands[i];
push_constant.flags = 0; //reset on each command for sanity
switch (c->type) {
#if 0
case Item::Command::TYPE_LINE: {
Item::CommandLine *line = static_cast<Item::CommandLine *>(c);
_set_texture_rect_mode(false);
_bind_canvas_texture(RID(), RID());
glVertexAttrib4f(VS::ARRAY_COLOR, line->color.r, line->color.g, line->color.b, line->color.a);
if (line->width <= 1) {
Vector2 verts[2] = {
Vector2(line->from.x, line->from.y),
Vector2(line->to.x, line->to.y)
};
#ifdef GLES_OVER_GL
if (line->antialiased)
glEnable(GL_LINE_SMOOTH);
#endif
//glLineWidth(line->width);
_draw_gui_primitive(2, verts, NULL, NULL);
#ifdef GLES_OVER_GL
if (line->antialiased)
glDisable(GL_LINE_SMOOTH);
#endif
} else {
//thicker line
Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5;
Vector2 verts[4] = {
line->from - t,
line->from + t,
line->to + t,
line->to - t,
};
//glLineWidth(line->width);
_draw_gui_primitive(4, verts, NULL, NULL);
#ifdef GLES_OVER_GL
if (line->antialiased) {
glEnable(GL_LINE_SMOOTH);
for (int j = 0; j < 4; j++) {
Vector2 vertsl[2] = {
verts[j],
verts[(j + 1) % 4],
};
_draw_gui_primitive(2, vertsl, NULL, NULL);
}
glDisable(GL_LINE_SMOOTH);
}
#endif
}
} break;
case Item::Command::TYPE_POLYLINE: {
Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(c);
_set_texture_rect_mode(false);
_bind_canvas_texture(RID(), RID());
if (pline->triangles.size()) {
_draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1);
#ifdef GLES_OVER_GL
glEnable(GL_LINE_SMOOTH);
if (pline->multiline) {
//needs to be different
} else {
_draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1);
}
glDisable(GL_LINE_SMOOTH);
#endif
} else {
#ifdef GLES_OVER_GL
if (pline->antialiased)
glEnable(GL_LINE_SMOOTH);
#endif
if (pline->multiline) {
int todo = pline->lines.size() / 2;
int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4);
int offset = 0;
while (todo) {
int to_draw = MIN(max_per_call, todo);
_draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1);
todo -= to_draw;
offset += to_draw * 2;
}
} else {
_draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1);
}
#ifdef GLES_OVER_GL
if (pline->antialiased)
glDisable(GL_LINE_SMOOTH);
#endif
}
} break;
#endif
case Item::Command::TYPE_RECT: {
const Item::CommandRect *rect = static_cast<const Item::CommandRect *>(c);
//bind pipeline
{
RID pipeline = pipeline_variants->variants[p_render_target_format][PIPELINE_VARIANT_QUAD].get_render_pipeline(RD::INVALID_ID, p_samples);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
}
//bind textures
Size2 texpixel_size;
{
TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(rect->texture_binding.binding_id);
ERR_CONTINUE(!texture_binding_ptr);
TextureBinding *texture_binding = *texture_binding_ptr;
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0);
if (texture_binding->key.texture.is_valid()) {
Size2i tex_size = storage->texture_2d_get_size(texture_binding->key.texture);
if (tex_size.x != 0 && tex_size.y != 0) {
texpixel_size.x = 1.0 / tex_size.x;
texpixel_size.y = 1.0 / tex_size.y;
}
}
}
Rect2 src_rect;
Rect2 dst_rect;
if (texpixel_size != Vector2()) {
push_constant.color_texture_pixel_size[0] = texpixel_size.x;
push_constant.color_texture_pixel_size[1] = texpixel_size.y;
src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1);
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
dst_rect.position.x += dst_rect.size.width;
dst_rect.size.width *= -1;
}
if (dst_rect.size.height < 0) {
dst_rect.position.y += dst_rect.size.height;
dst_rect.size.height *= -1;
}
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform
}
if (rect->flags & CANVAS_RECT_CLIP_UV) {
push_constant.flags |= FLAGS_CLIP_RECT_UV;
}
} else {
dst_rect = Rect2(rect->rect.position, rect->rect.size);
if (dst_rect.size.width < 0) {
dst_rect.position.x += dst_rect.size.width;
dst_rect.size.width *= -1;
}
if (dst_rect.size.height < 0) {
dst_rect.position.y += dst_rect.size.height;
dst_rect.size.height *= -1;
}
src_rect = Rect2(0, 0, 1, 1);
texpixel_size = Vector2(1, 1);
}
push_constant.modulation[0] = rect->modulate.r * p_modulate.r;
push_constant.modulation[1] = rect->modulate.g * p_modulate.g;
push_constant.modulation[2] = rect->modulate.b * p_modulate.b;
push_constant.modulation[3] = rect->modulate.a;
push_constant.src_rect[0] = src_rect.position.x;
push_constant.src_rect[1] = src_rect.position.y;
push_constant.src_rect[2] = src_rect.size.width;
push_constant.src_rect[3] = src_rect.size.height;
push_constant.dst_rect[0] = dst_rect.position.x;
push_constant.dst_rect[1] = dst_rect.position.y;
push_constant.dst_rect[2] = dst_rect.size.width;
push_constant.dst_rect[3] = dst_rect.size.height;
push_constant.color_texture_pixel_size[0] = texpixel_size.x;
push_constant.color_texture_pixel_size[1] = texpixel_size.y;
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
RD::get_singleton()->draw_list_draw(p_draw_list, true);
} break;
case Item::Command::TYPE_NINEPATCH: {
const Item::CommandNinePatch *np = static_cast<const Item::CommandNinePatch *>(c);
//bind pipeline
{
RID pipeline = pipeline_variants->variants[p_render_target_format][PIPELINE_VARIANT_NINEPATCH].get_render_pipeline(RD::INVALID_ID, p_samples);
RD::get_singleton()->draw_list_bind_render_pipeline(p_draw_list, pipeline);
}
//bind textures
Size2 texpixel_size;
{
TextureBinding **texture_binding_ptr = bindings.texture_bindings.getptr(np->texture_binding.binding_id);
ERR_CONTINUE(!texture_binding_ptr);
TextureBinding *texture_binding = *texture_binding_ptr;
RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, texture_binding->uniform_set, 0);
if (texture_binding->key.texture.is_valid()) {
Size2i tex_size = storage->texture_2d_get_size(texture_binding->key.texture);
if (tex_size.x != 0 && tex_size.y != 0) {
texpixel_size.x = 1.0 / tex_size.x;
texpixel_size.y = 1.0 / tex_size.y;
}
}
}
Rect2 src_rect;
Rect2 dst_rect(np->rect.position.x, np->rect.position.y, np->rect.size.x, np->rect.size.y);
if (texpixel_size == Size2()) {
texpixel_size = Size2(1, 1);
src_rect = Rect2(0, 0, 1, 1);
} else {
if (np->source != Rect2()) {
src_rect = Rect2(np->source.position.x * texpixel_size.width, np->source.position.y * texpixel_size.height, np->source.size.x * texpixel_size.width, np->source.size.y * texpixel_size.height);
texpixel_size = Size2(1.0 / np->source.size.width, 1.0 / np->source.size.height);
} else {
src_rect = Rect2(0, 0, 1, 1);
}
}
push_constant.modulation[0] = np->color.r * p_modulate.r;
push_constant.modulation[1] = np->color.g * p_modulate.g;
push_constant.modulation[2] = np->color.b * p_modulate.b;
push_constant.modulation[3] = np->color.a;
push_constant.src_rect[0] = src_rect.position.x;
push_constant.src_rect[1] = src_rect.position.y;
push_constant.src_rect[2] = src_rect.size.width;
push_constant.src_rect[3] = src_rect.size.height;
push_constant.dst_rect[0] = dst_rect.position.x;
push_constant.dst_rect[1] = dst_rect.position.y;
push_constant.dst_rect[2] = dst_rect.size.width;
push_constant.dst_rect[3] = dst_rect.size.height;
push_constant.color_texture_pixel_size[0] = texpixel_size.x;
push_constant.color_texture_pixel_size[1] = texpixel_size.y;
push_constant.flags |= int(np->axis_x) << FLAGS_NINEPATCH_H_MODE_SHIFT;
push_constant.flags |= int(np->axis_y) << FLAGS_NINEPATCH_V_MODE_SHIFT;
if (np->draw_center) {
push_constant.flags |= FLAGS_NINEPACH_DRAW_CENTER;
}
push_constant.ninepatch_margins[0] = np->margin[MARGIN_LEFT];
push_constant.ninepatch_margins[1] = np->margin[MARGIN_TOP];
push_constant.ninepatch_margins[2] = np->margin[MARGIN_RIGHT];
push_constant.ninepatch_margins[3] = np->margin[MARGIN_BOTTOM];
RD::get_singleton()->draw_list_set_push_constant(p_draw_list, &push_constant, sizeof(PushConstant));
RD::get_singleton()->draw_list_bind_index_array(p_draw_list, shader.quad_index_array);
RD::get_singleton()->draw_list_draw(p_draw_list, true);
} break;
#if 0
case Item::Command::TYPE_PRIMITIVE : {
Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(c);
_set_texture_rect_mode(false);
ERR_CONTINUE(primitive->points.size() < 1);
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->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);
}
if (primitive->colors.size() == 1 && primitive->points.size() > 1) {
Color col = primitive->colors[0];
glVertexAttrib4f(VS::ARRAY_COLOR, col.r, col.g, col.b, col.a);
} else if (primitive->colors.empty()) {
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
}
_draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), primitive->colors.ptr(), primitive->uvs.ptr());
} break;
case Item::Command::TYPE_POLYGON: {
Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(c);
_set_texture_rect_mode(false);
RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->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);
}
_draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->bones.ptr(), polygon->weights.ptr());
#ifdef GLES_OVER_GL
if (polygon->antialiased) {
glEnable(GL_LINE_SMOOTH);
_draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1);
glDisable(GL_LINE_SMOOTH);
}
#endif
} break;
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);
}
state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform);
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(VS::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);
}
}
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)
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 != VS::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);
if (amount == -1) {
amount = multi_mesh->size;
}
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);
glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer
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);
int color_ofs;
if (multi_mesh->transform_format == VS::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;
} else {
glDisableVertexAttribArray(10);
glVertexAttrib4f(10, 0, 0, 1, 0);
color_ofs = 8 * 4;
}
int custom_data_ofs = color_ofs;
switch (multi_mesh->color_format) {
case VS::MULTIMESH_COLOR_NONE: {
glDisableVertexAttribArray(11);
glVertexAttrib4f(11, 1, 1, 1, 1);
} break;
case VS::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;
} break;
case VS::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;
}
switch (multi_mesh->custom_data_format) {
case VS::MULTIMESH_CUSTOM_DATA_NONE: {
glDisableVertexAttribArray(12);
glVertexAttrib4f(12, 1, 1, 1, 1);
} break;
case VS::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);
} break;
case VS::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);
}
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);
} 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(VS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
VisualServerRaster::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 != VS::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, NULL);
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, NULL);
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;
case Item::Command::TYPE_CIRCLE: {
_set_texture_rect_mode(false);
Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(c);
static const int numpoints = 32;
Vector2 points[numpoints + 1];
points[numpoints] = circle->pos;
int indices[numpoints * 3];
for (int j = 0; j < numpoints; j++) {
points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / numpoints), Math::cos(j * Math_PI * 2.0 / numpoints)) * circle->radius;
indices[j * 3 + 0] = j;
indices[j * 3 + 1] = (j + 1) % numpoints;
indices[j * 3 + 2] = numpoints;
}
_bind_canvas_texture(RID(), RID());
_draw_polygon(indices, numpoints * 3, numpoints + 1, points, NULL, &circle->color, true, NULL, NULL);
//_draw_polygon(numpoints*3,indices,points,NULL,&circle->color,RID(),true);
//canvas_draw_circle(circle->indices.size(),circle->indices.ptr(),circle->points.ptr(),circle->uvs.ptr(),circle->colors.ptr(),circle->texture,circle->colors.size()==1);
} break;
case Item::Command::TYPE_TRANSFORM: {
Item::CommandTransform *transform = static_cast<Item::CommandTransform *>(c);
state.extra_matrix = transform->xform;
state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.extra_matrix);
} break;
case Item::Command::TYPE_CLIP_IGNORE: {
Item::CommandClipIgnore *ci = static_cast<Item::CommandClipIgnore *>(c);
if (current_clip) {
if (ci->ignore != reclip) {
if (ci->ignore) {
glDisable(GL_SCISSOR_TEST);
reclip = true;
} else {
glEnable(GL_SCISSOR_TEST);
//glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)),
//current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height);
int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y);
if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP])
y = current_clip->final_clip_rect.position.y;
glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y);
reclip = false;
}
}
}
} break;
#endif
}
}
}
void RasterizerCanvasRD::_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, int p_item_count, const Color &p_modulate, const Transform2D &p_transform) {
Item *current_clip = NULL;
RenderTargetFormat render_target_format = RENDER_TARGET_FORMAT_8_BIT_INT;
Transform2D canvas_transform_inverse = p_transform.affine_inverse();
RID framebuffer = storage->render_target_get_rd_framebuffer(p_to_render_target);
Vector<Color> clear_colors;
if (p_clear) {
clear_colors.push_back(p_clear_color);
}
#warning TODO obtain from framebuffer format eventually when this is implemented
RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, p_clear ? RD::INITIAL_ACTION_CLEAR : RD::INITIAL_ACTION_KEEP_COLOR, RD::FINAL_ACTION_READ_COLOR_DISCARD_DEPTH, clear_colors);
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, state.canvas_state_uniform_set, 3);
for (int i = 0; i < p_item_count; i++) {
Item *ci = items[i];
if (current_clip != ci->final_clip_owner) {
current_clip = ci->final_clip_owner;
//setup clip
if (current_clip) {
RD::get_singleton()->draw_list_enable_scissor(draw_list, current_clip->final_clip_rect);
} else {
RD::get_singleton()->draw_list_disable_scissor(draw_list);
}
}
if (false) { //not skeleton
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, shader.default_material_uniform_set, 1);
}
_render_item(draw_list, ci, render_target_format, texture_samples, p_modulate, canvas_transform_inverse);
}
RD::get_singleton()->draw_list_end();
}
void RasterizerCanvasRD::_update_canvas_state_uniform_set() {
if (state.canvas_state_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(state.canvas_state_uniform_set)) {
return; //nothing to update
}
Vector<RD::Uniform> uniforms;
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 0;
u.ids.push_back(state.canvas_state_buffer);
uniforms.push_back(u);
state.canvas_state_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader.default_version_rd_shader, 3); // uses index 3
}
void RasterizerCanvasRD::canvas_render_items(RID p_to_render_target, bool p_clear, const Color &p_clear_color, Item *p_item_list, const Color &p_modulate, Light *p_light_list, const Transform2D &p_canvas_transform) {
int item_count = 0;
//setup canvas state uniforms if needed
_update_canvas_state_uniform_set();
{
//update canvas state uniform buffer
State::Buffer state_buffer;
Size2i ssize = storage->render_target_get_size(p_to_render_target);
Transform screen_transform;
screen_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f);
screen_transform.scale(Vector3(2.0f / ssize.width, 2.0f / ssize.height, 1.0f));
_update_transform_to_mat4(screen_transform, state_buffer.screen_transform);
_update_transform_2d_to_mat4(p_canvas_transform, state_buffer.canvas_transform);
RD::get_singleton()->buffer_update(state.canvas_state_buffer, 0, sizeof(State::Buffer), &state_buffer, true);
}
//fill the list until rendering is possible.
Item *ci = p_item_list;
while (ci) {
items[item_count++] = ci;
bool backbuffer_copy = ci->copy_back_buffer; // || shader uses SCREEN_TEXTURE
if (!ci->next || backbuffer_copy || item_count == MAX_RENDER_ITEMS - 1) {
_render_items(p_to_render_target, p_clear, p_clear_color, item_count, p_modulate, p_canvas_transform);
//then reset
item_count = 0;
p_clear = false;
}
if (ci->copy_back_buffer) {
if (ci->copy_back_buffer->full) {
//_copy_texscreen(Rect2());
} else {
//_copy_texscreen(ci->copy_back_buffer->rect);
}
}
ci = ci->next;
}
}
void RasterizerCanvasRD::update() {
_dispose_bindings();
}
RasterizerCanvasRD::RasterizerCanvasRD(RasterizerStorageRD *p_storage) {
storage = p_storage;
{ //create default textures
RD::TextureFormat tformat;
tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
tformat.width = 4;
tformat.height = 4;
tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
tformat.type = RD::TEXTURE_TYPE_2D;
PoolVector<uint8_t> pv;
pv.resize(16 * 4);
for (int i = 0; i < 16; i++) {
pv.set(i * 4 + 0, 255);
pv.set(i * 4 + 1, 255);
pv.set(i * 4 + 2, 255);
pv.set(i * 4 + 3, 255);
}
{
Vector<PoolVector<uint8_t> > vpv;
vpv.push_back(pv);
default_textures.white_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
}
for (int i = 0; i < 16; i++) {
pv.set(i * 4 + 0, 0);
pv.set(i * 4 + 1, 0);
pv.set(i * 4 + 2, 0);
pv.set(i * 4 + 3, 255);
}
{
Vector<PoolVector<uint8_t> > vpv;
vpv.push_back(pv);
default_textures.black_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
}
for (int i = 0; i < 16; i++) {
pv.set(i * 4 + 0, 128);
pv.set(i * 4 + 1, 128);
pv.set(i * 4 + 2, 255);
pv.set(i * 4 + 3, 255);
}
{
Vector<PoolVector<uint8_t> > vpv;
vpv.push_back(pv);
default_textures.normal_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
}
for (int i = 0; i < 16; i++) {
pv.set(i * 4 + 0, 255);
pv.set(i * 4 + 1, 128);
pv.set(i * 4 + 2, 255);
pv.set(i * 4 + 3, 255);
}
{
Vector<PoolVector<uint8_t> > vpv;
vpv.push_back(pv);
default_textures.aniso_texture = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
}
for (int i = 0; i < 16; i++) {
pv.set(i * 4 + 0, 0);
pv.set(i * 4 + 1, 0);
pv.set(i * 4 + 2, 0);
pv.set(i * 4 + 3, 0);
}
default_textures.default_multimesh_tb = RD::get_singleton()->texture_buffer_create(16, RD::DATA_FORMAT_R8G8B8A8_UNORM, pv);
}
{ //create default samplers
for (int i = 1; i < VS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
for (int j = 1; j < VS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
RD::SamplerState sampler_state;
switch (i) {
case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
sampler_state.max_lod = 0;
} break;
case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.max_lod = 0;
} break;
case VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
} break;
case VS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIMPAMPS: {
sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
} break;
default: {
}
}
switch (j) {
case VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
} break;
case VS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
} break;
case VS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
} break;
default: {
}
}
default_samplers.samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
}
}
default_samplers.default_filter = VS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR;
default_samplers.default_repeat = VS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED;
}
{ //shader variants
Vector<String> variants;
variants.push_back(""); //none by default is first variant
variants.push_back("#define USE_NINEPATCH\n"); //ninepatch is the second variant
variants.push_back("#define USE_VERTEX_ARRAYS\n"); //vertex arrays is the last variant
variants.push_back("#define USE_POINT_SIZE\n"); //for point drawing
shader.canvas_shader.initialize(variants);
shader.default_version = shader.canvas_shader.version_create();
{
//framebuffer formats
RD::AttachmentFormat af;
af.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
af.samples = RD::TEXTURE_SAMPLES_1;
af.usage_flags = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
Vector<RD::AttachmentFormat> formats;
formats.push_back(af);
shader.framebuffer_formats[RENDER_TARGET_FORMAT_8_BIT_INT] = RD::get_singleton()->framebuffer_format_create(formats);
formats.clear();
af.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
formats.push_back(af);
shader.framebuffer_formats[RENDER_TARGET_FORMAT_16_BIT_FLOAT] = RD::get_singleton()->framebuffer_format_create(formats);
}
for (int i = 0; i < RENDER_TARGET_FORMAT_MAX; i++) {
RD::FramebufferFormatID fb_format = shader.framebuffer_formats[i];
for (int j = 0; j < PIPELINE_VARIANT_MAX; j++) {
RD::RenderPrimitive primitive[PIPELINE_VARIANT_MAX] = { RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_TRIANGLES, RD::RENDER_PRIMITIVE_LINES, RD::RENDER_PRIMITIVE_POINTS };
ShaderVariant shader_variants[PIPELINE_VARIANT_MAX] = { SHADER_VARIANT_QUAD, SHADER_VARIANT_NINEPATCH, SHADER_VARIANT_VERTICES, SHADER_VARIANT_VERTICES, SHADER_VARIANT_POINTS };
RID shader_variant = shader.canvas_shader.version_get_shader(shader.default_version, shader_variants[j]);
shader.pipeline_variants.variants[i][j].setup(shader_variant, fb_format, primitive[j], RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_blend(), j == PIPELINE_VARIANT_LINES ? RD::DYNAMIC_STATE_LINE_WIDTH : 0);
}
}
shader.default_version_rd_shader = shader.canvas_shader.version_get_shader(shader.default_version, 0);
}
{ //bindings
bindings.id_generator = 0;
//generate for 0
bindings.default_empty = request_texture_binding(RID(), RID(), RID(), VS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, VS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, RID());
{ //state allocate
state.canvas_state_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(State::Buffer));
}
}
{ // default index buffer
PoolVector<uint8_t> pv;
pv.resize(6 * 4);
{
PoolVector<uint8_t>::Write w = pv.write();
int *p32 = (int *)w.ptr();
p32[0] = 0;
p32[1] = 1;
p32[2] = 2;
p32[3] = 0;
p32[4] = 2;
p32[5] = 3;
}
RID index_buffer = RD::get_singleton()->index_buffer_create(6, RenderingDevice::INDEX_BUFFER_FORMAT_UINT32, pv);
shader.quad_index_array = RD::get_singleton()->index_array_create(index_buffer, 0, 6);
}
{ //default skeleton buffer
shader.default_material_skeleton_uniform = RD::get_singleton()->uniform_buffer_create(sizeof(SkeletonUniform));
SkeletonUniform su;
_update_transform_2d_to_mat4(Transform2D(), su.skeleton_inverse);
_update_transform_2d_to_mat4(Transform2D(), su.skeleton_transform);
RD::get_singleton()->buffer_update(shader.default_material_skeleton_uniform, 0, sizeof(SkeletonUniform), &su);
}
{ //default material uniform set
Vector<RD::Uniform> default_material_uniforms;
RD::Uniform u;
u.type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
u.binding = 2;
u.ids.push_back(shader.default_material_skeleton_uniform);
default_material_uniforms.push_back(u);
u.ids.clear();
u.type = RD::UNIFORM_TYPE_TEXTURE_BUFFER;
u.binding = 1;
u.ids.push_back(default_textures.default_multimesh_tb);
default_material_uniforms.push_back(u);
shader.default_material_uniform_set = RD::get_singleton()->uniform_set_create(default_material_uniforms, shader.default_version_rd_shader, 1);
}
ERR_FAIL_COND(sizeof(PushConstant) != 128);
}