add some UI

This commit is contained in:
wan-may 2024-04-27 22:38:23 -03:00
parent a2eeafcdb3
commit 8b766723f1
11 changed files with 391 additions and 2919 deletions

View File

@ -15,8 +15,15 @@ function t.load( filename )
return img, imgd
end
function t.save( data, filename )
function t.save( data, filename, format )
local w, h = data:getDimensions()
local str = ""
for x = 0, w - 1 do
for y = 0, h - 1 do
end
end
return str
end
return t

View File

@ -1,32 +1,79 @@
local t = {}
local lg = love.graphics
function t.onHover( button )
local t = {
name = "",
tooltip = "button",
icon = lg.newImage( "icons/eye.bmp" ),
x = 8,
y = 250,
w = 176,
h = 24,
visible = true,
callback = function( self ) return print( "clicked button: ", self.name, self.x, self.y, self.w, self.h, self.visible ) end
}
t.selected, t.next, t.prev = t, t, t
function t.contains( button, x, y )
return x < button.x + button.w and x > button.x
and y < button.y + button.h and y > button.y
end
function t.onClick( button )
function t.new( b )
b = setmetatable( b or {}, t )
b.next = t
t.prev.next = b
b.prev = t.prev
t.prev = b
return b
end
function t.newButton( name, tooltip, icon, x, y, w, h, callback )
return setmetatable( {
name = name,
tooltip = tooltip,
icon = icon,
x = x,
y = y,
w = w,
h = h,
callback = callback },
t )
local drawPassOngoing = false
function t.draw( b )
if b == t then
drawPassOngoing = not( drawPassOngoing )
if not drawPassOngoing then return end
elseif b.visible then
lg.rectangle( "line", b.x, b.y, b.w, b.h, 6 )
lg.printf( b.name,
b.x,
b.y + 0.5 * ( b.h- lg.getFont():getHeight() ),
b.w - 5,
"right" )
if b.icon then lg.draw( b.icon,
b.x, b.y + 0.5 * (b.h - b.icon:getHeight()),
0,
0.5, 0.5 )
end
if t.selected == b then
lg.rectangle( "fill", b.x, b.y, b.w, b.h, 6 )
end
end
return t.draw( b.next )
end
function t.draw( button )
function t.select( b )
t.selected = b
end
t.__index = t
t.__call = t.newButton
function t.selectNext()
repeat t.selected = t.selected.next until t.selected.visible
end
function t.selectPrev()
repeat t.selected = t.selected.prev until t.selected.visible
end
function t.selectIn( x, y )
t.selected = t
repeat t.selected = t.selected.next until (t.selected == t) or (t.selected.visible and t.selected:contains( x, y ))
end
function t.deselect( b )
t.selected = t
end
setmetatable( t, t )
t.__index = t
t.__call = t.new
return t

View File

@ -47,8 +47,8 @@ function Camera.Set( x, y, w, h )
tfTerritory:translate( -x * 512 / 360, y * 512 / 360 )
tfNodes:reset()
tfNodes:scale( w / 360, h / 200 )
tfNodes:translate( 180 - x , y + 100 )
tfNodes:scale( w / 360, -h / 200 )
tfNodes:translate( 180 - x , -y - 100 )
--tfNodes:translate( -x * 800 / 360, y * 400 / 200 )
end

File diff suppressed because it is too large Load Diff

BIN
data/graphics/blur.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View File

