#region FN_NODE_CONTEXT_INVOKE { addHotkey("Node_Text", "Output Dimension > Toggle", "D", MOD_KEY.none, function() /*=>*/ { PANEL_GRAPH_FOCUS_STR _n.inputs[9].setValue((_n.inputs[9].getValue() + 1) % 2); }); }); #endregion function Node_Text(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { name = "Draw Text"; font = f_p0; dimension_index = -1; newInput(0, nodeValue_Text("Text", self, "")) .setVisible(true, true); newInput(1, nodeValue_Path("Font", self, "")) .setDisplay(VALUE_DISPLAY.path_font) .setVisible(true, false); newInput(2, nodeValue_Int("Size", self, 16)); newInput(3, nodeValue_Bool("Anti-aliasing ", self, false)); newInput(4, nodeValue_Vec2("Character Range", self, [ 32, 128 ])); newInput(5, nodeValue_Color("Color", self, cola(c_white))); newInput(6, nodeValue_Vec2("Fixed Dimension", self, DEF_SURF )) .setVisible(true, false); newInput(7, nodeValue_Enum_Button("H Align", self, 0, [ THEME.inspector_text_halign, THEME.inspector_text_halign, THEME.inspector_text_halign])); newInput(8, nodeValue_Enum_Button("V Align", self, 0, [ THEME.inspector_text_valign, THEME.inspector_text_valign, THEME.inspector_text_valign ])); newInput(9, nodeValue_Enum_Scroll("Output Dimension", self, 1, [ "Fixed", "Dynamic" ])); newInput(10, nodeValue_Padding("Padding", self, [0, 0, 0, 0])); newInput(11, nodeValue_Float("Letter Spacing", self, 0)); newInput(12, nodeValue_Float("Line Height", self, 0)); newInput(13, nodeValue_PathNode("Path", self, noone)) .setVisible(true, true); newInput(14, nodeValue_Float("Path Shift", self, 0)); newInput(15, nodeValue_Bool("Scale to Fit", self, false)); newInput(16, nodeValue_Bool("Render Background", self, false)); newInput(17, nodeValue_Color("BG Color", self, cola(c_black))); newInput(18, nodeValue_Bool("Wave", self, false)); newInput(19, nodeValue_Float("Wave Amplitude", self, 4)); newInput(20, nodeValue_Float("Wave Scale", self, 30)); newInput(21, nodeValue_Rotation("Wave Phase", self, 0)); newInput(22, nodeValue_Float("Wave Shape", self, 0)) .setDisplay(VALUE_DISPLAY.slider, { range: [ 0, 3, 0.01 ] }); newInput(23, nodeValue_Bool("Typewriter", self, false)); newInput(24, nodeValue_Slider_Range("Range", self, [ 0, 1 ])); newInput(25, nodeValue_Enum_Button("Trim Type", self, 0 , [ "Character", "Word", "Line" ])); newInput(26, nodeValue_Bool("Use Full Text Size", self, true )); newInput(27, nodeValue_Int("Max Line Width", self, 0 )); newInput(28, nodeValue_Bool("Round Position", self, true )); input_display_list = [ 0, ["Output", true], 9, 6, 10, ["Alignment", false], 13, 14, 7, 8, 27, ["Font", false], 1, 2, 15, 3, 11, 12, ["Rendering", false], 5, ["Background", true, 16], 17, ["Wave", true, 18], 22, 19, 20, 21, ["Trim", true, 23], 25, 24, 26, ]; newOutput(0, nodeValue_Output("Surface Out", self, VALUE_TYPE.surface, noone)); attribute_surface_depth(); _font_current = ""; _size_current = 0; _aa_current = false; seed = seed_random(); draw_data = []; draw_font_data = []; #region tool tools = [ new NodeTool( "Edit Text", THEME.text_tools_edit ).setOnToggle(function() /*=>*/ { KEYBOARD_STRING = ""; var _currStr = getSingleValue(0); edit_cursor = 0; edit_cursor_sel = string_length(_currStr); }), ]; edit_cursor_hov = noone; edit_cursor = noone; edit_cursor_sel = noone; edit_typing = false; #endregion static generateFont = function(_path, _size, _aa) { if(PROJECT.animator.is_playing) return; if(font_exists(font) && _path == _font_current && _size == _size_current && _aa == _aa_current) return; _font_current = _path; _size_current = _size; _aa_current = _aa; if(!file_exists_empty(_path)) return; if(font != f_p0 && font_exists(font)) font_delete(font); font_add_enable_aa(_aa); font = font_add(_path, _size, false, false, 0, 127); } static step = function() { var _font = getSingleValue(1); var _dimt = getSingleValue(9); var _path = getSingleValue(13); var _use_path = _path != noone && struct_has(_path, "getPointDistance"); inputs[ 6].setVisible(_dimt == 0 || _use_path); inputs[ 7].setVisible(_dimt == 0 || _use_path); inputs[ 8].setVisible(_dimt == 0 || _use_path); inputs[ 9].setVisible(!_use_path); inputs[14].setVisible( _use_path); inputs[15].setVisible(_dimt == 0 && !_use_path && _font != ""); inputs[ 2].setVisible(_font != ""); inputs[ 3].setVisible(_font != ""); } static waveGet = function(_ind) { var _x = __wave_phase + _ind * __wave_scale; var _sine = dsin(_x) * __wave_ampli; var _squr = sign(_sine) * __wave_ampli; _squr = _squr != 0? _squr : __wave_ampli; var _taup = abs(_x + 90) % 360; var _tria = _taup > 180? 360 - _taup : _taup; _tria = (_tria / 180 * 2 - 1) * __wave_ampli; if(__wave_shape < 0) return _sine; else if(__wave_shape < 1) return lerp(_sine, _tria, frac(__wave_shape)); else if(__wave_shape < 2) return lerp(_tria, _squr, frac(__wave_shape)); else if(__wave_shape < 3) return abs(_x) % 360 > 360 * (0.5 - frac(__wave_shape) / 2)? -__wave_ampli : __wave_ampli; return random_range_seed(-1, 1, _x + seed) * __wave_ampli; } static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) { var _hov = false; var _pth = getSingleValue(13); if(struct_has(_pth, "drawOverlay")) { var hv = _pth.drawOverlay(hover, active, _x, _y, _s, _mx, _my, _snx, _sny); _hov |= bool(hv); } if(isNotUsingTool()) return _hov; var _dat = array_safe_get(draw_data, preview_index, 0); var _dft = array_safe_get(draw_font_data, preview_index, 0); if(_dat == 0) return _hov; var _cr_hover = noone; var _currStr = getSingleValue(0); var _crx0 = 0, _cry0 = 0; var _crx1 = 0, _cry1 = 0; var _crmin = min(edit_cursor, edit_cursor_sel); var _crmax = max(edit_cursor, edit_cursor_sel); draw_set_text(_dft[0], _dft[1], _dft[2], _dft[3]); for( var i = 0, n = array_length(_dat); i < n; i++ ) { var _tdat = _dat[i]; var _tx = _tdat[0]; var _ty = _tdat[1]; var _tchr = _tdat[2]; var _tsw = _tdat[3]; var _tsh = _tdat[4]; var _trot = _tdat[5]; var _tw = _tsw * string_width(_tchr); var _th = _tsh * string_height(_tchr); var _tbx0 = _x + _s * (_tx); var _tby0 = _y + _s * (_ty); var _tbx1 = _x + _s * (_tx + _tw); var _tby1 = _y + _s * (_ty + _th); var _tbxc = (_tbx0 + _tbx1) / 2; if(hover && point_in_rectangle(_mx, _my, _tbx0, _tby0, _tbxc, _tby1)) { _cr_hover = i; draw_set_color(COLORS._main_icon); draw_set_alpha(.5); draw_line_width(_tbx0, _tby0, _tbx0, _tby1, 2); draw_set_alpha(1); } else if(hover && point_in_rectangle(_mx, _my, _tbxc, _tby0, _tbx1, _tby1)) { _cr_hover = i + 1; draw_set_color(COLORS._main_icon); draw_set_alpha(.5); draw_line_width(_tbx1, _tby0, _tbx1, _tby1, 2); draw_set_alpha(1); } if(edit_cursor_sel != noone && i >= _crmin && i < _crmax) { draw_set_color(COLORS.widget_text_highlight); draw_set_alpha(0.5); draw_rectangle(_tbx0, _tby0, _tbx1 - 1, _tby1 - 1, false); draw_set_alpha(1); } // draw cursor if(i == edit_cursor) { _crx0 = _tbx0; _cry0 = _tby0; _crx1 = _tbx0; _cry1 = _tby1; } else if(i + 1 == edit_cursor && i + 1 == n) { _crx0 = _tbx1; _cry0 = _tby0; _crx1 = _tbx1; _cry1 = _tby1; } } edit_cursor_hov = _cr_hover; var _out = getSingleValue(0, preview_index, true); draw_surface_ext_safe(_out, _x, _y, _s, _s); if(edit_cursor != noone) { draw_set_color(COLORS._main_text_accent); draw_set_alpha((edit_typing || current_time % (PREFERENCES.caret_blink * 2000) > PREFERENCES.caret_blink * 1000) * 0.75 + 0.25); draw_line_width(_crx0, _cry0, _crx1, _cry1, 2); draw_set_alpha(1); } if(isUsingTool("Edit Text")) { HOTKEY_BLOCK = true; if(mouse_press(mb_left, active)) { edit_cursor = _cr_hover; edit_cursor_sel = noone; KEYBOARD_STRING = ""; } else if(_cr_hover != noone && mouse_click(mb_left, active)) { if(_cr_hover != edit_cursor) edit_cursor_sel = _cr_hover; } if(keyboard_check_pressed(ord("A")) && key_mod_press(CTRL)) { edit_cursor = 0; edit_cursor_sel = string_length(_currStr); } else if(edit_cursor != noone) { var _edit = false; if(KEYBOARD_PRESSED == vk_left) { edit_cursor = max(0, edit_cursor - 1); edit_cursor_sel = noone; } else if(KEYBOARD_PRESSED == vk_right) { edit_cursor = min(edit_cursor + 1, string_length(_currStr)); edit_cursor_sel = noone; } else if(KEYBOARD_PRESSED == vk_escape) { PANEL_PREVIEW.tool_current = noone; edit_cursor_sel = noone; } else if(edit_cursor_sel != noone && (KEYBOARD_STRING != "" || KEYBOARD_PRESSED == vk_backspace || KEYBOARD_PRESSED == vk_delete)) { _currStr = string_delete(_currStr, _crmin + 1, _crmax - _crmin); _edit = true; edit_cursor = _crmin; edit_cursor_sel = noone; } else if(KEYBOARD_PRESSED == vk_backspace) { _currStr = string_delete(_currStr, edit_cursor, 1); _edit = true; edit_cursor = max(0, edit_cursor - 1); } else if(KEYBOARD_PRESSED == vk_delete) { _currStr = string_delete(_currStr, edit_cursor + 1, 1); _edit = true; } else if(KEYBOARD_PRESSED == vk_enter) { _currStr = string_insert("\n", _currStr, edit_cursor + 1); _edit = true; edit_cursor += 1; KEYBOARD_STRING = ""; } else if(KEYBOARD_STRING != "") { _currStr = string_insert(KEYBOARD_STRING, _currStr, edit_cursor + 1); _edit = true; edit_cursor += string_length(KEYBOARD_STRING); KEYBOARD_STRING = ""; } if(_edit) inputs[0].setValue(_currStr); } } return _hov; } static getTool = function() { var _path = getInputData(13); return is_instanceof(_path, Node)? _path : self; } static processData = function(_outSurf, _data, _output_index, _array_index) { var str = _data[ 0]; var strRaw = str; var _font = _data[ 1]; var _size = _data[ 2]; var _aa = _data[ 3]; var _col = _data[ 5]; var _dim = _data[ 6]; var _hali = _data[ 7]; var _vali = _data[ 8]; var _dimt = _data[ 9]; var _padd = _data[10]; var _trck = _data[11]; var _line = _data[12]; var _path = _data[13]; var _pthS = _data[14]; var _scaF = _data[15]; var _ubg = _data[16]; var _bgc = _data[17]; var _wave = _data[18]; var _waveA = _data[19]; var _waveS = _data[20]; var _waveP = _data[21]; var _waveH = _data[22]; var _type = _data[23]; var _typeR = _data[24]; var _typeC = _data[25]; var _typeF = _data[26]; var _lineW = _data[27]; __rnd_pos = _data[28]; __dwData = array_create(string_length(str)); __dwDataI = 0; generateFont(_font, _size, _aa); draw_set_font(font); #region typewritter if(_type) { var _typAmo = 0; var _typSpa = []; switch(_typeC) { case 0 : _typAmo = string_length(str); break; case 1 : _typSpa = string_splice(str, [" ", "\n"], true); _typAmo = array_length(_typSpa); break; case 2 : _typSpa = string_splice(str, "\n", true); _typAmo = array_length(_typSpa); break; } var _typS = round(_typeR[0] * _typAmo); var _typE = round(_typeR[1] * _typAmo); var _typStr = ""; switch(_typeC) { case 0 : _typStr = string_copy( str, _typS, _typE - _typS); break; case 1 : _typStr = string_concat_ext(_typSpa, _typS, _typE - _typS); break; case 2 : _typStr = string_concat_ext(_typSpa, _typS, _typE - _typS); break; } str = _typStr; if(_typeF == false) strRaw = str; } #endregion #region cut string var _cut_lines = string_splice(str, "\n"); var _str_lines = []; var _line_widths = []; var _ind = 0; for( var i = 0, n = array_length(_cut_lines); i < n; i++ ) { var _str_line = _cut_lines[i]; if(_lineW == 0) { _str_lines[_ind] = _str_line; _line_widths[_ind] = string_width(_str_line) + _trck * (string_length(_str_line) - 1); _ind++; } else { var _lw = 0; var _lne = ""; for( var j = 1; j <= string_length(_str_line); j++ ) { var _chr = string_char_at(_str_line, j); var _chw = string_width(_chr) + _trck; if(_lw + _chw >= _lineW) { _str_lines[_ind] = _lne; _line_widths[_ind] = _lw - _trck; _ind++; _lne = ""; _lw = 0; } _lne += _chr; _lw += _chw; } if(_lne != "") { _str_lines[_ind] = _lne; _line_widths[_ind] = _lw - _trck; _ind++; } } } var _max_ww = 0; var _max_hh = 0; for( var i = 0, n = array_length(_str_lines); i < n; i++ ) { _max_ww = max(_max_ww, _line_widths[i]); _max_hh += string_height(_str_lines[i]); if(i) _max_hh += _line } #endregion #region dimension var ww = 0, _sw = 0; var hh = 0, _sh = 0; ww = _max_ww; hh = _max_hh; var _use_path = _path != noone && struct_has(_path, "getPointDistance"); var _ss = 1; if(_use_path) { _sw = _dim[0]; _sh = _dim[1]; } else if (_dimt == 0) { _sw = _dim[0]; _sh = _dim[1]; if(_scaF) _ss = min(_sw / ww, _sh / hh); } else { _sw = ww; _sh = hh; if(_wave) _sh += abs(_waveA) * 2; } _sw += _padd[PADDING.left] + _padd[PADDING.right]; _sh += _padd[PADDING.top] + _padd[PADDING.bottom]; _outSurf = surface_verify(_outSurf, _sw, _sh, attrDepth()); #endregion #region position var tx = 0, ty = _padd[PADDING.top], _ty = 0; if(_dimt == 0) { switch(_vali) { case 0 : ty = _padd[PADDING.top]; break; case 1 : ty = (_sh - hh * _ss) / 2; break; case 2 : ty = _sh - _padd[PADDING.bottom] - hh * _ss; break; } } if(_wave) ty += abs(_waveA); #endregion #region wave __wave = _wave; __wave_ampli = _waveA; __wave_scale = _waveS; __wave_phase = -_waveP; __wave_shape = _waveH; #endregion surface_set_shader(_outSurf, noone,, BLEND.alpha); if(_ubg) { draw_clear(_bgc); BLEND_ALPHA_MULP } __temp_pt = _path; __temp_ss = _ss; __temp_trck = _trck; if(_use_path) { var _pthl = _path.getLength(0), va; switch(_vali) { case 0 : ty = 0; va = fa_top; break; case 1 : ty = (_max_hh - line_get_height(font)) / 2; va = fa_center; break; case 2 : ty = _max_hh; va = fa_top; break; } for( var i = 0, n = array_length(_str_lines); i < n; i++ ) { var _str_line = _str_lines[i]; var _line_width = _line_widths[i]; draw_set_text(font, fa_left, va, _col); draw_font_data[_array_index] = [font, fa_left, va, _col]; switch(_hali) { case 0 : tx = 0; break; case 1 : tx = _pthl / 2 - _line_width / 2; break; case 2 : tx = _pthl - _line_width; break; } __temp_tx = tx + _pthS; __temp_ty = ty; __temp_p0 = new __vec2P(); __temp_p1 = new __vec2P(); string_foreach(_str_line, function(_chr, _ind) { var _p1 = __temp_pt.getPointDistance(__temp_tx, 0, __temp_p0); var _p2 = __temp_pt.getPointDistance(__temp_tx + .1, 0, __temp_p1); var _nor = point_direction(_p1.x, _p1.y, _p2.x, _p2.y); var _line_ang = _nor + 90; var _dx = lengthdir_x(__temp_ty, _line_ang); var _dy = lengthdir_y(__temp_ty, _line_ang); var _tx = _p1.x + _dx; var _ty = _p1.y + _dy; if(__wave) { var _wd = waveGet(_ind); _tx += lengthdir_x(_wd, _line_ang + 90); _ty += lengthdir_y(_wd, _line_ang + 90); } if(__rnd_pos) { _tx = round(_tx); _ty = round(_ty); } draw_text_transformed(_tx, _ty, _chr, 1, 1, _nor); __dwData[__dwDataI++] = [_tx, _ty, _chr, 1, 1, _nor]; __temp_tx += string_width(_chr) + __temp_trck; }); ty -= string_height(_str_line) + _line; } } else { for( var i = 0, n = array_length(_str_lines); i < n; i++ ) { var _str_line = _str_lines[i]; var _line_width = _line_widths[i]; draw_set_text(font, fa_left, fa_top, _col); draw_font_data[_array_index] = [font, fa_left, fa_top, _col]; tx = _padd[PADDING.left]; if(_dimt == 0) switch(_hali) { case 0 : tx = _padd[PADDING.left]; break; case 1 : tx = (_sw - _line_width * _ss) / 2; break; case 2 : tx = _sw - _padd[PADDING.right] - _line_width * _ss; break; } __temp_tx = tx; __temp_ty = ty; string_foreach(_str_line, function(_chr, _ind) { var _tx = __temp_tx; var _ty = __temp_ty; if(__wave) { var _wd = waveGet(_ind); _ty += _wd; } if(__rnd_pos) { _tx = round(_tx); _ty = round(_ty); } draw_text_transformed(_tx, _ty, _chr, __temp_ss, __temp_ss, 0); __dwData[__dwDataI++] = [_tx, _ty, _chr, __temp_ss, __temp_ss, 0]; __temp_tx += (string_width(_chr) + __temp_trck) * __temp_ss; }); ty += (string_height(_str_line) + _line) * _ss; } } surface_reset_shader(); array_resize(__dwData, __dwDataI); draw_data[_array_index] = __dwData; return _outSurf; } }