#include "../global.h" void brush_output_node_parse_inputs(brush_output_node_t *self) { gpu_texture_t *last_mask = g_context->brush_mask_image; gpu_texture_t *last_stencil = g_context->brush_stencil_image; logic_node_value_t *input0 = logic_node_input_get(self->base->inputs->buffer[0]); logic_node_value_t *input1 = logic_node_input_get(self->base->inputs->buffer[1]); logic_node_value_t *input2 = logic_node_input_get(self->base->inputs->buffer[2]); logic_node_value_t *input3 = logic_node_input_get(self->base->inputs->buffer[3]); logic_node_value_t *input4 = logic_node_input_get(self->base->inputs->buffer[4]); logic_node_value_t *input5 = logic_node_input_get(self->base->inputs->buffer[5]); logic_node_value_t *input6 = logic_node_input_get(self->base->inputs->buffer[6]); g_context->paint_vec = input0->_vec4; g_context->brush_nodes_radius = input1->_f32; g_context->brush_nodes_scale = input2->_f32; g_context->brush_nodes_angle = input3->_f32; logic_node_value_t *opac = input4; // Float or texture name if (opac == NULL) { opac = GC_ALLOC_INIT(logic_node_value_t, {._f32 = 1.0}); } if (opac->_str != NULL) { // string g_context->brush_mask_image_is_alpha = ends_with(opac->_str, ".a"); opac->_str = string_copy(substring(opac->_str, 0, string_last_index_of(opac->_str, "."))); g_context->brush_nodes_opacity = 1.0; i32 index = string_array_index_of(project_asset_names, opac->_str); if (index != -1) { asset_t *asset = project_assets->buffer[index]; g_context->brush_mask_image = project_get_image(asset); } } else { g_context->brush_nodes_opacity = opac->_f32; g_context->brush_mask_image = NULL; } g_context->brush_nodes_hardness = input5->_f32; logic_node_value_t *stencil = input6; // Float or texture name if (stencil == NULL) { stencil = GC_ALLOC_INIT(logic_node_value_t, {._f32 = 1.0}); } if (stencil->_str != NULL) { // string g_context->brush_stencil_image_is_alpha = ends_with(stencil->_str, ".a"); stencil->_str = string_copy(substring(stencil->_str, 0, string_last_index_of(stencil->_str, "."))); i32 index = string_array_index_of(project_asset_names, stencil->_str); if (index != -1) { asset_t *asset = project_assets->buffer[index]; g_context->brush_stencil_image = project_get_image(asset); } } else { g_context->brush_stencil_image = NULL; } if (last_mask != g_context->brush_mask_image || last_stencil != g_context->brush_stencil_image) { make_material_parse_paint_material(true); } g_context->brush_directional = self->raw->buttons->buffer[0]->default_value->buffer[0] > 0.0; } void brush_output_paint(brush_output_node_t *self) { bool down = mouse_down("left") || pen_down("tip"); // Set color pick if (down && g_context->tool == TOOL_TYPE_COLORID && project_assets->length > 0) { g_context->colorid_picked = true; ui_toolbar_handle->redraws = 1; } // Prevent painting the same spot bool same_spot = g_context->paint_vec.x == g_context->last_paint_x && g_context->paint_vec.y == g_context->last_paint_y; bool lazy = g_context->tool == TOOL_TYPE_BRUSH && g_context->brush_lazy_radius > 0; if (down && (same_spot || lazy)) { g_context->painted++; } else { g_context->painted = 0; } g_context->last_paint_x = g_context->paint_vec.x; g_context->last_paint_y = g_context->paint_vec.y; if (g_context->tool == TOOL_TYPE_PARTICLE) { g_context->painted = 0; // Always paint particles } if (g_context->painted == 0) { brush_output_node_parse_inputs(self); } if (g_context->painted <= 1) { g_context->pdirty = 1; g_context->rdirty = 2; sculpt_push_undo = true; } } void brush_output_node_run(brush_output_node_t *self, i32 from) { f32 left = 0.0; f32 right = 1.0; f32 top = 0.0; f32 bottom = 1.0; if (g_context->paint2d) { left = 1.0; right = (g_context->split_view ? 2.0 : 1.0) + ui_view2d_ww / (float)base_w(); } // Do not paint over floating toolbar if (context_is_floating_toolbar()) { i32 w = ui_toolbar_x() + ui_toolbar_w(false); left += w / (float)sys_w(); top += w / (float)sys_h(); #ifdef IRON_IOS if (config_is_iphone()) { top += w / (float)sys_h(); } #endif } // First time init if (g_context->last_paint_x < 0 || g_context->last_paint_y < 0) { g_context->last_paint_vec_x = g_context->paint_vec.x; g_context->last_paint_vec_y = g_context->paint_vec.y; } // Paint bounds if (g_context->paint_vec.x < left || g_context->paint_vec.x > right || g_context->paint_vec.y < top || g_context->paint_vec.y > bottom) { return; } // Do not paint over fill layer if (g_context->layer->fill_layer != NULL && g_context->tool != TOOL_TYPE_PICKER && g_context->tool != TOOL_TYPE_MATERIAL && g_context->tool != TOOL_TYPE_COLORID) { return; } // Do not paint over groups if (slot_layer_is_group(g_context->layer)) { return; } if (g_context->brush_locked) { return; } if (!slot_layer_is_visible(g_context->layer) && !g_context->paint2d) { return; } if (ui->is_hovered || base_is_dragging || base_is_resizing || ui->is_scrolling || ui->combo_selected_handle != NULL) { return; } brush_output_paint(self); } brush_output_node_t *brush_output_node_create(ui_node_t *raw, f32_array_t *args) { g_context->run_brush = brush_output_node_run; g_context->parse_brush_inputs = brush_output_node_parse_inputs; brush_output_node_t *n = GC_ALLOC_INIT(brush_output_node_t, {0}); n->base = logic_node_create(n); n->raw = raw; g_context->brush_output_node_inst = n; return n; } // let brush_output_node_def: node_t = { // id: 0, // name: _tr("Brush Output"), // type: "brush_output_node", // x: 0, // y: 0, // color: 0xff4982a0, // inputs: [ // { // id: 0, // node_id: 0, // name: _tr("Position"), // type: "VECTOR", // color: 0xff63c763, // default_value: f32_array_create_xyz(0.0, 0.0, 0.0), // min: 0.0, // max: 1.0, // precision: 100, // display: 0 // }, // { // id: 0, // node_id: 0, // name: _tr("Radius"), // type: "VALUE", // color: 0xffa1a1a1, // default_value: f32_array_create_x(1.0), // min: 0.0, // max: 1.0, // precision: 100, // display: 0 // }, // { // id: 0, // node_id: 0, // name: _tr("Scale"), // type: "VALUE", // color: 0xffa1a1a1, // default_value: f32_array_create_x(1.0), // min: 0.0, // max: 1.0, // precision: 100, // display: 0 // }, // { // id: 0, // node_id: 0, // name: _tr("Angle"), // type: "VALUE", // color: 0xffa1a1a1, // default_value: f32_array_create_x(0.0), // min: 0.0, // max: 1.0, // precision: 100, // display: 0 // }, // { // id: 0, // node_id: 0, // name: _tr("Opacity"), // type: "VALUE", // color: 0xffa1a1a1, // default_value: f32_array_create_x(1.0), // min: 0.0, // max: 1.0, // precision: 100, // display: 0 // }, // { // id: 0, // node_id: 0, // name: _tr("Hardness"), // type: "VALUE", // color: 0xffa1a1a1, // default_value: f32_array_create_x(1.0), // min: 0.0, // max: 1.0, // precision: 100, // display: 0 // }, // { // id: 0, // node_id: 0, // name: _tr("Stencil"), // type: "VALUE", // color: 0xffa1a1a1, // default_value: f32_array_create_x(1.0), // min: 0.0, // max: 1.0, // precision: 100, // display: 0 // } // ], // outputs: [], // buttons: [ // { // name: _tr("Directional"), // type: "BOOL", // output: 0, // default_value: f32_array_create_x(0), // data: NULL, // min: 0.0, // max: 1.0, // precision: 100, // height: 0 // } // ], // width: 0, // flags: 0 // };