--@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