· 8 years ago · May 13, 2018, 12:46 AM
1function SWEP:Initialize()
2
3 // other initialize code goes here
4
5 if CLIENT then
6
7 // Create a new table for every weapon instance
8 self.VElements = table.FullCopy( self.VElements )
9 self.WElements = table.FullCopy( self.WElements )
10 self.ViewModelBoneMods = table.FullCopy( self.ViewModelBoneMods )
11 self:SetWeaponHoldType( self.HoldType )
12
13 self:CreateModels(self.VElements) // create viewmodels
14 self:CreateModels(self.WElements) // create worldmodels
15
16 // init view model bone build function
17 if IsValid(self.Owner) then
18 local vm = self.Owner:GetViewModel()
19 if IsValid(vm) then
20 self:ResetBonePositions(vm)
21
22 // Init viewmodel visibility
23 if (self.ShowViewModel == nil or self.ShowViewModel) then
24 vm:SetColor(Color(255,255,255,255))
25 else
26 // we set the alpha to 1 instead of 0 because else ViewModelDrawn stops being called
27 vm:SetColor(Color(255,255,255,1))
28 // ^ stopped working in GMod 13 because you have to do Entity:SetRenderMode(1) for translucency to kick in
29 // however for some reason the view model resets to render mode 0 every frame so we just apply a debug material to prevent it from drawing
30 vm:SetMaterial("Debug/hsv")
31 end
32 end
33 end
34
35 end
36
37end
38
39function SWEP:Holster()
40
41 if CLIENT and IsValid(self.Owner) then
42 local vm = self.Owner:GetViewModel()
43 if IsValid(vm) then
44 self:ResetBonePositions(vm)
45 end
46 end
47
48 return true
49end
50
51function SWEP:OnRemove()
52 self:Holster()
53end
54
55if CLIENT then
56
57 SWEP.vRenderOrder = nil
58 function SWEP:ViewModelDrawn()
59
60 local vm = self.Owner:GetViewModel()
61 if !IsValid(vm) then return end
62
63 if (!self.VElements) then return end
64
65 self:UpdateBonePositions(vm)
66
67 if (!self.vRenderOrder) then
68
69 // we build a render order because sprites need to be drawn after models
70 self.vRenderOrder = {}
71
72 for k, v in pairs( self.VElements ) do
73 if (v.type == "Model") then
74 table.insert(self.vRenderOrder, 1, k)
75 elseif (v.type == "Sprite" or v.type == "Quad") then
76 table.insert(self.vRenderOrder, k)
77 end
78 end
79
80 end
81
82 for k, name in ipairs( self.vRenderOrder ) do
83
84 local v = self.VElements[name]
85 if (!v) then self.vRenderOrder = nil break end
86 if (v.hide) then continue end
87
88 local model = v.modelEnt
89 local sprite = v.spriteMaterial
90
91 if (!v.bone) then continue end
92
93 local pos, ang = self:GetBoneOrientation( self.VElements, v, vm )
94
95 if (!pos) then continue end
96
97 if (v.type == "Model" and IsValid(model)) then
98
99 model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
100 ang:RotateAroundAxis(ang:Up(), v.angle.y)
101 ang:RotateAroundAxis(ang:Right(), v.angle.p)
102 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
103
104 model:SetAngles(ang)
105 //model:SetModelScale(v.size)
106 local matrix = Matrix()
107 matrix:Scale(v.size)
108 model:EnableMatrix( "RenderMultiply", matrix )
109
110 if (v.material == "") then
111 model:SetMaterial("")
112 elseif (model:GetMaterial() != v.material) then
113 model:SetMaterial( v.material )
114 end
115
116 if (v.skin and v.skin != model:GetSkin()) then
117 model:SetSkin(v.skin)
118 end
119
120 if (v.bodygroup) then
121 for k, v in pairs( v.bodygroup ) do
122 if (model:GetBodygroup(k) != v) then
123 model:SetBodygroup(k, v)
124 end
125 end
126 end
127
128 if (v.surpresslightning) then
129 render.SuppressEngineLighting(true)
130 end
131
132 render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
133 render.SetBlend(v.color.a/255)
134 model:DrawModel()
135 render.SetBlend(1)
136 render.SetColorModulation(1, 1, 1)
137
138 if (v.surpresslightning) then
139 render.SuppressEngineLighting(false)
140 end
141
142 elseif (v.type == "Sprite" and sprite) then
143
144 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
145 render.SetMaterial(sprite)
146 render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
147
148 elseif (v.type == "Quad" and v.draw_func) then
149
150 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
151 ang:RotateAroundAxis(ang:Up(), v.angle.y)
152 ang:RotateAroundAxis(ang:Right(), v.angle.p)
153 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
154
155 cam.Start3D2D(drawpos, ang, v.size)
156 v.draw_func( self )
157 cam.End3D2D()
158
159 end
160
161 end
162
163 end
164
165 SWEP.wRenderOrder = nil
166 function SWEP:DrawWorldModel()
167
168 if (self.ShowWorldModel == nil or self.ShowWorldModel) then
169 self:DrawModel()
170 end
171
172 if (!self.WElements) then return end
173
174 if (!self.wRenderOrder) then
175
176 self.wRenderOrder = {}
177
178 for k, v in pairs( self.WElements ) do
179 if (v.type == "Model") then
180 table.insert(self.wRenderOrder, 1, k)
181 elseif (v.type == "Sprite" or v.type == "Quad") then
182 table.insert(self.wRenderOrder, k)
183 end
184 end
185
186 end
187
188 if (IsValid(self.Owner)) then
189 bone_ent = self.Owner
190 else
191 // when the weapon is dropped
192 bone_ent = self
193 end
194
195 for k, name in pairs( self.wRenderOrder ) do
196
197 local v = self.WElements[name]
198 if (!v) then self.wRenderOrder = nil break end
199 if (v.hide) then continue end
200
201 local pos, ang
202
203 if (v.bone) then
204 pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent )
205 else
206 pos, ang = self:GetBoneOrientation( self.WElements, v, bone_ent, "ValveBiped.Bip01_R_Hand" )
207 end
208
209 if (!pos) then continue end
210
211 local model = v.modelEnt
212 local sprite = v.spriteMaterial
213
214 if (v.type == "Model" and IsValid(model)) then
215
216 model:SetPos(pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z )
217 ang:RotateAroundAxis(ang:Up(), v.angle.y)
218 ang:RotateAroundAxis(ang:Right(), v.angle.p)
219 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
220
221 model:SetAngles(ang)
222 //model:SetModelScale(v.size)
223 local matrix = Matrix()
224 matrix:Scale(v.size)
225 model:EnableMatrix( "RenderMultiply", matrix )
226
227 if (v.material == "") then
228 model:SetMaterial("")
229 elseif (model:GetMaterial() != v.material) then
230 model:SetMaterial( v.material )
231 end
232
233 if (v.skin and v.skin != model:GetSkin()) then
234 model:SetSkin(v.skin)
235 end
236
237 if (v.bodygroup) then
238 for k, v in pairs( v.bodygroup ) do
239 if (model:GetBodygroup(k) != v) then
240 model:SetBodygroup(k, v)
241 end
242 end
243 end
244
245 if (v.surpresslightning) then
246 render.SuppressEngineLighting(true)
247 end
248
249 render.SetColorModulation(v.color.r/255, v.color.g/255, v.color.b/255)
250 render.SetBlend(v.color.a/255)
251 model:DrawModel()
252 render.SetBlend(1)
253 render.SetColorModulation(1, 1, 1)
254
255 if (v.surpresslightning) then
256 render.SuppressEngineLighting(false)
257 end
258
259 elseif (v.type == "Sprite" and sprite) then
260
261 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
262 render.SetMaterial(sprite)
263 render.DrawSprite(drawpos, v.size.x, v.size.y, v.color)
264
265 elseif (v.type == "Quad" and v.draw_func) then
266
267 local drawpos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
268 ang:RotateAroundAxis(ang:Up(), v.angle.y)
269 ang:RotateAroundAxis(ang:Right(), v.angle.p)
270 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
271
272 cam.Start3D2D(drawpos, ang, v.size)
273 v.draw_func( self )
274 cam.End3D2D()
275
276 end
277
278 end
279
280 end
281
282 function SWEP:GetBoneOrientation( basetab, tab, ent, bone_override )
283
284 local bone, pos, ang
285 if (tab.rel and tab.rel != "") then
286
287 local v = basetab[tab.rel]
288
289 if (!v) then return end
290
291 // Technically, if there exists an element with the same name as a bone
292 // you can get in an infinite loop. Let's just hope nobody's that stupid.
293 pos, ang = self:GetBoneOrientation( basetab, v, ent )
294
295 if (!pos) then return end
296
297 pos = pos + ang:Forward() * v.pos.x + ang:Right() * v.pos.y + ang:Up() * v.pos.z
298 ang:RotateAroundAxis(ang:Up(), v.angle.y)
299 ang:RotateAroundAxis(ang:Right(), v.angle.p)
300 ang:RotateAroundAxis(ang:Forward(), v.angle.r)
301
302 else
303
304 bone = ent:LookupBone(bone_override or tab.bone)
305
306 if (!bone) then return end
307
308 pos, ang = Vector(0,0,0), Angle(0,0,0)
309 local m = ent:GetBoneMatrix(bone)
310 if (m) then
311 pos, ang = m:GetTranslation(), m:GetAngles()
312 end
313
314 if (IsValid(self.Owner) and self.Owner:IsPlayer() and
315 ent == self.Owner:GetViewModel() and self.ViewModelFlip) then
316 ang.r = -ang.r // Fixes mirrored models
317 end
318
319 end
320
321 return pos, ang
322 end
323
324 function SWEP:CreateModels( tab )
325
326 if (!tab) then return end
327
328 // Create the clientside models here because Garry says we can't do it in the render hook
329 for k, v in pairs( tab ) do
330 if (v.type == "Model" and v.model and v.model != "" and (!IsValid(v.modelEnt) or v.createdModel != v.model) and
331 string.find(v.model, ".mdl") and file.Exists (v.model, "GAME") ) then
332
333 v.modelEnt = ClientsideModel(v.model, RENDER_GROUP_VIEW_MODEL_OPAQUE)
334 if (IsValid(v.modelEnt)) then
335 v.modelEnt:SetPos(self:GetPos())
336 v.modelEnt:SetAngles(self:GetAngles())
337 v.modelEnt:SetParent(self)
338 v.modelEnt:SetNoDraw(true)
339 v.createdModel = v.model
340 else
341 v.modelEnt = nil
342 end
343
344 elseif (v.type == "Sprite" and v.sprite and v.sprite != "" and (!v.spriteMaterial or v.createdSprite != v.sprite)
345 and file.Exists ("materials/"..v.sprite..".vmt", "GAME")) then
346
347 local name = v.sprite.."-"
348 local params = { ["$basetexture"] = v.sprite }
349 // make sure we create a unique name based on the selected options
350 local tocheck = { "nocull", "additive", "vertexalpha", "vertexcolor", "ignorez" }
351 for i, j in pairs( tocheck ) do
352 if (v[j]) then
353 params["$"..j] = 1
354 name = name.."1"
355 else
356 name = name.."0"
357 end
358 end
359
360 v.createdSprite = v.sprite
361 v.spriteMaterial = CreateMaterial(name,"UnlitGeneric",params)
362
363 end
364 end
365
366 end
367
368 local allbones
369 local hasGarryFixedBoneScalingYet = false
370
371 function SWEP:UpdateBonePositions(vm)
372
373 if self.ViewModelBoneMods then
374
375 if (!vm:GetBoneCount()) then return end
376
377 // !! WORKAROUND !! //
378 // We need to check all model names :/
379 local loopthrough = self.ViewModelBoneMods
380 if (!hasGarryFixedBoneScalingYet) then
381 allbones = {}
382 for i=0, vm:GetBoneCount() do
383 local bonename = vm:GetBoneName(i)
384 if (self.ViewModelBoneMods[bonename]) then
385 allbones[bonename] = self.ViewModelBoneMods[bonename]
386 else
387 allbones[bonename] = {
388 scale = Vector(1,1,1),
389 pos = Vector(0,0,0),
390 angle = Angle(0,0,0)
391 }
392 end
393 end
394
395 loopthrough = allbones
396 end
397 // !! ----------- !! //
398
399 for k, v in pairs( loopthrough ) do
400 local bone = vm:LookupBone(k)
401 if (!bone) then continue end
402
403 // !! WORKAROUND !! //
404 local s = Vector(v.scale.x,v.scale.y,v.scale.z)
405 local p = Vector(v.pos.x,v.pos.y,v.pos.z)
406 local ms = Vector(1,1,1)
407 if (!hasGarryFixedBoneScalingYet) then
408 local cur = vm:GetBoneParent(bone)
409 while(cur >= 0) do
410 local pscale = loopthrough[vm:GetBoneName(cur)].scale
411 ms = ms * pscale
412 cur = vm:GetBoneParent(cur)
413 end
414 end
415
416 s = s * ms
417 // !! ----------- !! //
418
419 if vm:GetManipulateBoneScale(bone) != s then
420 vm:ManipulateBoneScale( bone, s )
421 end
422 if vm:GetManipulateBoneAngles(bone) != v.angle then
423 vm:ManipulateBoneAngles( bone, v.angle )
424 end
425 if vm:GetManipulateBonePosition(bone) != p then
426 vm:ManipulateBonePosition( bone, p )
427 end
428 end
429 else
430 self:ResetBonePositions(vm)
431 end
432
433 end
434
435 function SWEP:ResetBonePositions(vm)
436
437 if (!vm:GetBoneCount()) then return end
438 for i=0, vm:GetBoneCount() do
439 vm:ManipulateBoneScale( i, Vector(1, 1, 1) )
440 vm:ManipulateBoneAngles( i, Angle(0, 0, 0) )
441 vm:ManipulateBonePosition( i, Vector(0, 0, 0) )
442 end
443
444 end
445
446 /**************************
447 Global utility code
448 **************************/
449
450 // Fully copies the table, meaning all tables inside this table are copied too and so on (normal table.Copy copies only their reference).
451 // Does not copy entities of course, only copies their reference.
452 // WARNING: do not use on tables that contain themselves somewhere down the line or you'll get an infinite loop
453 function table.FullCopy( tab )
454
455 if (!tab) then return nil end
456
457 local res = {}
458 for k, v in pairs( tab ) do
459 if (type(v) == "table") then
460 res[k] = table.FullCopy(v) // recursion ho!
461 elseif (type(v) == "Vector") then
462 res[k] = Vector(v.x, v.y, v.z)
463 elseif (type(v) == "Angle") then
464 res[k] = Angle(v.p, v.y, v.r)
465 else
466 res[k] = v
467 end
468 end
469
470 return res
471
472 end
473
474end