Last active
September 18, 2023 21:37
-
-
Save CheezusChrust/7aabdec7020e0034f2de8e7104bfbbb7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--@name Mesh Loader | |
--@author Cheezus | |
--@shared | |
local debugPrints = true -- Shows info about tri count and loading progress | |
if CLIENT then | |
local globalScale = Vector(0.1) -- Scale all meshes added by this amount, or add a scale vector to individual meshes | |
local offsetPos = Vector(0, 0, 0) -- Offsets are relative to chip/base | |
local offsetAngle = Angle(0, 0, 0) | |
local disableTexFiltering = false -- Disable texture filtering (smoothing) for all meshes | |
-- color and scale parameters can be added optionally for individual meshes, can leave them out if they aren't used | |
local meshes = { | |
{ | |
mdl = "https://f001.backblazeb2.com/file/cheezus-sharex/ShareX/2023/02/15/88014032/gun.obj", | |
texture = "https://i.imgur.com/lLPN47x.jpeg", | |
}, | |
{ | |
mdl = "https://f001.backblazeb2.com/file/cheezus-sharex/ShareX/2023/02/15/00154639/barrel.obj", | |
texture = "sprops/sprops_grid_12x12", | |
}, | |
} | |
-- For colorful printing | |
local W, R, G = Color(255, 255, 255), Color(255, 0, 0), Color(0, 255, 0) | |
local base = chip() | |
timer.create("requestBase", 1, 0, function() | |
net.start("requestBase") | |
net.send() | |
end) | |
net.receive("sendBase", function() | |
local ent = net.readEntity() | |
timer.stop("requestBase") | |
base = isValid(ent) and ent or chip() | |
for _, v in ipairs(meshes) do | |
if isValid(v.holo) then | |
v.holo:setPos(base:localToWorld(offsetPos)) | |
v.holo:setAngles(base:localToWorldAngles(offsetAngle)) | |
end | |
end | |
end) | |
local alreadyDownloadedMats = {} | |
local buildThread = coroutine.wrap(function() | |
for k, v in ipairs(meshes) do | |
local holo = hologram.create(base:localToWorld(offsetPos), base:localToWorldAngles(offsetAngle), "models/Combine_Helicopter/helicopter_bomb01.mdl") | |
holo:setParent(base) | |
v.holo = holo | |
if not alreadyDownloadedMats[v.texture] then | |
local mat = material.create("VertexLitGeneric") | |
if not v.texture or v.texture == "" then | |
v.texture = "hunter/myplastic" | |
end | |
if v.texture:sub(1, 4) == "http" then | |
if hasPermission("material.urlcreate", v.texture) then | |
mat:setTextureURL("$basetexture", v.texture, function(_, _, width, height, layout) | |
if not width or not height then | |
mat:setTexture("$basetexture", "hunter/myplastic") | |
print(true, W, "Failed to create texture for mesh ", G, k, W, ": ", R, "invalid texture URL") | |
return | |
end | |
local xScale = 1024 / width | |
local yScale = 1024 / height | |
layout(0, 0, width * xScale, height * yScale) | |
alreadyDownloadedMats[v.texture] = k | |
end) | |
else | |
mat:setTexture("$basetexture", "hunter/myplastic") | |
print(true, W, "Failed to create texture for mesh ", G, k, W, ": ", R, "missing permission material.urlcreate OR url not whitelisted") | |
end | |
else | |
mat:setTexture("$basetexture", v.texture) | |
end | |
v.mat = mat | |
else | |
v.mat = meshes[alreadyDownloadedMats[v.texture]].mat | |
print(nil, W, "Reused material for mesh ", G, k) | |
end | |
local success = false | |
local triangles = mesh.trianglesLeft() | |
try(function() | |
_, v.finalMesh = next(mesh.createFromObj(v.meshData, true)) | |
success = true | |
end, function(err) | |
print(true, W, "Failed to build mesh ", G, k, W, ": ", R, err.message) | |
end) | |
if success then | |
print(nil, W, "Built mesh " .. k, W, ": ", G, triangles - mesh.trianglesLeft(), W, " tris") | |
end | |
end | |
return true | |
end) | |
local triangles = mesh.trianglesLeft() | |
local function doneBuilding() | |
local triCount = triangles - mesh.trianglesLeft() | |
setName("Mesh Loader - " .. triCount .. " tris") | |
print(false, W, "Finished, using ", G, triCount, W, " tris") | |
for _, v in ipairs(meshes) do | |
if v.finalMesh then | |
v.holo:setMesh(v.finalMesh) | |
v.holo:setMeshMaterial(v.mat) | |
v.holo:setRenderBounds(Vector(-200), Vector(200)) | |
v.holo:setScale((v.scale or Vector(1)) * globalScale) | |
v.holo:setColor(v.color or Color(255)) | |
if disableTexFiltering then | |
v.holo:setFilterMag(0) | |
v.holo:setFilterMin(0) | |
end | |
end | |
end | |
end | |
local function buildMeshes() | |
setName("Mesh Loader - Building meshes...") | |
hook.add("think", "build", function() | |
while chip():getQuotaAverage() < chip():getQuotaMax() / 4 do | |
if buildThread() then | |
doneBuilding() | |
hook.remove("think", "build") | |
return | |
end | |
end | |
end) | |
end | |
local failed | |
local alreadyDownloaded = {} | |
local download = coroutine.create(function() | |
for k, v in ipairs(meshes) do | |
if not alreadyDownloaded[v.mdl] then | |
http.get(v.mdl, function(data) | |
if data[1] == "<" or data[1] == "{" then | |
failed = true | |
return | |
end | |
v.meshData = data | |
alreadyDownloaded[v.mdl] = k | |
print(nil, W, "Downloaded mesh data for mesh ", G, k, W, ", size: ", G, math.round(#data / 1048576, 3) .. "mb") | |
end, function(err) | |
print(true, W, "HTTP error - ", R, err) | |
failed = true | |
end) | |
else | |
v.meshData = meshes[alreadyDownloaded[v.mdl]].meshData | |
print(nil, W, "Reused mesh data for mesh ", G, k) | |
end | |
coroutine.yield() | |
end | |
end) | |
timer.create("downloadMeshes", 0.1, 0, function() | |
if coroutine.status(download) ~= "dead" then | |
if http.canRequest() then | |
coroutine.resume(download) | |
end | |
elseif failed then | |
timer.remove("downloadMeshes") | |
print(true, W, "Failed to get mesh - ", R, "URL did not return OBJ format") | |
else | |
local loaded = true | |
for _, v in ipairs(meshes) do | |
if not v.meshData then loaded = false end | |
end | |
if loaded then | |
buildMeshes() | |
timer.remove("downloadMeshes") | |
end | |
end | |
end) | |
else | |
wire.adjustPorts({ | |
Base = "entity" | |
}) | |
net.receive("requestBase", function(_, ply) | |
local base = wire.ports.Base | |
if not isValid(base) then return end | |
net.start("sendBase") | |
net.writeEntity(base) | |
net.send(ply) | |
end) | |
end | |
local oldPrint = print | |
local col = SERVER and Color(3, 169, 244) or Color(222, 169, 9) | |
local prefix = SERVER and "[Server] " or "[Client] " | |
function print(warn, ...) | |
if #{...} == 0 then | |
oldPrint(col, prefix, Color(255, 255, 255), warn) | |
return | |
end | |
if (debugPrints and not warn) or warn then | |
oldPrint(col, prefix, ...) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment