Created
July 27, 2015 20:17
-
-
Save boq/b5f94fa9410ec05aea31 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- this program is crude and ugly sometimes ugly. But it's tutorial/demo and not good programming practices tutorial | |
| local args = {...} | |
| side = args[1] | |
| point_num = args[2] | |
| if not point_num or point_num < 1 then | |
| point_num = 8 | |
| end | |
| local p = peripheral.wrap(side) | |
| p.clear() | |
| -- constants | |
| INACTIVE_MARKER_COLOR = 0x0000FF | |
| INACTIVE_MARKER_OPACITY = 0.6 | |
| ACTIVE_MARKER_COLOR = 0xFF0000 | |
| ACTIVE_MARKER_OPACITY = 1 | |
| INITIAL_COLOR = 3 | |
| DRAW_AREA_WIDTH = 200 | |
| DRAW_AREA_HEIGHT = 200 | |
| -- we use setZ to control drawing order and more importantly, order of checking component clicks | |
| -- drawing are is separated into few layers: | |
| LAYER_POINT_SELECTORS = 2 -- for clickable point selectors | |
| LAYER_DRAW_AREA = 1 -- for invisible, clickable draw area. It's is needed, since only drawables report coordinates on mouse event | |
| -- components (like THE POLYGON) by default are on layer 0 | |
| LAYER_BACKGROUND = -2 -- semi-transparent background, for showing drawing area | |
| -- background | |
| local background = p.addBox(0, 0, DRAW_AREA_WIDTH, DRAW_AREA_HEIGHT, 0x000000, 0.2) | |
| background.setAlignment("middle","middle") | |
| background.setZ(LAYER_BACKGROUND) | |
| -- click capture box (invisible overlay) | |
| local draw_area = p.addBox(0, 0, DRAW_AREA_WIDTH, DRAW_AREA_HEIGHT, 0xFFFFFF, 0.0) | |
| draw_area.setAlignment("middle","middle") | |
| draw_area.setZ(LAYER_DRAW_AREA) | |
| -- color selectors | |
| COLORS = { | |
| 0xEB8844, | |
| 0xC354CD, | |
| 0x6689D3, | |
| 0xDECF2A, | |
| 0x41CD34, | |
| 0xD88198, | |
| 0x434343, | |
| 0xABABAB, | |
| 0x287697, | |
| 0x7B2FBE, | |
| 0x253192, | |
| 0x51301A, | |
| 0x3B511A, | |
| 0xB3312C, | |
| 0x1E1B1B, | |
| 0xF0F0F0, | |
| } | |
| -- list of buttons, for updating when point selection changes | |
| local color_buttons = {} | |
| for meta = 1,16 do | |
| local button_x = (meta - 8) * 18 | |
| local button_y = 0 | |
| local button = p.addIcon(button_x, button_y, "minecraft:wool", meta) | |
| button.setAlignment("middle","bottom") | |
| button.setVisible(false) | |
| button.setUserdata({index = meta, rgb = COLORS[meta]}) -- keeping freeform data so we can later identify what was clicked | |
| color_buttons[meta] = button | |
| end | |
| -- color selection marker (just background box) | |
| local color_marker = p.addBox(0,0,16,16, 0x000000, 0.5) | |
| color_marker.setAlignment("middle","bottom") | |
| color_marker.setZ(LAYER_BACKGROUND) | |
| color_marker.setVisible(false) | |
| -- move color selection marker under selected color | |
| function mark_color(color_selector) | |
| assert(color_selector) | |
| color_marker.setX(color_selector.getX()) | |
| color_marker.setY(color_selector.getY()) | |
| end | |
| -- toggle color selector visibility | |
| function change_color_selectors_visibility(visibility) | |
| for _,v in pairs(color_buttons) do | |
| v.setVisible(visibility) | |
| end | |
| color_marker.setVisible(visibility) | |
| end | |
| -- just simple method for drawing equilateral triangles | |
| function set_triangle_position(triangle, x, y) | |
| local H = 4 | |
| local A = 2 / math.sqrt(3) * H | |
| triangle.setP1({x + 0, y - H * 2/3}) | |
| triangle.setP2({x - A/2, y + H * 1/3}) | |
| triangle.setP3({x + A/2, y + H * 1/3}) | |
| end | |
| -- THE POLYGON | |
| local polygon = p.addGradientPolygon() | |
| polygon.setScreenAnchor("middle","middle") | |
| -- triangles for marking and selecting polygons vertices | |
| local point_markers = {} | |
| for i = 1,point_num do | |
| local angle = 2 * math.pi / point_num * i | |
| local point_x = 80 * math.cos(angle) | |
| local point_y = 80 * math.sin(angle) | |
| -- 'points' table works like native Lua tables - setting value at index that does not exists will expand that list (all new values except last are nulls). During rendering null values are just skipped | |
| polygon.setPoints({point_x, point_y, COLORS[INITIAL_COLOR]}, i) | |
| -- creating marker triangle | |
| local point_marker = p.addTriangle({0,0},{0,0},{0,0}, INACTIVE_MARKER_COLOR, INACTIVE_MARKER_OPACITY) | |
| set_triangle_position(point_marker, point_x, point_y) | |
| point_marker.setZ(LAYER_POINT_SELECTORS) | |
| point_marker.setScreenAnchor("middle","middle") | |
| point_marker.setUserdata({index = i, color_index = INITIAL_COLOR}) -- again, some metadata for handling clicks | |
| point_markers[i] = point_marker | |
| end | |
| -- store intial point configuration for later | |
| -- getPoints() returns full list, but getPoints(index) returns just single value | |
| local initial_points = polygon.getPoints() | |
| local reset_label = p.addText(0,0,"RESET", 0xFF0000) | |
| reset_label.setAlignment("right","bottom") | |
| -- currently selected point | |
| local active_point = 1 | |
| -- change colors of all point selectors | |
| function select_point(point_index) | |
| assert(point_index) | |
| active_point = point_index | |
| for _,marker in pairs(point_markers) do | |
| if marker.getUserdata().index == point_index then | |
| marker.setColor(ACTIVE_MARKER_COLOR) | |
| marker.setOpacity(ACTIVE_MARKER_OPACITY) | |
| else | |
| marker.setColor(INACTIVE_MARKER_COLOR) | |
| marker.setOpacity(INACTIVE_MARKER_OPACITY) | |
| end | |
| end | |
| end | |
| -- change color of currently selected point | |
| function set_point_color(component) | |
| assert(component) | |
| local color_userdata = component.getUserdata() | |
| local color_index = color_userdata.index | |
| local rgb = color_userdata.rgb | |
| assert(color_index) | |
| assert(rgb) | |
| -- update polygon point | |
| -- getPoints() returns full list, but getPoints(index) returns just single value | |
| local point = polygon.getPoints(active_point) | |
| point.rgb = rgb | |
| -- same here: setPoints({...}) sets full list, but setPoints(value, index) sets single value | |
| polygon.setPoints(point, active_point) | |
| -- now we needs to update marker triangle color | |
| local point_marker = point_markers[active_point] | |
| local point_userdata = point_marker.getUserdata() | |
| point_userdata.color_index = color_index | |
| point_marker.setUserdata(point_userdata) | |
| end | |
| function sign(val) | |
| if val < 0 then return -1 | |
| elseif val > 0 then return 1 | |
| else return 0 | |
| end | |
| end | |
| function handle_scroll(distance) | |
| if (distance == 0) then return end | |
| local selected_marker = point_markers[active_point] | |
| local userdata = selected_marker.getUserdata() | |
| local current_color = userdata.color_index | |
| local next_color = math.min(math.max(current_color + sign(distance), 1), 16) | |
| local color_selector = color_buttons[next_color] | |
| set_point_color(color_selector) | |
| mark_color(color_selector) | |
| end | |
| -- move currently selected point | |
| function move_point(x, y) | |
| -- change point in polygon... | |
| local point = polygon.getPoints(active_point) | |
| point.x = x | |
| point.y = y | |
| polygon.setPoints(point, active_point) | |
| -- ... and move marker | |
| set_triangle_position(point_markers[active_point], x, y) | |
| end | |
| function reset_polygon() | |
| polygon.setPoints(initial_points) -- restore initial configuration | |
| for i,v in ipairs(point_markers) do -- restore metadata | |
| v.setUserdata({index = i, color_index = INITIAL_COLOR}) | |
| set_triangle_position(v, initial_points[i].x, initial_points[i].y) | |
| end | |
| select_point(1) | |
| mark_color(color_buttons[INITIAL_COLOR]) | |
| end | |
| mark_color(color_buttons[INITIAL_COLOR]) | |
| select_point(1) | |
| p.sync() | |
| function pack(...) | |
| return {...} | |
| end | |
| -- setup done, start event loop | |
| while true do | |
| evt = pack(os.pullEvent()) | |
| -- full list of glasses events: https://gist.github.com/boq/9a098b89ee102cbf1b2b | |
| print(evt[1]) | |
| if evt[1] == "key" then | |
| break -- exit loop | |
| elseif evt[1] == "glasses_capture" then | |
| -- player uses keyboard | |
| local uuid = evt[4] | |
| local control = p.getCaptureControl(uuid) | |
| control.setBackground(0xFFFFFF, 0) | |
| -- replace hotbar with color selector | |
| control.toggleGuiElements({hotbar = false, crosshairs = false, health = false, armor = false, food = false, experience = false}) | |
| change_color_selectors_visibility(true) | |
| elseif evt[1] == "glasses_release" then | |
| change_color_selectors_visibility(false) | |
| elseif evt[1] == "glasses_component_mouse_down" then | |
| -- mouse click | |
| local objectId = evt[5] | |
| local component = p.getObjectById(objectId) | |
| local component_type = component.getType() | |
| local buttonId = evt[9] | |
| if component_type == "triangle" and buttonId == 1 then -- right click triangle to select point | |
| -- point selection | |
| local userdata = component.getUserdata() -- {index, color_index} | |
| select_point(userdata.index) | |
| local color_selector = color_buttons[userdata.color_index] | |
| mark_color(color_selector) | |
| elseif component_type == "item" then -- click wool icon to change color of currect point | |
| mark_color(component) | |
| set_point_color(component) | |
| elseif objectId == draw_area.getId() and buttonId == 0 then -- left click invisible area to move to new position | |
| local clickX = evt[7] - DRAW_AREA_WIDTH / 2 | |
| local clickY = evt[8] - DRAW_AREA_HEIGHT / 2 | |
| move_point(clickX, clickY) | |
| elseif objectId == reset_label.getId() then | |
| reset_polygon() | |
| end | |
| elseif evt[1] == "glasses_mouse_scroll" then | |
| handle_scroll(evt[5]) | |
| elseif evt[1] == "glasses_component_mouse_wheel" then | |
| handle_scroll(evt[9]) | |
| end | |
| p.sync() | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment