diff options
| author | Lizzy Fleckenstein <lizzy@vlhl.dev> | 2026-06-22 22:55:22 +0200 |
|---|---|---|
| committer | Lizzy Fleckenstein <lizzy@vlhl.dev> | 2026-06-22 22:55:22 +0200 |
| commit | 0d739394fb36a10257751cd48874a42eb620f7a3 (patch) | |
| tree | 7d10e5a291e47c924867da0fec34aff48af72522 /main.lua | |
| download | love-quadtree-0d739394fb36a10257751cd48874a42eb620f7a3.tar.xz | |
init
Diffstat (limited to 'main.lua')
| -rw-r--r-- | main.lua | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..267943b --- /dev/null +++ b/main.lua @@ -0,0 +1,228 @@ +local quadtree = require("quadtree") +local ok, bit = pcall(require, "bit") +if not ok then + ok, bit = pcall(require, "bit32") + if not ok then error("no bit library") end +end + +local state + +function love.load() + love.graphics.setBackgroundColor(1, 1, 1) + love.window.setTitle("Quadtree") + local w, h = love.window.getMode() + love.window.setMode(w, h, { resizable = true }) + + state = {} + state.map = quadtree.new(1, 1, 0.01) + state.pos = { x = state.map.width/2, y = state.map.height/2 } + state.zoom = 25 + state.poly = {} + state.draft = {} + state.mode = "move" + local font = love.graphics.newFont(20) + state.text = { + move = love.graphics.newText(font, "Mode: Move\n\nControls:\nDrag: Move map"), + polygon = love.graphics.newText(font, "Mode: Polygon\n\nControls:\nClick: Add vertex\nP: Finish polygon\n"), + debug = love.graphics.newText(font, "Mode: Debug\n\nControls:\nClick: Print debug info about node"), + general = love.graphics.newText(font, +[[ +M: Switch to Move Mode +P: Switch to Polygon Mode +D: Switch to Debug Mode +Q: Quit +Mouse Wheel: Zoom map +]] + ) + } + return ed +end + +local function proj(x, y) + local w, h = love.graphics:getDimensions() + return w/2+(x-state.pos.x)*state.zoom, h/2-(y-state.pos.y)*state.zoom +end + +local function unproj(x, y) + local w, h = love.graphics:getDimensions() + return state.pos.x+(x-w/2)/state.zoom, state.pos.y+(-y+h/2)/state.zoom +end + +local function add_to_map(poly) + quadtree.insert(state.map, poly, 0.8) +end + +local function poly_bounds(poly) + local x1, y1, x2, y2 + for _, p in ipairs(poly) do + x1 = math.min(x1 or p.x, p.x) + x2 = math.max(x2 or p.x, p.x) + y1 = math.min(y1 or p.y, p.y) + y2 = math.max(y2 or p.y, p.y) + end + return x1, y1, x2, y2 +end + +local function shift_poly(poly, x, y) + local new = {} + for _, p in ipairs(poly) do + table.insert(new, { x = p.x + x, y = p.y + y}) + end + return new +end + +local function grow_map(poly) + local x1, y1, x2, y2 = poly_bounds(poly) + local x1, y1, x2, y2 = x1-2, y1-2, x2+2, y2+2 + local w, h = state.map.width, state.map.height + if x1 < 0 or y1 < 0 then + local ox, oy = -math.min(0, x1), -math.min(0, y1) + x2, y2 = x2 + ox, y2 + oy + w, h = w + ox, h + oy + state.pos.x, state.pos.y = state.pos.x+ox, state.pos.y+oy + poly = shift_poly(poly, ox, oy) + for i, p in ipairs(state.poly) do + state.poly[i] = shift_poly(p, ox, oy) + end + end + w, h = math.max(w, x2), math.max(h, y2) + if w ~= state.map.width or h ~= state.map.height then + state.map = quadtree.new(w, h, 0.02) + for _, p in ipairs(state.poly) do + add_to_map(p) + end + end + return poly +end + +local function add_poly(poly) + if not quadtree.poly_simple(poly) then + return + end + + poly = grow_map(poly) + + for _, tri in ipairs(quadtree.triangulate(poly)) do + add_to_map(tri) + table.insert(state.poly, tri) + end +end + +local function bin(x) + local s = "" + for i = 1, 16 do + s = bit.band(x, 1) .. s + x = bit.rshift(x, 1) + end + return s +end + +function love.mousepressed(x, y, button) + local x, y = unproj(x, y) + if button ~= 1 then + return + end + if state.mode == "polygon" then + table.insert(state.draft, { x = x, y = y }) + elseif state.mode == "debug" then + print("---") + for _, d in ipairs(quadtree.debug) do + if x >= d.p1[1] and x < d.p2[1] and y >= d.p1[2] and y < d.p2[2] then + print(d.msg, "x="..bin(d.bits[1]), "y="..bin(d.bits[2]), "g="..bin(d.g)) + end + end + end +end + +function love.mousemoved(x, y, dx, dy, istouch) + if state.mode == "move" then + if love.mouse.isDown(1) then + state.pos.x = state.pos.x - dx/state.zoom + state.pos.y = state.pos.y + dy/state.zoom + end + end +end + +function love.wheelmoved(x, y) + local cx, cy = love.mouse.getPosition() + local ox, oy = unproj(cx, cy) + + local factor = y < 0 and 0.9 or 1.1 + state.zoom = state.zoom * factor + + local nx, ny = unproj(cx, cy) + state.pos.x = state.pos.x+ox-nx + state.pos.y = state.pos.y+oy-ny +end + +function love.keypressed(key) + if key == "p" then + if state.mode == "polygon" then + if #state.draft >= 3 then + add_poly(state.draft) + end + state.draft = {} + state.mode = "move" + else + state.mode = "polygon" + end + elseif key == "d" then + state.mode = "debug" + elseif key == "m" then + state.mode = "move" + elseif key == "q" then + love.event.quit() + end +end + +local function draw_node(node, w, h, x, y) + if node == true then + love.graphics.setColor(0.7, 0.7, 0.7) + love.graphics.rectangle("fill", x, y, w, h) + elseif node then + local w, h = w/2, h/2 + draw_node(node[1], w, h, x, y) + draw_node(node[2], w, h, x, y+h) + draw_node(node[3], w, h, x+w, y) + draw_node(node[4], w, h, x+w, y+h) + return + end + + love.graphics.setColor(0, 0, 0) + love.graphics.rectangle("line", x, y, w, h) +end + +local function make_verts(poly) + local verts = {} + for _, p in ipairs(poly) do + local x, y = proj(p.x, p.y) + table.insert(verts, x) + table.insert(verts, y) + end + return verts +end + +function love.draw() + love.graphics.setLineWidth(1) + draw_node(state.map.root, state.map.width*state.zoom, -state.map.height*state.zoom, proj(0, 0)) + + love.graphics.setColor(0, 0, 1) + love.graphics.setLineWidth(3) + for _, pl in ipairs(state.poly) do + love.graphics.polygon("line", make_verts(pl)) + end + + love.graphics.setColor(0, 1, 1) + if #state.draft == 1 then + -- love.graphics.setPointWidth(3) + love.graphics.points(proj(state.draft[1].x, state.draft[1].y)) + elseif #state.draft >= 2 then + love.graphics.line(make_verts(state.draft)) + end + + love.graphics.setColor(0, 0, 0) + love.graphics.draw(state.text[state.mode]) + love.graphics.draw(state.text.general, 0, state.text[state.mode]:getHeight()) +end + +return editor_new |
