diffuse lighting; gltf loading; ending screen
This commit is contained in:
parent
6a23bf6570
commit
b167e9360b
|
@ -1,3 +1,26 @@
|
||||||
Assets:
|
===DKJSON===
|
||||||
|
*Copyright (C) 2010-2024 David Heiko Kolf*
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
===ASSETS===
|
||||||
Johann Wilhelm Weis-Cuiller, photo par Ji-Elle sur Wikipedia: https://commons.wikimedia.org/wiki/File:Johann_Wilhelm_Weis-Cuiller.jpg licenced under CC-BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/
|
Johann Wilhelm Weis-Cuiller, photo par Ji-Elle sur Wikipedia: https://commons.wikimedia.org/wiki/File:Johann_Wilhelm_Weis-Cuiller.jpg licenced under CC-BY-SA 4.0: https://creativecommons.org/licenses/by-sa/4.0/
|
||||||
Coffee spoon MET 17847.jpg, CC0 https://commons.wikimedia.org/wiki/File:Coffee_spoon_MET_17847.jpg
|
Coffee spoon MET 17847.jpg, CC0 https://commons.wikimedia.org/wiki/File:Coffee_spoon_MET_17847.jpg
|
|
@ -23,4 +23,8 @@ ENTER TO KEEP]],
|
||||||
mouseSensitivity = "TURN SPEED",
|
mouseSensitivity = "TURN SPEED",
|
||||||
language = "LANGUAGE",
|
language = "LANGUAGE",
|
||||||
FOV = "FOV",
|
FOV = "FOV",
|
||||||
|
win = [[
|
||||||
|
YOU'RE WINNER!
|
||||||
|
|
||||||
|
]]
|
||||||
}
|
}
|
|
@ -1,82 +0,0 @@
|
||||||
local love = assert( love )
|
|
||||||
|
|
||||||
local mat4 = require( "mat4" )
|
|
||||||
local alph = 1/math.sqrt(2)
|
|
||||||
local testMesh = love.graphics.newMesh(
|
|
||||||
{--attributes
|
|
||||||
{"VertexPosition", "float", 4},
|
|
||||||
{"VertexColor", "float", 3},
|
|
||||||
{"VertexTexCoord", "float", 2},
|
|
||||||
},
|
|
||||||
{--vertices
|
|
||||||
{ 1, 0, -alph, 1,
|
|
||||||
1, 1, 1,
|
|
||||||
1, 0 },
|
|
||||||
{ -1, 0, -alph, 1,
|
|
||||||
1, 0, 0,
|
|
||||||
0, 0 },
|
|
||||||
{ 0, 1, alph, 1,
|
|
||||||
0, 1, 0,
|
|
||||||
1, 1, },
|
|
||||||
{ 0, -1, alph, 1,
|
|
||||||
0, 0, 1,
|
|
||||||
0, 1, },
|
|
||||||
},
|
|
||||||
"strip",
|
|
||||||
"static"
|
|
||||||
)
|
|
||||||
testMesh:setVertexMap{ 1,2,3,4,1,2 }
|
|
||||||
local rockTexture = love.graphics.newImage( "tex/rock.png" )
|
|
||||||
rockTexture:setWrap( "repeat", "repeat" )
|
|
||||||
testMesh:setTexture( rockTexture )
|
|
||||||
|
|
||||||
--Transforms
|
|
||||||
mat4.randomise()
|
|
||||||
local instanceTransforms = love.graphics.newMesh( {
|
|
||||||
{"itx", "float", 4},
|
|
||||||
{"ity", "float", 4},
|
|
||||||
{"itz", "float", 4},
|
|
||||||
{"itw", "float", 4}}, 1024, nil, "static" )
|
|
||||||
instanceTransforms:setVertices( mat4.data )
|
|
||||||
testMesh:attachAttribute( "itx", instanceTransforms, "perinstance" )
|
|
||||||
testMesh:attachAttribute( "ity", instanceTransforms, "perinstance" )
|
|
||||||
testMesh:attachAttribute( "itz", instanceTransforms, "perinstance" )
|
|
||||||
testMesh:attachAttribute( "itw", instanceTransforms, "perinstance" )
|
|
||||||
|
|
||||||
|
|
||||||
local instanceShader = [[
|
|
||||||
varying vec4 itxdbg;
|
|
||||||
#ifdef VERTEX
|
|
||||||
attribute vec4 itx;
|
|
||||||
attribute vec4 ity;
|
|
||||||
attribute vec4 itz;
|
|
||||||
attribute vec4 itw;
|
|
||||||
uniform mat4 view;
|
|
||||||
uniform mat4 proj;
|
|
||||||
vec4 position( mat4 _, vec4 pos ){
|
|
||||||
mat4 inst = mat4( itx, ity, itz, itw );
|
|
||||||
vec4 cam = view*pos;
|
|
||||||
itxdbg = itw;
|
|
||||||
return proj * cam;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef PIXEL
|
|
||||||
vec4 effect( vec4 color, Image tex, vec2 texuv, vec2 scruv) {
|
|
||||||
return color * Texel(tex, texuv) * vec4( 2.0, 2.0, 2.0, itxdbg.w ) ;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
]]
|
|
||||||
instanceShader = love.graphics.newShader( instanceShader, instanceShader )
|
|
||||||
|
|
||||||
return { draw = function( view, proj )
|
|
||||||
love.graphics.push( "all" )
|
|
||||||
love.graphics.setShader( instanceShader )
|
|
||||||
instanceShader:send( "view", "column", view )
|
|
||||||
instanceShader:send( "proj", "column", proj )
|
|
||||||
io.flush()
|
|
||||||
love.graphics.drawInstanced( testMesh, 30, 0, 0 )
|
|
||||||
love.graphics.pop()
|
|
||||||
end,
|
|
||||||
update = function()
|
|
||||||
mat4.randomise()
|
|
||||||
end}
|
|
|
@ -3,19 +3,14 @@ local gpu = require( "gpu" )
|
||||||
local t = {}
|
local t = {}
|
||||||
|
|
||||||
local canvas
|
local canvas
|
||||||
local shaders = {
|
|
||||||
matte = require( "shaders.matte" ),
|
|
||||||
bell = require( "shaders.bell" ),
|
|
||||||
sky = require( "shaders.sky" ),
|
|
||||||
}
|
|
||||||
|
|
||||||
local meshes = {}
|
local meshes = {}
|
||||||
local drawLists = {}
|
|
||||||
local isDebugging = false
|
local isDebugging = false
|
||||||
local tf = love.math.newTransform()
|
local tf = love.math.newTransform()
|
||||||
local debugTF = love.math.newTransform()
|
local debugTF = love.math.newTransform()
|
||||||
|
local sky
|
||||||
for k in pairs( shaders ) do drawLists[k] = {} end
|
local bell
|
||||||
|
local contempra
|
||||||
|
|
||||||
function t.start()
|
function t.start()
|
||||||
canvas = {
|
canvas = {
|
||||||
|
@ -24,26 +19,15 @@ function t.start()
|
||||||
depth = true,
|
depth = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
drawLists.sky = require( "models.sky" )
|
sky = require( "models.sky" )
|
||||||
shaders.sky:send( "cube", drawLists.sky.tex )
|
bell = require( "models.bell" )
|
||||||
|
contempra = require( "models.contempra" )
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.debug()
|
function t.debug()
|
||||||
isDebugging = true
|
isDebugging = true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function sky( view )
|
|
||||||
love.graphics.push( "all" )
|
|
||||||
love.graphics.setDepthMode( "always", false )
|
|
||||||
love.graphics.setMeshCullMode( "none" )
|
|
||||||
love.graphics.setShader( shaders.sky )
|
|
||||||
local s = shaders.sky
|
|
||||||
local rot = { view[1], view[2], view[3], {0, 0, 0, 1} }
|
|
||||||
s:send( "view", "column", rot )
|
|
||||||
love.graphics.draw( drawLists.sky.mesh )
|
|
||||||
love.graphics.pop()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function matte( )
|
local function matte( )
|
||||||
local list = drawLists.matte
|
local list = drawLists.matte
|
||||||
local shader = shaders.matte
|
local shader = shaders.matte
|
||||||
|
@ -54,20 +38,6 @@ local function matte( )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function bell( )
|
|
||||||
local list = drawLists.bell
|
|
||||||
local shader = shaders.bell
|
|
||||||
love.graphics.setShader( shader )
|
|
||||||
|
|
||||||
for mesh in pairs( list ) do
|
|
||||||
love.graphics.drawInstanced( mesh, 7 )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[function t.setViewDirection( x, y, z )
|
|
||||||
shaders.sky:send( "viewVec", {x, y, z} )
|
|
||||||
end]]
|
|
||||||
|
|
||||||
function t.draw( view, proj )
|
function t.draw( view, proj )
|
||||||
|
|
||||||
if isDebugging then
|
if isDebugging then
|
||||||
|
@ -82,14 +52,10 @@ function t.draw( view, proj )
|
||||||
love.graphics.replaceTransform( tf )
|
love.graphics.replaceTransform( tf )
|
||||||
love.graphics.setMeshCullMode( "back" )
|
love.graphics.setMeshCullMode( "back" )
|
||||||
|
|
||||||
for _, s in pairs( shaders ) do
|
sky.draw( view, proj )
|
||||||
s:send( "view", "column", view )
|
bell.draw( view, proj )
|
||||||
s:send( "proj", "column", proj )
|
contempra.draw( view, proj )
|
||||||
end
|
|
||||||
|
|
||||||
sky( view )
|
|
||||||
matte()
|
|
||||||
bell()
|
|
||||||
|
|
||||||
love.graphics.pop()
|
love.graphics.pop()
|
||||||
love.graphics.setColor( 1, 1, 1, 1 )
|
love.graphics.setColor( 1, 1, 1, 1 )
|
|
@ -0,0 +1,752 @@
|
||||||
|
-- Module options:
|
||||||
|
local always_use_lpeg = false
|
||||||
|
local register_global_module_table = false
|
||||||
|
local global_module_name = 'json'
|
||||||
|
|
||||||
|
--[==[
|
||||||
|
|
||||||
|
David Kolf's JSON module for Lua 5.1 - 5.4
|
||||||
|
|
||||||
|
Version 2.8
|
||||||
|
|
||||||
|
|
||||||
|
For the documentation see the corresponding readme.txt or visit
|
||||||
|
<http://dkolf.de/dkjson-lua/>.
|
||||||
|
|
||||||
|
You can contact the author by sending an e-mail to 'david' at the
|
||||||
|
domain 'dkolf.de'.
|
||||||
|
|
||||||
|
|
||||||
|
Copyright (C) 2010-2024 David Heiko Kolf
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
--]==]
|
||||||
|
|
||||||
|
-- global dependencies:
|
||||||
|
local pairs, type, tostring, tonumber, getmetatable, setmetatable =
|
||||||
|
pairs, type, tostring, tonumber, getmetatable, setmetatable
|
||||||
|
local error, require, pcall, select = error, require, pcall, select
|
||||||
|
local floor, huge = math.floor, math.huge
|
||||||
|
local strrep, gsub, strsub, strbyte, strchar, strfind, strlen, strformat =
|
||||||
|
string.rep, string.gsub, string.sub, string.byte, string.char,
|
||||||
|
string.find, string.len, string.format
|
||||||
|
local strmatch = string.match
|
||||||
|
local concat = table.concat
|
||||||
|
|
||||||
|
local json = { version = "dkjson 2.8" }
|
||||||
|
|
||||||
|
local jsonlpeg = {}
|
||||||
|
|
||||||
|
if register_global_module_table then
|
||||||
|
if always_use_lpeg then
|
||||||
|
_G[global_module_name] = jsonlpeg
|
||||||
|
else
|
||||||
|
_G[global_module_name] = json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local _ENV = nil -- blocking globals in Lua 5.2 and later
|
||||||
|
|
||||||
|
pcall (function()
|
||||||
|
-- Enable access to blocked metatables.
|
||||||
|
-- Don't worry, this module doesn't change anything in them.
|
||||||
|
local debmeta = require "debug".getmetatable
|
||||||
|
if debmeta then getmetatable = debmeta end
|
||||||
|
end)
|
||||||
|
|
||||||
|
json.null = setmetatable ({}, {
|
||||||
|
__tojson = function () return "null" end
|
||||||
|
})
|
||||||
|
|
||||||
|
local function isarray (tbl)
|
||||||
|
local max, n, arraylen = 0, 0, 0
|
||||||
|
for k,v in pairs (tbl) do
|
||||||
|
if k == 'n' and type(v) == 'number' then
|
||||||
|
arraylen = v
|
||||||
|
if v > max then
|
||||||
|
max = v
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if type(k) ~= 'number' or k < 1 or floor(k) ~= k then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if k > max then
|
||||||
|
max = k
|
||||||
|
end
|
||||||
|
n = n + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if max > 10 and max > arraylen and max > n * 2 then
|
||||||
|
return false -- don't create an array with too many holes
|
||||||
|
end
|
||||||
|
return true, max
|
||||||
|
end
|
||||||
|
|
||||||
|
local escapecodes = {
|
||||||
|
["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
|
||||||
|
["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"
|
||||||
|
}
|
||||||
|
|
||||||
|
local function escapeutf8 (uchar)
|
||||||
|
local value = escapecodes[uchar]
|
||||||
|
if value then
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
local a, b, c, d = strbyte (uchar, 1, 4)
|
||||||
|
a, b, c, d = a or 0, b or 0, c or 0, d or 0
|
||||||
|
if a <= 0x7f then
|
||||||
|
value = a
|
||||||
|
elseif 0xc0 <= a and a <= 0xdf and b >= 0x80 then
|
||||||
|
value = (a - 0xc0) * 0x40 + b - 0x80
|
||||||
|
elseif 0xe0 <= a and a <= 0xef and b >= 0x80 and c >= 0x80 then
|
||||||
|
value = ((a - 0xe0) * 0x40 + b - 0x80) * 0x40 + c - 0x80
|
||||||
|
elseif 0xf0 <= a and a <= 0xf7 and b >= 0x80 and c >= 0x80 and d >= 0x80 then
|
||||||
|
value = (((a - 0xf0) * 0x40 + b - 0x80) * 0x40 + c - 0x80) * 0x40 + d - 0x80
|
||||||
|
else
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
if value <= 0xffff then
|
||||||
|
return strformat ("\\u%.4x", value)
|
||||||
|
elseif value <= 0x10ffff then
|
||||||
|
-- encode as UTF-16 surrogate pair
|
||||||
|
value = value - 0x10000
|
||||||
|
local highsur, lowsur = 0xD800 + floor (value/0x400), 0xDC00 + (value % 0x400)
|
||||||
|
return strformat ("\\u%.4x\\u%.4x", highsur, lowsur)
|
||||||
|
else
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fsub (str, pattern, repl)
|
||||||
|
-- gsub always builds a new string in a buffer, even when no match
|
||||||
|
-- exists. First using find should be more efficient when most strings
|
||||||
|
-- don't contain the pattern.
|
||||||
|
if strfind (str, pattern) then
|
||||||
|
return gsub (str, pattern, repl)
|
||||||
|
else
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function quotestring (value)
|
||||||
|
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
|
||||||
|
value = fsub (value, "[%z\1-\31\"\\\127]", escapeutf8)
|
||||||
|
if strfind (value, "[\194\216\220\225\226\239]") then
|
||||||
|
value = fsub (value, "\194[\128-\159\173]", escapeutf8)
|
||||||
|
value = fsub (value, "\216[\128-\132]", escapeutf8)
|
||||||
|
value = fsub (value, "\220\143", escapeutf8)
|
||||||
|
value = fsub (value, "\225\158[\180\181]", escapeutf8)
|
||||||
|
value = fsub (value, "\226\128[\140-\143\168-\175]", escapeutf8)
|
||||||
|
value = fsub (value, "\226\129[\160-\175]", escapeutf8)
|
||||||
|
value = fsub (value, "\239\187\191", escapeutf8)
|
||||||
|
value = fsub (value, "\239\191[\176-\191]", escapeutf8)
|
||||||
|
end
|
||||||
|
return "\"" .. value .. "\""
|
||||||
|
end
|
||||||
|
json.quotestring = quotestring
|
||||||
|
|
||||||
|
local function replace(str, o, n)
|
||||||
|
local i, j = strfind (str, o, 1, true)
|
||||||
|
if i then
|
||||||
|
return strsub(str, 1, i-1) .. n .. strsub(str, j+1, -1)
|
||||||
|
else
|
||||||
|
return str
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- locale independent num2str and str2num functions
|
||||||
|
local decpoint, numfilter
|
||||||
|
|
||||||
|
local function updatedecpoint ()
|
||||||
|
decpoint = strmatch(tostring(0.5), "([^05+])")
|
||||||
|
-- build a filter that can be used to remove group separators
|
||||||
|
numfilter = "[^0-9%-%+eE" .. gsub(decpoint, "[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0") .. "]+"
|
||||||
|
end
|
||||||
|
|
||||||
|
updatedecpoint()
|
||||||
|
|
||||||
|
local function num2str (num)
|
||||||
|
return replace(fsub(tostring(num), numfilter, ""), decpoint, ".")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function str2num (str)
|
||||||
|
local num = tonumber(replace(str, ".", decpoint))
|
||||||
|
if not num then
|
||||||
|
updatedecpoint()
|
||||||
|
num = tonumber(replace(str, ".", decpoint))
|
||||||
|
end
|
||||||
|
return num
|
||||||
|
end
|
||||||
|
|
||||||
|
local function addnewline2 (level, buffer, buflen)
|
||||||
|
buffer[buflen+1] = "\n"
|
||||||
|
buffer[buflen+2] = strrep (" ", level)
|
||||||
|
buflen = buflen + 2
|
||||||
|
return buflen
|
||||||
|
end
|
||||||
|
|
||||||
|
function json.addnewline (state)
|
||||||
|
if state.indent then
|
||||||
|
state.bufferlen = addnewline2 (state.level or 0,
|
||||||
|
state.buffer, state.bufferlen or #(state.buffer))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local encode2 -- forward declaration
|
||||||
|
|
||||||
|
local function addpair (key, value, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||||
|
local kt = type (key)
|
||||||
|
if kt ~= 'string' and kt ~= 'number' then
|
||||||
|
return nil, "type '" .. kt .. "' is not supported as a key by JSON."
|
||||||
|
end
|
||||||
|
if prev then
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = ","
|
||||||
|
end
|
||||||
|
if indent then
|
||||||
|
buflen = addnewline2 (level, buffer, buflen)
|
||||||
|
end
|
||||||
|
-- When Lua is compiled with LUA_NOCVTN2S this will fail when
|
||||||
|
-- numbers are mixed into the keys of the table. JSON keys are always
|
||||||
|
-- strings, so this would be an implicit conversion too and the failure
|
||||||
|
-- is intentional.
|
||||||
|
buffer[buflen+1] = quotestring (key)
|
||||||
|
buffer[buflen+2] = ":"
|
||||||
|
return encode2 (value, indent, level, buffer, buflen + 2, tables, globalorder, state)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function appendcustom(res, buffer, state)
|
||||||
|
local buflen = state.bufferlen
|
||||||
|
if type (res) == 'string' then
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = res
|
||||||
|
end
|
||||||
|
return buflen
|
||||||
|
end
|
||||||
|
|
||||||
|
local function exception(reason, value, state, buffer, buflen, defaultmessage)
|
||||||
|
defaultmessage = defaultmessage or reason
|
||||||
|
local handler = state.exception
|
||||||
|
if not handler then
|
||||||
|
return nil, defaultmessage
|
||||||
|
else
|
||||||
|
state.bufferlen = buflen
|
||||||
|
local ret, msg = handler (reason, value, state, defaultmessage)
|
||||||
|
if not ret then return nil, msg or defaultmessage end
|
||||||
|
return appendcustom(ret, buffer, state)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function json.encodeexception(reason, value, state, defaultmessage)
|
||||||
|
return quotestring("<" .. defaultmessage .. ">")
|
||||||
|
end
|
||||||
|
|
||||||
|
encode2 = function (value, indent, level, buffer, buflen, tables, globalorder, state)
|
||||||
|
local valtype = type (value)
|
||||||
|
local valmeta = getmetatable (value)
|
||||||
|
valmeta = type (valmeta) == 'table' and valmeta -- only tables
|
||||||
|
local valtojson = valmeta and valmeta.__tojson
|
||||||
|
if valtojson then
|
||||||
|
if tables[value] then
|
||||||
|
return exception('reference cycle', value, state, buffer, buflen)
|
||||||
|
end
|
||||||
|
tables[value] = true
|
||||||
|
state.bufferlen = buflen
|
||||||
|
local ret, msg = valtojson (value, state)
|
||||||
|
if not ret then return exception('custom encoder failed', value, state, buffer, buflen, msg) end
|
||||||
|
tables[value] = nil
|
||||||
|
buflen = appendcustom(ret, buffer, state)
|
||||||
|
elseif value == nil then
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = "null"
|
||||||
|
elseif valtype == 'number' then
|
||||||
|
local s
|
||||||
|
if value ~= value or value >= huge or -value >= huge then
|
||||||
|
-- This is the behaviour of the original JSON implementation.
|
||||||
|
s = "null"
|
||||||
|
else
|
||||||
|
s = num2str (value)
|
||||||
|
end
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = s
|
||||||
|
elseif valtype == 'boolean' then
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = value and "true" or "false"
|
||||||
|
elseif valtype == 'string' then
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = quotestring (value)
|
||||||
|
elseif valtype == 'table' then
|
||||||
|
if tables[value] then
|
||||||
|
return exception('reference cycle', value, state, buffer, buflen)
|
||||||
|
end
|
||||||
|
tables[value] = true
|
||||||
|
level = level + 1
|
||||||
|
local isa, n = isarray (value)
|
||||||
|
if n == 0 and valmeta and valmeta.__jsontype == 'object' then
|
||||||
|
isa = false
|
||||||
|
end
|
||||||
|
local msg
|
||||||
|
if isa then -- JSON array
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = "["
|
||||||
|
for i = 1, n do
|
||||||
|
buflen, msg = encode2 (value[i], indent, level, buffer, buflen, tables, globalorder, state)
|
||||||
|
if not buflen then return nil, msg end
|
||||||
|
if i < n then
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = ","
|
||||||
|
end
|
||||||
|
end
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = "]"
|
||||||
|
else -- JSON object
|
||||||
|
local prev = false
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = "{"
|
||||||
|
local order = valmeta and valmeta.__jsonorder or globalorder
|
||||||
|
if order then
|
||||||
|
local used = {}
|
||||||
|
n = #order
|
||||||
|
for i = 1, n do
|
||||||
|
local k = order[i]
|
||||||
|
local v = value[k]
|
||||||
|
if v ~= nil then
|
||||||
|
used[k] = true
|
||||||
|
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||||
|
if not buflen then return nil, msg end
|
||||||
|
prev = true -- add a seperator before the next element
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for k,v in pairs (value) do
|
||||||
|
if not used[k] then
|
||||||
|
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||||
|
if not buflen then return nil, msg end
|
||||||
|
prev = true -- add a seperator before the next element
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else -- unordered
|
||||||
|
for k,v in pairs (value) do
|
||||||
|
buflen, msg = addpair (k, v, prev, indent, level, buffer, buflen, tables, globalorder, state)
|
||||||
|
if not buflen then return nil, msg end
|
||||||
|
prev = true -- add a seperator before the next element
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if indent then
|
||||||
|
buflen = addnewline2 (level - 1, buffer, buflen)
|
||||||
|
end
|
||||||
|
buflen = buflen + 1
|
||||||
|
buffer[buflen] = "}"
|
||||||
|
end
|
||||||
|
tables[value] = nil
|
||||||
|
else
|
||||||
|
return exception ('unsupported type', value, state, buffer, buflen,
|
||||||
|
"type '" .. valtype .. "' is not supported by JSON.")
|
||||||
|
end
|
||||||
|
return buflen
|
||||||
|
end
|
||||||
|
|
||||||
|
function json.encode (value, state)
|
||||||
|
state = state or {}
|
||||||
|
local oldbuffer = state.buffer
|
||||||
|
local buffer = oldbuffer or {}
|
||||||
|
state.buffer = buffer
|
||||||
|
updatedecpoint()
|
||||||
|
local ret, msg = encode2 (value, state.indent, state.level or 0,
|
||||||
|
buffer, state.bufferlen or 0, state.tables or {}, state.keyorder, state)
|
||||||
|
if not ret then
|
||||||
|
error (msg, 2)
|
||||||
|
elseif oldbuffer == buffer then
|
||||||
|
state.bufferlen = ret
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
state.bufferlen = nil
|
||||||
|
state.buffer = nil
|
||||||
|
return concat (buffer)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function loc (str, where)
|
||||||
|
local line, pos, linepos = 1, 1, 0
|
||||||
|
while true do
|
||||||
|
pos = strfind (str, "\n", pos, true)
|
||||||
|
if pos and pos < where then
|
||||||
|
line = line + 1
|
||||||
|
linepos = pos
|
||||||
|
pos = pos + 1
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return strformat ("line %d, column %d", line, where - linepos)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function unterminated (str, what, where)
|
||||||
|
return nil, strlen (str) + 1, "unterminated " .. what .. " at " .. loc (str, where)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function scanwhite (str, pos)
|
||||||
|
while true do
|
||||||
|
pos = strfind (str, "%S", pos)
|
||||||
|
if not pos then return nil end
|
||||||
|
local sub2 = strsub (str, pos, pos + 1)
|
||||||
|
if sub2 == "\239\187" and strsub (str, pos + 2, pos + 2) == "\191" then
|
||||||
|
-- UTF-8 Byte Order Mark
|
||||||
|
pos = pos + 3
|
||||||
|
elseif sub2 == "//" then
|
||||||
|
pos = strfind (str, "[\n\r]", pos + 2)
|
||||||
|
if not pos then return nil end
|
||||||
|
elseif sub2 == "/*" then
|
||||||
|
pos = strfind (str, "*/", pos + 2)
|
||||||
|
if not pos then return nil end
|
||||||
|
pos = pos + 2
|
||||||
|
else
|
||||||
|
return pos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local escapechars = {
|
||||||
|
["\""] = "\"", ["\\"] = "\\", ["/"] = "/", ["b"] = "\b", ["f"] = "\f",
|
||||||
|
["n"] = "\n", ["r"] = "\r", ["t"] = "\t"
|
||||||
|
}
|
||||||
|
|
||||||
|
local function unichar (value)
|
||||||
|
if value < 0 then
|
||||||
|
return nil
|
||||||
|
elseif value <= 0x007f then
|
||||||
|
return strchar (value)
|
||||||
|
elseif value <= 0x07ff then
|
||||||
|
return strchar (0xc0 + floor(value/0x40),
|
||||||
|
0x80 + (floor(value) % 0x40))
|
||||||
|
elseif value <= 0xffff then
|
||||||
|
return strchar (0xe0 + floor(value/0x1000),
|
||||||
|
0x80 + (floor(value/0x40) % 0x40),
|
||||||
|
0x80 + (floor(value) % 0x40))
|
||||||
|
elseif value <= 0x10ffff then
|
||||||
|
return strchar (0xf0 + floor(value/0x40000),
|
||||||
|
0x80 + (floor(value/0x1000) % 0x40),
|
||||||
|
0x80 + (floor(value/0x40) % 0x40),
|
||||||
|
0x80 + (floor(value) % 0x40))
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function scanstring (str, pos)
|
||||||
|
local lastpos = pos + 1
|
||||||
|
local buffer, n = {}, 0
|
||||||
|
while true do
|
||||||
|
local nextpos = strfind (str, "[\"\\]", lastpos)
|
||||||
|
if not nextpos then
|
||||||
|
return unterminated (str, "string", pos)
|
||||||
|
end
|
||||||
|
if nextpos > lastpos then
|
||||||
|
n = n + 1
|
||||||
|
buffer[n] = strsub (str, lastpos, nextpos - 1)
|
||||||
|
end
|
||||||
|
if strsub (str, nextpos, nextpos) == "\"" then
|
||||||
|
lastpos = nextpos + 1
|
||||||
|
break
|
||||||
|
else
|
||||||
|
local escchar = strsub (str, nextpos + 1, nextpos + 1)
|
||||||
|
local value
|
||||||
|
if escchar == "u" then
|
||||||
|
value = tonumber (strsub (str, nextpos + 2, nextpos + 5), 16)
|
||||||
|
if value then
|
||||||
|
local value2
|
||||||
|
if 0xD800 <= value and value <= 0xDBff then
|
||||||
|
-- we have the high surrogate of UTF-16. Check if there is a
|
||||||
|
-- low surrogate escaped nearby to combine them.
|
||||||
|
if strsub (str, nextpos + 6, nextpos + 7) == "\\u" then
|
||||||
|
value2 = tonumber (strsub (str, nextpos + 8, nextpos + 11), 16)
|
||||||
|
if value2 and 0xDC00 <= value2 and value2 <= 0xDFFF then
|
||||||
|
value = (value - 0xD800) * 0x400 + (value2 - 0xDC00) + 0x10000
|
||||||
|
else
|
||||||
|
value2 = nil -- in case it was out of range for a low surrogate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
value = value and unichar (value)
|
||||||
|
if value then
|
||||||
|
if value2 then
|
||||||
|
lastpos = nextpos + 12
|
||||||
|
else
|
||||||
|
lastpos = nextpos + 6
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not value then
|
||||||
|
value = escapechars[escchar] or escchar
|
||||||
|
lastpos = nextpos + 2
|
||||||
|
end
|
||||||
|
n = n + 1
|
||||||
|
buffer[n] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if n == 1 then
|
||||||
|
return buffer[1], lastpos
|
||||||
|
elseif n > 1 then
|
||||||
|
return concat (buffer), lastpos
|
||||||
|
else
|
||||||
|
return "", lastpos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local scanvalue -- forward declaration
|
||||||
|
|
||||||
|
local function scantable (what, closechar, str, startpos, nullval, objectmeta, arraymeta)
|
||||||
|
local tbl, n = {}, 0
|
||||||
|
local pos = startpos + 1
|
||||||
|
if what == 'object' then
|
||||||
|
setmetatable (tbl, objectmeta)
|
||||||
|
else
|
||||||
|
setmetatable (tbl, arraymeta)
|
||||||
|
end
|
||||||
|
while true do
|
||||||
|
pos = scanwhite (str, pos)
|
||||||
|
if not pos then return unterminated (str, what, startpos) end
|
||||||
|
local char = strsub (str, pos, pos)
|
||||||
|
if char == closechar then
|
||||||
|
return tbl, pos + 1
|
||||||
|
end
|
||||||
|
local val1, err
|
||||||
|
val1, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||||
|
if err then return nil, pos, err end
|
||||||
|
pos = scanwhite (str, pos)
|
||||||
|
if not pos then return unterminated (str, what, startpos) end
|
||||||
|
char = strsub (str, pos, pos)
|
||||||
|
if char == ":" then
|
||||||
|
if val1 == nil then
|
||||||
|
return nil, pos, "cannot use nil as table index (at " .. loc (str, pos) .. ")"
|
||||||
|
end
|
||||||
|
pos = scanwhite (str, pos + 1)
|
||||||
|
if not pos then return unterminated (str, what, startpos) end
|
||||||
|
local val2
|
||||||
|
val2, pos, err = scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||||
|
if err then return nil, pos, err end
|
||||||
|
tbl[val1] = val2
|
||||||
|
pos = scanwhite (str, pos)
|
||||||
|
if not pos then return unterminated (str, what, startpos) end
|
||||||
|
char = strsub (str, pos, pos)
|
||||||
|
else
|
||||||
|
n = n + 1
|
||||||
|
tbl[n] = val1
|
||||||
|
end
|
||||||
|
if char == "," then
|
||||||
|
pos = pos + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scanvalue = function (str, pos, nullval, objectmeta, arraymeta)
|
||||||
|
pos = pos or 1
|
||||||
|
pos = scanwhite (str, pos)
|
||||||
|
if not pos then
|
||||||
|
return nil, strlen (str) + 1, "no valid JSON value (reached the end)"
|
||||||
|
end
|
||||||
|
local char = strsub (str, pos, pos)
|
||||||
|
if char == "{" then
|
||||||
|
return scantable ('object', "}", str, pos, nullval, objectmeta, arraymeta)
|
||||||
|
elseif char == "[" then
|
||||||
|
return scantable ('array', "]", str, pos, nullval, objectmeta, arraymeta)
|
||||||
|
elseif char == "\"" then
|
||||||
|
return scanstring (str, pos)
|
||||||
|
else
|
||||||
|
local pstart, pend = strfind (str, "^%-?[%d%.]+[eE]?[%+%-]?%d*", pos)
|
||||||
|
if pstart then
|
||||||
|
local number = str2num (strsub (str, pstart, pend))
|
||||||
|
if number then
|
||||||
|
return number, pend + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
pstart, pend = strfind (str, "^%a%w*", pos)
|
||||||
|
if pstart then
|
||||||
|
local name = strsub (str, pstart, pend)
|
||||||
|
if name == "true" then
|
||||||
|
return true, pend + 1
|
||||||
|
elseif name == "false" then
|
||||||
|
return false, pend + 1
|
||||||
|
elseif name == "null" then
|
||||||
|
return nullval, pend + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil, pos, "no valid JSON value at " .. loc (str, pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function optionalmetatables(...)
|
||||||
|
if select("#", ...) > 0 then
|
||||||
|
return ...
|
||||||
|
else
|
||||||
|
return {__jsontype = 'object'}, {__jsontype = 'array'}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function json.decode (str, pos, nullval, ...)
|
||||||
|
local objectmeta, arraymeta = optionalmetatables(...)
|
||||||
|
return scanvalue (str, pos, nullval, objectmeta, arraymeta)
|
||||||
|
end
|
||||||
|
|
||||||
|
function json.use_lpeg ()
|
||||||
|
local g = require ("lpeg")
|
||||||
|
|
||||||
|
if type(g.version) == 'function' and g.version() == "0.11" then
|
||||||
|
error "due to a bug in LPeg 0.11, it cannot be used for JSON matching"
|
||||||
|
end
|
||||||
|
|
||||||
|
local pegmatch = g.match
|
||||||
|
local P, S, R = g.P, g.S, g.R
|
||||||
|
|
||||||
|
local function ErrorCall (str, pos, msg, state)
|
||||||
|
if not state.msg then
|
||||||
|
state.msg = msg .. " at " .. loc (str, pos)
|
||||||
|
state.pos = pos
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Err (msg)
|
||||||
|
return g.Cmt (g.Cc (msg) * g.Carg (2), ErrorCall)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function ErrorUnterminatedCall (str, pos, what, state)
|
||||||
|
return ErrorCall (str, pos - 1, "unterminated " .. what, state)
|
||||||
|
end
|
||||||
|
|
||||||
|
local SingleLineComment = P"//" * (1 - S"\n\r")^0
|
||||||
|
local MultiLineComment = P"/*" * (1 - P"*/")^0 * P"*/"
|
||||||
|
local Space = (S" \n\r\t" + P"\239\187\191" + SingleLineComment + MultiLineComment)^0
|
||||||
|
|
||||||
|
local function ErrUnterminated (what)
|
||||||
|
return g.Cmt (g.Cc (what) * g.Carg (2), ErrorUnterminatedCall)
|
||||||
|
end
|
||||||
|
|
||||||
|
local PlainChar = 1 - S"\"\\\n\r"
|
||||||
|
local EscapeSequence = (P"\\" * g.C (S"\"\\/bfnrt" + Err "unsupported escape sequence")) / escapechars
|
||||||
|
local HexDigit = R("09", "af", "AF")
|
||||||
|
local function UTF16Surrogate (match, pos, high, low)
|
||||||
|
high, low = tonumber (high, 16), tonumber (low, 16)
|
||||||
|
if 0xD800 <= high and high <= 0xDBff and 0xDC00 <= low and low <= 0xDFFF then
|
||||||
|
return true, unichar ((high - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function UTF16BMP (hex)
|
||||||
|
return unichar (tonumber (hex, 16))
|
||||||
|
end
|
||||||
|
local U16Sequence = (P"\\u" * g.C (HexDigit * HexDigit * HexDigit * HexDigit))
|
||||||
|
local UnicodeEscape = g.Cmt (U16Sequence * U16Sequence, UTF16Surrogate) + U16Sequence/UTF16BMP
|
||||||
|
local Char = UnicodeEscape + EscapeSequence + PlainChar
|
||||||
|
local String = P"\"" * (g.Cs (Char ^ 0) * P"\"" + ErrUnterminated "string")
|
||||||
|
local Integer = P"-"^(-1) * (P"0" + (R"19" * R"09"^0))
|
||||||
|
local Fractal = P"." * R"09"^0
|
||||||
|
local Exponent = (S"eE") * (S"+-")^(-1) * R"09"^1
|
||||||
|
local Number = (Integer * Fractal^(-1) * Exponent^(-1))/str2num
|
||||||
|
local Constant = P"true" * g.Cc (true) + P"false" * g.Cc (false) + P"null" * g.Carg (1)
|
||||||
|
local SimpleValue = Number + String + Constant
|
||||||
|
local ArrayContent, ObjectContent
|
||||||
|
|
||||||
|
-- The functions parsearray and parseobject parse only a single value/pair
|
||||||
|
-- at a time and store them directly to avoid hitting the LPeg limits.
|
||||||
|
local function parsearray (str, pos, nullval, state)
|
||||||
|
local obj, cont
|
||||||
|
local start = pos
|
||||||
|
local npos
|
||||||
|
local t, nt = {}, 0
|
||||||
|
repeat
|
||||||
|
obj, cont, npos = pegmatch (ArrayContent, str, pos, nullval, state)
|
||||||
|
if cont == 'end' then
|
||||||
|
return ErrorUnterminatedCall (str, start, "array", state)
|
||||||
|
end
|
||||||
|
pos = npos
|
||||||
|
if cont == 'cont' or cont == 'last' then
|
||||||
|
nt = nt + 1
|
||||||
|
t[nt] = obj
|
||||||
|
end
|
||||||
|
until cont ~= 'cont'
|
||||||
|
return pos, setmetatable (t, state.arraymeta)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parseobject (str, pos, nullval, state)
|
||||||
|
local obj, key, cont
|
||||||
|
local start = pos
|
||||||
|
local npos
|
||||||
|
local t = {}
|
||||||
|
repeat
|
||||||
|
key, obj, cont, npos = pegmatch (ObjectContent, str, pos, nullval, state)
|
||||||
|
if cont == 'end' then
|
||||||
|
return ErrorUnterminatedCall (str, start, "object", state)
|
||||||
|
end
|
||||||
|
pos = npos
|
||||||
|
if cont == 'cont' or cont == 'last' then
|
||||||
|
t[key] = obj
|
||||||
|
end
|
||||||
|
until cont ~= 'cont'
|
||||||
|
return pos, setmetatable (t, state.objectmeta)
|
||||||
|
end
|
||||||
|
|
||||||
|
local Array = P"[" * g.Cmt (g.Carg(1) * g.Carg(2), parsearray)
|
||||||
|
local Object = P"{" * g.Cmt (g.Carg(1) * g.Carg(2), parseobject)
|
||||||
|
local Value = Space * (Array + Object + SimpleValue)
|
||||||
|
local ExpectedValue = Value + Space * Err "value expected"
|
||||||
|
local ExpectedKey = String + Err "key expected"
|
||||||
|
local End = P(-1) * g.Cc'end'
|
||||||
|
local ErrInvalid = Err "invalid JSON"
|
||||||
|
ArrayContent = (Value * Space * (P"," * g.Cc'cont' + P"]" * g.Cc'last'+ End + ErrInvalid) + g.Cc(nil) * (P"]" * g.Cc'empty' + End + ErrInvalid)) * g.Cp()
|
||||||
|
local Pair = g.Cg (Space * ExpectedKey * Space * (P":" + Err "colon expected") * ExpectedValue)
|
||||||
|
ObjectContent = (g.Cc(nil) * g.Cc(nil) * P"}" * g.Cc'empty' + End + (Pair * Space * (P"," * g.Cc'cont' + P"}" * g.Cc'last' + End + ErrInvalid) + ErrInvalid)) * g.Cp()
|
||||||
|
local DecodeValue = ExpectedValue * g.Cp ()
|
||||||
|
|
||||||
|
jsonlpeg.version = json.version
|
||||||
|
jsonlpeg.encode = json.encode
|
||||||
|
jsonlpeg.null = json.null
|
||||||
|
jsonlpeg.quotestring = json.quotestring
|
||||||
|
jsonlpeg.addnewline = json.addnewline
|
||||||
|
jsonlpeg.encodeexception = json.encodeexception
|
||||||
|
jsonlpeg.using_lpeg = true
|
||||||
|
|
||||||
|
function jsonlpeg.decode (str, pos, nullval, ...)
|
||||||
|
local state = {}
|
||||||
|
state.objectmeta, state.arraymeta = optionalmetatables(...)
|
||||||
|
local obj, retpos = pegmatch (DecodeValue, str, pos, nullval, state)
|
||||||
|
if state.msg then
|
||||||
|
return nil, state.pos, state.msg
|
||||||
|
else
|
||||||
|
return obj, retpos
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- cache result of this function:
|
||||||
|
json.use_lpeg = function () return jsonlpeg end
|
||||||
|
jsonlpeg.use_lpeg = json.use_lpeg
|
||||||
|
|
||||||
|
return jsonlpeg
|
||||||
|
end
|
||||||
|
|
||||||
|
if always_use_lpeg then
|
||||||
|
return json.use_lpeg()
|
||||||
|
end
|
||||||
|
|
||||||
|
return json
|
||||||
|
|
|
@ -7,10 +7,15 @@ local CURVE = 45
|
||||||
|
|
||||||
local vertices = {}
|
local vertices = {}
|
||||||
|
|
||||||
|
local function dr( y )
|
||||||
|
return -math.pow( 1-y, -2/3 ) * 0.6/3
|
||||||
|
end
|
||||||
|
|
||||||
local function radius( y )
|
local function radius( y )
|
||||||
return math.max( 0,
|
return math.pow( math.max( 0,
|
||||||
0.6 * math.pow( (1-y), 1/3 ) +
|
0.6 * math.pow( (1-y), 1/3 ) +
|
||||||
0.1 * math.exp( -5*y ))
|
0.1 * math.exp( -5*y )),
|
||||||
|
1.1)
|
||||||
end
|
end
|
||||||
|
|
||||||
local loops = {}
|
local loops = {}
|
||||||
|
@ -24,11 +29,12 @@ do
|
||||||
local x, z = 1, 0
|
local x, z = 1, 0
|
||||||
y = y + 1 / #loops
|
y = y + 1 / #loops
|
||||||
local r = radius( y )
|
local r = radius( y )
|
||||||
|
local dy = dr( y )
|
||||||
for j = 1, DETAIL + 1 do
|
for j = 1, DETAIL + 1 do
|
||||||
--need the extra vertex so the texture wraps correctly
|
--need the extra vertex so the texture wraps correctly
|
||||||
local u = 5 * ( j - 1 ) / DETAIL
|
local u = 5 * ( j - 1 ) / DETAIL
|
||||||
local v = 3 * (1.0 - y) - 0.85
|
local v = 3 * (1.0 - y) - 1.0
|
||||||
vertices[ n ] = { r * x, y, r * z, u, v }
|
vertices[ n ] = { r * x, y, r * z, u, v, x, 0, z }
|
||||||
loop[j] = n
|
loop[j] = n
|
||||||
n = n + 1
|
n = n + 1
|
||||||
x, z = c*x+s*z, c*z-s*x
|
x, z = c*x+s*z, c*z-s*x
|
||||||
|
@ -55,25 +61,46 @@ local bellMesh = lg.newMesh(
|
||||||
{--attributes
|
{--attributes
|
||||||
{"VertexPosition", "float", 3},
|
{"VertexPosition", "float", 3},
|
||||||
{"VertexTexCoord", "float", 2},
|
{"VertexTexCoord", "float", 2},
|
||||||
|
{"VertexNormal", "float", 3},
|
||||||
},
|
},
|
||||||
vertices,
|
vertices,
|
||||||
"strip",
|
"strip",
|
||||||
"static"
|
"static"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
local bellPositions = {}
|
||||||
do
|
do
|
||||||
local c, s = math.cos( 2*math.pi / 7 ), -math.sin( 2*math.pi / 7 )
|
local c, s = math.cos( 2*math.pi / 7 ), -math.sin( 2*math.pi / 7 )
|
||||||
local instanceMesh = {}
|
|
||||||
local x, z = 1, 0
|
local x, z = 1, 0
|
||||||
local r = 15
|
local r = 15
|
||||||
for i = 1, 7 do
|
for i = 1, 7 do
|
||||||
instanceMesh[i] = { i / 2, r * x, r * z, (i-1)/6 }
|
bellPositions[i] = { i / 2, r * x, r * z, (i-1)/6 }
|
||||||
x, z = c*x+s*z, c*z-s*x
|
x, z = c*x+s*z, c*z-s*x
|
||||||
end
|
end
|
||||||
bellMesh:attachAttribute( "bellInstance",
|
bellMesh:attachAttribute( "bellInstance",
|
||||||
lg.newMesh({{"bellInstance","float",4}}, instanceMesh, nil, "static" ),
|
lg.newMesh({{"bellInstance","float",4}}, bellPositions, nil, "static" ),
|
||||||
"perinstance" )
|
"perinstance" )
|
||||||
end
|
end
|
||||||
|
|
||||||
bellMesh:setVertexMap( constructVertexMap() )
|
bellMesh:setVertexMap( constructVertexMap() )
|
||||||
return bellMesh
|
do
|
||||||
|
local bellTexture = lg.newImage( "tex/bell-height.png", {mipmaps = true} )
|
||||||
|
bellTexture:setWrap( "repeat", "clampzero" )
|
||||||
|
bellMesh:setTexture( bellTexture )
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = {}
|
||||||
|
|
||||||
|
t.shader = require( "shaders.bell" )
|
||||||
|
t.mesh = bellMesh
|
||||||
|
|
||||||
|
function t.draw( view, proj )
|
||||||
|
local s = t.shader
|
||||||
|
s:send( "view", "column", view )
|
||||||
|
s:send( "proj", "column", proj )
|
||||||
|
lg.setShader(s)
|
||||||
|
lg.drawInstanced( t.mesh, 7 )
|
||||||
|
end
|
||||||
|
|
||||||
|
return t
|
Binary file not shown.
|
@ -0,0 +1,155 @@
|
||||||
|
{
|
||||||
|
"asset":{
|
||||||
|
"copyright":"wan-may",
|
||||||
|
"generator":"Khronos glTF Blender I/O v4.2.70",
|
||||||
|
"version":"2.0"
|
||||||
|
},
|
||||||
|
"scene":0,
|
||||||
|
"scenes":[
|
||||||
|
{
|
||||||
|
"name":"Scene",
|
||||||
|
"nodes":[
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodes":[
|
||||||
|
{
|
||||||
|
"mesh":0,
|
||||||
|
"name":"Phone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh":1,
|
||||||
|
"name":"Handset"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes":[
|
||||||
|
{
|
||||||
|
"name":"Phone",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":0,
|
||||||
|
"NORMAL":1
|
||||||
|
},
|
||||||
|
"indices":2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name":"Handset",
|
||||||
|
"primitives":[
|
||||||
|
{
|
||||||
|
"attributes":{
|
||||||
|
"POSITION":3,
|
||||||
|
"NORMAL":4
|
||||||
|
},
|
||||||
|
"indices":5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors":[
|
||||||
|
{
|
||||||
|
"bufferView":0,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":260,
|
||||||
|
"max":[
|
||||||
|
1.3268864154815674,
|
||||||
|
0.43300557136535645,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-1.517603874206543,
|
||||||
|
0.0002872943878173828,
|
||||||
|
-1
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":1,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":260,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":2,
|
||||||
|
"componentType":5123,
|
||||||
|
"count":546,
|
||||||
|
"type":"SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":3,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":76,
|
||||||
|
"max":[
|
||||||
|
1.3234574794769287,
|
||||||
|
0.728451132774353,
|
||||||
|
-0.10927927494049072
|
||||||
|
],
|
||||||
|
"min":[
|
||||||
|
-1.482479214668274,
|
||||||
|
0.10958258807659149,
|
||||||
|
-0.8433066010475159
|
||||||
|
],
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":4,
|
||||||
|
"componentType":5126,
|
||||||
|
"count":76,
|
||||||
|
"type":"VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView":5,
|
||||||
|
"componentType":5123,
|
||||||
|
"count":120,
|
||||||
|
"type":"SCALAR"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bufferViews":[
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":3120,
|
||||||
|
"byteOffset":0,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":3120,
|
||||||
|
"byteOffset":3120,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":1092,
|
||||||
|
"byteOffset":6240,
|
||||||
|
"target":34963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":912,
|
||||||
|
"byteOffset":7332,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":912,
|
||||||
|
"byteOffset":8244,
|
||||||
|
"target":34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer":0,
|
||||||
|
"byteLength":240,
|
||||||
|
"byteOffset":9156,
|
||||||
|
"target":34963
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers":[
|
||||||
|
{
|
||||||
|
"byteLength":9396,
|
||||||
|
"uri":"contempra.bin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
local dkjson = require( "lib.dkjson" )
|
||||||
|
local love = assert( love )
|
||||||
|
local shader = require( "shaders.flat" )
|
||||||
|
local mat = require( "mat4" )
|
||||||
|
|
||||||
|
local attributeNames = {
|
||||||
|
POSITION = "VertexPosition",
|
||||||
|
NORMAL = "VertexNormal",
|
||||||
|
}
|
||||||
|
|
||||||
|
local types = {
|
||||||
|
["SCALAR"] = 1,
|
||||||
|
["VEC3"] = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
local componentTypes = {
|
||||||
|
[5121] = "byte",
|
||||||
|
[5123] = "unorm16",
|
||||||
|
[5126] = "float",
|
||||||
|
}
|
||||||
|
|
||||||
|
local elementComponentTypes = {
|
||||||
|
[5123] = "uint16",
|
||||||
|
[5126] = "uint32",
|
||||||
|
}
|
||||||
|
|
||||||
|
local asset
|
||||||
|
local buffer
|
||||||
|
do
|
||||||
|
local fd = assert( love.filesystem.newFileData( "models/contempra.gltf" ) )
|
||||||
|
asset = dkjson.decode( fd:getString() )
|
||||||
|
buffer = love.filesystem.newFileData( "models/contempra.bin" )
|
||||||
|
end
|
||||||
|
|
||||||
|
--load all the bufferViews
|
||||||
|
local bufferViews = {}
|
||||||
|
for i, view in pairs( asset.bufferViews ) do
|
||||||
|
bufferViews[i] = love.data.newByteData( buffer, view.byteOffset, view.byteLength )
|
||||||
|
end
|
||||||
|
|
||||||
|
local function attributeFormat( attributeName, accessor )
|
||||||
|
return {attributeNames[attributeName], componentTypes[accessor.componentType], types[accessor.type] }
|
||||||
|
end
|
||||||
|
|
||||||
|
local function lgMesh( primitive )
|
||||||
|
assert( not( primitive.mode ) ) --triangles only
|
||||||
|
|
||||||
|
local finalMesh
|
||||||
|
for name, accIdx in pairs( primitive.attributes ) do
|
||||||
|
local acc = asset.accessors[accIdx+1]
|
||||||
|
|
||||||
|
local mesh = love.graphics.newMesh(
|
||||||
|
{attributeFormat(name, acc)}, --vertexformat
|
||||||
|
acc.count,
|
||||||
|
"triangles",
|
||||||
|
"static"
|
||||||
|
)
|
||||||
|
|
||||||
|
local bfv = bufferViews[1+acc.bufferView]
|
||||||
|
mesh:setVertices( bfv )
|
||||||
|
|
||||||
|
if finalMesh then
|
||||||
|
finalMesh:attachAttribute( attributeNames[name], mesh )
|
||||||
|
else
|
||||||
|
finalMesh = mesh
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
do
|
||||||
|
local acc = asset.accessors[1+primitive.indices]
|
||||||
|
local bfv = bufferViews[1+acc.bufferView]
|
||||||
|
finalMesh:setVertexMap(bfv, elementComponentTypes[acc.componentType] )
|
||||||
|
end
|
||||||
|
return finalMesh
|
||||||
|
end
|
||||||
|
|
||||||
|
local phone = lgMesh( asset.meshes[1].primitives[1] )
|
||||||
|
local handset = lgMesh( asset.meshes[2].primitives[1] )
|
||||||
|
|
||||||
|
|
||||||
|
local obj = {
|
||||||
|
isRinging = false,
|
||||||
|
isTalking = false,
|
||||||
|
x = 2,
|
||||||
|
y = 0.25,
|
||||||
|
z = -2,
|
||||||
|
size = 0.1,
|
||||||
|
}
|
||||||
|
|
||||||
|
local phoneTF = mat.TRS(
|
||||||
|
obj.size,obj.size,obj.size,
|
||||||
|
0,0.12,0,
|
||||||
|
obj.x, obj.y, obj.z)
|
||||||
|
|
||||||
|
local lx, lz = 1, 0
|
||||||
|
local c, s = math.cos( 0.01 ), math.sin( 0.01 )
|
||||||
|
function obj.draw( view, proj )
|
||||||
|
|
||||||
|
love.graphics.setColor( 1,0.2,0.2,1 )
|
||||||
|
love.graphics.setMeshCullMode( "none" ) --debug
|
||||||
|
shader:send( "view", "column", view )
|
||||||
|
shader:send( "proj", "column", proj )
|
||||||
|
|
||||||
|
lx, lz = c*lx+s*lz,c*lz-s*lx
|
||||||
|
shader:send( "light", {0, 1, 0} )
|
||||||
|
love.graphics.setShader( shader )
|
||||||
|
shader:send( "mdl", "column", phoneTF )
|
||||||
|
love.graphics.draw( phone )
|
||||||
|
love.graphics.draw( handset )
|
||||||
|
end
|
||||||
|
|
||||||
|
function obj.ring()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function obj.answer()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return obj
|
|
@ -27,7 +27,7 @@ mesh:setVertexMap{
|
||||||
5, 1, 7,
|
5, 1, 7,
|
||||||
1, 7, 3,
|
1, 7, 3,
|
||||||
}
|
}
|
||||||
local cubemap = love.graphics.newCubeImage(
|
local cubemap = lg.newCubeImage(
|
||||||
{
|
{
|
||||||
"tex/cubemap_0.png",
|
"tex/cubemap_0.png",
|
||||||
"tex/cubemap_1.png",
|
"tex/cubemap_1.png",
|
||||||
|
@ -37,4 +37,19 @@ local cubemap = love.graphics.newCubeImage(
|
||||||
"tex/cubemap_5.png",
|
"tex/cubemap_5.png",
|
||||||
},
|
},
|
||||||
{mipmaps = true} )
|
{mipmaps = true} )
|
||||||
return { mesh = mesh, tex = cubemap }
|
|
||||||
|
local shader = require( "shaders.sky" )
|
||||||
|
shader:send( "cube", cubemap )
|
||||||
|
|
||||||
|
local function draw( view, proj )
|
||||||
|
lg.push( "all" )
|
||||||
|
lg.setDepthMode( "always", false )
|
||||||
|
lg.setMeshCullMode( "none" )
|
||||||
|
--get view matrix without translation
|
||||||
|
shader:send( "proj", "column", proj )
|
||||||
|
shader:send( "view", "column", {view[1], view[2], view[3], {0, 0, 0, 1}} )
|
||||||
|
lg.setShader( shader )
|
||||||
|
lg.draw( mesh )
|
||||||
|
lg.pop()
|
||||||
|
end
|
||||||
|
return { draw = draw }
|
|
@ -1,9 +1,9 @@
|
||||||
--camera and character controller
|
--camera and character controller
|
||||||
local math = assert( math )
|
local math = assert( math )
|
||||||
local mat = require( "mat4" )
|
local mat = require( "mat4" )
|
||||||
|
local sfx = require( "sfx" )
|
||||||
|
|
||||||
local maxPitch = math.pi / 2
|
local maxPitch = math.pi / 2
|
||||||
local speed = 2
|
|
||||||
|
|
||||||
local function logistic( x )
|
local function logistic( x )
|
||||||
return 1.0 / ( 1.0 + math.exp( x ) )
|
return 1.0 / ( 1.0 + math.exp( x ) )
|
||||||
|
@ -11,18 +11,21 @@ end
|
||||||
|
|
||||||
local player = {
|
local player = {
|
||||||
turnRate = 0,
|
turnRate = 0,
|
||||||
rate = 0.01,
|
rate = 0.01, --tick rate
|
||||||
|
speed = 2, --movement speed m/s
|
||||||
x = 0,
|
x = 0,
|
||||||
y = 0.5,
|
y = 0.5,
|
||||||
z = 0,
|
z = 3,
|
||||||
vx = 0,
|
vx = 0,
|
||||||
vz = 0,
|
vz = 0,
|
||||||
yaw = 0,
|
yaw = 1.5,
|
||||||
pitch = 0,
|
pitch = 0,
|
||||||
desx = 0,
|
desx = 0,
|
||||||
desz = 0,
|
desz = 0,
|
||||||
view = mat.id(),
|
view = mat.id(),
|
||||||
proj = mat.id(),
|
proj = mat.id(),
|
||||||
|
footstepTimer = 0,
|
||||||
|
footstepStride = 0.5 --seconds before taking a step
|
||||||
}
|
}
|
||||||
|
|
||||||
function player:updateDesiredDirection( forward, left, right, back )
|
function player:updateDesiredDirection( forward, left, right, back )
|
||||||
|
@ -35,10 +38,7 @@ function player:updateDesiredDirection( forward, left, right, back )
|
||||||
self.desx, self.desz = x * c + z * s, -x * s + z * c
|
self.desx, self.desz = x * c + z * s, -x * s + z * c
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[function player:getViewDirection()
|
|
||||||
local cy, sy, cp, sp = math.cos(self.yaw), math.sin(self.yaw), math.cos( self.pitch ), math.sin( self.yaw )
|
|
||||||
return cy, sp, 1
|
|
||||||
end]]
|
|
||||||
|
|
||||||
function player:setFOV( fov )
|
function player:setFOV( fov )
|
||||||
self.proj = mat.projection( 0.05, 100, math.rad( fov or 90 ) )
|
self.proj = mat.projection( 0.05, 100, math.rad( fov or 90 ) )
|
||||||
|
@ -54,14 +54,64 @@ function player:turn( dx, dy )
|
||||||
self.pitch + dy * self.turnRate ))
|
self.pitch + dy * self.turnRate ))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function sqDistance( x, y, a, b )
|
||||||
|
return (x-a)*(x-a)+(y-b)*(y-b)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function dot( x, y, a, b )
|
||||||
|
return x * a + y * b
|
||||||
|
end
|
||||||
|
|
||||||
|
--segment ixy->fxy, point cxy
|
||||||
|
local function distanceToSegment( ix, iy, fx, fy, cx, cy )
|
||||||
|
local d = sqDistance( ix, iy, fx, fy )
|
||||||
|
if d < 0.00001 then return sqDistance( ix, iy, cx, cy ) end
|
||||||
|
local t = math.min( 1, math.max( 0, dot( cx - ix, cy - iy, fx - ix, fy - iy) / d ))
|
||||||
|
local u = 1.0 - t
|
||||||
|
return sqDistance( cx, cy, u*ix+t*fx,u*iy+t*fy )
|
||||||
|
end
|
||||||
|
|
||||||
|
--collide in 2D on the xz-plane.
|
||||||
|
local function collide( ix, iz, fx, fz, circles, lines )
|
||||||
|
local x, z = ix, iz
|
||||||
|
for _, circle in pairs( circles ) do
|
||||||
|
if distanceToSegment( ix, iz, fx, fz ) then
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, line in pairs( lines ) do
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
return x, z, fx, fz
|
||||||
|
end
|
||||||
|
|
||||||
function player:update()
|
function player:update()
|
||||||
self.vx = self.desx * speed
|
self.vx = self.desx * self.speed
|
||||||
self.vz = self.desz * speed
|
self.vz = self.desz * self.speed
|
||||||
|
|
||||||
self.x = self.x + self.vx * self.rate
|
self.x = self.x + self.vx * self.rate
|
||||||
self.z = self.z + self.vz * self.rate
|
self.z = self.z + self.vz * self.rate
|
||||||
|
|
||||||
self.view = mat.view( self.x, self.y, self.z, self.yaw, self.pitch )
|
self.view = mat.view( self.x, self.y, self.z, self.yaw, self.pitch )
|
||||||
|
|
||||||
|
self:footstep()
|
||||||
|
end
|
||||||
|
|
||||||
|
function player:isMoving()
|
||||||
|
return
|
||||||
|
self.vx > 0.01 or self.vz > 0.01 or
|
||||||
|
self.vx < 0.01 or self.vz < 0.01
|
||||||
|
end
|
||||||
|
|
||||||
|
function player:footstep()
|
||||||
|
if not self:isMoving() then return end
|
||||||
|
self.footstepTimer = self.footstepTimer + self.rate
|
||||||
|
if self.footstepTimer > self.footstepStride then
|
||||||
|
self.footstepTimer = 0
|
||||||
|
return sfx.playFootstep()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function player:tostring()
|
function player:tostring()
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
local love = assert( love )
|
local love = assert( love )
|
||||||
local player = require( "player" )
|
local player = require( "player" )
|
||||||
local settings = require( "settings" )
|
local settings = require( "settings" )
|
||||||
local renderer = require( "renderer" )
|
local world = require( "level.world" )
|
||||||
local world = require( "scenes.world" )
|
|
||||||
local mat = require( "mat4" )
|
local mat = require( "mat4" )
|
||||||
local t = {}
|
local t = {}
|
||||||
|
|
||||||
|
@ -11,26 +10,16 @@ local frameStart = love.timer.getTime()
|
||||||
local rockTexture = love.graphics.newImage( "tex/rock.png", { mipmaps = true } )
|
local rockTexture = love.graphics.newImage( "tex/rock.png", { mipmaps = true } )
|
||||||
rockTexture:setWrap( "repeat", "repeat" )
|
rockTexture:setWrap( "repeat", "repeat" )
|
||||||
function t.play()
|
function t.play()
|
||||||
love.graphics.setNewFont( 14 )
|
--love.graphics.setNewFont( 14 )
|
||||||
t.mousepressed() --grab window
|
t.mousepressed() --grab window
|
||||||
player:setTurnRate( settings.mouseSensitivity.val )
|
player:setTurnRate( settings.mouseSensitivity.val )
|
||||||
player:setFOV( settings.FOV.val )
|
player:setFOV( settings.FOV.val )
|
||||||
renderer.start()
|
world.start()
|
||||||
|
|
||||||
local plane = require( "models/plane" )
|
--[[local spike = require( "models/spike" )
|
||||||
plane:setTexture( rockTexture )
|
|
||||||
renderer.add( plane )
|
|
||||||
|
|
||||||
local spike = require( "models/spike" )
|
|
||||||
spike:setTexture( rockTexture )
|
spike:setTexture( rockTexture )
|
||||||
renderer.add( spike )
|
renderer.add( spike )
|
||||||
renderer.update( spike, mat.TRS( 0.3, 12, 0.3, 0, 0, 0, 4, 0, 3) )
|
renderer.update( spike, mat.TRS( 0.3, 12, 0.3, 0, 0, 0, 4, 0, 3) )]]
|
||||||
|
|
||||||
local bellTexture = love.graphics.newImage( "tex/bell-height.png", { mipmaps = true } )
|
|
||||||
bellTexture:setWrap( "repeat", "clampzero" )
|
|
||||||
local bell = require( "models/bell" )
|
|
||||||
bell:setTexture( bellTexture )
|
|
||||||
renderer.add( bell, "bell" )
|
|
||||||
|
|
||||||
local scene = require( "scene" )
|
local scene = require( "scene" )
|
||||||
return scene.load( t )
|
return scene.load( t )
|
||||||
|
@ -38,7 +27,7 @@ end
|
||||||
|
|
||||||
function t.draw()
|
function t.draw()
|
||||||
|
|
||||||
renderer.draw( player.view, player.proj )
|
world.draw( player.view, player.proj )
|
||||||
|
|
||||||
local y = 0
|
local y = 0
|
||||||
for k, v in pairs(love.graphics.getStats()) do
|
for k, v in pairs(love.graphics.getStats()) do
|
||||||
|
@ -69,8 +58,6 @@ function t.update( dt )
|
||||||
player:update()
|
player:update()
|
||||||
end
|
end
|
||||||
|
|
||||||
--renderer.setViewDirection( player:getViewDirection() )
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.mousepressed( x, y, button, isTouch, presses )
|
function t.mousepressed( x, y, button, isTouch, presses )
|
||||||
|
@ -87,7 +74,9 @@ function t.keypressed( key, code, isrepeat )
|
||||||
|
|
||||||
end
|
end
|
||||||
if code == "q" then
|
if code == "q" then
|
||||||
renderer.debug()
|
local strings = require( "i18n" )
|
||||||
|
local slideshow = require( "scenes.slideshow" )
|
||||||
|
return slideshow.play( strings.win, love.event.quit, "tex/win.jpg" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,14 +9,14 @@ local cachedSettingVal = nil
|
||||||
local menu = {}
|
local menu = {}
|
||||||
local time = 0
|
local time = 0
|
||||||
for i, setting in ipairs( settings ) do
|
for i, setting in ipairs( settings ) do
|
||||||
menu[i] = { x = 410, y = 10 + i * 25, w = love.graphics.getWidth() - 410 , h = 25 }
|
menu[i] = { x = 350, y = 10 + i * 25, w = love.graphics.getWidth() - 410 , h = 25 }
|
||||||
end
|
end
|
||||||
|
|
||||||
local terrain = love.graphics.newMesh( {
|
local terrain = love.graphics.newMesh( {
|
||||||
{ 0, 0, 0, 0, 1, 0.8, 0.8, 0.5, },
|
{ 0, 0, 0, 0, 0.8, 0.8, 1, 0.4, },
|
||||||
{ 0, 1, 0, 0.1, 1, 0.8, 0.8, 0.5, },
|
{ 0, 1, 0, 1, 0.8, 0.8, 1, 0.4, },
|
||||||
{ 1, 1, 0.1, 0.1, 0, 0, 0, 0.01, },
|
{ 1, 1, 1, 1, 1, 0, 0, 0.01, },
|
||||||
{ 1, 0, 0.1, 0, 0, 0, 0, 0.01, },
|
{ 1, 0, 1, 0, 1, 0, 0, 0.01, },
|
||||||
})
|
})
|
||||||
|
|
||||||
local function restoreCachedSetting()
|
local function restoreCachedSetting()
|
||||||
|
@ -45,7 +45,7 @@ function t.keypressed( key, code, isRepeat )
|
||||||
if code == "return" then
|
if code == "return" then
|
||||||
local slideshow = require( "scenes.slideshow" )
|
local slideshow = require( "scenes.slideshow" )
|
||||||
local main = require( "scenes.main" )
|
local main = require( "scenes.main" )
|
||||||
return slideshow.play( strings.intro, main.play )
|
return slideshow.play( strings.intro, main.play, "tex/jared.jpg" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -110,24 +110,22 @@ function t.update( dt )
|
||||||
local x, y = terrain:getVertexAttribute( i, 1 )
|
local x, y = terrain:getVertexAttribute( i, 1 )
|
||||||
x = ( x > 0 ) and 0.5 or 0
|
x = ( x > 0 ) and 0.5 or 0
|
||||||
y = ( y > 0 ) and 0.5 or 0
|
y = ( y > 0 ) and 0.5 or 0
|
||||||
terrain:setVertexAttribute( i, 2, x - 0.04 * time, y - 0.05 * time )
|
terrain:setVertexAttribute( i, 2, x + 0.01 * time, y + 0.00 * time )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
do
|
do
|
||||||
local tex = love.graphics.newImage( "tex/terrain.png" )
|
local tex = love.graphics.newImage( "tex/terrain.jpg" )
|
||||||
tex:setFilter( "nearest", "nearest" )
|
|
||||||
tex:setWrap( "repeat", "repeat" )
|
tex:setWrap( "repeat", "repeat" )
|
||||||
terrain:setTexture( tex )
|
terrain:setTexture( tex )
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.draw()
|
function t.draw()
|
||||||
|
love.graphics.setScissor()
|
||||||
love.graphics.setScissor( 0, 0, 400, love.graphics.getHeight() )
|
love.graphics.setColor( 1, 1, 1, 1 )
|
||||||
|
love.graphics.draw( terrain, 0, 0, 0, love.graphics.getWidth(), love.graphics.getHeight() )
|
||||||
love.graphics.draw( terrain, 0, 0, 0, 400, love.graphics.getHeight() )
|
love.graphics.setScissor()
|
||||||
|
love.graphics.setScissor( 350, 0, love.graphics.getWidth() - 400, love.graphics.getHeight() )
|
||||||
love.graphics.setScissor( 400, 0, love.graphics.getWidth() - 400, love.graphics.getHeight() )
|
|
||||||
|
|
||||||
love.graphics.setColor( 1, 0.1, 0.1, 0.2 )
|
love.graphics.setColor( 1, 0.1, 0.1, 0.2 )
|
||||||
if mouseOverSetting then
|
if mouseOverSetting then
|
||||||
|
@ -147,22 +145,24 @@ function t.draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.setColor( 1, 1, 1, 1 )
|
love.graphics.setColor( 1, 1, 1, 1 )
|
||||||
love.graphics.print( strings.settingsMenuTitle, 400 , 0 )
|
love.graphics.print( strings.settingsMenuTitle, 360 , 0 )
|
||||||
|
|
||||||
for i, setting in ipairs( settings ) do
|
for i, setting in ipairs( settings ) do
|
||||||
local x, y = menu[i].x, menu[i].y
|
local x, y = menu[i].x, menu[i].y
|
||||||
--love.graphics.rectangle( "line", x, y, love.graphics.getWidth() / 2, 25 )
|
--love.graphics.rectangle( "line", x, y, love.graphics.getWidth() / 2, 25 )
|
||||||
love.graphics.print( strings[setting.setting], x + 10, y )
|
love.graphics.print( strings[setting.setting], x + 20, y )
|
||||||
love.graphics.print( setting.val, x + 250, y )
|
love.graphics.print( setting.val, x + 250, y )
|
||||||
end
|
end
|
||||||
|
|
||||||
if currentSetting then
|
if currentSetting then
|
||||||
love.graphics.print( strings.settingsMenuBackspace, 400, love.graphics.getHeight() - 2 * love.graphics.getFont():getHeight())
|
love.graphics.print( strings.settingsMenuBackspace, 360, love.graphics.getHeight() - 2 * love.graphics.getFont():getHeight())
|
||||||
if settings[currentSetting].type == "number" then
|
if settings[currentSetting].type == "number" or
|
||||||
love.graphics.print( strings.settingsMenuScroll, 400, love.graphics.getHeight() - 3 * love.graphics.getFont():getHeight())
|
settings[currentSetting].type == "list"
|
||||||
|
then
|
||||||
|
love.graphics.print( strings.settingsMenuScroll, 360, love.graphics.getHeight() - 3 * love.graphics.getFont():getHeight())
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
love.graphics.print( strings.toContinue, 400, love.graphics.getHeight() - love.graphics.getFont():getHeight() )
|
love.graphics.print( strings.toContinue, 360, love.graphics.getHeight() - love.graphics.getFont():getHeight() )
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -11,18 +11,21 @@ local t = {}
|
||||||
|
|
||||||
local len = 0
|
local len = 0
|
||||||
local time = 0
|
local time = 0
|
||||||
|
local quad
|
||||||
|
|
||||||
local function noop() end
|
local function noop() end
|
||||||
t.mousemoved = noop
|
t.mousemoved = noop
|
||||||
t.mousepressed = noop
|
t.mousepressed = noop
|
||||||
t.wheelmoved = noop
|
t.wheelmoved = noop
|
||||||
|
|
||||||
|
|
||||||
function t.keypressed( key, code, isRepeat )
|
function t.keypressed( key, code, isRepeat )
|
||||||
if code == "return" then
|
if code == "return" then
|
||||||
if printString ~= fullString then
|
if printString ~= fullString then
|
||||||
printString = fullString
|
printString = fullString
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
|
quad = nil
|
||||||
return loadNextScene()
|
return loadNextScene()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -33,6 +36,7 @@ function t.draw()
|
||||||
love.graphics.setColor( 1, 0.2, 0.2 )
|
love.graphics.setColor( 1, 0.2, 0.2 )
|
||||||
love.graphics.printf( printString, 10, 10, math.min( 400, love.graphics.getWidth() / 2 ), "left" )
|
love.graphics.printf( printString, 10, 10, math.min( 400, love.graphics.getWidth() / 2 ), "left" )
|
||||||
love.graphics.print( strings.toContinue, 10, love.graphics.getHeight() - love.graphics.getFont():getHeight() )
|
love.graphics.print( strings.toContinue, 10, love.graphics.getHeight() - love.graphics.getFont():getHeight() )
|
||||||
|
if quad then love.graphics.draw( quad, 450, 0, 0, 0.3, 0.3) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.update( dt )
|
function t.update( dt )
|
||||||
|
@ -45,10 +49,11 @@ function t.update( dt )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function t.play( str, nextScene )
|
function t.play( str, nextScene, img )
|
||||||
loadNextScene = nextScene
|
loadNextScene = nextScene
|
||||||
fullString = str
|
fullString = str
|
||||||
printString = ""
|
printString = ""
|
||||||
|
if img then quad = love.graphics.newImage( img ) end
|
||||||
love.graphics.setScissor()
|
love.graphics.setScissor()
|
||||||
love.graphics.clear( )
|
love.graphics.clear( )
|
||||||
return scene.load( t )
|
return scene.load( t )
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
local renderer = require( "renderer" )
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
local sfx = {}
|
||||||
|
|
||||||
|
function sfx.playFootstep()
|
||||||
|
print( "step" )
|
||||||
|
end
|
||||||
|
return sfx
|
|
@ -1,12 +1,14 @@
|
||||||
return love.graphics.newShader[[
|
return love.graphics.newShader[[
|
||||||
#define fog vec4( 0.85, 0.85, 1.0, 1.0 )
|
#define fog vec4( 0.85, 0.85, 1.0, 1.0 )
|
||||||
#define fogHigh vec4( 1.0, 1.0, 0.85, 1.0 )
|
#define fogHigh vec4( 1.0, 1.0, 0.85, 1.0 )
|
||||||
|
#define sunDir 0.1 * vec3( 0.9, 0.2, 0.5 )
|
||||||
varying float depth;
|
varying float depth;
|
||||||
varying float height;
|
varying float height;
|
||||||
varying float instanceColor;
|
varying float instanceColor;
|
||||||
#ifdef VERTEX
|
#ifdef VERTEX
|
||||||
//per instance: (uniform) scale and xz position
|
//per instance: (uniform) scale and xz position
|
||||||
attribute vec4 bellInstance;
|
attribute vec4 bellInstance;
|
||||||
|
attribute vec3 vertexNormal;
|
||||||
uniform mat4 view;
|
uniform mat4 view;
|
||||||
uniform mat4 proj;
|
uniform mat4 proj;
|
||||||
vec4 position( mat4 _, vec4 pos ){
|
vec4 position( mat4 _, vec4 pos ){
|
||||||
|
@ -21,12 +23,12 @@ return love.graphics.newShader[[
|
||||||
#endif
|
#endif
|
||||||
#ifdef PIXEL
|
#ifdef PIXEL
|
||||||
vec4 effect( vec4 color, Image tex, vec2 texuv, vec2 scruv) {
|
vec4 effect( vec4 color, Image tex, vec2 texuv, vec2 scruv) {
|
||||||
vec4 bellColor = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.2,0.0,0.0,1.0), instanceColor );
|
vec4 icolor = mix( vec4(1.0,1.0,1.0,1.0), vec4(0.5,0.0,0.0,1.0), instanceColor );
|
||||||
return vec4(
|
vec4 texel = Texel( tex, texuv );
|
||||||
mix( mix( bellColor * color * Texel( tex, texuv ), fog,
|
vec4 bellColor = icolor * (texel + (1.0 - texel.a));
|
||||||
clamp( depth / 20.0, 0.0, 1.0)), fogHigh,
|
return color * mix( mix( bellColor,
|
||||||
clamp( height / 20.0, 0.0, 1.0)).rgb,
|
fog, clamp( depth / 80.0, 0.0, 1.0)),
|
||||||
1.0 );
|
fogHigh, clamp( height / 20.0, 0.0, 1.0));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
]]
|
]]
|
|
@ -0,0 +1,34 @@
|
||||||
|
return love.graphics.newShader[[
|
||||||
|
#define fog vec4( 0.85, 0.85, 1.0, 1.0 )
|
||||||
|
#define fogHigh vec4( 1.0, 1.0, 0.9, 1.0 )
|
||||||
|
varying float depth;
|
||||||
|
varying vec3 normal;
|
||||||
|
varying vec4 world;
|
||||||
|
#ifdef VERTEX
|
||||||
|
uniform mat4 mdl;
|
||||||
|
uniform mat4 view;
|
||||||
|
uniform mat4 proj;
|
||||||
|
attribute vec3 VertexNormal;
|
||||||
|
vec4 position( mat4 _, vec4 pos ){
|
||||||
|
normal = VertexNormal;
|
||||||
|
world = mdl * pos;
|
||||||
|
vec4 eye = view * world;
|
||||||
|
depth = -eye.z;
|
||||||
|
return proj*eye;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef PIXEL
|
||||||
|
uniform vec3 light;
|
||||||
|
vec4 effect( vec4 color, Image tex, vec2 texuv, vec2 scruv) {
|
||||||
|
vec3 norm = normalize( normal );
|
||||||
|
vec3 toLight = normalize( light - world.xyz );
|
||||||
|
float diff = max( dot( norm, light ), 0.5 );
|
||||||
|
|
||||||
|
vec4 mainColor = vec4( diff * color.rgb, color.a );
|
||||||
|
|
||||||
|
return mix( mix( mainColor, fog,
|
||||||
|
clamp( depth / 80.0, 0.0, 1.0)), fogHigh,
|
||||||
|
clamp( world.y / 20.0, 0.0, 1.0)) ;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
]]
|
|
@ -18,7 +18,7 @@ return love.graphics.newShader[[
|
||||||
#ifdef PIXEL
|
#ifdef PIXEL
|
||||||
vec4 effect( vec4 color, Image tex, vec2 texuv, vec2 scruv) {
|
vec4 effect( vec4 color, Image tex, vec2 texuv, vec2 scruv) {
|
||||||
return mix( mix( color * Texel( tex, texuv ), fog,
|
return mix( mix( color * Texel( tex, texuv ), fog,
|
||||||
clamp( depth / 20.0, 0.0, 1.0)), fogHigh,
|
clamp( depth / 80.0, 0.0, 1.0)), fogHigh,
|
||||||
clamp( height / 20.0, 0.0, 1.0)) ;
|
clamp( height / 20.0, 0.0, 1.0)) ;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -13,9 +13,10 @@ varying vec3 viewDir;
|
||||||
#ifdef PIXEL
|
#ifdef PIXEL
|
||||||
uniform samplerCube cube;
|
uniform samplerCube cube;
|
||||||
vec4 effect( vec4 color, Image _, vec2 __, vec2 ___) {
|
vec4 effect( vec4 color, Image _, vec2 __, vec2 ___) {
|
||||||
return mix( fog,
|
return color * Texel( cube, viewDir ) + 0.5 * dot( viewDir, vec3( 0.0, 1.0, 0.0 ));
|
||||||
Texel( cube, viewDir ),
|
//mix( fog,
|
||||||
dot(viewDir, vec3(0.0, 1.0, 0.0 )));;
|
//Texel( cube, viewDir ),
|
||||||
|
//dot(viewDir, vec3(0.0, 0.0, 1.0 )));;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
]]
|
]]
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
After Width: | Height: | Size: 400 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.8 MiB |
Binary file not shown.
After Width: | Height: | Size: 127 KiB |
Loading…
Reference in New Issue