let uniforms_ext_ortho_p: mat4_t = mat4_ortho(-0.5, 0.5, -0.5, 0.5, -0.5, 0.5); function uniforms_ext_init() { uniforms_i32_links = uniforms_ext_i32_link; uniforms_f32_links = uniforms_ext_f32_link; uniforms_vec2_links = uniforms_ext_vec2_link; uniforms_vec3_links = uniforms_ext_vec3_link; uniforms_vec4_links = uniforms_ext_vec4_link; uniforms_mat4_links = uniforms_ext_mat4_link; uniforms_tex_links = uniforms_ext_tex_link; } function uniforms_ext_i32_link(object: object_t, mat: material_data_t, link: string): i32 { if (link == "_bloom_current_mip") { return render_path_base_bloom_current_mip; } return INT_MAX; } function uniforms_ext_f32_link(object: object_t, mat: material_data_t, link: string): f32 { if (link == "_brush_radius") { let decal: bool = context_is_decal(); let decal_mask: bool = decal && operator_shortcut(map_get(config_keymap, "decal_mask") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN); let brush_decal_mask_radius: f32 = context_raw.brush_decal_mask_radius; brush_decal_mask_radius *= context_raw.paint2d ? 0.55 * ui_view2d_pan_scale : 2.0; let radius: f32 = decal_mask ? brush_decal_mask_radius : context_raw.brush_radius; let val: f32 = (radius * context_raw.brush_nodes_radius) / 15.0; if (config_raw.pressure_radius && pen_down()) { val *= pen_pressure * config_raw.pressure_sensitivity; } let scale2d: f32 = (900 / base_h()) * config_raw.window_scale; if (!decal) { val *= context_raw.paint2d ? 0.55 * scale2d * ui_view2d_pan_scale : 2; } else { val *= scale2d; // Projection ratio } return val; } else if (link == "_vignette_strength") { return config_raw.rp_vignette; } else if (link == "_grain_strength") { return config_raw.rp_grain; } else if (link == "_tonemap_strength") { let tonemap: bool = context_raw.viewport_mode == viewport_mode_t.LIT || context_raw.viewport_mode == viewport_mode_t.PATH_TRACE; return tonemap ? 1.0 : 0.0; } else if (link == "_bloom_sample_scale") { return render_path_base_bloom_sample_scale; } else if (link == "_bloom_strength") { return context_raw.viewport_mode == viewport_mode_t.PATH_TRACE ? 0.2 : 0.02; } else if (link == "_brush_scale_x") { return 1 / context_raw.brush_scale_x; } else if (link == "_brush_opacity") { let val: f32 = context_raw.brush_opacity * context_raw.brush_nodes_opacity; if (config_raw.pressure_opacity && pen_down()) { val *= pen_pressure * config_raw.pressure_sensitivity; } return val; } else if (link == "_brush_hardness") { let decal_mask: bool = context_is_decal_mask_paint(); if (context_raw.tool != tool_type_t.BRUSH && context_raw.tool != tool_type_t.ERASER && context_raw.tool != tool_type_t.CLONE && !decal_mask) { return 1.0; } let val: f32 = context_raw.brush_hardness * context_raw.brush_nodes_hardness; if (config_raw.pressure_hardness && pen_down()) { val *= pen_pressure * config_raw.pressure_sensitivity; } if (context_raw.paint2d) { val *= 1.0 / ui_view2d_pan_scale; } else { val *= val; } return val; } else if (link == "_brush_scale") { if (context_raw.tool == tool_type_t.GIZMO) { let atlas_w: i32 = config_get_scene_atlas_res(); let item_w: i32 = config_get_layer_res(); let atlas_stride: i32 = atlas_w / item_w; return atlas_stride; } let fill: bool = context_raw.layer.fill_layer != null; let val: f32 = (fill ? context_raw.layer.scale : context_raw.brush_scale) * context_raw.brush_nodes_scale; return val; } else if (link == "_object_id") { return array_index_of(project_paint_objects, object.ext); } else if (link == "_dilate_radius") { return util_uv_dilatemap != null ? config_raw.dilate_radius : 0.0; } else if (link == "_decal_layer_dim") { let sc: vec4_t = mat4_get_scale(context_raw.layer.decal_mat); return sc.z * 0.5; } else if (link == "_picker_opacity") { return context_raw.picked_color.opacity; } else if (link == "_picker_occlusion") { return context_raw.picked_color.occlusion; } else if (link == "_picker_roughness") { return context_raw.picked_color.roughness; } else if (link == "_picker_metallic") { return context_raw.picked_color.metallic; } else if (link == "_picker_height") { return context_raw.picked_color.height; } else if (link == "_taa_blend") { if (render_path_base_taa_frame == 0) { return 0.0; } if (context_raw.ddirty > 1 || context_raw.pdirty > 0) { camera_object_taa_frames = 2; return 0.5; } camera_object_taa_frames = 6; return 0.833; } if (parser_material_script_links != null) { let keys: string[] = map_keys(parser_material_script_links); for (let i: i32 = 0; i < keys.length; ++i) { let key: string = keys[i]; let script: string = map_get(parser_material_script_links, key); let result: f32 = f32_nan(); if (script != "") { result = js_eval(script); } return result; } } return f32_nan(); } function uniforms_ext_vec2_link(object: object_t, mat: material_data_t, link: string): vec2_t { if (link == "_gbuffer_size") { let gbuffer2: render_target_t = map_get(render_path_render_targets, "gbuffer2"); return vec2_create(gbuffer2._image.width, gbuffer2._image.height); } else if (link == "_clone_delta") { return vec2_create(context_raw.clone_delta_x, context_raw.clone_delta_y); } else if (link == "_texpaint_size") { return vec2_create(config_get_texture_res_x(), config_get_texture_res_y()); } else if (link == "_brush_angle") { let brush_angle: f32 = context_raw.brush_angle + context_raw.brush_nodes_angle; let angle: f32 = context_raw.layer.fill_layer != null ? context_raw.layer.angle : brush_angle; angle *= (math_pi() / 180); if (config_raw.pressure_angle && pen_down()) { angle *= pen_pressure * config_raw.pressure_sensitivity; } return vec2_create(math_cos(-angle), math_sin(-angle)); } return vec2_nan(); } function uniforms_ext_vec3_link(object: object_t, mat: material_data_t, link: string): vec4_t { let v: vec4_t = vec4_nan(); if (link == "_brush_direction") { v = _uniforms_vec; // Discard first paint for directional brush let allow_paint: bool = context_raw.prev_paint_vec_x != context_raw.last_paint_vec_x && context_raw.prev_paint_vec_y != context_raw.last_paint_vec_y && context_raw.prev_paint_vec_x > 0 && context_raw.prev_paint_vec_y > 0; let x: f32 = context_raw.paint_vec.x; let y: f32 = context_raw.paint_vec.y; let lastx: f32 = context_raw.prev_paint_vec_x; let lasty: f32 = context_raw.prev_paint_vec_y; if (context_raw.paint2d) { x = vec2d(x); lastx = vec2d(lastx); } let angle: f32 = math_atan2(-y + lasty, x - lastx) - math_pi() / 2; v = vec4_create(math_cos(angle), math_sin(angle), allow_paint ? 1 : 0); context_raw.prev_paint_vec_x = context_raw.last_paint_vec_x; context_raw.prev_paint_vec_y = context_raw.last_paint_vec_y; return v; } else if (link == "_decal_layer_loc") { v = _uniforms_vec; v = vec4_create(context_raw.layer.decal_mat.m30, context_raw.layer.decal_mat.m31, context_raw.layer.decal_mat.m32); return v; } else if (link == "_decal_layer_nor") { v = _uniforms_vec; v = vec4_create(context_raw.layer.decal_mat.m20, context_raw.layer.decal_mat.m21, context_raw.layer.decal_mat.m22); v = vec4_norm(v); return v; } else if (link == "_picker_base") { v = _uniforms_vec; v = vec4_create(color_get_rb(context_raw.picked_color.base) / 255, color_get_gb(context_raw.picked_color.base) / 255, color_get_bb(context_raw.picked_color.base) / 255); return v; } else if (link == "_picker_normal") { v = _uniforms_vec; v = vec4_create(color_get_rb(context_raw.picked_color.normal) / 255, color_get_gb(context_raw.picked_color.normal) / 255, color_get_bb(context_raw.picked_color.normal) / 255); return v; } else if (link == "_particle_hit") { v = _uniforms_vec; v = vec4_create(context_raw.particle_hit_x, context_raw.particle_hit_y, context_raw.particle_hit_z); return v; } else if (link == "_particle_hit_last") { v = _uniforms_vec; v = vec4_create(context_raw.last_particle_hit_x, context_raw.last_particle_hit_y, context_raw.last_particle_hit_z); return v; } return v; } function vec2d(x: f32): f32 { // Transform from 3d viewport coord to 2d view coord context_raw.paint2d_view = false; let res: f32 = (x * base_w() - base_w()) / ui_view2d_ww; context_raw.paint2d_view = true; return res; } function uniforms_ext_vec4_link(object: object_t, mat: material_data_t, link: string): vec4_t { if (link == "_input_brush") { let down: bool = mouse_down() || pen_down(); let v: vec4_t = vec4_create(context_raw.paint_vec.x, context_raw.paint_vec.y, down ? 1.0 : 0.0, context_raw.paint2d ? 1.0 : 0.0); if (context_raw.paint2d) { v.x = vec2d(v.x); } return v; } else if (link == "_input_brush_last") { let down: bool = mouse_down() || pen_down(); let v: vec4_t = vec4_create(context_raw.last_paint_vec_x, context_raw.last_paint_vec_y, down ? 1.0 : 0.0, context_raw.paint2d ? 1.0 : 0.0); if (context_raw.paint2d) { v.x = vec2d(v.x); } return v; } else if (link == "_envmap_data") { return vec4_create(context_raw.envmap_angle, math_sin(-context_raw.envmap_angle), math_cos(-context_raw.envmap_angle), scene_world.strength * 1.5); } else if (link == "_envmap_data_world") { let tonemap: bool = context_raw.viewport_mode == viewport_mode_t.LIT || context_raw.viewport_mode == viewport_mode_t.PATH_TRACE; return vec4_create(context_raw.envmap_angle, tonemap ? 0.0 : 1.0, 0.0, context_raw.show_envmap ? scene_world.strength : 1.0); } else if (link == "_stencil_transform") { let v: vec4_t = vec4_create(context_raw.brush_stencil_x, context_raw.brush_stencil_y, context_raw.brush_stencil_scale, context_raw.brush_stencil_angle); if (context_raw.paint2d) { v.x = vec2d(v.x); } return v; } else if (link == "_decal_mask") { let decal_mask: bool = context_is_decal_mask_paint(); let val: f32 = (context_raw.brush_radius * context_raw.brush_nodes_radius) / 15.0; let scale2d: f32 = (900 / base_h()) * config_raw.window_scale; val *= scale2d; // Projection ratio let v: vec4_t = vec4_create(context_raw.decal_x, context_raw.decal_y, decal_mask ? 1 : 0, val); if (context_raw.paint2d) { v.x = vec2d(v.x); } return v; } return vec4_nan(); } function uniforms_ext_mat4_link(object: object_t, mat: material_data_t, link: string): mat4_t { if (link == "_decal_layer_matrix") { // Decal layer let m: mat4_t = mat4_inv(context_raw.layer.decal_mat); let f: f32 = object.parent.transform.scale.x * object.transform.scale_world; m = mat4_scale(m, vec4_create(f, f, f, 1.0)); m = mat4_mult_mat(m, uniforms_ext_ortho_p); return m; } return mat4_nan(); } function uniforms_ext_tex_link(object: object_t, mat: material_data_t, link: string): gpu_texture_t { if (link == "_texpaint_undo") { let i: i32 = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1; let rt: render_target_t = map_get(render_path_render_targets, "texpaint_undo" + i); return rt._image; } else if (link == "_texpaint_nor_undo") { let i: i32 = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1; let rt: render_target_t = map_get(render_path_render_targets, "texpaint_nor_undo" + i); return rt._image; } else if (link == "_texpaint_pack_undo") { let i: i32 = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1; let rt: render_target_t = map_get(render_path_render_targets, "texpaint_pack_undo" + i); return rt._image; } else if (link == "_texpaint_sculpt_undo") { let i: i32 = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1; let rt: render_target_t = map_get(render_path_render_targets, "texpaint_sculpt_undo" + i); return rt._image; } else if (link == "_texcolorid") { if (project_assets.length == 0) { let rt: render_target_t = map_get(render_path_render_targets, "empty_white"); return rt._image; } else { return project_get_image(project_assets[context_raw.colorid_handle.i]); } } else if (link == "_textexttool") { // Opacity map for text return context_raw.text_tool_image; } else if (link == "_texbrushmask") { return context_raw.brush_mask_image; } else if (link == "_texbrushstencil") { return context_raw.brush_stencil_image; } else if (link == "_texparticle") { let rt: render_target_t = map_get(render_path_render_targets, "texparticle"); return rt._image; } else if (link == "_texuvmap") { if (!util_uv_uvmap_cached) { sys_notify_on_next_frame(util_uv_cache_uv_map); } return util_uv_uvmap; } else if (link == "_textrianglemap") { if (!util_uv_trianglemap_cached) { sys_notify_on_next_frame(util_uv_cache_triangle_map); } return util_uv_trianglemap; } else if (link == "_texuvislandmap") { sys_notify_on_next_frame(util_uv_cache_uv_island_map); if (util_uv_uvislandmap_cached) { return util_uv_uvislandmap; } else { let rt: render_target_t = map_get(render_path_render_targets, "empty_black"); return rt._image; } } else if (link == "_texdilatemap") { return util_uv_dilatemap; } if (starts_with(link, "_texpaint_pack_vert")) { let tid: string = substring(link, link.length - 1, link.length); let rt: render_target_t = map_get(render_path_render_targets, "texpaint_pack" + tid); return rt._image; } if (starts_with(link, "_texpaint_vert")) { let tid: i32 = parse_int(substring(link, link.length - 1, link.length)); return tid < project_layers.length ? project_layers[tid].texpaint : null; } if (starts_with(link, "_texpaint_nor")) { let tid: i32 = parse_int(substring(link, link.length - 1, link.length)); return tid < project_layers.length ? project_layers[tid].texpaint_nor : null; } if (starts_with(link, "_texpaint_pack")) { let tid: i32 = parse_int(substring(link, link.length - 1, link.length)); return tid < project_layers.length ? project_layers[tid].texpaint_pack : null; } if (starts_with(link, "_texpaint_sculpt")) { let tid: i32 = parse_int(substring(link, link.length - 1, link.length)); return tid < project_layers.length ? project_layers[tid].texpaint_sculpt : null; } if (starts_with(link, "_texpaint")) { let tid: i32 = parse_int(substring(link, link.length - 1, link.length)); return tid < project_layers.length ? project_layers[tid].texpaint : null; } if (starts_with(link, "_texblur_")) { let id: string = substring(link, 9, link.length); if (context_raw.node_previews != null) { return map_get(context_raw.node_previews, id); } else { let rt: render_target_t = map_get(render_path_render_targets, "empty_black"); return rt._image; } } if (starts_with(link, "_texwarp_")) { let id: string = substring(link, 9, link.length); if (context_raw.node_previews != null) { return map_get(context_raw.node_previews, id); } else { let rt: render_target_t = map_get(render_path_render_targets, "empty_black"); return rt._image; } } if (starts_with(link, "_texbake_")) { let id: string = substring(link, 9, link.length); if (context_raw.node_previews != null) { return map_get(context_raw.node_previews, id); } else { let rt: render_target_t = map_get(render_path_render_targets, "empty_black"); return rt._image; } } if (link == "_camera_texture") { let rt: render_target_t = map_get(render_path_render_targets, "last"); return rt._image; } return null; }