225 lines
5.9 KiB
Lua
225 lines
5.9 KiB
Lua
--@name koptilnya/mesh_loader/cl_builder
|
|
--@client
|
|
--@include /koptilnya/libs/table.txt
|
|
--@include obj_parser.txt
|
|
--@include /koptilnya/libs/utils.txt
|
|
--@include /koptilnya/libs/constants.txt
|
|
require("/koptilnya/libs/table.txt")
|
|
require("obj_parser.txt")
|
|
require("/koptilnya/libs/utils.txt")
|
|
require("/koptilnya/libs/constants.txt")
|
|
|
|
MeshBuilder = class("MeshBuilder")
|
|
|
|
function MeshBuilder:initialize(link)
|
|
self.link = link
|
|
self.meshData = {}
|
|
|
|
self._objects = {}
|
|
self._cachedMaterials = {}
|
|
self._parser = ObjParser:new(link)
|
|
self._parser.onLoaded = function(parser, objData)
|
|
self:_onObjLoaded(objData)
|
|
end
|
|
self._parser.onParsed = function(parser, meshData, usedTriangles)
|
|
self:_onObjParsed(meshData, usedTriangles)
|
|
end
|
|
self._parser:parse()
|
|
|
|
if IS_ME then
|
|
net.receive("initialized", function()
|
|
net.readEntity(function(ply)
|
|
notification.addProgress(tostring(ply:getUserID()), string.format("%s is loading mesh", ply:getName()))
|
|
end)
|
|
end)
|
|
|
|
net.receive("obj_parsed", function()
|
|
net.readEntity(function(ply)
|
|
notification.kill(tostring(ply:getUserID()))
|
|
end)
|
|
end)
|
|
|
|
net.receive("player_disconnect", function()
|
|
notification.kill(net.readString())
|
|
end)
|
|
|
|
net.receive("starfall_error", function()
|
|
net.readEntity(function(ply)
|
|
notification.kill(tostring(ply:getUserID()))
|
|
end)
|
|
end)
|
|
end
|
|
|
|
hook.add("starfallerror", "_starfallerror", function(ent, ply, err)
|
|
if ent ~= chip() then return end
|
|
|
|
net.start("starfall_error")
|
|
net.writeEntity(ply)
|
|
net.send()
|
|
end)
|
|
|
|
net.receive("objects", function()
|
|
self:_onReceiveObjects()
|
|
end)
|
|
|
|
hook.add("Removed", "_Removed", function()
|
|
for k, v in pairs(self._cachedMaterials) do
|
|
if type(v) == "Material" then
|
|
v:destroy()
|
|
end
|
|
end
|
|
end)
|
|
end
|
|
|
|
function MeshBuilder:_onObjLoaded(objData)
|
|
self:onObjLoaded(objData)
|
|
end
|
|
|
|
function MeshBuilder:_onObjParsed(meshData, usedTriangles)
|
|
net.start("obj_parsed")
|
|
net.send()
|
|
|
|
self:onObjParsed(meshData, usedTriangles)
|
|
|
|
self.meshData = meshData
|
|
|
|
self:_applyMeshes()
|
|
end
|
|
|
|
function MeshBuilder:_onReceiveObjects()
|
|
self._objects = {}
|
|
|
|
local hasNext = net.readBit()
|
|
|
|
while hasNext == 1 do
|
|
local name = net.readString()
|
|
local mat = net.readTable()
|
|
|
|
net.readEntity(function(ent)
|
|
local holo = ent:toHologram()
|
|
local isCustomMaterial = (#table.getKeys(mat) > 1 and mat.basetexture) or isURL(mat.basetexture)
|
|
|
|
if (isCustomMaterial) then
|
|
mat = self:_createMaterial(mat.shader, mat.basetexture, mat.bumpmap, mat.options)
|
|
else
|
|
hasErr, mat = pcall(material.load, mat.basetexture)
|
|
|
|
if not hasErr then
|
|
mat = material.load("models/debug/debugwhite")
|
|
end
|
|
end
|
|
|
|
local object = {name = name, mat = mat, holo = holo}
|
|
|
|
table.insert(self._objects, object)
|
|
end)
|
|
|
|
hasNext = net.readBit()
|
|
end
|
|
|
|
timer.simple(0.5, function()
|
|
self:onHologramsReceived(self._objects)
|
|
self:_applyMeshes()
|
|
end)
|
|
end
|
|
|
|
function MeshBuilder:_applyMeshes()
|
|
for _, v in pairs(self._objects) do
|
|
if self.meshData[v.name] ~= nil then
|
|
local color = v.holo:getColor()
|
|
|
|
v.holo:setRenderBounds(Vector(-200), Vector(200))
|
|
v.holo:setMesh(self.meshData[v.name])
|
|
v.holo:setMeshMaterial(v.mat)
|
|
|
|
v.meshApplied = true
|
|
end
|
|
end
|
|
|
|
if #self._objects > 0 then
|
|
self:onMeshesApplied()
|
|
end
|
|
end
|
|
|
|
function MeshBuilder:_setTexture(mat, name, texture, layoutOptions)
|
|
if isURL(texture) then
|
|
texture = texture .. "#hack" .. math.random(1337)
|
|
layoutOptions = layoutOptions or {}
|
|
|
|
mat:setTextureURL(name, texture, function(_, _, _, _, layout)
|
|
if not layout then return end
|
|
|
|
local x = layoutOptions.x or 0
|
|
local y = layoutOptions.y or 0
|
|
local w = layoutOptions.w or 1024
|
|
local h = layoutOptions.h or 1024
|
|
|
|
layout(x, y, w, h)
|
|
end)
|
|
else
|
|
mat:setTexture(name, texture)
|
|
end
|
|
end
|
|
|
|
function MeshBuilder:_createMaterial(shader, basetexture, bumpmap, options)
|
|
shader = shader or "VertexLitGeneric"
|
|
basetexture = basetexture or "models/debug/debugwhite"
|
|
bumpmap = bumpmap or ""
|
|
options = options or {}
|
|
|
|
local checksum = crc(shader .. basetexture .. bumpmap .. json.encode(options))
|
|
|
|
if self._cachedMaterials[checksum] ~= nil then
|
|
return self._cachedMaterials[checksum]
|
|
end
|
|
|
|
local mat = material.create(shader)
|
|
|
|
self:_setTexture(mat, "$basetexture", basetexture, options.baseLayout)
|
|
|
|
if bumpmap ~= "" then
|
|
self:_setTexture(mat, "$bumpmap", bumpmap, options.bumpLayout)
|
|
end
|
|
|
|
options.baseLayout = nil
|
|
options.bumpLayout = nil
|
|
|
|
for k, v in pairs(options) do
|
|
if k == "envmap" then
|
|
mat:setTexture("$envmap", v)
|
|
elseif type(v) == "string" then
|
|
mat:setString("$" .. k, v)
|
|
elseif type(v) == "number" then
|
|
if string.match(tostring(v), "%.") then
|
|
mat:setFloat("$" .. k, v)
|
|
else
|
|
mat:setInt("$" .. k, v)
|
|
end
|
|
elseif type(v) == "nil" then
|
|
mat:setUndefined("$" .. k, v)
|
|
elseif type(v) == "Vector" then
|
|
mat:setVector("$" .. k, v)
|
|
end
|
|
end
|
|
|
|
self._cachedMaterials[checksum] = mat
|
|
|
|
--mat:recompute()
|
|
|
|
return mat
|
|
end
|
|
|
|
-- STUB
|
|
|
|
function MeshBuilder:onObjLoaded(objData)
|
|
end
|
|
|
|
function MeshBuilder:onObjParsed(meshData, usedTriangles)
|
|
end
|
|
|
|
function MeshBuilder:onHologramsReceived(objects)
|
|
end
|
|
|
|
function MeshBuilder:onMeshesApplied()
|
|
end
|