From c3c6d95ef99edf722850bb9e2d5f2e6bdb7dbd86 Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Thu, 14 May 2026 23:02:52 -0400 Subject: [PATCH 1/6] Start skinned mesh support --- lua/entities/starfall_hologram/cl_init.lua | 11 +- lua/entities/starfall_prop/cl_init.lua | 7 +- lua/starfall/libs_sh/entities.lua | 1 - lua/starfall/libs_sh/mesh.lua | 162 ++++++++++++--------- 4 files changed, 104 insertions(+), 77 deletions(-) diff --git a/lua/entities/starfall_hologram/cl_init.lua b/lua/entities/starfall_hologram/cl_init.lua index 667447102..f0c820c8f 100644 --- a/lua/entities/starfall_hologram/cl_init.lua +++ b/lua/entities/starfall_hologram/cl_init.lua @@ -143,12 +143,13 @@ function ENT:Draw(flags) end function ENT:GetRenderMesh() - local selfTbl = self:GetTable() - if selfTbl.custom_mesh then - if selfTbl.custom_mesh_data[selfTbl.custom_mesh] then - return { Mesh = selfTbl.custom_mesh, Material = selfTbl.Material--[[, Matrix = self.HoloMatrix]] } + local ent_tbl = self:GetTable() + local custom_mesh = ent_tbl.custom_mesh + if custom_mesh then + if custom_mesh.mesh then + return { Mesh = custom_mesh.mesh, Material = ent_tbl.Material--[[, Matrix = self.HoloMatrix]] } else - selfTbl.custom_mesh = nil + ent_tbl.custom_mesh = nil end end end diff --git a/lua/entities/starfall_prop/cl_init.lua b/lua/entities/starfall_prop/cl_init.lua index f6cbc520a..37839eb18 100644 --- a/lua/entities/starfall_prop/cl_init.lua +++ b/lua/entities/starfall_prop/cl_init.lua @@ -66,9 +66,10 @@ end function ENT:GetRenderMesh() local ent_tbl = Ent_GetTable(self) - if ent_tbl.custom_mesh then - if ent_tbl.custom_mesh_data[ent_tbl.custom_mesh] then - return { Mesh = ent_tbl.custom_mesh, Material = ent_tbl.Material--[[, Matrix = ent_tbl.render_matrix]] } + local custom_mesh = ent_tbl.custom_mesh + if custom_mesh then + if custom_mesh.mesh then + return { Mesh = custom_mesh.mesh, Material = ent_tbl.Material--[[, Matrix = ent_tbl.render_matrix]] } else ent_tbl.custom_mesh = nil end diff --git a/lua/starfall/libs_sh/entities.lua b/lua/starfall/libs_sh/entities.lua index 4cd6528aa..519845db1 100644 --- a/lua/starfall/libs_sh/entities.lua +++ b/lua/starfall/libs_sh/entities.lua @@ -126,7 +126,6 @@ if CLIENT then checkpermission(instance, ent, "entities.setRenderProperty") if mesh then ent_tbl.custom_mesh = instance.Types.Mesh.Unwrap(mesh) - ent_tbl.custom_mesh_data = instance.data.meshes else ent_tbl.custom_mesh = nil end diff --git a/lua/starfall/libs_sh/mesh.lua b/lua/starfall/libs_sh/mesh.lua index b1250b1b1..455dc9c49 100644 --- a/lua/starfall/libs_sh/mesh.lua +++ b/lua/starfall/libs_sh/mesh.lua @@ -804,24 +804,29 @@ function mesh_library.findConvexHull(vertices, threaded) end if CLIENT then - local meshData = {} - instance.data.meshes = meshData + local mesh_methods, mesh_meta, wrap, unwrap = instance.Types.Mesh.Methods, instance.Types.Mesh, instance.Types.Mesh.Wrap, instance.Types.Mesh.Unwrap + + local instanceMeshes = {} + + local function registerMesh(mesh, ntriangles) + local meshdata = { ntriangles = ntriangles, matrices = {}, isSkinned = false, mesh = mesh } + instanceMeshes[meshdata] = true + end - local function destroyMesh(ply, mesh) - plyTriangleCount:free(ply, meshData[mesh].ntriangles) + local function destroyMesh(ply, meshdata) + plyTriangleCount:free(ply, meshdata.ntriangles) plyMeshCount:free(ply, 1) - mesh:Destroy() - meshData[mesh] = nil + meshdata.mesh:Destroy() + meshdata.mesh = nil + instanceMeshes[meshdata] = nil end instance:AddHook("deinitialize", function() - for mesh in pairs(meshData) do + for mesh in pairs(instanceMeshes) do destroyMesh(instance.player, mesh) end end) - local mesh_methods, mesh_meta, wrap, unwrap = instance.Types.Mesh.Methods, instance.Types.Mesh, instance.Types.Mesh.Wrap, instance.Types.Mesh.Unwrap - local vertexCheck = { color = function(v) return dgetmeta(v) == col_meta end, normal = function(v) return dgetmeta(v) == vec_meta end, @@ -841,7 +846,8 @@ if CLIENT then pos = vunwrap, u = function(x) return x end, v = function(x) return x end, - userdata = function(x) return x end + userdata = function(x) return x end, + weights = function(x) return x end, } --- Creates a mesh from vertex data. @@ -877,12 +883,13 @@ if CLIENT then end if threaded then thread_yield(0) end - local mesh = Mesh() - mesh:BuildFromTriangles(unwrapped) - meshData[mesh] = { ntriangles = ntriangles } + plyTriangleCount:use(instance.player, ntriangles) plyMeshCount:use(instance.player, 1) - return wrap(mesh) + + local mesh = Mesh() + mesh:BuildFromTriangles(unwrapped) + return wrap(registerMesh(mesh, ntriangles)) end --- Creates a mesh from an obj file. Only supports triangular meshes with normals and texture coordinates. @@ -907,8 +914,7 @@ if CLIENT then local mesh = Mesh() mesh:BuildFromTriangles(vertices) - meshData[mesh] = { ntriangles = ntriangles } - meshes[name] = wrap(mesh) + meshes[name] = wrap(registerMesh(mesh, ntriangles)) if threaded then thread_yield() end end return meshes @@ -919,12 +925,8 @@ if CLIENT then -- @client function mesh_library.createEmpty() checkpermission(instance, nil, "mesh") - plyMeshCount:use(instance.player, 1) - - local mesh = Mesh() - meshData[mesh] = { ntriangles = 0 } - return wrap(mesh) + return wrap(registerMesh(Mesh(), 0)) end local function wrapVertex(p) @@ -1031,20 +1033,17 @@ if CLIENT then if mesh_obj == nil then if not instance.data.render.isRendering then SF.Throw("Not in rendering hook.", 2) end plyTriangleRenderBurst:use(instance.player, tri_count) - meshgenerating = true mesh.Begin(prim_type, prim_count) else - mesh_obj = unwrap(mesh_obj) - local mesh_tbl = meshData[mesh_obj] - if not mesh_tbl then SF.Throw("Tried to use invalid mesh.", 2) end + local meshdata = unwrap(mesh_obj) -- Garrysmod bug, crash if mesh isn't empty - if mesh_tbl.ntriangles ~= 0 then SF.Throw("mesh.generate requires an empty mesh to populate.", 2) end + if meshdata.ntriangles ~= 0 then SF.Throw("mesh.generate requires an empty mesh to populate.", 2) end plyTriangleCount:use(instance.player, tri_count) - mesh_tbl.ntriangles = tri_count - meshgenerating = mesh_obj - mesh.Begin(mesh_obj, prim_type, prim_count) + meshdata.ntriangles = tri_count + mesh.Begin(meshdata.mesh, prim_type, prim_count) end + meshgenerating = true instance.canyield = false local ok, err = pcall(func) instance.canyield = true @@ -1053,95 +1052,122 @@ if CLIENT then if not ok then error(err) end end - --- Sets the vertex color by RGBA values + --- Writes the vertex color by RGBA values to the vertex data + -- @name mesh_library.writeColor + -- @class function -- @param number r Number, red value -- @param number g Number, green value -- @param number b Number, blue value -- @param number a Number, alpha value -- @client - function mesh_library.writeColor(r, g, b, a) - mesh.Color(r, g, b, a) - end + mesh_library.writeColor = mesh.Color - --- Sets the vertex normal + --- Writes the vertex normal to the vertex data + -- @name mesh_library.writeNormal + -- @class function -- @param Vector normal Normal -- @client - function mesh_library.writeNormal(normal) - mesh.Normal(vunwrap1(normal)) - end + mesh_library.writeNormal = mesh.Normal - --- Sets the vertex position + --- Writes the vertex position to the vertex data + -- @name mesh_library.writePosition + -- @class function -- @param Vector position Position -- @client - function mesh_library.writePosition(pos) - mesh.Position(vunwrap1(pos)) - end + mesh_library.writePosition = mesh.Position - --- Sets the vertex texture coordinates + --- Writes the vertex texture coordinates to the vertex data + -- @name mesh_library.writeUV + -- @class function -- @param number stage Stage of the texture coordinate -- @param number u U coordinate -- @param number v V coordinate -- @client - function mesh_library.writeUV(stage, u, v) - mesh.TexCoord(stage, u, v) - end + mesh_library.writeUV = mesh.TexCoord - --- Sets the vertex tangent user data + --- Writes the vertex tangent user data to the vertex data + -- @name mesh_library.writeUserData + -- @class function -- @param number x x -- @param number y y -- @param number z z -- @param number handedness -- @client - function mesh_library.writeUserData(x, y, z, handedness) - mesh.UserData(x, y, z, handedness) - end + mesh_library.writeUserData = mesh.UserData - --- Draws a quad using 4 vertices + --- Writes a quad using 4 vertices to the vertex data + -- @name mesh_library.writeQuad + -- @class function -- @param Vector v1 Vertex1 position -- @param Vector v2 Vertex2 position -- @param Vector v3 Vertex3 position -- @param Vector v4 Vertex4 position -- @param Color col The color for the vertices. -- @client - function mesh_library.writeQuad(v1, v2, v3, v4, col) - mesh.Quad(vunwrap1(v1), vunwrap2(v2), vunwrap3(v3), vunwrap4(v4), col) - end + mesh_library.writeQuad = mesh.Quad - --- Draws a quad using a position, normal and size + --- Writes a quad using a position, normal and size to the vertex data + -- @name mesh_library.writeQuadEasy + -- @class function -- @param Vector position -- @param Vector normal -- @param number w -- @param number h -- @param Color col The color for the vertices. -- @client - function mesh_library.writeQuadEasy(position, normal, w, h, col) - mesh.QuadEasy(vunwrap1(position), vunwrap2(normal), w, h, col) - end + mesh_library.writeQuadEasy = mesh.QuadEasy + + --- Writes bone data to the vertex data + -- @name mesh_library.writeBoneData + -- @class function + -- @param number index The slot index for the vertex, either 0 or 1. + -- @param number matrixId The matrix index for the vertex, in the range of 0 -> 52. This is 0-indexed whereas mesh:setMatrix is 1-indexed + -- @param number weight How much influence that matrix will have on this vertex, in the range of 0 -> 1 + mesh_library.writeBoneData = mesh.BoneData --- Pushes the vertex data onto the render stack + -- @name mesh_library.advanceVertex + -- @class function -- @client - function mesh_library.advanceVertex() - mesh.AdvanceVertex() - end + mesh_library.advanceVertex = mesh.AdvanceVertex --- Draws the mesh. Must be in a 3D rendering context. -- @client function mesh_methods:draw() - local mesh = unwrap(self) - local meshdata = meshData[mesh] - if not meshdata then SF.Throw("Tried to use invalid mesh.", 2) end + local meshdata = unwrap(self) if not instance.data.render.isRendering then SF.Throw("Not in rendering hook.", 2) end plyTriangleRenderBurst:use(instance.player, meshdata.ntriangles) - mesh:Draw() + if meshdata.isSkinned then + meshdata.mesh:DrawSkinned(meshdata.matrices) + else + meshdata.mesh:Draw() + end + end + + --- Sets the matrix of the skinned mesh + -- @param number index The matrix index representing a bone in range 1 -> 53 + -- @param VMatrix matrix The matrix to set the bone to + -- @client + function mesh_methods:setMatrix(index, matrix) + -- Todo + end + + --- Sets the matrix of the skinned mesh + -- @param number index The matrix index representing a bone in range 1 -> 53 + -- @return VMatrix The matrix of the bone + -- @client + function mesh_methods:getMatrix(index) + -- Todo end --- Frees the mesh from memory -- @client function mesh_methods:destroy() - local mesh = unwrap(self) - if not meshData[mesh] then SF.Throw("Tried to use invalid mesh.", 2) end - if meshgenerating == mesh then SF.Throw("Cannot destroy mesh currently being generated.", 2) end - destroyMesh(instance.player, mesh) + local meshdata = unwrap(self) + if meshgenerating then SF.Throw("Cannot destroy mesh while generating!", 2) end + destroyMesh(instance.player, meshdata) + mesh_meta.sf2sensitive[self] = nil + mesh_meta.sensitive2sf[meshdata.mesh] = nil end end From ac4c5b7a563105ea199adf507d731ea7aca93e5d Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Thu, 14 May 2026 23:16:16 -0400 Subject: [PATCH 2/6] Fixes --- lua/starfall/libs_sh/mesh.lua | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/lua/starfall/libs_sh/mesh.lua b/lua/starfall/libs_sh/mesh.lua index 455dc9c49..81da9a43a 100644 --- a/lua/starfall/libs_sh/mesh.lua +++ b/lua/starfall/libs_sh/mesh.lua @@ -811,6 +811,7 @@ if CLIENT then local function registerMesh(mesh, ntriangles) local meshdata = { ntriangles = ntriangles, matrices = {}, isSkinned = false, mesh = mesh } instanceMeshes[meshdata] = true + return meshdata end local function destroyMesh(ply, meshdata) @@ -822,8 +823,8 @@ if CLIENT then end instance:AddHook("deinitialize", function() - for mesh in pairs(instanceMeshes) do - destroyMesh(instance.player, mesh) + for meshdata in pairs(instanceMeshes) do + destroyMesh(instance.player, meshdata) end end) @@ -1063,18 +1064,18 @@ if CLIENT then mesh_library.writeColor = mesh.Color --- Writes the vertex normal to the vertex data - -- @name mesh_library.writeNormal - -- @class function -- @param Vector normal Normal -- @client - mesh_library.writeNormal = mesh.Normal + function mesh_library.writeNormal(normal) + mesh.Normal(vunwrap1(normal)) + end --- Writes the vertex position to the vertex data - -- @name mesh_library.writePosition - -- @class function -- @param Vector position Position -- @client - mesh_library.writePosition = mesh.Position + function mesh_library.writePosition(pos) + mesh.Position(vunwrap1(pos)) + end --- Writes the vertex texture coordinates to the vertex data -- @name mesh_library.writeUV @@ -1096,26 +1097,26 @@ if CLIENT then mesh_library.writeUserData = mesh.UserData --- Writes a quad using 4 vertices to the vertex data - -- @name mesh_library.writeQuad - -- @class function -- @param Vector v1 Vertex1 position -- @param Vector v2 Vertex2 position -- @param Vector v3 Vertex3 position -- @param Vector v4 Vertex4 position -- @param Color col The color for the vertices. -- @client - mesh_library.writeQuad = mesh.Quad + function mesh_library.writeQuad(v1, v2, v3, v4, col) + mesh.Quad(vunwrap1(v1), vunwrap2(v2), vunwrap3(v3), vunwrap4(v4), col) + end --- Writes a quad using a position, normal and size to the vertex data - -- @name mesh_library.writeQuadEasy - -- @class function -- @param Vector position -- @param Vector normal -- @param number w -- @param number h -- @param Color col The color for the vertices. -- @client - mesh_library.writeQuadEasy = mesh.QuadEasy + function mesh_library.writeQuadEasy(position, normal, w, h, col) + mesh.QuadEasy(vunwrap1(position), vunwrap2(normal), w, h, col) + end --- Writes bone data to the vertex data -- @name mesh_library.writeBoneData @@ -1163,11 +1164,11 @@ if CLIENT then --- Frees the mesh from memory -- @client function mesh_methods:destroy() - local meshdata = unwrap(self) if meshgenerating then SF.Throw("Cannot destroy mesh while generating!", 2) end + local meshdata = unwrap(self) destroyMesh(instance.player, meshdata) mesh_meta.sf2sensitive[self] = nil - mesh_meta.sensitive2sf[meshdata.mesh] = nil + mesh_meta.sensitive2sf[meshdata] = nil end end From 306cc3f57c09417268be1e0fef2c72cfb49c46a1 Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Fri, 15 May 2026 21:02:46 -0400 Subject: [PATCH 3/6] Add matrix function --- lua/starfall/libs_sh/mesh.lua | 36 +++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/lua/starfall/libs_sh/mesh.lua b/lua/starfall/libs_sh/mesh.lua index 81da9a43a..64e80432f 100644 --- a/lua/starfall/libs_sh/mesh.lua +++ b/lua/starfall/libs_sh/mesh.lua @@ -809,7 +809,7 @@ if CLIENT then local instanceMeshes = {} local function registerMesh(mesh, ntriangles) - local meshdata = { ntriangles = ntriangles, matrices = {}, isSkinned = false, mesh = mesh } + local meshdata = { ntriangles = ntriangles, matrices = {}, mesh = mesh } instanceMeshes[meshdata] = true return meshdata end @@ -1135,30 +1135,42 @@ if CLIENT then --- Draws the mesh. Must be in a 3D rendering context. -- @client function mesh_methods:draw() - local meshdata = unwrap(self) if not instance.data.render.isRendering then SF.Throw("Not in rendering hook.", 2) end + local meshdata = unwrap(self) plyTriangleRenderBurst:use(instance.player, meshdata.ntriangles) - if meshdata.isSkinned then + if meshdata.matrices[1]~=nil then meshdata.mesh:DrawSkinned(meshdata.matrices) else meshdata.mesh:Draw() end end - --- Sets the matrix of the skinned mesh - -- @param number index The matrix index representing a bone in range 1 -> 53 - -- @param VMatrix matrix The matrix to set the bone to + --- Sets the number of matrices to be used for the skinned mesh. + -- @param number count The number of bone matrices to use in range 1 -> 53 -- @client - function mesh_methods:setMatrix(index, matrix) - -- Todo + function mesh_methods:setBoneMatrices(count) + local meshdata = unwrap(self) + count = math.Clamp(math.floor(count), 0, 53) + if #meshdata.matrices == count then return end + for i=#meshdata.matrices+1, count do + meshdata.matrices[i] = Matrix() + end + for i=count+1, 53 do + meshdata.matrices[i] = nil + end end - --- Sets the matrix of the skinned mesh + --- Returns a table of the bone matrices. Editing a matrix will edit the bone -- @param number index The matrix index representing a bone in range 1 -> 53 - -- @return VMatrix The matrix of the bone + -- @return table Table of VMatrix representing each bone -- @client - function mesh_methods:getMatrix(index) - -- Todo + function mesh_methods:getBoneMatrices() + local meshdata = unwrap(self) + local ret = {} + for i=1, #meshdata.matrices do + ret[i] = mwrap(meshdata.matrices[i]) + end + return ret end --- Frees the mesh from memory From 3f68291b9e7178c75d10fe2c92c2072a9e667bc6 Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Sat, 16 May 2026 02:39:20 -0400 Subject: [PATCH 4/6] Combine methods --- lua/starfall/libs_sh/mesh.lua | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/lua/starfall/libs_sh/mesh.lua b/lua/starfall/libs_sh/mesh.lua index 64e80432f..4f228012a 100644 --- a/lua/starfall/libs_sh/mesh.lua +++ b/lua/starfall/libs_sh/mesh.lua @@ -814,9 +814,9 @@ if CLIENT then return meshdata end - local function destroyMesh(ply, meshdata) - plyTriangleCount:free(ply, meshdata.ntriangles) - plyMeshCount:free(ply, 1) + local function destroyMesh(meshdata) + plyTriangleCount:free(instance.player, meshdata.ntriangles) + plyMeshCount:free(instance.player, 1) meshdata.mesh:Destroy() meshdata.mesh = nil instanceMeshes[meshdata] = nil @@ -824,7 +824,7 @@ if CLIENT then instance:AddHook("deinitialize", function() for meshdata in pairs(instanceMeshes) do - destroyMesh(instance.player, meshdata) + destroyMesh(meshdata) end end) @@ -1147,25 +1147,19 @@ if CLIENT then --- Sets the number of matrices to be used for the skinned mesh. -- @param number count The number of bone matrices to use in range 1 -> 53 + -- @return table Table of reference VMatrix to each bone. Modifying them will modify the bone matrix -- @client - function mesh_methods:setBoneMatrices(count) + function mesh_methods:setupBoneMatrices(count) local meshdata = unwrap(self) count = math.Clamp(math.floor(count), 0, 53) - if #meshdata.matrices == count then return end - for i=#meshdata.matrices+1, count do - meshdata.matrices[i] = Matrix() - end - for i=count+1, 53 do - meshdata.matrices[i] = nil + if #meshdata.matrices ~= count then + for i=#meshdata.matrices+1, count do + meshdata.matrices[i] = Matrix() + end + for i=count+1, 53 do + meshdata.matrices[i] = nil + end end - end - - --- Returns a table of the bone matrices. Editing a matrix will edit the bone - -- @param number index The matrix index representing a bone in range 1 -> 53 - -- @return table Table of VMatrix representing each bone - -- @client - function mesh_methods:getBoneMatrices() - local meshdata = unwrap(self) local ret = {} for i=1, #meshdata.matrices do ret[i] = mwrap(meshdata.matrices[i]) @@ -1178,7 +1172,7 @@ if CLIENT then function mesh_methods:destroy() if meshgenerating then SF.Throw("Cannot destroy mesh while generating!", 2) end local meshdata = unwrap(self) - destroyMesh(instance.player, meshdata) + destroyMesh(meshdata) mesh_meta.sf2sensitive[self] = nil mesh_meta.sensitive2sf[meshdata] = nil end From 223a874dd61ce142c7e1aae8efa2c73109b61436 Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Sat, 16 May 2026 19:03:18 -0400 Subject: [PATCH 5/6] Add createEmptySkinned --- lua/starfall/libs_sh/mesh.lua | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/lua/starfall/libs_sh/mesh.lua b/lua/starfall/libs_sh/mesh.lua index 4f228012a..b84157bcc 100644 --- a/lua/starfall/libs_sh/mesh.lua +++ b/lua/starfall/libs_sh/mesh.lua @@ -808,8 +808,9 @@ if CLIENT then local instanceMeshes = {} - local function registerMesh(mesh, ntriangles) - local meshdata = { ntriangles = ntriangles, matrices = {}, mesh = mesh } + local function registerMesh(mesh, ntriangles, isskinned) + local meshdata = { ntriangles = ntriangles, mesh = mesh } + if isskinned then meshdata.matrices = {} end instanceMeshes[meshdata] = true return meshdata end @@ -890,7 +891,7 @@ if CLIENT then local mesh = Mesh() mesh:BuildFromTriangles(unwrapped) - return wrap(registerMesh(mesh, ntriangles)) + return wrap(registerMesh(mesh, ntriangles, false)) end --- Creates a mesh from an obj file. Only supports triangular meshes with normals and texture coordinates. @@ -915,7 +916,7 @@ if CLIENT then local mesh = Mesh() mesh:BuildFromTriangles(vertices) - meshes[name] = wrap(registerMesh(mesh, ntriangles)) + meshes[name] = wrap(registerMesh(mesh, ntriangles, false)) if threaded then thread_yield() end end return meshes @@ -927,7 +928,16 @@ if CLIENT then function mesh_library.createEmpty() checkpermission(instance, nil, "mesh") plyMeshCount:use(instance.player, 1) - return wrap(registerMesh(Mesh(), 0)) + return wrap(registerMesh(Mesh(), 0, false)) + end + + --- Creates a skinned mesh without any vertex data. + -- @return Mesh Mesh object + -- @client + function mesh_library.createEmptySkinned() + checkpermission(instance, nil, "mesh") + plyMeshCount:use(instance.player, 1) + return wrap(registerMesh(Mesh(nil, 2), 0, true)) end local function wrapVertex(p) @@ -1138,7 +1148,7 @@ if CLIENT then if not instance.data.render.isRendering then SF.Throw("Not in rendering hook.", 2) end local meshdata = unwrap(self) plyTriangleRenderBurst:use(instance.player, meshdata.ntriangles) - if meshdata.matrices[1]~=nil then + if meshdata.matrices then meshdata.mesh:DrawSkinned(meshdata.matrices) else meshdata.mesh:Draw() @@ -1151,6 +1161,7 @@ if CLIENT then -- @client function mesh_methods:setupBoneMatrices(count) local meshdata = unwrap(self) + if not meshdata.matrices then SF.Throw("Unable to setup bones on non skinned mesh!", 2) end count = math.Clamp(math.floor(count), 0, 53) if #meshdata.matrices ~= count then for i=#meshdata.matrices+1, count do From 8928a3b9858357394e3ecfa317d7c25a8353f4a4 Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Sat, 16 May 2026 19:14:43 -0400 Subject: [PATCH 6/6] Couple fixes --- lua/starfall/libs_sh/mesh.lua | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lua/starfall/libs_sh/mesh.lua b/lua/starfall/libs_sh/mesh.lua index b84157bcc..06ff66261 100644 --- a/lua/starfall/libs_sh/mesh.lua +++ b/lua/starfall/libs_sh/mesh.lua @@ -848,8 +848,7 @@ if CLIENT then pos = vunwrap, u = function(x) return x end, v = function(x) return x end, - userdata = function(x) return x end, - weights = function(x) return x end, + userdata = function(x) return x end } --- Creates a mesh from vertex data. @@ -1132,7 +1131,7 @@ if CLIENT then -- @name mesh_library.writeBoneData -- @class function -- @param number index The slot index for the vertex, either 0 or 1. - -- @param number matrixId The matrix index for the vertex, in the range of 0 -> 52. This is 0-indexed whereas mesh:setMatrix is 1-indexed + -- @param number matrixId The matrix index for the vertex, in the range of 1 -> 53. -- @param number weight How much influence that matrix will have on this vertex, in the range of 0 -> 1 mesh_library.writeBoneData = mesh.BoneData