@ -3,6 +3,18 @@ local t = {}
local lfs = love.filesystem
local lg = love.graphics
local polygon = { x = 180, X = -180, y = 100, Y = -100 } --default empty bounding box
local polymt = { __index = polygon }
function polygon:formatDisplayInfo()
return ([[
x: %f
y: %f
X: %f
Y: %f
N: %d]]):format( self.x, self.y, self.X, self.Y, #self )
end
function t.load( filename )
local polys = { visible = true }
local poly = {}
@ -12,7 +24,7 @@ function t.load( filename )
if line:find "b" then
k = 1
if #poly > 2 then n = n + 1 end
poly = {}
poly = setmetatable({}, polymt) --axis-aligned bounding box
polys[n] = poly
else
local _, _, x, y = line:find( "(%g+)%s+(%g+)" )
@ -20,12 +32,16 @@ function t.load( filename )
if x and y then
poly[k], poly[ k + 1 ] = x, y
k = k + 2
if x < poly.x then poly.x = x end
if x > poly.X then poly.X = x end
if y < poly.y then poly.y = y end
if y > poly.Y then poly.Y = y end
else
print( "LINES: malformed line:", filename, line )
end
end
end
if not polys[n] or (#(polys[n]) < 3) then
polys[n] = nil
n = n - 1
@ -35,25 +51,51 @@ function t.load( filename )
return setmetatable( polys, {__index = t } )
end
function t.selectNearest( lines, wx, wy )
local d = math.huge
local nearest
for i, poly in ipairs( lines ) do
if poly.x - 5 < wx and
poly.X + 5 > wx and
poly.y - 5 < wy and
poly.Y + 5 > wy then
for k = 1, #poly, 2 do
local x, y = poly[k], poly[k + 1]
local r = ( x - wx ) * ( x - wx ) + ( y - wy ) * ( y - wy )
if r < d then
d = r
nearest = poly
end
end
end
end
return nearest
end
function t.save( lines, filename )
print( "=== SAVING LINES ===" )
local str = {}
for i, poly in ipairs( lines ) do
str[i] = table.concat( poly, " " )
end
str = table.concat( str, "\nb\n" ):gsub("(%S+) (%S+) ", "%1 %2\n")
return str
end
function t.newPolygon( x, y )
end
function t.addToCurrentPolygon( x, y )
end
function t.deletePolygon( poly )
end
function t.drawPolygonEditHandles( poly )
end
function t.draw( lines )

266
main.lua
View File

@ -14,11 +14,14 @@ function love.load()
assert( lfs.createDirectory( SAVEDIRECTORY.."data/graphics" ))
love.graphics.setNewFont( 12, "mono" )
love.graphics.setNewFont( 14 )--, "mono" )
end
function love.directorydropped( path )
if map.path then assert( love.filesystem.unmount( map.path ) ) end
if map.path then
assert( love.filesystem.unmount( map.path ) )
map.loaded = false
end
love.filesystem.mount( path, "" )
return map.load( path )
end
@ -37,72 +40,34 @@ function love.update( dt )
end
local toolButtons = {
"Brush",
"Move Nodes",
"Add Nodes",
"Edit Node",
"Draw Polygon",
"Erase Polygon"
}
local layerButtons = {
"Africa",
"Europe",
"North America",
"South America",
"Asia",
"Russia",
"Travel Nodes",
"AI Markers",
"Cities",
"Coastlines",
"Coastlines Low",
"Sailable"
}
function love.draw()
if not map.loaded then
return love.graphics.print( "Drag and drop folder to begin.")
local w, h = love.graphics.getDimensions()
return love.graphics.printf( "Drag and drop folder to begin.", w / 2 - 200, h / 2 - 128, 200, "center")
end
love.graphics.push( "all" )
map.draw()
love.graphics.pop()
--Layer buttons.
do
love.graphics.setColor( 1, 1, 1, 1 )
local h = love.graphics.getHeight() - 60
for x = 0, 300, 30 do
love.graphics.rectangle( "line", x, h, 30, 30 )
end
end
--Status bar.
local x, y = love.mouse.getPosition()
local wx, wy = Camera.GetWorldCoordinate( x, y )
local bx, by = Camera.GetBitmapCoordinate( x, y )
local h = love.graphics.getHeight() - 30
love.graphics.setColor( 0.2, 0.1, 0.1, 1.0 )
love.graphics.rectangle( "fill", 0, h, love.graphics.getWidth() / 2, 30 )
local h = love.graphics.getHeight() - 60
love.graphics.setColor( 0.1, 0.1, 0.5, 0.8 )
love.graphics.rectangle( "fill", 0, 0, 250, love.graphics.getHeight() )
love.graphics.setColor( 1, 1, 1, 1 )
love.graphics.rectangle( "line", 0, h, love.graphics.getWidth() / 2, 30 )
love.graphics.print(("SCREEN\t%d\t%d\nWORLD \t%5.2f\t%5.2f"):format(x, y, wx, wy), 0, h)
love.graphics.print(("BITMAP\t%5.2f\t%5.2f"):format(bx, by), 200, h )
love.graphics.print(([[
SCREEN%8d%8d
WORLD %8.2f%8.2f
BITMAP%8.2f%8.2f]]):format(x, y, wx, wy, bx, by), 0, 0)
--Edit box.
love.graphics.rectangle( "line", love.graphics.getWidth() / 2, h, love.graphics.getWidth() / 2, 30 )
if map.selected then
love.graphics.setColor( 0.2, 0.1, 0.1, 1.0 )
love.graphics.rectangle( "fill", 0, 0, 150 ,100 )
love.graphics.setColor( 1, 1, 1, 1 )
love.graphics.rectangle( "line", 0, 0, 150 ,100 )
love.graphics.setColor( 1.2, 1.1, 1.1, 1.5 )
love.graphics.print( map.selected:formatDisplayInfo(), 0, 0 )
end
if map.selected then love.graphics.print( map.selected:formatDisplayInfo(), 0, 80 ) end
if map.selectionLocked then end
love.graphics.setColor( 1, 1, 1, 0.8 )
button:draw()
end
function love.resize(w, h)
@ -113,59 +78,166 @@ function love.wheelmoved(x, y)
Camera.Zoom( (y > 0) and 0.5 or -0.5 )
end
function love.mousepressed( x, y, button, istouch, presses )
function love.mousepressed( x, y, mouseButton, istouch, presses )
local wx, wy = Camera.GetWorldCoordinate( x, y )
if map.loaded then
if button == 1 then
map.cities.lockSelection()
else
map.cities.unlockSelection()
end
end
print( ("MOUSE\tx %f\ty %f\twx %f\twy %f"):format(x, y, wx, wy) )
if button.selected and button.selected:contains( x, y ) then button.selected:callback() end
end
function love.mousemoved( x, y, dx, dy, istouch )
local wx, wy = Camera.GetWorldCoordinate( x, y )
if map.loaded then
if map.cities.visible then map.selected = map.cities:selectNearest( wx, wy )
elseif map.travelnodes.visible then map.selected = map.travelnodes:selectNearest( wx, wy )
elseif map.ainodes.visible then map.selected = map.ainodes:selectNearest( wx, wy )
end
if not map.loaded then return end
--mouse over menu
button.selectIn( x, y )
--mouse on map
if map.selectionLocked then return end
if map.editLayer and map.editLayer.selectNearest then
map.selected = map.editLayer:selectNearest( Camera.GetWorldCoordinate( x, y ) )
end
end
local function ToggleVisibility( layer )
if not layer then return end
local ml
if map[layer] then ml = map[layer] end
if map.territory[layer] then ml = map.territory[layer] end
assert( ml )
ml.visible = not( ml.visible )
print( layer, ml.visible )
end
local layerVisibilityKeybinds = {
["1"] = "africa",
["2"] = "europe",
["3"] = "northamerica",
["4"] = "southamerica",
["5"] = "southasia",
["6"] = "russia",
["7"] = "sailable",
["8"] = "coastlines",
["9"] = "coastlinesLow",
["0"] = "international",
["-"] = "cities",
["="] = "travelnodes",
["backspace"] = "ainodes",
}
function love.keypressed(key)
ToggleVisibility( layerVisibilityKeybinds[key] )
function love.keypressed(key, code, isRepeat)
wasKeyPressed = true
if code == "down" then return button.selectNext() end
if code == "up" then return button.selectPrev() end
if code == "return" then return button.selected:callback() end
if key == "l" then
return map.save()
end
if key == "c" then
map.selectionLocked = not( map.selectionLocked )
end
end
do
button.new{ name = "UNDO", y = 250, callback = map.undo }
local function toolCallback( self )
local f = (map.layers[self.layer])[self.name]
if f then return f(self) end
end
local tools = {
button.new{ name = "SELECT"},
button.new{ name = "ERASE",},
button.new{ name = "MOVE", },
button.new{ name = "ADD", },
button.new{ name = "EDIT", },
button.new{ name = "DRAW", },
}
for i, v in ipairs( tools ) do
v.callback = toolCallback
v.y = 250 + (v.h + 4) * ( i + 1 )
v.visible = false
end
local layerButtons = {}
local function back( self )
for k, button in pairs( tools ) do button.visible = false end
for k, button in pairs( layerButtons ) do button.visible = true end
self.visible = false
map.editLayer = false
end
local backButton = button.new{
name = "BACK",
visible = false,
y = 250 + button.h + 4,
callback = back,
}
local layers = {
{ name = "AF", layer = "africa" },
{ name = "EU", layer = "europe" },
{ name = "NA", layer = "northamerica" },
{ name = "SA", layer = "southamerica" },
{ name = "AS", layer = "southasia" },
{ name = "RU", layer = "russia" },
{ name = "PATH", layer = "travelnodes" },
{ name = "AI", layer = "ainodes" },
{ name = "CITY", layer = "cities" },
{ name = "COAST", layer = "coastlines" },
{ name = "LOW", layer = "coastlinesLow"},
{ name = "SAIL", layer = "sailable" },
}
local visibilityIcon = love.graphics.newImage( "icons/eye.bmp" )
local function toggleVisibleLayer( self )
if not (self and self.layer) then return end
local ml = map.layers[ self.layer ]
ml.visible = not( ml.visible )
self.icon = ml.visible and visibilityIcon
end
local soloIcon = love.graphics.newImage( "icons/eye.bmp" )
local function soloVisibleLayer( self )
--hide icons for disabled invisible layers
print( "===SOLO LAYER===", self.layer )
for i, button in ipairs( layerButtons ) do
if button.layer ~= self.layer then
button.icon = false
end
end
for k, layer in pairs( map.layers ) do
print( "invisible layer, map:", k, layer)
layer.visible = false
end
map.layers[ self.layer ].visible = true
end
local function editLayer( self )
map.editLayer = map.layers[ self.layer ]
for k, button in pairs( layerButtons ) do button.visible = false end
for k, button in pairs( tools ) do
button.visible = true
button.layer = self.layer
end
backButton.visible = true
return soloVisibleLayer( self )
end
local function copy( i, target )
for k, v in pairs( layers[i] ) do
target[k] = target[k] or v
end
return target
end
local y = 250
for i = 1, #layers do
layerButtons[ 3 * i - 2 ] = button.new( copy( i, {
x = 8,
y = y + (button.h + 4) * i,
w = 112,
callback = editLayer
}))
layerButtons[ 3 * i - 1 ] = button.new( copy( i, {
x = 128,
y = y + (button.h + 4) * i,
w = 24,
name = "V",
callback = toggleVisibleLayer,
icon = visibilityIcon,
}))
layerButtons[ 3 * i ] = button.new( copy( i, {
x = 160,
y = y + (button.h + 4) * i,
w = 24,
name = "S",
callback = soloVisibleLayer,
icon = soloIcon
}))
end
end

87
map.lua
View File

@ -6,11 +6,31 @@ local Nodes = require 'travelNodes'
local Camera = require 'camera'
local Territory = require 'territory'
local map = {
loaded = false,
--flat list of editable layers for convenience
local layers = {
coastlines = false,
coastlinesLow = false,
international = false,
africa = false,
europe = false,
northamerica = false,
russia = false,
southamerica = false,
southasia = false,
travelnodes = false,
sailable = false,
ainodes = false,
cities = false,
}
local map = {
layers = layers,
path = false,
loaded = false,
selected = false,
selectionLocked = false,
editLayer = false,
territory = {
africa = false,
europe = false,
@ -19,6 +39,11 @@ local map = {
southamerica = false,
southasia = false
},
background = false,
coastlines = false,
coastlinesLow = false,
international = false,
travelnodes = false,
sailable = false,
ainodes = false,
@ -26,6 +51,7 @@ local map = {
}
function map.load( path )
map.background = lg.newImage( "data/graphics/blur.bmp" )
map.cities = Cities.load( "data/earth/cities.dat" )
map.coastlines = Lines.load( "data/earth/coastlines.dat" )
map.coastlinesLow = Lines.load( "data/earth/coastlines-low.dat" )
@ -38,6 +64,11 @@ function map.load( path )
end
map.loaded = true
map.path = path
--update references
for k, v in pairs( layers ) do
layers[k] = map[k] or map.territory[k]
end
end
function map.draw()
@ -45,10 +76,13 @@ function map.draw()
if not map.loaded then return end
do --territory
lg.setColor( 1,1,1,1)
lg.setLineJoin( "none" )
lg.replaceTransform( Camera.tfTerritory )
lg.setBlendMode( "add" )
lg.setColor( 1, 1, 1, 0.2 )
lg.draw( map.background )
lg.setColor( 1, 1, 1, 0.5 )
for k, v in pairs(map.territory) do
if v.visible then
v:draw()
@ -78,12 +112,21 @@ function map.draw()
do --all this stuff is drawn in world coordinates, ( -180, 180 ) x ( -100, 100 )
lg.replaceTransform( Camera.tf )
if map.selected then
lg.setColor( 1.0, 0.5, 0.5, 0.9 )
lg.setLineJoin( "miter" )
lg.setLineWidth( 1.0 / Camera.zoom )
lg.circle( "line", map.selected.x, map.selected.y, 0.2 + 1.0 / Camera.zoom )
if map.selected[1] then --lines
local p = map.selected
lg.setColor( 0.4, 0.5, 0.8, 0.5 )
lg.setLineWidth( 0.2 / Camera.zoom )
lg.rectangle( "fill", p.x, p.y, p.X - p.x, p.Y - p.y )
lg.setColor( 1.0, 0, 0, 1 )
lg.line( p )
else --points
lg.setColor( 1.0, 0.5, 0.5, 0.9 )
lg.setLineJoin( "miter" )
lg.setLineWidth( 1.0 / Camera.zoom )
lg.circle( "line", map.selected.x, map.selected.y, 0.2 + 1.0 / Camera.zoom )
end
end
if map.cities.visible then --points
@ -94,7 +137,7 @@ function map.draw()
lg.setColor( 1, 1, 0.0, 0.5 )
map.cities.drawCapitals()
end
if map.ainodes.visible then
@ -128,29 +171,33 @@ function map.draw()
map.travelnodes:draw()
end
end
end
end
local function write( filename, string )
--[[local function write( filename, string )
os.rename( filename, filename..".bak" ) --just in case :^)
local file = assert( io.open( filename, "w+" ) )
assert( file:write( string ) )
file:close()
end]]
local function write( filename, string )
print( "Pretending to write", string:len(), "bytes to", filename )
end
function map.save()
write( map.path.."/data/earth/cities.dat", map.cities:save())
map.coastlines.save()
map.coastlinesLow.save()
map.international.save()
map.sailable.save()
map.travelnodes.save()
map.ainodes.save()
write( map.path.."/data/earth/coastlines.dat", map.coastlines:save())
write( map.path.."/data/earth/coastlines-low.dat", map.coastlinesLow:save())
write( map.path.."/data/earth/international.dat", map.international:save())
map.sailable:save()
map.travelnodes:save()
map.ainodes:save()
for k, v in pairs(map.territory) do
map.territory[k].save()
map.territory[k]:save()
end
end
@ -158,4 +205,8 @@ function map.hover(x, y)
end
function map.undo()
print( "=== UNDO ===" )
end
return map

View File

@ -1,2 +0,0 @@
local jit = require 'jit'
for k, v in pairs( jit.opt ) do print(k , v ) end

View File

@ -144,12 +144,8 @@ function t.computeBorder( territory, threshold, key )
end
end
function t.drawConnections( nodes )
end
function t.save( nodes, filename )
function t.save( territory )
end
return t

View File

@ -14,17 +14,17 @@ local function isConnected( startNode, endNode )
local ix, iy, fx, fy = startNode.x, startNode.y, endNode.x, endNode.y
if fx < -180 then fx = fx + 180 end
if fx > 180 then fx = fx - 180 end
local dx, dy = fx - ix, fy - iy
local mag = math.sqrt( dx * dx + dy * dy )
local n = 2 * math.floor( mag )
dx, dy = 0.5 * dx / mag, 0.5 * dy / mag
for i = 1, n do
ix, iy = ix + dx, iy + dy
if not( isSailable( ix, -iy ) ) then return nil end
end
return true
end
@ -41,39 +41,43 @@ function travelNode:formatDisplayInfo()
LATITUDE: %3.2f]]):format( self.idx, self.x, self.y )
end
local function worldToBitmap( x, y )
end
local function bitmapToWorld( x, y )
return 360 * ( x - 800 ) / 800 - 360 / 2 + 360,
360 * ( 600 / 800 ) * ( y - 600 ) / 600 + 180
end
function t.load( filename, sailable )
isSailable = sailable
local img, imgd = bmp.load( filename )
local nodes = { visible = true, nodes = {}, points = {}, connections = {}, img = img }
print( "=== Loading Nodes: ===" )
local n = 1
for x = 0, 799 do
for y = 0, 399 do
if imgd:getPixel( x, 399 - y ) > 0 then
local long = 360 * ( x - 800 ) / 800 - 360 / 2 + 360
local lat = 360 * ( 600 / 800 ) * ( 600 - y ) / 600 - 180
nodes.nodes[n] = setmetatable({x = long, y = -lat, idx = n}, mtTravelNode )
print( nodes.nodes[n]:formatDisplayInfo() )
local long, lat = bitmapToWorld( x, y )
nodes.nodes[n] = setmetatable({x = long, y = lat, idx = n}, mtTravelNode )
nodes.points[ 2 * n - 1 ] = long
nodes.points[ 2 * n ] = lat
n = n + 1
end
end
end
for i, srcNode in ipairs( nodes.nodes ) do
local adjacent = {}
for j, destNode in ipairs( nodes.nodes ) do
adjacent[j] = isConnected( srcNode, destNode )
end
nodes.connections[i] = adjacent
end
print( "=== Nodes Loaded ===" )
nodes.nodes = locationQuery.New( nodes.nodes )
setmetatable( nodes, {__index = t} )
return nodes
@ -81,7 +85,7 @@ end
--Determine if graph has more than one connected component.
function t.isConnected( nodes )
end
function t.draw( nodes )
@ -92,18 +96,18 @@ function t.draw( nodes )
end
function t.drawConnections( nodes )
for i, connection in pairs( nodes.connections ) do
for j in pairs( connection ) do
local ix, iy, fx, fy = nodes.nodes[i].x, nodes.nodes[i].y, nodes.nodes[j].x, nodes.nodes[j].y
lg.line( ix, -iy, fx, -fy )
lg.line( ix, iy, fx, fy )
end
end
end
function t.save( nodes, filename )
end
return t