summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorubq323 <ubq323@ubq323.website>2023-02-23 11:53:10 +0000
committerubq323 <ubq323@ubq323.website>2023-02-25 01:51:36 +0000
commit41a7a40ecf71613c6cb3f7823491c45d9c9c63e0 (patch)
tree737c9955ef433642d3fcfc45bd3ce8c0bb3041fd
parent447f46c1710f507622306a338cc8c82b1ce3aa5c (diff)
implement new rendering system using gpu instancing
this has extremely better performance on my machine also, player is circle now
-rw-r--r--client/chunk.lua42
-rw-r--r--client/conf.lua1
-rw-r--r--client/drawing2.lua144
-rw-r--r--client/main.lua21
-rw-r--r--common/map.lua4
-rw-r--r--server/server.lua2
6 files changed, 205 insertions, 9 deletions
diff --git a/client/chunk.lua b/client/chunk.lua
new file mode 100644
index 0000000..73fe949
--- /dev/null
+++ b/client/chunk.lua
@@ -0,0 +1,42 @@
+local class = require"common.class"
+local chunk = require"common.chunk"
+local Chunk = require"common.chunk".Chunk
+local CHUNK_SIZE = require"common.constants".CHUNK_SIZE
+
+local ChunkC = class.extend(chunk.Chunk)
+function ChunkC.make(cls,...)
+ local self = chunk.Chunk.make(cls,...)
+ self.imesh = cls.imesh_from_chunk_data(self)
+ return self
+end
+local function tile_to_vattr(tile)
+ -- for now tiles are always numbers
+ -- so this just returns the input
+ -- this function might move to drawing.lua once it does something less trivial
+ assert(type(tile) == "number","can't send non-numerical tile to gpu")
+ return tile
+end
+function ChunkC.imesh_from_chunk_data(the_chunk)
+ local mesh_data = {}
+ for q=0,CHUNK_SIZE-1 do
+ for r =0,CHUNK_SIZE-1 do
+ local t = the_chunk:_atqr(q,r)
+ table.insert(mesh_data,{tile_to_vattr(t)})
+ end
+ end
+
+ local imesh = love.graphics.newMesh({
+ {"tile_type","float",1}
+ }, mesh_data, nil, "dynamic")
+
+ return imesh
+end
+
+function ChunkC.set_at(self,hoffs,tile)
+ Chunk.set_at(self,hoffs,tile)
+
+ local idx = chunk.index(hoffs.q,hoffs.r)
+ self.imesh:setVertexAttribute(idx, 1, tile_to_vattr(tile))
+end
+
+return {ChunkC=ChunkC}
diff --git a/client/conf.lua b/client/conf.lua
index 76459ff..3a68be3 100644
--- a/client/conf.lua
+++ b/client/conf.lua
@@ -1,5 +1,6 @@
function love.conf(t)
t.window.title = "hexagon emulator"
t.window.resizable = true
+ t.window.msaa =4
end
diff --git a/client/drawing2.lua b/client/drawing2.lua
new file mode 100644
index 0000000..e09d7dc
--- /dev/null
+++ b/client/drawing2.lua
@@ -0,0 +1,144 @@
+local CHUNK_SIZE = require"common.constants".CHUNK_SIZE
+local coords = require"common.coords"
+
+local tau = 2*math.pi
+
+-- funny hexagon
+local vertices = {}
+-- v[1] {0,0}, fill
+-- v[2-7] edge, fill
+-- v[8-13] inner, outline
+-- v[14-19] outer, outline
+local map = {}
+
+do
+ local function ix(n) return n%6 end
+ local function th(n) return tau*(ix(n)+0.5)/6 end
+ local cos,sin = math.cos,math.sin
+ local OLWIDTH = 0.11
+ local hw = OLWIDTH/2
+ local ri,ro = 1-hw,1+hw
+ local function ve(n,f) return {cos(th(n)),sin(th(n)), f} end
+ local function vi(n,f) return {ri*cos(th(n)),ri*sin(th(n)), f} end
+ local function vo(n,f) return {ro*cos(th(n)),ro*sin(th(n)), f} end
+ local function apv(...) for _,x in ipairs({...}) do table.insert(vertices,x) end end
+ local function apm(...) for _,x in ipairs({...}) do table.insert(map,x) end end
+
+ vertices[1] = {0,0, 1}
+ for n=0,5 do apv(ve(n,1)) end
+ for n=0,5 do apv(vi(n,0)) end
+ for n=0,5 do apv(vo(n,0)) end
+
+ -- fill area
+ for n=0,5 do apm(1, 2+n, 2+ix(1+n) ) end
+
+ local function ii(n) return 8+ix(n) end
+ local function oi(n) return 14+ix(n) end
+
+ -- outline area
+ for n=0,5 do
+ apm( ii(n), oi(n), oi(n+1) )
+ apm( ii(n), oi(n+1), ii(n+1) )
+ end
+end
+
+local shape_mesh = love.graphics.newMesh({
+ {"VertexPosition","float",2},
+ {"fillness","float",1},
+},vertices,"triangles","static")
+shape_mesh:setVertexMap(map)
+
+local function c(...) return {love.math.colorFromBytes(...)} end
+-- taken from breadquest
+local colors = {
+ {0,0,0},
+ c(255,64,64), -- red
+ c(255,128,0), -- orange
+ c(192,192,64), -- yellow
+ c(0,192,0), -- green
+ c(0,192,192), -- teal
+ c(64,64,255), -- blue
+ c(192,0,192), -- purple
+ c(128,128,128), -- grey
+
+ c(0xe7,0x9e,0), -- ubqorange
+}
+
+local shader = love.graphics.newShader([[
+#pragma language glsl3
+
+const mat2 hex_to_pos = mat2( sqrt(3), 0, sqrt(3)/2, 1.5);
+#define CHUNK_SIZE ]]..tostring(CHUNK_SIZE)..[[.0
+
+
+uniform vec3 colors[10];
+
+uniform float zoom;
+
+attribute float tile_type;
+attribute float fillness;
+
+varying vec4 tcol;
+
+const float zthr0 = 2.7;
+const float zthr1 = 6;
+const float zthrd = zthr1-zthr0;
+
+vec4 position(mat4 transform_projection, vec4 vertex_position)
+{
+
+
+ vec2 instance_pos = vec2( floor(love_InstanceID/CHUNK_SIZE), mod(love_InstanceID, CHUNK_SIZE) );
+ vertex_position.xy += hex_to_pos * instance_pos;
+
+ float a = clamp( (zoom-zthr0)/zthrd, 0, 1);
+ a = max(fillness, a);
+
+ int tidx = int(tile_type);
+ tcol = (tidx == 0) ? vec4(0.0) : vec4(fillness*colors[tidx], a);
+
+
+ return transform_projection * vertex_position;
+}
+]],[[
+#pragma language glsl3
+
+varying vec4 tcol;
+vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords)
+{
+ // return vec4(tcol.xyz,0.5);
+ return tcol;
+}
+]])
+
+shader:send("colors",unpack(colors))
+
+
+local function set_imesh(im)
+ shape_mesh:detachAttribute("tile_type")
+ shape_mesh:attachAttribute("tile_type",im,"perinstance")
+end
+
+local function draw_map(camera,map)
+ shader:send("zoom",camera.zoom)
+ love.graphics.setShader(shader)
+
+ local count = CHUNK_SIZE*CHUNK_SIZE
+ for _,ch in map:iter_chunks() do
+ if ch then
+ -- todo: skip chunks that aren't on screen, maybe
+ local htl,hbr = ch.cp:extents()
+ local tl = htl:to_pos()
+
+ set_imesh(ch.imesh)
+ love.graphics.drawInstanced(shape_mesh, count, tl.x, tl.y)
+ end
+ end
+
+ love.graphics.setShader()
+end
+
+
+
+
+return {draw_map=draw_map}
diff --git a/client/main.lua b/client/main.lua
index f74cfa9..e37e18f 100644
--- a/client/main.lua
+++ b/client/main.lua
@@ -13,11 +13,12 @@ local drawing = require"drawing"
local coords = require"common.coords"
local Pos = coords.Pos
local camera = require"camera".Camera:make()
-local Chunk = require"common.chunk".Chunk
+local ChunkC = require"chunk".ChunkC
local util = require"util"
local Map = require"common.map".Map
local movement = require"movement"
local msgbox = require"msgbox"
+local drawing2 = require"drawing2"
-- local pprint=require"common.pprint"
-- pprint.setup{show_all=true}
@@ -97,12 +98,14 @@ end
local function draw_player(pl,islocal)
local hplsz = PLAYER_SIZE/2
love.graphics.setColor(pl.color)
- love.graphics.rectangle("fill",pl.pos.x-hplsz,pl.pos.y-hplsz,PLAYER_SIZE,PLAYER_SIZE)
+ love.graphics.circle("fill",pl.pos.x,pl.pos.y, hplsz)
+ -- love.graphics.rectangle("fill",pl.pos.x-hplsz,pl.pos.y-hplsz,PLAYER_SIZE,PLAYER_SIZE)
-- love.graphics.print(tostring(pl.id),pl.pos.x,pl.pos.y)
if islocal then
love.graphics.setLineWidth(0.01)
love.graphics.setColor(0.5,0,0)
- love.graphics.rectangle("line",pl.pos.x-hplsz,pl.pos.y-hplsz,PLAYER_SIZE,PLAYER_SIZE)
+ love.graphics.circle("line",pl.pos.x,pl.pos.y,hplsz)
+ -- love.graphics.rectangle("line",pl.pos.x-hplsz,pl.pos.y-hplsz,PLAYER_SIZE,PLAYER_SIZE)
end
end
@@ -111,7 +114,7 @@ local remote_players = {}
local function update_local_player(pl,dt)
local SPEED = 8*math.sqrt(3) -- 8 hexagonheights per second
- if love.keyboard.isDown("lshift") then SPEED = SPEED*2.5 end
+ if love.keyboard.isDown("lshift") then SPEED = SPEED*2 end
local function kd(code)
if love.keyboard.isScancodeDown(code) then return 1 else return 0 end
end
@@ -131,13 +134,14 @@ local function update_local_player(pl,dt)
local try_pos = Pos:make(pl.pos.x + SPEED*dt*dx, pl.pos.y + SPEED*dt*dy)
pl.pos = movement.collide_with_terrain(pl.pos,try_pos,map)
+ -- pl.pos = try_pos
pl.pos_dirty = true
end
local function sync_local_player(pl)
-- send updated info about local player to server
if pl.pos_dirty then
- peer:send(json.encode{t="ppos",x=pl.pos.x,y=pl.pos.y})
+ peer:send(json.encode{t="ppos",x=pl.pos.x,y=pl.pos.y},1)
pl.pos_dirty = false
end
end
@@ -223,7 +227,7 @@ function love.update(dt)
local pl = j.pl
local_player = {pos=coords.Pos:make(pl.x,pl.y),color=pl.color,id=pl.id}
elseif op == "chunk" then
- local ch = Chunk:from_packet_data(j)
+ local ch = ChunkC:from_packet_data(j)
map:add_chunk(ch)
elseif op == "settile" then
local h = coords.Hex:make(j.q,j.r)
@@ -244,7 +248,9 @@ function love.draw()
end
camera:apply_trans()
- drawing.draw_map(camera,map)
+ -- drawing.draw_map(camera,map)
+ drawing2.draw_map(camera,map)
+
if local_player then
draw_player(local_player,true)
@@ -301,6 +307,7 @@ function love.draw()
love.graphics.line(tw,y,tw,y+th)
end
+
end
function love.load()
diff --git a/common/map.lua b/common/map.lua
index 1028982..67e2834 100644
--- a/common/map.lua
+++ b/common/map.lua
@@ -8,8 +8,10 @@
-- to test whether a chunk needs to be loaded you do if map:chunk(cp) == nil then ... end.
-- it will probably also do things relating to entities and multiblock things
+-- note that the Map never creates any Chunks itself, which means it should be agnostic
+-- to whatever actual Chunk class is being used (ChunkC or ChunkS or whatever)
+
local class = require"common.class"
-local chunk = require"common.chunk"
local coords = require"common.coords"
local CHUNK_SIZE = require"common.constants".CHUNK_SIZE
diff --git a/server/server.lua b/server/server.lua
index f78bdd0..03a5fd9 100644
--- a/server/server.lua
+++ b/server/server.lua
@@ -103,7 +103,7 @@ local function handle_ev(ev)
-- print(player.id,"-->",player.pos[1],player.pos[2])
for i,otherplayer in ipairs(playerlist) do
if otherplayer ~= player then
- otherplayer.peer:send(player_move_packet(player,x,y))
+ otherplayer.peer:send(player_move_packet(player,x,y),1)
end
end
elseif op == "settile" then