mirror of
https://github.com/Ttanasart-pt/Pixel-Composer.git
synced 2024-12-30 17:06:27 +01:00
503 lines
No EOL
17 KiB
Text
503 lines
No EOL
17 KiB
Text
function Node_Tile_Drawer(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor {
|
|
name = "Tile Drawer";
|
|
bypass_grid = true;
|
|
|
|
tileset = noone;
|
|
gmTileLayer = noone;
|
|
|
|
newInput( 0, nodeValue_Tileset("Tileset", self, noone))
|
|
.setVisible(true, true);
|
|
|
|
newInput( 1, nodeValue_IVec2("Map size", self, [ 16, 16 ]));
|
|
|
|
newInput( 2, nodeValue_Bool("Animated", self, false));
|
|
|
|
newInput( 3, nodeValueSeed(self));
|
|
|
|
input_display_list = [ 3, 1, 0 ];
|
|
input_display_list_tileset = ["Tileset", false, noone, noone];
|
|
input_display_list_autoterrains = ["Autoterrains", true, noone, noone];
|
|
input_display_list_palette = ["Palette", true, noone, noone];
|
|
input_display_list_animated = ["Animated tiles",true, 2, noone];
|
|
input_display_list_rule = ["Rules", true, noone, noone];
|
|
|
|
newOutput(0, nodeValue_Output("Rendered", self, VALUE_TYPE.surface, noone));
|
|
|
|
newOutput(1, nodeValue_Output("Tilemap", self, VALUE_TYPE.surface, noone));
|
|
|
|
newOutput(2, nodeValue_Output("Tileset", self, VALUE_TYPE.tileset, noone));
|
|
|
|
newOutput(3, nodeValue_Output("Tile Data", self, VALUE_TYPE.struct, {}));
|
|
outputs[3].editWidget.shorted = true;
|
|
|
|
output_display_list = [ 2, 1, 0, 3 ];
|
|
|
|
#region ++++ data ++++
|
|
canvas_surface = surface_create_empty(1, 1, surface_rgba16float);
|
|
canvas_buffer = buffer_create(1, buffer_grow, 1);
|
|
|
|
drawing_surface = noone;
|
|
draw_stack = ds_list_create();
|
|
|
|
preview_drawing_tile = surface_create_empty(1, 1);
|
|
preview_draw_overlay = surface_create_empty(1, 1);
|
|
preview_draw_overlay_tile = surface_create_empty(1, 1);
|
|
|
|
_preview_draw_mask = surface_create_empty(1, 1);
|
|
preview_draw_mask = surface_create_empty(1, 1);
|
|
|
|
temp_surface = [ 0, 0, 0 ];
|
|
selection_mask = noone;
|
|
#endregion
|
|
|
|
#region ++++ selection ++++
|
|
selecting = false;
|
|
selection_x = 0;
|
|
selection_y = 0;
|
|
|
|
selection_mask = noone;
|
|
#endregion
|
|
|
|
#region ++++ tool object ++++
|
|
tool_brush = new tiler_tool_brush(self, noone, false);
|
|
tool_eraser = new tiler_tool_brush(self, noone, true);
|
|
tool_fill = new tiler_tool_fill( self, noone, tool_attribute);
|
|
|
|
tool_rectangle = new tiler_tool_shape(self, noone, CANVAS_TOOL_SHAPE.rectangle);
|
|
tool_ellipse = new tiler_tool_shape(self, noone, CANVAS_TOOL_SHAPE.ellipse);
|
|
#endregion
|
|
|
|
#region ++++ tools ++++
|
|
tool_attribute.size = 1;
|
|
tool_size_edit = new textBox(TEXTBOX_INPUT.number, function(val) { tool_attribute.size = max(1, round(val)); }).setSlideType(true)
|
|
.setFont(f_p3)
|
|
.setSideButton(button(function() { dialogPanelCall(new Panel_Node_Canvas_Pressure(self), mouse_mx, mouse_my, { anchor: ANCHOR.top | ANCHOR.left }) })
|
|
.setIcon(THEME.pen_pressure, 0, COLORS._main_icon));
|
|
tool_size = [ "Size", tool_size_edit, "size", tool_attribute ];
|
|
|
|
tool_attribute.fillType = 0;
|
|
tool_fil8_edit = new buttonGroup( [ THEME.canvas_fill_type, THEME.canvas_fill_type, THEME.canvas_fill_type ], function(val) { tool_attribute.fillType = val; })
|
|
.setTooltips( [ "Edge", "Edge + Corner" ] )
|
|
.setCollape(false);
|
|
tool_fil8 = [ "Fill", tool_fil8_edit, "fillType", tool_attribute ];
|
|
|
|
tool_pencil = new NodeTool( "Pencil", THEME.canvas_tools_pencil)
|
|
.setSetting(tool_size)
|
|
.setToolObject(tool_brush);
|
|
|
|
tool_tile_picker = false;
|
|
|
|
tools = [
|
|
tool_pencil,
|
|
|
|
new NodeTool( "Eraser", THEME.canvas_tools_eraser)
|
|
.setSetting(tool_size)
|
|
.setToolObject(tool_eraser),
|
|
|
|
new NodeTool( "Rectangle", [ THEME.canvas_tools_rect_fill ])
|
|
.setSetting(tool_size)
|
|
.setToolObject(tool_rectangle),
|
|
|
|
new NodeTool( "Ellipse", [ THEME.canvas_tools_ellip_fill ])
|
|
.setSetting(tool_size)
|
|
.setToolObject(tool_ellipse),
|
|
|
|
new NodeTool( "Fill", THEME.canvas_tools_bucket)
|
|
.setSetting(tool_fil8)
|
|
.setToolObject(tool_fill),
|
|
];
|
|
#endregion
|
|
|
|
function apply_draw_surface() {
|
|
if(!is_surface(canvas_surface) || !is_surface(drawing_surface)) return;
|
|
|
|
surface_set_shader(canvas_surface, sh_draw_tile_apply, true, BLEND.over);
|
|
draw_surface(drawing_surface, 0, 0);
|
|
surface_reset_shader();
|
|
|
|
triggerRender();
|
|
}
|
|
|
|
function reset_surface(surface) {
|
|
surface_set_shader(surface, noone, true, BLEND.over);
|
|
draw_surface(canvas_surface, 0, 0);
|
|
surface_reset_shader();
|
|
}
|
|
|
|
static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny, params) {
|
|
if(tileset == noone) return;
|
|
|
|
var _mapSize = current_data[1];
|
|
var _tileSiz = tileset.tileSize;
|
|
|
|
canvas_surface = surface_verify(canvas_surface, _mapSize[0], _mapSize[1], surface_rgba16float);
|
|
|
|
if(!surface_valid(drawing_surface, _mapSize[0], _mapSize[1], surface_rgba16float)) return false;
|
|
|
|
#region surfaces
|
|
var _outDim = [ _tileSiz[0] * _mapSize[0], _tileSiz[1] * _mapSize[1] ];
|
|
|
|
preview_draw_overlay = surface_verify(preview_draw_overlay, _mapSize[0], _mapSize[1], surface_rgba16float);
|
|
preview_drawing_tile = surface_verify(preview_drawing_tile, _mapSize[0] * _tileSiz[0], _mapSize[1] * _tileSiz[1]);
|
|
preview_draw_overlay_tile = surface_verify(preview_draw_overlay_tile, _mapSize[0] * _tileSiz[0], _mapSize[1] * _tileSiz[1]);
|
|
|
|
var __s = surface_get_target();
|
|
var _sw = surface_get_width(__s);
|
|
var _sh = surface_get_height(__s);
|
|
|
|
_preview_draw_mask = surface_verify(_preview_draw_mask, _mapSize[0], _mapSize[1]);
|
|
preview_draw_mask = surface_verify( preview_draw_mask, _sw, _sh);
|
|
|
|
#endregion
|
|
|
|
var _currTool = PANEL_PREVIEW.tool_current;
|
|
var _tool = _currTool == noone? noone : _currTool.getToolObject();
|
|
|
|
if(!is(_tool, tiler_tool))
|
|
_tool = noone;
|
|
|
|
if(_tool) { // tool action
|
|
var brush = tileset.brush;
|
|
|
|
brush.node = self;
|
|
brush.brush_size = tool_attribute.size;
|
|
brush.autoterrain = is(tileset.object_selecting, tiler_brush_autoterrain)? tileset.object_selecting : noone;
|
|
|
|
_tool.brush = brush;
|
|
_tool.subtool = _currTool.selecting;
|
|
_tool.apply_draw_surface = apply_draw_surface;
|
|
_tool.drawing_surface = drawing_surface;
|
|
_tool.tile_size = _tileSiz;
|
|
|
|
if(!tool_tile_picker) {
|
|
_tool.step(hover, active, _x, _y, _s, _mx, _my, _snx, _sny);
|
|
|
|
surface_set_target(preview_draw_overlay);
|
|
DRAW_CLEAR
|
|
_tool.drawPreview(hover, active, _x, _y, _s, _mx, _my, _snx, _sny);
|
|
surface_reset_target();
|
|
|
|
surface_set_target(_preview_draw_mask);
|
|
DRAW_CLEAR
|
|
_tool.drawMask(hover, active, _x, _y, _s, _mx, _my, _snx, _sny);
|
|
surface_reset_target();
|
|
|
|
surface_set_target(preview_draw_mask);
|
|
DRAW_CLEAR
|
|
draw_surface_ext(_preview_draw_mask, _x, _y, _s * _tileSiz[0], _s * _tileSiz[1], 0, c_white, 1);
|
|
surface_reset_target();
|
|
|
|
if(_tool.brush_resizable) {
|
|
if(hover && key_mod_press(CTRL)) {
|
|
if(mouse_wheel_down()) tool_attribute.size = max( 1, tool_attribute.size - 1);
|
|
if(mouse_wheel_up()) tool_attribute.size = min(64, tool_attribute.size + 1);
|
|
}
|
|
|
|
brush.sizing(hover, active, _x, _y, _s, _mx, _my, _snx, _sny);
|
|
}
|
|
|
|
surface_set_shader(preview_draw_overlay_tile, sh_draw_tile_map, true, BLEND.over);
|
|
shader_set_2("dimension", _outDim);
|
|
|
|
shader_set_surface("indexTexture", preview_draw_overlay);
|
|
shader_set_2("indexTextureDim", surface_get_dimension(preview_draw_overlay));
|
|
|
|
tileset.shader_submit();
|
|
|
|
draw_empty();
|
|
surface_reset_shader();
|
|
|
|
draw_surface_ext(preview_draw_overlay_tile, _x, _y, _s, _s, 0, c_white, 1);
|
|
|
|
params.panel.drawNodeGrid();
|
|
|
|
shader_set(sh_brush_outline);
|
|
shader_set_f("dimension", _sw, _sh);
|
|
draw_surface(preview_draw_mask, 0, 0);
|
|
shader_reset();
|
|
}
|
|
|
|
if(tool_tile_picker) {
|
|
var _mtx = floor(round((_mx - _x) / _s - 0.5) / _tileSiz[0]);
|
|
var _mty = floor(round((_my - _y) / _s - 0.5) / _tileSiz[1]);
|
|
|
|
var _mrx = _x + _mtx * _s * _tileSiz[0];
|
|
var _mry = _y + _mty * _s * _tileSiz[1];
|
|
|
|
draw_set_color(COLORS._main_accent);
|
|
draw_rectangle(_mrx, _mry, _mrx + _s * _tileSiz[0], _mry + _s * _tileSiz[0], true);
|
|
|
|
var _cc = surface_getpixel_ext(canvas_surface, _mtx, _mty);
|
|
|
|
if(is_array(_cc)) {
|
|
params.panel.sample_data = {
|
|
type: "tileset",
|
|
drawFn: tileset.drawTile,
|
|
index: _cc[0] - 1,
|
|
};
|
|
|
|
if(mouse_click(mb_left, active)) {
|
|
brush.brush_indices = [[[ _cc[0] - 1, _cc[1] ]]];
|
|
brush.brush_width = 1;
|
|
brush.brush_height = 1;
|
|
|
|
tool_tile_picker = false;
|
|
}
|
|
}
|
|
|
|
if(!key_mod_press(ALT))
|
|
tool_tile_picker = false;
|
|
}
|
|
|
|
if(hover && key_mod_press(ALT))
|
|
tool_tile_picker = true;
|
|
}
|
|
|
|
// if(!array_empty(tileset.autoterrain)) {
|
|
// draw_surface_ext_safe(tileset.autoterrain[0].mask_surface, 32, 32, 8, 8, 0, c_white, 1);
|
|
// }
|
|
// if(surface_exists(canvas_surface)) draw_surface_ext(canvas_surface, 32, 32, 8, 8, 0, c_white, 1);
|
|
// if(surface_exists(drawing_surface)) draw_surface_ext(drawing_surface, 232, 32, 8, 8, 0, c_white, 1);
|
|
// draw_surface_ext(preview_draw_overlay, 432, 32, 8, 8, 0, c_white, 1);
|
|
}
|
|
|
|
////- Update
|
|
|
|
static preGetInputs = function() {
|
|
if(gmTileLayer == noone) return;
|
|
|
|
inputs[1].setValue([ gmTileLayer.tiles.SerialiseWidth, gmTileLayer.tiles.SerialiseHeight ]);
|
|
}
|
|
|
|
static processData = function(_outData, _data, _output_index, _array_index) {
|
|
tileset = _data[0];
|
|
_outData[2] = tileset;
|
|
|
|
if(tileset == noone) {
|
|
input_display_list = [ 3, 1, 0 ];
|
|
return _outData;
|
|
}
|
|
|
|
input_display_list_tileset[3] = tileset.tile_selector.b_toggle;
|
|
input_display_list_autoterrains[3] = tileset.autoterrain_selector.b_toggle;
|
|
input_display_list_palette[3] = tileset.palette_viewer.b_toggle;
|
|
input_display_list_animated[3] = tileset.animated_viewer.b_toggle;
|
|
input_display_list_rule[3] = tileset.rules.b_toggle;
|
|
|
|
input_display_list = [ 3, 1, 0,
|
|
input_display_list_tileset, tileset.tile_selector,
|
|
input_display_list_autoterrains, tileset.autoterrain_selector,
|
|
input_display_list_palette, tileset.palette_viewer,
|
|
input_display_list_animated, tileset.animated_viewer,
|
|
input_display_list_rule, tileset.rules,
|
|
]
|
|
|
|
var _tileSet = tileset.texture;
|
|
var _tileSiz = tileset.tileSize;
|
|
var _mapSize = _data[1];
|
|
var _animated = _data[2];
|
|
var _seed = _data[3];
|
|
update_on_frame = _animated;
|
|
|
|
if(!is_surface(canvas_surface) && buffer_exists(canvas_buffer)) {
|
|
canvas_surface = surface_create(_mapSize[0], _mapSize[1], surface_rgba16float);
|
|
buffer_set_surface(canvas_buffer, canvas_surface, 0);
|
|
} else
|
|
canvas_surface = surface_verify(canvas_surface, _mapSize[0], _mapSize[1], surface_rgba16float);
|
|
|
|
drawing_surface = surface_verify(drawing_surface, _mapSize[0], _mapSize[1], surface_rgba16float);
|
|
temp_surface[0] = surface_verify(temp_surface[0], _mapSize[0], _mapSize[1], surface_rgba16float);
|
|
temp_surface[1] = surface_verify(temp_surface[1], _mapSize[0], _mapSize[1], surface_rgba16float);
|
|
temp_surface[2] = surface_verify(temp_surface[2], _mapSize[0], _mapSize[1], surface_rgba16float);
|
|
|
|
surface_set_shader(drawing_surface, noone, true, BLEND.over);
|
|
draw_surface(canvas_surface, 0, 0);
|
|
surface_reset_shader();
|
|
|
|
if(!is_surface(_tileSet)) return _outData;
|
|
|
|
var _outDim = [ _tileSiz[0] * _mapSize[0], _tileSiz[1] * _mapSize[1] ];
|
|
|
|
var _tileOut = surface_verify(_outData[0], _outDim[0], _outDim[1]);
|
|
var _tileMap = surface_verify(_outData[1], _mapSize[0], _mapSize[1], surface_rgba16float);
|
|
|
|
canvas_buffer = buffer_verify(canvas_buffer, _mapSize[0] * _mapSize[1] * 8);
|
|
buffer_get_surface(canvas_buffer, canvas_surface, 0);
|
|
|
|
surface_set_shader(temp_surface[2], sh_sample, true, BLEND.over);
|
|
draw_surface(canvas_surface, 0, 0);
|
|
surface_reset_shader();
|
|
|
|
var _applied = tileset.rules.apply(temp_surface[2], _seed);
|
|
|
|
surface_set_shader(_tileMap, sh_sample, true, BLEND.over);
|
|
draw_surface(_applied, 0, 0);
|
|
surface_reset_shader();
|
|
|
|
surface_set_shader(_tileOut, sh_draw_tile_map, true, BLEND.over);
|
|
shader_set_2("dimension", _outDim);
|
|
|
|
shader_set_surface("indexTexture", _tileMap);
|
|
shader_set_2("indexTextureDim", surface_get_dimension(_tileMap));
|
|
|
|
shader_set_f("frame", CURRENT_FRAME);
|
|
tileset.shader_submit();
|
|
|
|
draw_empty();
|
|
surface_reset_shader();
|
|
|
|
var tileData = _outData[3];
|
|
var amo = _mapSize[0] * _mapSize[1];
|
|
|
|
if(gmTileLayer != noone) {
|
|
var tileArr = array_verify(struct_try_get(tileData, "data"), amo);
|
|
var i = 0;
|
|
var b;
|
|
|
|
buffer_to_start(canvas_buffer);
|
|
|
|
repeat(amo) {
|
|
b = buffer_read(canvas_buffer, buffer_f16);
|
|
buffer_read(canvas_buffer, buffer_f16);
|
|
buffer_read(canvas_buffer, buffer_f16);
|
|
buffer_read(canvas_buffer, buffer_f16);
|
|
|
|
b = round(b);
|
|
|
|
switch(b) {
|
|
case 0 : tileArr[i] = 0; break;
|
|
default : tileArr[i] = b - 1; break;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
tileData.tileset = tileset;
|
|
tileData.data = tileArr;
|
|
tileData.preview = _tileOut;
|
|
}
|
|
|
|
return [ _tileOut, _tileMap, tileset, tileData ];
|
|
}
|
|
|
|
////- GM
|
|
|
|
static bindTile = function(_gmTile) {
|
|
gmTileLayer = _gmTile;
|
|
|
|
inputs[0].editable = gmTileLayer == noone;
|
|
inputs[1].editable = gmTileLayer == noone;
|
|
inputs[2].editable = gmTileLayer == noone;
|
|
|
|
outputs[0].setVisible(gmTileLayer == noone);
|
|
outputs[1].setVisible(gmTileLayer == noone);
|
|
outputs[2].setVisible(gmTileLayer == noone);
|
|
outputs[3].setVisible(gmTileLayer != noone);
|
|
|
|
if(gmTileLayer == noone) return;
|
|
|
|
display_name = gmTileLayer.name;
|
|
|
|
var _w = gmTileLayer.tiles.SerialiseWidth;
|
|
var _h = gmTileLayer.tiles.SerialiseHeight;
|
|
inputs[1].setValue([ _w, _h ]);
|
|
|
|
var _form = struct_try_get(gmTileLayer.tiles, "TileDataFormat", 0), _data = [];
|
|
var _b = buffer_create(_w * _h * 8, buffer_grow, 1);
|
|
buffer_to_start(_b);
|
|
|
|
if(_form == 0) {
|
|
_data = gmTileLayer.tiles.TileSerialiseData;
|
|
|
|
for( var i = 0, n = array_length(_data); i < n; i++ ) {
|
|
buffer_write(_b, buffer_f16, _data[i]);
|
|
buffer_write(_b, buffer_f16, 0);
|
|
buffer_write(_b, buffer_f16, 0);
|
|
buffer_write(_b, buffer_f16, 0);
|
|
}
|
|
|
|
} else if(_form == 1) {
|
|
_data = gmTileLayer.tiles.TileCompressedData;
|
|
|
|
var _amo, _til;
|
|
|
|
for( var i = 0, n = array_length(_data); i < n; i += 2 ) {
|
|
_amo = -_data[i + 0];
|
|
_til = _data[i + 1];
|
|
_til = max(0, _til + bool(_til));
|
|
|
|
repeat(_amo) {
|
|
buffer_write(_b, buffer_f16, _til);
|
|
buffer_write(_b, buffer_f16, 0);
|
|
buffer_write(_b, buffer_f16, 0);
|
|
buffer_write(_b, buffer_f16, bool(_til));
|
|
}
|
|
}
|
|
}
|
|
|
|
buffer_delete_safe(canvas_buffer);
|
|
canvas_buffer = _b;
|
|
canvas_surface = surface_verify(canvas_surface, _w, _h, surface_rgba16float);
|
|
buffer_set_surface(canvas_buffer, canvas_surface, 0);
|
|
}
|
|
|
|
////- Serialize
|
|
|
|
static attributeSerialize = function() {
|
|
var _attr = {
|
|
canvas : surface_encode(canvas_surface),
|
|
gm_key: gmTileLayer == noone? noone : gmTileLayer.roomObject.key,
|
|
gm_name: gmTileLayer == noone? noone : gmTileLayer.name,
|
|
}
|
|
|
|
return _attr;
|
|
}
|
|
|
|
static attributeDeserialize = function(attr) {
|
|
|
|
if(struct_has(attr, "gm_key") && project.bind_gamemaker) {
|
|
var _room = project.bind_gamemaker.getResourceFromPath(attr.gm_key);
|
|
var _name = attr[$ "gm_name"];
|
|
if(_room != noone && !is_undefined(_name))
|
|
bindTile(_room.getLayerFromName(_name));
|
|
}
|
|
|
|
if(struct_has(attr, "canvas")) {
|
|
var _canv = attr.canvas;
|
|
|
|
surface_free_safe(canvas_surface);
|
|
canvas_surface = surface_decode(_canv);
|
|
|
|
var _dim = surface_get_dimension(canvas_surface);
|
|
buffer_delete_safe(canvas_buffer);
|
|
canvas_buffer = buffer_from_surface(canvas_surface, false, buffer_grow);
|
|
}
|
|
|
|
}
|
|
|
|
////- Actions
|
|
|
|
function resizeBBOX(bbox) {
|
|
var _nw = bbox[2] - bbox[0];
|
|
var _nh = bbox[3] - bbox[1];
|
|
var _dx = -bbox[0];
|
|
var _dy = -bbox[1];
|
|
|
|
gmTileLayer.tiles.SerialiseWidth = _nw;
|
|
gmTileLayer.tiles.SerialiseHeight = _nh;
|
|
|
|
var _newSurf = surface_create(_nw, _nh, surface_rgba16float);
|
|
surface_set_target(_newSurf);
|
|
DRAW_CLEAR
|
|
BLEND_OVERRIDE
|
|
draw_surface_safe(canvas_surface, _dx, _dy);
|
|
BLEND_NORMAL
|
|
surface_reset_target();
|
|
|
|
surface_free_safe(canvas_surface);
|
|
canvas_surface = _newSurf;
|
|
|
|
triggerRender();
|
|
}
|
|
|
|
} |