diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/json.lua b/code/ryzom/client/data/gamedev/interfaces_v3/json.lua new file mode 100644 index 000000000..66d473ec0 --- /dev/null +++ b/code/ryzom/client/data/gamedev/interfaces_v3/json.lua @@ -0,0 +1,379 @@ +-- +-- json.lua +-- +-- Copyright (c) 2015 rxi +-- +-- This library is free software; you can redistribute it and/or modify it +-- under the terms of the MIT license. See LICENSE for details. +-- + +local json = { _version = "0.1.0" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\\\", + [ "\"" ] = "\\\"", + [ "\b" ] = "\\b", + [ "\f" ] = "\\f", + [ "\n" ] = "\\n", + [ "\r" ] = "\\r", + [ "\t" ] = "\\t", +} + +local escape_char_map_inv = { [ "\\/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return escape_char_map[c] or string.format("\\u%04x", c:byte()) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if val[1] ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.3f", val) +end + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(3, 6), 16 ) + local n2 = tonumber( s:sub(9, 12), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local has_unicode_escape = false + local has_surrogate_escape = false + local has_escape = false + local last + for j = i + 1, #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + end + + if last == 92 then -- "\\" (escape char) + if x == 117 then -- "u" (unicode escape sequence) + local hex = str:sub(j + 1, j + 5) + if not hex:find("%x%x%x%x") then + decode_error(str, j, "invalid unicode escape in string") + end + if hex:find("^[dD][89aAbB]") then + has_surrogate_escape = true + else + has_unicode_escape = true + end + else + local c = string.char(x) + if not escape_chars[c] then + decode_error(str, j, "invalid escape char '" .. c .. "' in string") + end + has_escape = true + end + last = nil + + elseif x == 34 then -- '"' (end of string) + local s = str:sub(i + 1, j - 1) + if has_surrogate_escape then + s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape) + end + if has_unicode_escape then + s = s:gsub("\\u....", parse_unicode_escape) + end + if has_escape then + s = s:gsub("\\.", escape_char_map_inv) + end + return s, j + 1 + + else + last = x + end + end + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + return ( parse(str, next_char(str, 1, space_chars, true)) ) +end + + +return json diff --git a/code/ryzom/client/data/gamedev/interfaces_v3/sceneedit.lua b/code/ryzom/client/data/gamedev/interfaces_v3/sceneedit.lua new file mode 100644 index 000000000..8f907808a --- /dev/null +++ b/code/ryzom/client/data/gamedev/interfaces_v3/sceneedit.lua @@ -0,0 +1,592 @@ +json = dofile("user/json.lua") + +--- Parse interface of ark_scene_editor_edit_menu --- +local script = [[ + + + +]] +parseInterfaceFromString(script) + + +if SceneEditor == nil then + SceneEditor = { + Shapes = {}, + Groups = {}, + LastEditedGroup = nil, + HaveUpdate = nil + + }; +end + + +function debug(text) + local message = ucstring() + message:fromUtf8(tostring(text)) + displaySystemInfo(message, "SYS") +end + + +function SceneEditor:init(scene_id, form_url, translations, icons_url) + self.sceneId = scene_id + self.baseUrl = form_url + self.iconsUrl = icons_url + self.T = translations +end + +function SceneEditor:reset() + self.Shapes = {} + self.Groups = {} + self.LastEditedGroup = nil + self.HaveUpdate = nil + runAH(nil, "remove_shapes", "") + self:get_html("Reseted") +end + +function SceneEditor:show_menu() + if (rightClick) then + SceneEditor:launch_menu() + end +end + + +function SceneEditor:launch_menu(id) + -- SelectedInstanceId can be set by client application + if id ~= nil then + SelectedInstanceId = id + end + local menu = getUI("ui:interface:ark_scene_editor_edit_menu") + menu:setMinW(85) + menu:updateCoords() + menu = menu:getRootMenu() + menu:reset() + menu:addLine(ucstring("-- SHAPE EDITION --"), "", "", "shape_header") + menu:addLine(ucstring("Move"), "", "", "shape_move") + menu:addSubMenu(1) + local subMenu = menu:getSubMenu(1) + subMenu:addIconLine(ucstring("Axe X"), "lua", "setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:move_x()')", "shape_move_x", "ark_move_x.tga") + subMenu:addIconLine(ucstring("Axe Y"), "lua", "setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:move_y()')", "shape_move_y", "ark_move_y.tga") + subMenu:addIconLine(ucstring("Axe Z"), "lua", "x, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:move_z()')", "shape_move_z", "ark_move_z.tga") + subMenu:addIconLine(ucstring("Axes X & Y"), "lua", "setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:move_xy()')", "shape_move_xy", "ark_move_xy.tga") + subMenu:addIconLine(ucstring("Axes X & Y Snap to ground"), "lua", "setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:move_xysnap()')", "shape_move_xy_snap", "ark_move_xysnap.tga") + subMenu:addSeparator() + subMenu:addIconLine(ucstring("Move to player"), "lua", "SceneEditor:move_player()", "shape_move_player", "ark_move_player.tga") + + menu:addLine(ucstring("Rotate"), "", "", "shape_rotate") + menu:addSubMenu(2) + subMenu = menu:getSubMenu(2) + subMenu:addIconLine(ucstring("Axe X"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:rotate(SelectedInstanceId, \"x\")')", "shape_rotate_x", "ark_rotate_x.tga") + subMenu:addIconLine(ucstring("Axe Y"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:rotate(SelectedInstanceId, \"y\")')", "shape_rotate_y", "ark_rotate_y.tga") + subMenu:addIconLine(ucstring("Axe Z"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:rotate(SelectedInstanceId, \"z\")')", "shape_rotate_z", "ark_rotate_z.tga") + + menu:addLine(ucstring("Scale"), "", "", "shape_scale") + menu:addSubMenu(3) + subMenu = menu:getSubMenu(3) + subMenu:addIconLine(ucstring("Axe X"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:scale(SelectedInstanceId, \"x\")')", "shape_scale_x", "ark_scale_x.tga") + subMenu:addIconLine(ucstring("Axe Y"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:scale(SelectedInstanceId, \"y\")')", "shape_scale_y", "ark_scale_y.tga") + subMenu:addIconLine(ucstring("Axe Z"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:scale(SelectedInstanceId, \"z\")')", "shape_scale_z", "ark_scale_z.tga") + + menu:addLine(ucstring("-- COLLISION EDITION --"), "", "", "col_header") + menu:addLine(ucstring("Move"), "", "", "col_move") + menu:addSubMenu(5) + subMenu = menu:getSubMenu(5) + subMenu:addIconLine(ucstring("Axe X"), "lua", "setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:col_move_x()')", "col_move_x", "ark_move_x.tga") + subMenu:addIconLine(ucstring("Axe Y"), "lua", "setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:col_move_y()')", "col_move_y", "ark_move_y.tga") + subMenu:addIconLine(ucstring("Axe Z"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:col_move_z()')", "col_move_z", "ark_move_xy.tga") + subMenu:addIconLine(ucstring("Axe X & Y"), "lua", "setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:col_move_xy()')", "col_move_xy", "ark_move_xy.tga") + subMenu:addSeparator() + subMenu:addIconLine(ucstring("Move to Shape"), "lua", "SceneEditor:col_move_to_shape()", "col_move_to_shape", "ark_move_player.tga") + + menu:addIconLine(ucstring("Rotate"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:col_rotate(SelectedInstanceId, \"x\")')", "col_rotate_x", "ark_rotate_x.tga") + + menu:addLine(ucstring("Scale"), "", "", "col_scale") + menu:addSubMenu(7) + subMenu = menu:getSubMenu(7) + subMenu:addIconLine(ucstring("Axe X"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:col_scale(SelectedInstanceId, \"x\")')", "col_scale_x", "ark_scale_x.tga") + subMenu:addIconLine(ucstring("Axe Y"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:col_scale(SelectedInstanceId, \"y\")')", "col_scale_y", "ark_scale_y.tga") + subMenu:addIconLine(ucstring("Axe Z"), "lua", "ARK_SHAPE_LATEST_X, ARK_SHAPE_LATEST_Y = getMousePos(); setOnDraw(getUI('ui:interface:ark_scene_editor'), 'SceneEditor:col_scale(SelectedInstanceId, \"z\")')", "col_scale_z", "ark_scale_z.tga") + + launchContextMenuInGame("ui:interface:ark_scene_editor_edit_menu") +end + + +function arcc_tools_check_rclick() + root = getUI("ui:interface") + local rx, ry = getMousePos() + i_id = getShapeIdAt(rx, ry) + if i_id >= 0 then + setOnDraw(getUI("ui:interface:ark_scene_editor"), "") + end +end + +function SceneEditor:move(id, axe) + local d, mx, my = getMouseDown() + if d then + setOnDraw(getUI("ui:interface:ark_scene_editor"), "") + SceneEditor:set_modified(id) + self:get_html("Moved") + else + local x,y,z = getGroundAtMouse() + if axe == "x" then moveShape(id, tostring(x), "+0", "+0") end + if axe == "y" then moveShape(id, "+0", tostring(y), "+0") end + if axe == "z" then + mx, my = getMousePos() + moveShape(id, "+0", "+0", "+"..tostring((my-ARK_SHAPE_LATEST_Y)/100)) + ARK_SHAPE_LATEST_Y = my + end + if axe == "xysnap" then moveShape(id, tostring(x), tostring(y), tostring(z)) end + if axe == "xy" then moveShape(id, tostring(x), tostring(y), "+0") end + if axe == "player" then + x, y, z = getPlayerPos() + moveShape(id, tostring(x), tostring(y), tostring(z)) + SceneEditor:set_modified(id) + self:get_html("Moved to player") + end + + end +end + +function SceneEditor:rotate(id, axe) + local d, mx, my = getMouseDown() + if d then + setOnDraw(getUI("ui:interface:ark_scene_editor"), "") + SceneEditor:set_modified(id) + self:get_html("Rotate") + else + mx, my = getMousePos() + if axe == "x" then rotateShape(id, "+"..tostring((my-ARK_SHAPE_LATEST_Y)/100), "+0", "+0") end + if axe == "y" then rotateShape(id, "+0", "+"..tostring((my-ARK_SHAPE_LATEST_Y)/100), "+0") end + if axe == "z" then rotateShape(id, "+0", "+0", "+"..tostring((mx-ARK_SHAPE_LATEST_X)/100)) end + ARK_SHAPE_LATEST_X = mx + ARK_SHAPE_LATEST_Y = my + end +end + +function SceneEditor:scale(id, axe) + local d, mx, my = getMouseDown() + if d then + setOnDraw(getUI("ui:interface:ark_scene_editor"), "") + SceneEditor:set_modified(id) + self:get_html("Rotate") + else + mx, my = getMousePos() + local setup = {} + if axe == "x" then setup["scale x"]="+"..tostring((mx-ARK_SHAPE_LATEST_X)/100) end + if axe == "y" then setup["scale y"]="+"..tostring((mx-ARK_SHAPE_LATEST_X)/100) end + if axe == "z" then setup["scale z"]="+"..tostring((my-ARK_SHAPE_LATEST_Y)/100) end + setupShape(id, setup) + ARK_SHAPE_LATEST_X = mx + ARK_SHAPE_LATEST_Y = my + end +end + + +function SceneEditor:move_x() + self:move(SelectedInstanceId, "x") +end + +function SceneEditor:move_y() + self:move(SelectedInstanceId, "y") +end + +function SceneEditor:move_xy() + self:move(SelectedInstanceId, "xy") +end + +function SceneEditor:move_xysnap() + self:move(SelectedInstanceId, "xysnap") +end + +function SceneEditor:move_z() + self:move(SelectedInstanceId, "z") +end + +function SceneEditor:move_player() + self:move(SelectedInstanceId, "player") +end + + +function SceneEditor:col_move(id, axe) + local d, mx, my = getMouseDown() + + if d then + setOnDraw(getUI("ui:interface:ark_scene_editor"), "") + self:set_modified(id) + self:get_html("Updated") + else + local x,y,z = getGroundAtMouse() + local setup = {} + if axe == "x" then setup["col pos x"]=tostring(x) end + if axe == "y" then setup["col pos y"]=tostring(y) end + if axe == "z" then + mx, my = getMousePos() + setup["col pos z"]="+"..tostring((my-ARK_SHAPE_LATEST_Y)/100) + ARK_SHAPE_LATEST_X = mx + ARK_SHAPE_LATEST_Y = my + end + if axe == "xy" then setup["col pos x"]=tostring(x); setup["col pos y"]=tostring(y) end + if axe == "shape" then + x, y, z = getShapePos(id) + setup["col pos x"]=tostring(x) + setup["col pos y"]=tostring(y) + self:set_modified(id) + setupShape(id, setup) + self:get_html("Updated") + else + setupShape(id, setup) + end + end +end + +function SceneEditor:col_rotate(id, axe) + local d, mx, my = getMouseDown() + if d then + setOnDraw(getUI("ui:interface:ark_scene_editor"), "") + SceneEditor:set_modified(id) + self:get_html("Rotate") + else + mx, my = getMousePos() + local setup = {} + setup["col orientation"]="+"..tostring((mx-ARK_SHAPE_LATEST_X)/100) + setupShape(id, setup) + ARK_SHAPE_LATEST_X = mx + ARK_SHAPE_LATEST_Y = my + end +end + + + +function SceneEditor:col_scale(id, axe) + local d, mx, my = getMouseDown() + if d then + setOnDraw(getUI("ui:interface:ark_scene_editor"), "") + SceneEditor:set_modified(id) + self:get_html("Rotate") + else + mx, my = getMousePos() + local setup = {} + if axe == "x" then setup["col size x"]="+"..tostring((mx-ARK_SHAPE_LATEST_X)/100) end + if axe == "y" then setup["col size y"]="+"..tostring((mx-ARK_SHAPE_LATEST_X)/100) end + if axe == "z" then setup["col size z"]="+"..tostring((my-ARK_SHAPE_LATEST_Y)/100) end + setupShape(id, setup) + ARK_SHAPE_LATEST_X = mx + ARK_SHAPE_LATEST_Y = my + end +end + + +function SceneEditor:set_modified(id) + self.Groups[self.Shapes[id].group].props.modified=true + self.Shapes[id].modified = "modified" + self.HaveUpdate = true +end + + +function SceneEditor:col_move_x() + self:col_move(SelectedInstanceId, "x") +end + +function SceneEditor:col_move_y() + self:col_move(SelectedInstanceId, "y") +end +function SceneEditor:col_move_z() + self:col_move(SelectedInstanceId, "z") +end + + +function SceneEditor:col_move_xy() + self:col_move(SelectedInstanceId, "xy") +end + + +function SceneEditor:col_move_to_shape() + self:col_move(SelectedInstanceId, "shape") +end + + +function SceneEditor:setup_shape(shape_id, setup) + final_setup = self.Shapes[new_shape.id].setup + if final_setup == nil then + final_setup = {} + end + for k,v in pairs(setup) do + final_setup[k] = v + end + self.Shapes[new_shape.id].setup = final_setup + setupShape(shape_id, setup) +end + +function SceneEditor:add(shape) + if self.LastEditedGroup == nil then + self:get_html(''..self.T["no_selected_group"]..'', '000000') + end + local new_shape = {} + new_shape.file = shape + new_shape.group = self.LastEditedGroup + self.Groups[new_shape.group].props.modified=true + new_shape.db_id = self.Groups[new_shape.group].props.count + 1 + new_shape.modified = "added" + new_shape_id = addShape(shape, 0, 0, 0, "user", 1, true, "", "SceneEditor:show_menu()") + table.insert(self.Groups[new_shape.group], new_shape_id) + self.Groups[new_shape.group].props.count = self.Groups[new_shape.group].props.count + 1 + self.Shapes[new_shape_id] = new_shape + self:get_html("Added") +end + + +function SceneEditor:removeShape(shape_id) + deleteShape(shape_id) + local group = self.Shapes[shape_id].group + for k,g_shape_id in pairs(self.Groups[group]) do + if shape_id == g_shape_id then + self.Groups[group][k] = nil + end + end + self:set_modified(shape_id) + self.Shapes[shape_id] = nil + self:get_html("Removed") +end + +function SceneEditor:addGroup(name, count, show, edit) + if name == nil then + return + end + if self.Groups[name] == nil then + self.Groups[name] = {} + self.Groups[name].props = {} + self.Groups[name].props.count = count + self.Groups[name].props.show = show + self.Groups[name].props.edit = edit + self.Groups[name].props.modified = false + else + self.Groups[name].props.show = show + self.Groups[name].props.edit = edit + end +end + +function SceneEditor:editGroup(group) + if self.LastEditedGroup then + self:removeGroup(self.LastEditedGroup) + self:addGroup(self.LastEditedGroup, 0, true, false) + end + self:removeGroup(group); + self:addGroup(group, 0, true, true) + self.LastEditedGroup = group +end + +function SceneEditor:addFromDb(group, db_id, json_shape) + shape = json.decode(json_shape) + shape.db_id = db_id + + shape.group = group + shape.modified = "" + if hide then + shape_id = addShape(shape.file, shape.pos[1], shape.pos[2], shape.pos[3], "user", 1, false, "", "") + else + shape_id = addShape(shape.file, shape.pos[1], shape.pos[2], shape.pos[3], "user", 1, true, "", "SceneEditor:show_menu()") + end + rotateShape(shape_id, tostring(shape.rot[1]), tostring(shape.rot[2]), tostring(shape.rot[3])) + setupShape(shape_id, shape.setup) + self.Shapes[shape_id] = shape + table.insert(self.Groups[group], shape_id) + if db_id > self.Groups[group].props.count then + self.Groups[group].props.count = db_id + end +end + + +function SceneEditor:removeGroup(group) + if self.Groups[group] == nil then + return + end + + for k,shape_id in pairs(self.Groups[group]) do + if k ~= "props" then + self.Shapes[shape_id] = nil + deleteShape(shape_id) + end + end + self.Groups[group] = nil + if self.LastEditedGroup == group then + self.LastEditedGroup = nil + local ui = getUI("ui:interface:ark_list_of_shapes") + if ui then + ui.active=false + end + end + self:get_html("Group Removed") +end + +function SceneEditor:enc64(data) + local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + return ((data:gsub('.', function(x) + local r,b='',x:byte() + for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end + return r; + end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) + if (#x < 6) then return '' end + local c=0 + for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end + return b:sub(c+1,c+1) + end)..({ '', '==', '=' })[#data%3+1]) +end + +function SceneEditor:get_vector(x, y, z) + local vector = {} + table.insert(vector, x) + table.insert(vector, y) + table.insert(vector, z) + + return vector +end + +function SceneEditor:get_random_color() + local r = math.random(44, 66); + local g = math.random(44, 66); + local b = math.random(44, 66); + return '#'..tostring(r)..tostring(g)..tostring(b) + +end + +function pairsByKeys(t, f) + local a = {} + for n in pairs(t) do table.insert(a, n) end + table.sort(a, f) + local i = 0 -- iterator variable + local iter = function () -- iterator function + i = i + 1 + if a[i] == nil then + return nil + else + return a[i], t[a[i]] + end + end + return iter +end + +function SceneEditor:show_shape_list() + local ui = getUI("ui:interface:ark_list_of_shapes") + local need_setup = ui == nil + if need_setup then + WebBrowser:openWindow("ark_list_of_shapes", self.baseUrl..'_ListShapes') + ui = getUI("ui:interface:ark_list_of_shapes") + ui.pop_min_w = 400 + ui.w = 400 + getUI("ui:interface:ark_list_of_shapes:browser:header_opened:browse_redo").active=false + getUI("ui:interface:ark_list_of_shapes:browser:header_opened:browse_undo").active=false + getUI("ui:interface:ark_list_of_shapes:browser:header_opened:browse_refresh").active=false + getUI("ui:interface:ark_list_of_shapes:browser:header_opened:browse_home").active=false + else + ui.active = true + end +end + + +function SceneEditor:get_html_section(message, color) + return '
'..message..'
' +end + +function SceneEditor:get_html(message, message_bg) + local new_group = '  '..self.T[' + local show_hide_cols = '  '..self.T[' + local reset_scene = ''..self.T[' + + local html = '
'..self.T["sceno_editor"]..'
'..self:get_html_section(message..''..new_group..show_hide_cols..reset_scene, (message_bg or SceneEditor:get_random_color())) + + html = html .. '
\ + ' + local groups = {} + for shape_id, shape in pairs(self.Shapes) do + if shape.group == nil then + shape.group = "" + end + + if groups[shape.group] == nil then + groups[shape.group] = {} + end + table.insert(groups[shape.group], shape_id) + end + + for group, shapes in pairsByKeys(self.Groups) do + local groupname = group + html = html .. ''..shapes_html + + end + + html = html .. '
\ + \ + " + end + end + end + else + if self.HaveUpdate == nil then + html = html .. '  '..self.T["edit"]..'' + html = html .. '
 '..groupname..' ('..(self.Groups[group].props.count or '0')..') ' + + + if self.Groups[group].props.show then + if self.Groups[group].props.edit then + html = html .. ''..self.T[' + if self.HaveUpdate then + html = html .. ''..self.T["cancel"]..'' + else + html = html .. ''..self.T["hide"]..'' + end + else + html = html .. ''..self.T["hide"]..'' + end + else + html = html .. ''..self.T["show"]..'' + end + + local shapes_html = "" + local show = self.Groups[group].props.show + if self.Groups[group].props.edit then + shapes_id = groups[group] + if shapes_id then + for k,shape_id in pairs(shapes_id) do + shape = {} + if self.Shapes[shape_id] then + shape["db_id"] = self.Shapes[shape_id].db_id + shape["file"] = self.Shapes[shape_id].file + shape["pos"] = self:get_vector(getShapePos(shape_id)) + scale_x, scale_y, scale_z = getShapeScale(shape_id) + shape["rot"] = self:get_vector(getShapeRot(shape_id)) + colpos_x, colpos_y, colpos_z = getShapeColPos(shape_id) + colscale_x, colscale_y, colscale_z = getShapeColScale(shape_id) + shape["setup"] = {} + shape["setup"]["scale x"] = scale_x + shape["setup"]["scale y"] = scale_y + shape["setup"]["scale z"] = scale_z + shape["setup"]["col pos x"] = shape["pos"][1]+colpos_x + shape["setup"]["col pos y"] = shape["pos"][2]+colpos_y + shape["setup"]["col size x"] = colscale_x + shape["setup"]["col size y"] = colscale_y + shape["setup"]["col size z"] = colscale_z + local color = "202020" + if k % 2 == 0 then + color = "101010" + end + local text_color = "ef9b64" + if self.Shapes[shape_id].modified == "modified" then + text_color = "aa5555" + else + if self.Shapes[shape_id].modified == "added" then + text_color = "55aa55" + end + end + shapes_html = shapes_html .. "
 "..'#'..(shape.db_id or '0').." "..shape.file.."
'..self.T["remove"]..'' + end + end + + if self.Groups[group].props.modified then + html = html .. '  ' + end + html = html .. '
' + ui = getUI("ui:interface:ark_scene_editor:browser:content:html", false) + if ui then + ui:renderHtml(html) + end +end +