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) -- luacheck: no redefined shader:send("zoom",camera.zoom) love.graphics.setShader(shader) local cam_tl,cam_br = camera:extents() 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() local br = hbr:to_pos() if br.x < cam_tl.x or cam_br.x < tl.x or br.y < cam_tl.y or cam_br.y < tl.y then -- definitely not visible on screen -- this does not catch every single nonvisible chunk goto next end set_imesh(ch.imesh) love.graphics.drawInstanced(shape_mesh, count, tl.x, tl.y) end ::next:: end love.graphics.setShader() end return {draw_map=draw_map}