#include "global.h" void sculpt_import_mesh_pack_to_texture(mesh_data_t *mesh, slot_layer_t *l) { buffer_t *b = buffer_create(config_get_texture_res_x() * config_get_texture_res_y() * 4 * 4); for (i32 i = 0; i < math_floor(mesh->index_array->length); ++i) { i32 index = mesh->index_array->buffer[i]; buffer_set_f32(b, 4 * i * 4, mesh->vertex_arrays->buffer[0]->values->buffer[index * 4] / 32767.0); buffer_set_f32(b, 4 * i * 4 + 1 * 4, mesh->vertex_arrays->buffer[0]->values->buffer[index * 4 + 1] / 32767.0); buffer_set_f32(b, 4 * i * 4 + 2 * 4, mesh->vertex_arrays->buffer[0]->values->buffer[index * 4 + 2] / 32767.0); f32 nor_x = mesh->vertex_arrays->buffer[1]->values->buffer[index * 2] / 32767.0f; f32 nor_y = mesh->vertex_arrays->buffer[1]->values->buffer[index * 2 + 1] / 32767.0f; f32 nor_z = mesh->vertex_arrays->buffer[0]->values->buffer[index * 4 + 3] / 32767.0f; f32 l1 = math_abs(nor_x) + math_abs(nor_y) + math_abs(nor_z); f32 oct_x = l1 > 0.0f ? nor_x / l1 : 0.0f; f32 oct_y = l1 > 0.0f ? nor_y / l1 : 0.0f; if (nor_z < 0.0f) { f32 ox = oct_x; f32 oy = oct_y; oct_x = (1.0f - math_abs(oy)) * (ox >= 0.0f ? 1.0f : -1.0f); oct_y = (1.0f - math_abs(ox)) * (oy >= 0.0f ? 1.0f : -1.0f); } buffer_set_f32(b, 4 * i * 4 + 3 * 4, (oct_x + 1.0f) * 0.5f + math_floor((oct_y + 1.0f) * 0.5f * 255.0f + 0.5f)); } gpu_texture_t *imgmesh = gpu_create_texture_from_bytes(b, config_get_texture_res_x(), config_get_texture_res_y(), GPU_TEXTURE_FORMAT_RGBA128); draw_begin(l->texpaint_sculpt, false, 0); draw_set_pipeline(pipes_copy128); draw_scaled_image(imgmesh, 0, 0, config_get_texture_res_x(), config_get_texture_res_y()); draw_set_pipeline(NULL); draw_end(); } node_shader_context_t *sculpt_make_sculpt_run(material_t *data, material_context_t *matcon) { char *context_id = "paint"; shader_context_t *props = GC_ALLOC_INIT(shader_context_t, {.name = context_id, .depth_write = false, .compare_mode = "always", .cull_mode = "none", .vertex_elements = any_array_create_from_raw( (void *[]){ GC_ALLOC_INIT(vertex_element_t, {.name = "pos", .data = "float2"}), }, 1), .color_attachments = any_array_create_from_raw( (void *[]){ "RGBA128", "R8", }, 2)}); node_shader_context_t *con_paint = node_shader_context_create(data, props); con_paint->data->color_writes_red = u8_array_create_from_raw( (u8[]){ true, true, true, true, }, 4); con_paint->data->color_writes_green = u8_array_create_from_raw( (u8[]){ true, true, true, true, }, 4); con_paint->data->color_writes_blue = u8_array_create_from_raw( (u8[]){ true, true, true, true, }, 4); con_paint->data->color_writes_alpha = u8_array_create_from_raw( (u8[]){ true, true, true, true, }, 4); node_shader_t *kong = node_shader_context_make_kong(con_paint); bool decal = context_is_decal(); node_shader_add_out(kong, "tex_coord: float2"); node_shader_write_vert(kong, "var madd: float2 = float2(0.5, 0.5);"); node_shader_write_vert(kong, "output.tex_coord = input.pos.xy * madd + madd;"); node_shader_write_vert(kong, "output.tex_coord.y = 1.0 - output.tex_coord.y;"); node_shader_write_vert(kong, "output.pos = float4(input.pos.xy, 0.0, 1.0);"); node_shader_write_attrib_frag(kong, "var tex_coord: float2 = input.tex_coord;"); node_shader_write_attrib_frag(kong, "var sculpt_uv: float2 = tex_coord;"); node_shader_add_constant(kong, "inp: float4", "_input_brush"); node_shader_add_constant(kong, "inplast: float4", "_input_brush_last"); node_shader_add_texture(kong, "gbufferD", NULL); kong->frag_out = "float4[2]"; node_shader_add_constant(kong, "brush_radius: float", "_brush_radius"); node_shader_add_constant(kong, "brush_opacity: float", "_brush_opacity"); node_shader_add_constant(kong, "brush_hardness: float", "_brush_hardness"); if (g_context->tool == TOOL_TYPE_BRUSH || g_context->tool == TOOL_TYPE_ERASER || g_context->tool == TOOL_TYPE_CLONE || g_context->tool == TOOL_TYPE_BLUR || g_context->tool == TOOL_TYPE_SMUDGE || g_context->tool == TOOL_TYPE_PARTICLE || decal) { node_shader_write_frag(kong, "var dist: float = 0.0;"); node_shader_write_frag(kong, "var depth: float = sample_lod(gbufferD, sampler_linear, constants.inp.xy, 0.0).r;"); node_shader_add_constant(kong, "invVP: float4x4", "_inv_view_proj_matrix"); // node_shader_write_frag(kong, "var winp: float4 = float4(float2(constants.inp.x, 1.0 - constants.inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);"); node_shader_write_frag(kong, "var winp: float4 = float4(float2(constants.inp.x, 1.0 - constants.inp.y) * 2.0 - 1.0, depth, 1.0);"); node_shader_write_frag(kong, "winp = constants.invVP * winp;"); node_shader_write_frag(kong, "winp.xyz = winp.xyz / winp.w;"); node_shader_add_constant(kong, "W: float4x4", "_world_matrix"); // node_shader_add_constant(kong, "texpaint_undo_size: float2", "_size(texpaint_sculpt_undo)"); //// // node_shader_write_attrib_frag(kong, "var wposition: float3 = (constants.W * texpaint_sculpt_undo[uint2(uint(tex_coord.x * // constants.texpaint_undo_size.x), uint(tex_coord.y * constants.texpaint_undo_size.y))]).xyz;"); node_shader_write_attrib_frag(kong, "var read_undo: float4 = texpaint_sculpt_undo[uint2(uint(tex_coord.x * 2048.0), uint(tex_coord.y * 2048.0))];"); node_shader_write_attrib_frag(kong, "var wposition: float3 = (constants.W * float4(read_undo.xyz, 1.0)).xyz;"); node_shader_write_frag(kong, "var depthlast: float = sample_lod(gbufferD, sampler_linear, constants.inplast.xy, 0.0).r;"); node_shader_write_frag(kong, "var winplast: float4 = float4(float2(constants.inplast.x, 1.0 - constants.inplast.y) * 2.0 - 1.0, depthlast, 1.0);"); node_shader_write_frag(kong, "winplast = constants.invVP * winplast;"); node_shader_write_frag(kong, "winplast.xyz = winplast.xyz / winplast.w;"); if (!decal) { node_shader_write_frag(kong, "dist = distance(wposition.xyz, winp.xyz);"); node_shader_write_frag(kong, "if (dist > constants.brush_radius) { discard; }"); } } else if (g_context->tool == TOOL_TYPE_FILL) { node_shader_write_frag(kong, "var dist: float = 0.0;"); node_shader_add_constant(kong, "W: float4x4", "_world_matrix"); node_shader_write_attrib_frag(kong, "var read_undo: float4 = texpaint_sculpt_undo[uint2(uint(tex_coord.x * 2048.0), uint(tex_coord.y * 2048.0))];"); node_shader_write_attrib_frag(kong, "var wposition: float3 = (constants.W * float4(read_undo.xyz, 1.0)).xyz;"); } if (decal) { // Project wposition to screen-space and compute decal tex_coord node_shader_add_constant(kong, "VP: float4x4", "_view_proj_matrix"); node_shader_write_attrib_frag(kong, "var decal_ndc: float4 = constants.VP * float4(wposition.xyz, 1.0);"); node_shader_write_attrib_frag(kong, "var sp: float3 = decal_ndc.xyz / decal_ndc.w;"); node_shader_write_attrib_frag(kong, "sp.x = sp.x * 0.5 + 0.5;"); node_shader_write_attrib_frag(kong, "sp.y = sp.y * 0.5 + 0.5;"); node_shader_write_attrib_frag(kong, "sp.y = 1.0 - sp.y;"); node_shader_add_constant(kong, "aspect_ratio: float", "_aspect_ratio_window"); node_shader_add_constant(kong, "decal_mask: float4", "_decal_mask"); node_shader_write_attrib_frag(kong, "var uvsp: float2 = sp.xy;"); node_shader_write_attrib_frag(kong, "uvsp = uvsp - constants.decal_mask.xy;"); node_shader_write_attrib_frag(kong, "uvsp.x *= constants.aspect_ratio;"); node_shader_write_attrib_frag(kong, "uvsp = uvsp * (0.21 / (constants.decal_mask.w * 0.9));"); f32 angle = g_context->brush_angle + g_context->brush_nodes_angle; if (angle != 0.0) { node_shader_add_constant(kong, "brush_angle: float2", "_brush_angle"); node_shader_write_attrib_frag(kong, "uvsp = float2(uvsp.x * constants.brush_angle.x - uvsp.y * constants.brush_angle.y, uvsp.x * " "constants.brush_angle.y + uvsp.y * constants.brush_angle.x);"); } node_shader_add_constant(kong, "brush_scale_x: float", "_brush_scale_x"); node_shader_write_attrib_frag(kong, "uvsp.x *= constants.brush_scale_x;"); node_shader_write_attrib_frag(kong, "uvsp += float2(0.5, 0.5);"); node_shader_write_attrib_frag(kong, "if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) { discard; }"); node_shader_add_constant(kong, "brush_scale: float", "_brush_scale"); node_shader_write_attrib_frag(kong, "tex_coord = uvsp * constants.brush_scale;"); } // parser_material_parse may add vertex elements i32 velen = con_paint->data->vertex_elements->length; // parser_material_parse_height = true; // parser_material_parse_height_as_channel = true; shader_out_t *sout = parser_material_parse(g_context->material->canvas, con_paint, kong, matcon); con_paint->data->vertex_elements->length = velen; // node_shader_write_frag(kong, string("var height: float = %s.r;", sout->out_basecol)); node_shader_write_frag(kong, string("var disp: float3 = %s;", sout->out_basecol)); if (kong->frag_bposition) { kong->frag_bposition = false; node_shader_write_attrib_frag(kong, "var bposition: float3 = wposition.xyz;"); } node_shader_write_frag(kong, "var basecol: float3 = float3(1.0, 1.0, 1.0);"); node_shader_write_frag(kong, string("var opacity: float = %s;", sout->out_opacity)); node_shader_write_frag(kong, "if (opacity == 0.0) { discard; }"); node_shader_write_frag(kong, "var str: float = clamp((constants.brush_radius - dist) * constants.brush_hardness * 1.0, 0.0, 1.0) * opacity;"); node_shader_add_texture(kong, "texpaint_sculpt_undo", "_texpaint_sculpt_undo"); node_shader_write_frag(kong, "var sample_undo: float4 = sample_lod(texpaint_sculpt_undo, sampler_linear, sculpt_uv, 0.0);"); node_shader_write_frag(kong, "var raw_undo: float4 = texpaint_sculpt_undo[uint2(uint(tex_coord.x * 2048.0), uint(tex_coord.y * 2048.0))];"); if (g_context->layer->fill_layer != NULL) { node_shader_add_function(kong, str_octahedron_wrap); node_shader_write_frag(kong, "var nor_v: float = floor(raw_undo.a) / 255.0;"); node_shader_write_frag(kong, "var nor_oct: float2 = float2(raw_undo.a - floor(raw_undo.a), nor_v) * 2.0 - 1.0;"); node_shader_write_frag(kong, "var nor_z: float = 1.0 - abs(nor_oct.x) - abs(nor_oct.y);"); node_shader_write_frag(kong, "var nor_xyz: float3 = float3(nor_oct.xy, nor_z);"); node_shader_write_frag(kong, "if (nor_z < 0.0) { nor_xyz.xy = octahedron_wrap(nor_oct.xy); }"); node_shader_write_frag(kong, "var n: float3 = normalize((constants.W * float4(normalize(nor_xyz), 0.0)).xyz);"); } else { node_shader_write_frag(kong, "if (sample_undo.r == 0.0 && sample_undo.g == 0.0 && sample_undo.b == 0.0) { discard; }"); node_shader_add_function(kong, str_octahedron_wrap); node_shader_add_texture(kong, "gbuffer0_undo", NULL); node_shader_write_frag(kong, "var g0_undo: float2 = sample_lod(gbuffer0_undo, sampler_linear, constants.inp.xy, 0.0).rg;"); node_shader_write_frag(kong, "var wn: float3;"); node_shader_write_frag(kong, "wn.z = 1.0 - abs(g0_undo.x) - abs(g0_undo.y);"); node_shader_write_frag(kong, "if (wn.z >= 0.0) { wn.xy = g0_undo.xy; } else { wn.xy = octahedron_wrap(g0_undo.xy); }"); node_shader_write_frag(kong, "var n: float3 = normalize(wn);"); } node_shader_write_frag(kong, "output[0] = float4(sample_undo.rgb + n * disp * str, raw_undo.a);"); node_shader_write_frag(kong, "output[1] = float4(str, 0.0, 0.0, 1.0);"); parser_material_finalize(con_paint); con_paint->data->shader_from_source = true; gpu_create_shaders_from_kong(node_shader_get(kong), &con_paint->data->vertex_shader, &con_paint->data->fragment_shader, &con_paint->data->_->vertex_shader_size, &con_paint->data->_->fragment_shader_size); return con_paint; } void sculpt_make_mesh_run(node_shader_t *kong, slot_layer_t *l) { node_shader_add_constant(kong, "WVP: float4x4", "_world_view_proj_matrix"); i32 lid = l->id; node_shader_add_texture(kong, "texpaint_sculpt", string("_texpaint_sculpt%s", i32_to_string(lid))); node_shader_add_constant(kong, "texpaint_sculpt_size: float2", string("_size(_texpaint_sculpt%s)", i32_to_string(lid))); // node_shader_write_vert(kong, "var meshpos: float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(vertex_id() % constants.texpaint_sculpt_size.x, // vertex_id() / constants.texpaint_sculpt_size.y), 0.0).xyz;"); node_shader_write_vert(kong, "var meshpos: float4 = texpaint_sculpt[uint2(uint(float(vertex_id()) % constants.texpaint_sculpt_size.x), " "uint(float(vertex_id()) / constants.texpaint_sculpt_size.y))];"); // + input.pos.xyz * 0.000001 node_shader_write_vert(kong, "output.pos = constants.WVP * float4(meshpos.xyz, 1.0);"); kong->frag_n = false; node_shader_add_constant(kong, "N: float3x3", "_normal_matrix"); node_shader_add_out(kong, "wnormal: float3"); node_shader_write_attrib_vert(kong, "var base_vertex0: float = float(vertex_id()) - (float(vertex_id()) % float(3));"); node_shader_write_attrib_vert(kong, "var base_vertex1: float = base_vertex0 + 1.0;"); node_shader_write_attrib_vert(kong, "var base_vertex2: float = base_vertex0 + 2.0;"); // node_shader_write_attrib_vert(kong, "var meshpos0: float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(base_vertex0 % // constants.texpaint_sculpt_size.x, base_vertex0 / constants.texpaint_sculpt_size.y), 0.0).xyz;"); node_shader_write_attrib_vert(kong, "var meshpos1: // float3 = sample_lod(texpaint_sculpt, sampler_linear, uint2(base_vertex1 % constants.texpaint_sculpt_size.x, base_vertex1 / // constants.texpaint_sculpt_size.y), 0.0).xyz;"); node_shader_write_attrib_vert(kong, "var meshpos2: float3 = sample_lod(texpaint_sculpt, sampler_linear, // uint2(base_vertex2 % constants.texpaint_sculpt_size.x, base_vertex2 / constants.texpaint_sculpt_size.y), 0.0).xyz;"); node_shader_write_attrib_vert(kong, "var meshpos0: float4 = texpaint_sculpt[uint2(uint(base_vertex0 % constants.texpaint_sculpt_size.x), uint(base_vertex0 " "/ constants.texpaint_sculpt_size.y))];"); node_shader_write_attrib_vert(kong, "var meshpos1: float4 = texpaint_sculpt[uint2(uint(base_vertex1 % constants.texpaint_sculpt_size.x), uint(base_vertex1 " "/ constants.texpaint_sculpt_size.y))];"); node_shader_write_attrib_vert(kong, "var meshpos2: float4 = texpaint_sculpt[uint2(uint(base_vertex2 % constants.texpaint_sculpt_size.x), uint(base_vertex2 " "/ constants.texpaint_sculpt_size.y))];"); node_shader_write_attrib_vert(kong, "var meshnor: float3 = normalize(cross(meshpos2.xyz - meshpos1.xyz, meshpos0.xyz - meshpos1.xyz));"); node_shader_write_attrib_vert(kong, "output.wnormal = constants.N * meshnor;"); node_shader_write_attrib_frag(kong, "var n: float3 = normalize(input.wnormal);"); } void sculpt_init_sculpt_texture(slot_layer_t *l, mesh_data_t *md) { i32 id = l->id; { render_target_t *t = render_target_create(); t->name = string("texpaint_sculpt%s", i32_to_string(id)); t->width = config_get_texture_res_x(); t->height = config_get_texture_res_y(); t->format = "RGBA128"; l->texpaint_sculpt = render_path_create_render_target(t)->_image; } sculpt_import_mesh_pack_to_texture(md, l); } void sculpt_init() { if (any_map_get(render_path_render_targets, "gbuffer0_undo") != NULL) { return; } mesh_data_t *md = g_context->paint_object->data; i16_array_t *posa = i16_array_create(md->index_array->length * 4); i16_array_t *nora = i16_array_create(md->index_array->length * 2); i16_array_t *texa = i16_array_create(md->index_array->length * 2); for (i32 i = 0; i < posa->length; ++i) { posa->buffer[i] = 32767; } for (i32 i = 0; i < md->index_array->length; ++i) { i32 index = md->index_array->buffer[i]; posa->buffer[i * 4] = md->vertex_arrays->buffer[0]->values->buffer[index * 4]; posa->buffer[i * 4 + 1] = md->vertex_arrays->buffer[0]->values->buffer[index * 4 + 1]; posa->buffer[i * 4 + 2] = md->vertex_arrays->buffer[0]->values->buffer[index * 4 + 2]; posa->buffer[i * 4 + 3] = md->vertex_arrays->buffer[0]->values->buffer[index * 4 + 3]; nora->buffer[i * 2] = md->vertex_arrays->buffer[1]->values->buffer[index * 2]; nora->buffer[i * 2 + 1] = md->vertex_arrays->buffer[1]->values->buffer[index * 2 + 1]; texa->buffer[i * 2] = md->vertex_arrays->buffer[2]->values->buffer[index * 2]; texa->buffer[i * 2 + 1] = md->vertex_arrays->buffer[2]->values->buffer[index * 2 + 1]; } u32_array_t *inda = u32_array_create(md->index_array->length); for (i32 i = 0; i < inda->length; ++i) { inda->buffer[i] = i; } mesh_data_t *raw = GC_ALLOC_INIT(mesh_data_t, {.name = md->name, .vertex_arrays = any_array_create_from_raw( (void *[]){ GC_ALLOC_INIT(vertex_array_t, {.values = posa, .attrib = "pos", .data = "short4norm"}), GC_ALLOC_INIT(vertex_array_t, {.values = nora, .attrib = "nor", .data = "short2norm"}), GC_ALLOC_INIT(vertex_array_t, {.values = texa, .attrib = "tex", .data = "short2norm"}), }, 3), .index_array = inda, .scale_pos = 1.0, .scale_tex = 1.0}); md = mesh_data_create(raw); mesh_object_set_data(g_context->paint_object, md); make_material_parse_paint_material(true); make_material_parse_mesh_material(); { render_target_t *t = render_target_create(); t->name = "gbuffer0_undo"; t->width = 0; t->height = 0; t->format = "RGBA64"; t->scale = render_path_base_get_super_sampling(); render_path_create_render_target(t); } { render_target_t *t = render_target_create(); t->name = "gbufferD_undo"; t->width = 0; t->height = 0; t->format = "R32"; t->scale = render_path_base_get_super_sampling(); render_path_create_render_target(t); } render_path_load_shader("Scene/copy_pass/copyR32_pass"); for (i32 i = 0; i < history_undo_layers->length; ++i) { char *ext = string("_undo%s", i32_to_string(i)); slot_layer_t *ul = history_undo_layers->buffer[i]; render_target_t *t = render_target_create(); t->name = string("texpaint_sculpt%s", ext); t->width = config_get_texture_res_x(); t->height = config_get_texture_res_y(); t->format = "RGBA128"; ul->texpaint_sculpt = render_path_create_render_target(t)->_image; } } void sculpt_layers_create_sculpt_layer() { slot_layer_t *l = layers_new_layer(true, -1, NULL); mesh_data_t *md = g_context->paint_object->data; sculpt_init_sculpt_texture(l, md); sculpt_init(); } void render_path_sculpt_commands() { if (g_context->pdirty <= 0) { return; } i32 tid = g_context->layer->id; char *texpaint_sculpt = string("texpaint_sculpt%s", i32_to_string(tid)); render_path_set_target("texpaint_blend1", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0); render_path_bind_target("texpaint_blend0", "tex"); render_path_draw_shader("Scene/copy_pass/copyR8_pass"); string_array_t *additional = any_array_create_from_raw( (void *[]){ "texpaint_blend0", }, 1); render_path_set_target(texpaint_sculpt, additional, NULL, GPU_CLEAR_NONE, 0, 0.0); render_path_bind_target("gbufferD_undo", "gbufferD"); if (g_context->xray || g_config->brush_angle_reject) { render_path_bind_target("gbuffer0", "gbuffer0"); } render_path_bind_target("texpaint_blend1", "paintmask"); render_path_bind_target("gbuffer0_undo", "gbuffer0_undo"); material_context_t *material_context = NULL; shader_context_t *shader_context = NULL; material_data_t *mat = project_paint_objects->buffer[0]->material; for (i32 j = 0; j < mat->contexts->length; ++j) { if (string_equals(mat->contexts->buffer[j]->name, "paint")) { shader_context = shader_data_get_context(mat->_->shader, "paint"); material_context = mat->contexts->buffer[j]; break; } } gpu_set_pipeline(shader_context->_->pipe); uniforms_set_context_consts(shader_context, _render_path_bind_params); uniforms_set_obj_consts(shader_context, project_paint_objects->buffer[0]->base); uniforms_set_material_consts(shader_context, material_context); gpu_set_vertex_buffer(const_data_screen_aligned_vb); gpu_set_index_buffer(const_data_screen_aligned_ib); gpu_draw(); render_path_end(); } void render_path_sculpt_begin() { if (!render_path_paint_paint_enabled()) { return; } render_path_paint_push_undo_last = history_push_undo; if (history_push_undo && history_undo_layers != NULL) { history_paint(); render_path_set_target("gbuffer0_undo", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0); render_path_bind_target("gbuffer0", "tex"); render_path_draw_shader("Scene/copy_pass/copyRGBA64_pass"); render_path_set_target("gbufferD_undo", NULL, NULL, GPU_CLEAR_NONE, 0, 0.0); render_path_bind_target("main", "tex"); render_path_draw_shader("Scene/copy_pass/copyR32_pass"); } if (sculpt_push_undo && history_undo_layers != NULL) { history_paint(); } } void slot_layer_apply_sculpt(slot_layer_t *raw) { if (raw->texpaint_sculpt == NULL) { return; } mesh_object_t *o = project_paint_objects->buffer[0]; mesh_data_t *g = o->data; i16_array_t *va0 = g->vertex_arrays->buffer[0]->values; i32 num_verts = math_floor(va0->length / 4.0); buffer_t *pixels = gpu_get_texture_pixels(raw->texpaint_sculpt); f32 max_abs = 1.0; for (i32 i = 0; i < num_verts; ++i) { f32 x = math_abs(buffer_get_f32(pixels, i * 16)); f32 y = math_abs(buffer_get_f32(pixels, i * 16 + 4)); f32 z = math_abs(buffer_get_f32(pixels, i * 16 + 8)); if (x > max_abs) max_abs = x; if (y > max_abs) max_abs = y; if (z > max_abs) max_abs = z; } if (max_abs > 1.0) { o->base->transform->scale_world = g->scale_pos = g->scale_pos * max_abs; transform_build_matrix(o->base->transform); } for (i32 i = 0; i < num_verts; ++i) { va0->buffer[i * 4] = math_floor(buffer_get_f32(pixels, i * 16) / max_abs * 32767.0); va0->buffer[i * 4 + 1] = math_floor(buffer_get_f32(pixels, i * 16 + 4) / max_abs * 32767.0); va0->buffer[i * 4 + 2] = math_floor(buffer_get_f32(pixels, i * 16 + 8) / max_abs * 32767.0); } mesh_data_build_vertices(g->_->vertex_buffer, o->data->vertex_arrays); util_mesh_calc_normals(true); render_path_raytrace_ready = false; slot_layer_delete(raw); }