/ gui_advplayerlist_mascot_GL4.lua
gui_advplayerlist_mascot_GL4.lua
1 -- file: utilites_GL4.lua 2 -- author: chmod777 3 -- license: GNU GPL, v2 or later 4 5 function widget:GetInfo() 6 return { 7 name = 'AdvPlayersList Mascot GL4', 8 desc = 'Shows a mascot sitting on top of the adv-playerlist (use /mascot to switch)', 9 author = 'Floris, (GL4 by chmod777)', 10 date = '23 may 2015', 11 license = 'GNU GPL, v2 or later', 12 layer = 0, 13 enabled = false, 14 } 15 end 16 17 --------------------------------------------------------------------------------------------------- 18 -- Config 19 --------------------------------------------------------------------------------------------------- 20 21 local imageDirectory = ':l:'..LUAUI_DIRNAME..'Images/advplayerslist_mascot/' 22 local customImageDirectory = LUAUI_DIRNAME..'Widgets/chmod777_includes/images/' 23 24 local OPTIONS = {} 25 OPTIONS.defaults = { -- these will be loaded when switching style, but the style will overwrite the those values 26 name = 'Defaults', 27 imageSize = 55, 28 xOffset = -1.6, 29 yOffset = -58/5, 30 blinkDuration = 0.12, 31 blinkTimeout = 6, 32 } 33 table.insert(OPTIONS, { 34 name = 'Floris Cat', 35 body = imageDirectory..'floriscat_body.png', 36 head = imageDirectory..'floriscat_head.png', 37 headblink = imageDirectory..'floriscat_headblink.png', 38 santahat = imageDirectory..'santahat.png', 39 imageSize = 53, 40 xOffset = -1.6, 41 yOffset = -58/5, 42 head_xOffset = 0, 43 head_yOffset = 0, 44 }) 45 table.insert(OPTIONS, { 46 name = 'GrumpyCat', 47 body = imageDirectory..'grumpycat_body.png', 48 head = imageDirectory..'grumpycat_head.png', 49 headblink = imageDirectory..'grumpycat_headblink.png', 50 santahat = imageDirectory..'santahat.png', 51 imageSize = 53, 52 xOffset = -1.6, 53 yOffset = -58/5, 54 head_xOffset = 0, 55 head_yOffset = 0, 56 }) 57 table.insert(OPTIONS, { 58 name = "Teifion's MrBeans", 59 body = imageDirectory..'mrbeans_body.png', 60 head = imageDirectory..'mrbeans_head.png', 61 headblink = imageDirectory..'mrbeans_headblink.png', 62 santahat = imageDirectory..'santahat.png', 63 imageSize = 50, 64 xOffset = -1.6, 65 yOffset = -58/4, 66 head_xOffset = -0.01, 67 head_yOffset = 0.13, 68 }) 69 70 --------------------------------------------------------------------------------------------------- 71 -- Add custom mascots here 72 --------------------------------------------------------------------------------------------------- 73 74 table.insert(OPTIONS, { 75 name = 'Doge', 76 body = customImageDirectory..'dogedog.png', 77 head = nil, 78 headblink = nil, 79 santahat = imageDirectory..'santahat.png', 80 imageSize = 50, 81 xOffset = 0, 82 yOffset = -8, 83 head_xOffset = 5/100, 84 head_yOffset = 6/100, 85 }) 86 87 --------------------------------------------------------------------------------------------------- 88 -- Declarations 89 --------------------------------------------------------------------------------------------------- 90 91 local currentOption = 1 92 93 local usedImgSize = OPTIONS[currentOption].imageSize 94 local chobbyInterface 95 96 local xPos = 0 97 local yPos = 0 98 99 local isBlinking = false 100 local blinkStart = nil 101 local blinkEnd = nil 102 local rot = 0 103 local bob = 0 104 105 local positionChanged = false 106 local xOffset = 0 107 local yOffset = 0 108 local xHeadOffset = 0 109 local yHeadOffset = 0 110 111 local mascotChanged = false 112 local bodyTexture = nil 113 local headTexture = nil 114 local head = nil 115 local headblink = nil 116 local hatTexture = nil 117 118 local mascotVAO = nil 119 local mascotVBO = nil 120 local mascotIndexVBO = nil 121 local mascotInstanceVBO = nil 122 local confettiParticleCount = 60 123 local maxElements = 3 + confettiParticleCount 124 local baseElements = 0 125 local extendedElements = 0 126 127 local mascotShaderWrapper = nil 128 local mascotShader = nil 129 local shaderConfig = {} 130 131 local math_isInRect = math.isInRect 132 local pi = math.pi 133 local sin = math.sin 134 local random = math.random 135 local floor = math.floor 136 137 local gl_Texture = gl.Texture 138 local gl_UseShader = gl.UseShader 139 local gl_Uniform = gl.Uniform 140 141 local GL_TRIANGLES = GL.TRIANGLES 142 143 local luaShaderDir = 'LuaUI/Widgets/Include/' 144 local LuaShader = VFS.Include(luaShaderDir..'LuaShader.lua') 145 VFS.Include(luaShaderDir..'instancevbotable.lua') 146 147 local function shallow_copy(t) 148 local t2 = {} 149 for k,v in pairs(t) do 150 t2[k] = v 151 end 152 return t2 153 end 154 155 local OPTIONS_original = shallow_copy(OPTIONS) 156 OPTIONS_original.defaults = nil 157 158 --------------------------------------------------------------------------------------------------- 159 -- Santa hats in December 160 --------------------------------------------------------------------------------------------------- 161 162 local drawSantahat = false 163 if os.date('%m') == '12' and os.date('%d') >= '12' then 164 drawSantahat = true 165 end 166 167 --------------------------------------------------------------------------------------------------- 168 -- GL Stuff 169 --------------------------------------------------------------------------------------------------- 170 171 local vsSrc = [[ 172 #version 420 173 precision highp int; 174 precision highp float; 175 176 // vertex attributes 177 layout (location = 0) in vec2 coords; 178 layout (location = 1) in vec2 uv; 179 180 // instance attributes 181 layout (location = 2) in ivec4 instanceFlags; // see buildInstanceVBOData 182 layout (location = 3) in vec2 confettiStartPos; 183 layout (location = 4) in float confettiSpeed; 184 layout (location = 5) in float confettiRandomSeed; 185 186 uniform vec2 viewGeometry; // x, y 187 uniform vec2 screenPos; // x, y 188 uniform float imgSize; 189 uniform vec4 offsets; // offset.xy, headOffset.xy 190 uniform vec2 bobRotation; // x -> bob, y -> rotation 191 uniform float confettiTime; 192 193 const float CONFETTI_SCALE = 0.05; 194 195 out DataVS { 196 vec2 uv; 197 float drawHead; 198 float drawHat; 199 float isConfetti; 200 float confettiPalletIndex; 201 } vs_out; 202 203 vec2 rotate(vec2 v, float a) { 204 float s = sin(a); 205 float c = cos(a); 206 mat2 m = mat2(c, s, -s, c); 207 return m * v; 208 } 209 210 void main() { 211 int isConfettiI = instanceFlags.x & 0x10; 212 bool isConfetti = bool(isConfettiI); 213 214 vs_out.uv = uv; 215 vs_out.drawHead = float(instanceFlags.x & 0x04); 216 vs_out.drawHat = float(instanceFlags.x & 0x08); 217 vs_out.isConfetti = float(isConfettiI); 218 vs_out.confettiPalletIndex = float(instanceFlags.y); 219 220 bool useHeadRotation = bool(instanceFlags.x & 0x01); 221 bool useHeadOffset = bool(instanceFlags.x & 0x02); 222 223 vec2 offset = offsets.xy; 224 vec2 headOffset = offsets.zw; 225 float bob = bobRotation.x; 226 float rotation = bobRotation.y; 227 228 vec2 imgSize2 = vec2(imgSize); 229 230 vec2 coord = coords.xy; 231 vec2 translate = screenPos.xy; 232 233 if (useHeadOffset) { 234 translate += fma(headOffset, imgSize2, vec2(0.0, 7)); 235 } 236 if (useHeadRotation) { 237 // Center, rotate, then uncenter. 238 // Note that the quad has coords 0->1. 239 coord = rotate(coords.xy - 0.5, radians(rotation)) + 0.5; 240 241 translate.y += bob; 242 } 243 244 245 if (isConfetti) { 246 imgSize2 *= CONFETTI_SCALE; 247 248 vec2 travel = vec2(confettiTime) * vec2(confettiRandomSeed, confettiSpeed); 249 float ground = confettiRandomSeed * 0.1; // so that they don't stack up in a line 250 if (travel.y < confettiStartPos.y - ground) { 251 translate += confettiStartPos - vec2(sin(travel.x), travel.y); 252 } else { 253 translate += vec2(confettiStartPos.x, ground); 254 } 255 } 256 257 coord = fma(coord, imgSize2, vec2(translate)) / viewGeometry.xy; 258 coord = fma(coord, vec2(2.0), vec2(-1.0)); 259 260 gl_Position = vec4(coord.x, coord.y, 0, 1); 261 } 262 ]] 263 264 local fsSrc = [[ 265 #version 330 266 267 #extension GL_ARB_uniform_buffer_object : require 268 #extension GL_ARB_shading_language_420pack: require 269 270 layout (binding = 0) uniform sampler2D body; 271 layout (binding = 1) uniform sampler2D head; 272 layout (binding = 2) uniform sampler2D hat; 273 274 const vec3 CONFETTI_PALLET[5] = { 275 vec3(0.6588, 0.3922, 0.9922), // purple 276 vec3(0.1608, 0.8039, 1.0), // blue 277 vec3(0.4706, 1.0, 0.2667), // green 278 vec3(1.0, 0.4431, 0.5529), // red 279 vec3(0.9922, 1.0, 0.4157), // yellow 280 }; 281 const float CONFETTI_ALPHA = 0.6; 282 283 in DataVS { 284 vec2 uv; 285 float drawHead; 286 float drawHat; 287 float isConfetti; 288 float confettiPalletIndex; 289 } vs_in; 290 291 out vec4 fragColor; 292 293 void main() { 294 bool drawHeadB = vs_in.drawHead > 0.5; 295 bool drawHatB = vs_in.drawHat > 0.5; 296 bool isConfettiB = vs_in.isConfetti > 0.5; 297 int palletIndex = int(vs_in.confettiPalletIndex); 298 299 vec4 textureSample = texture(body, vs_in.uv); 300 if (drawHeadB) { 301 textureSample = texture(head, vs_in.uv); 302 } 303 if (drawHatB) { 304 textureSample = texture(hat, vs_in.uv); 305 } 306 307 if (isConfettiB) { 308 fragColor.xyz = CONFETTI_PALLET[palletIndex]; 309 fragColor.a = CONFETTI_ALPHA; 310 } else { 311 fragColor = textureSample; 312 } 313 } 314 ]] 315 316 local screenPosUniformLoc = nil 317 local drawHeadUniformLoc = nil 318 local imgSizeUniformLoc = nil 319 local offsetsUniformLoc = nil 320 local bobRotationUniformLoc = nil 321 local viewGeometryUniformLoc = nil 322 local confettiTimeUniformLoc = nil 323 324 function initShader() 325 mascotShaderWrapper = LuaShader({ 326 vertex = vsSrc:gsub('//__DEFINES__', LuaShader.CreateShaderDefinesString(shaderConfig)), 327 fragment = fsSrc:gsub('//__DEFINES__', LuaShader.CreateShaderDefinesString(shaderConfig)), 328 uniformInt = {}, 329 uniformFloat = {} 330 }, 'mascotShader') 331 local shaderCompiled = mascotShaderWrapper:Initialize() 332 333 if not shaderCompiled then 334 Spring.Echo('Failed to compile mascotShader GL4') 335 local shLog = gl.GetShaderLog() or '' 336 Spring.Echo(shLog) 337 widgetHandler:RemoveWidget() 338 end 339 340 mascotShader = mascotShaderWrapper.shaderObj 341 342 screenPosUniformLoc = gl.GetUniformLocation(mascotShader, 'screenPos') 343 imgSizeUniformLoc = gl.GetUniformLocation(mascotShader, 'imgSize') 344 offsetsUniformLoc = gl.GetUniformLocation(mascotShader, 'offsets') 345 bobRotationUniformLoc = gl.GetUniformLocation(mascotShader, 'bobRotation') 346 viewGeometryUniformLoc = gl.GetUniformLocation(mascotShader, 'viewGeometry') 347 confettiTimeUniformLoc = gl.GetUniformLocation(mascotShader, 'confettiTime') 348 end 349 350 local function TableConcat(t1,t2) 351 for i=1,#t2 do 352 t1[#t1+1] = t2[i] 353 end 354 return t1 355 end 356 local function ZeroExtend(t, n) 357 while #t <= 7 do 358 t[#t+1] = 0 359 end 360 return t 361 end 362 363 local function buildInstanceVBOData() 364 -- x flags 365 -- 1 - useHeadRotation 366 -- 2 - useHeadOffset 367 -- 4 - drawHead 368 -- 8 - drawHat 369 -- 16 - isConfetti 370 -- y confetti pallet 371 -- 0-purple, 1-blue, 2-green, 3-red, 4-yellow 372 -- z,w unused 373 -- confetti starting position x, y 374 -- confetti random seead 375 local USE_HEAD_ROTATION = 1 376 local USE_HEAD_OFFSET = 2 377 local DRAW_HEAD = 4 378 local DRAW_HAT = 8 379 local IS_CONFETTI = 16 380 381 local instanceVBOData = {} 382 local numFields = 8 383 baseElements = 0 384 385 if bodyTexture ~= nil then 386 local bodyInstanceData = {} 387 ZeroExtend(bodyInstanceData, numFields) 388 TableConcat(instanceVBOData, bodyInstanceData) 389 baseElements = baseElements + 1 390 end 391 392 if headTexture ~= nil then 393 local headInstanceData = {USE_HEAD_ROTATION+USE_HEAD_OFFSET+DRAW_HEAD} 394 ZeroExtend(headInstanceData, numFields) 395 TableConcat(instanceVBOData, headInstanceData) 396 baseElements = baseElements + 1 397 end 398 399 if drawSantahat and hatTexture ~= nil then 400 local hatInstanceData 401 if headTexture == nil then 402 hatInstanceData = {USE_HEAD_OFFSET+DRAW_HAT} 403 else 404 hatInstanceData = {USE_HEAD_ROTATION+USE_HEAD_OFFSET+DRAW_HAT} 405 end 406 ZeroExtend(hatInstanceData, numFields) 407 TableConcat(instanceVBOData, hatInstanceData) 408 baseElements = baseElements + 1 409 end 410 411 for i = baseElements, baseElements+confettiParticleCount-1 do 412 local confettiIndex = floor(random(0,4)) 413 local startX = random(0,70) 414 local startY = random(80,120) 415 local confettiSpeed = random(50, 80) 416 local confettiRandomSeed = random(10, 20) 417 instanceVBOData[i*8+1] = IS_CONFETTI 418 instanceVBOData[i*8+2] = confettiIndex 419 instanceVBOData[i*8+3] = 0 420 instanceVBOData[i*8+4] = 0 421 instanceVBOData[i*8+5] = startX 422 instanceVBOData[i*8+6] = startY 423 instanceVBOData[i*8+7] = confettiSpeed 424 instanceVBOData[i*8+8] = confettiRandomSeed 425 end 426 427 return instanceVBOData 428 end 429 430 local function initGLBuffers() 431 mascotVAO = gl.GetVAO() 432 if mascotVAO == nil then 433 Spring.Echo('Mascot GL4: Failed to get VAO') 434 widgetHandler:RemoveWidget() 435 end 436 437 mascotVBO = gl.GetVBO(GL.ARRAY_BUFFER, false) 438 if mascotVBO == nil then 439 Spring.Echo('Mascot GL4: Failed to get ARRAY_BUFFER VBO') 440 widgetHandler:RemoveWidget() 441 end 442 local minX,minY = 0,0 443 local maxX,maxY = 1,1 444 local minU,minV = 0,1 445 local maxU,maxV = 1,0 446 447 local rectVBOData = { 448 minX,minY, minU,minV, --bl 449 minX,maxY, minU,maxV, --br 450 maxX,maxY, maxU,maxV, --tr 451 maxX,minY, maxU,minV, --tl 452 } 453 local numVertices = 4 454 mascotVBO:Define(numVertices, { 455 {id = 0, name = 'coords', size = 2, type = GL.FLAOT}, 456 {id = 1, name = 'uv', size = 2, type = GL.FLAOT}, 457 }) 458 mascotVBO:Upload(rectVBOData) 459 mascotVAO:AttachVertexBuffer(mascotVBO) 460 461 mascotIndexVBO = gl.GetVBO(GL.ELEMENT_ARRAY_BUFFER, false) 462 if mascotVBO == nil then 463 Spring.Echo('Mascot GL4: Failed to get ELEMENT_ARRAY_BUFFER VBO') 464 widgetHandler:RemoveWidget() 465 end 466 local indexVBOData = { 467 2, 1, 0, 468 3, 2, 0, 469 } 470 local numIndices = 6 471 mascotIndexVBO:Define(numIndices) 472 mascotIndexVBO:Upload(indexVBOData) 473 mascotVAO:AttachIndexBuffer(mascotIndexVBO) 474 475 mascotInstanceVBO = gl.GetVBO(GL.ARRAY_BUFFER, false) 476 if mascotInstanceVBO == nil then 477 Spring.Echo('Mascot GL4: Failed to get ARRAY_BUFFER VBO') 478 widgetHandler:RemoveWidget() 479 end 480 local instanceVBOLayout = { 481 {id = 2, name = 'instanceFlags', size = 4, type = GL.INT}, 482 {id = 3, name = 'confettiStartOffset', size = 2, type = GL.FLAOT}, 483 {id = 4, name = 'confettiSpeed', size = 1, type = GL.FLAOT}, 484 {id = 5, name = 'confettiRandomSeed', size = 1, type = GL.FLAOT}, 485 } 486 mascotInstanceVBO:Define(maxElements, instanceVBOLayout) 487 mascotVAO:AttachInstanceBuffer(mascotInstanceVBO) 488 489 return true 490 end 491 492 --------------------------------------------------------------------------------------------------- 493 -- Manage Options 494 --------------------------------------------------------------------------------------------------- 495 496 local function toggleOptions(option) 497 if OPTIONS[option] then 498 currentOption = option 499 else 500 currentOption = currentOption + 1 501 if not OPTIONS[currentOption] then 502 currentOption = 1 503 end 504 end 505 506 loadOption() 507 updatePosition(true) 508 end 509 510 function loadOption() 511 local appliedOption = OPTIONS_original[currentOption] 512 OPTIONS[currentOption] = shallow_copy(OPTIONS.defaults) 513 514 for option, value in pairs(appliedOption) do 515 OPTIONS[currentOption][option] = value 516 end 517 518 if currentOption > 3 then 519 local imageFiles = VFS.DirList(customImageDirectory) 520 local foundBody = false 521 local bodyPath = OPTIONS[currentOption]['body'] 522 for i=1, #imageFiles do 523 local windowsPathAsSTD = imageFiles[i]:gsub('\\', '/') 524 if (bodyPath == imageFiles[i]) or (bodyPath == windowsPathAsSTD) then 525 foundBody = true 526 break 527 end 528 end 529 if not foundBody then 530 Spring.Echo('Missing file: '..OPTIONS[currentOption]['body']..' Going to next mascot.') 531 toggleOptions() 532 return 533 end 534 end 535 536 mascotChanged = true 537 bodyTexture = OPTIONS[currentOption]['body'] 538 head = OPTIONS[currentOption]['head'] 539 headblink = OPTIONS[currentOption]['headblink'] 540 hatTexture = OPTIONS[currentOption]['santahat'] 541 xOffset = OPTIONS[currentOption]['xOffset'] 542 yOffset = OPTIONS[currentOption]['yOffset'] 543 xHeadOffset = OPTIONS[currentOption]['head_xOffset'] 544 yHeadOffset = OPTIONS[currentOption]['head_yOffset'] 545 if not isBlinking or headBlink == nil then 546 headTexture = head 547 else 548 headTexture = headBlink 549 end 550 551 blinkStart = OPTIONS[currentOption]['blinkTimeout'] 552 blinkEnd = blinkStart + OPTIONS[currentOption]['blinkDuration'] 553 554 if mascotInstanceVBO then 555 local instanceVBOData = buildInstanceVBOData() 556 mascotInstanceVBO:Upload(instanceVBOData) 557 end 558 end 559 560 function widget:MousePress(mx, my, mb) 561 if mb == 1 and math_isInRect(mx, my, xPos, yPos, xPos+usedImgSize, yPos+usedImgSize) then 562 toggleOptions() 563 end 564 end 565 566 function widget:TextCommand(command) 567 if string.sub(command, 1, 6) == 'mascot' then 568 toggleOptions(tonumber(string.sub(command, 8))) 569 Spring.Echo('Playerlist mascot: '..OPTIONS[currentOption].name) 570 end 571 end 572 573 function widget:GetConfigData() 574 return {currentOption = currentOption} 575 end 576 577 function widget:SetConfigData(data) 578 if data.currentOption ~= nil and OPTIONS[data.currentOption] ~= nil then 579 currentOption = data.currentOption or currentOption 580 end 581 end 582 583 --------------------------------------------------------------------------------------------------- 584 -- Updates 585 --------------------------------------------------------------------------------------------------- 586 587 local updateViewGeometry = true 588 function widget:ViewResize() 589 updatePosition(true) 590 updateViewGeometry = true 591 end 592 593 local parentPos = {} 594 function updatePosition(force) 595 local prevPos = parentPos 596 if WG['displayinfo'] ~= nil then 597 parentPos = WG['displayinfo'].GetPosition() 598 elseif WG['unittotals'] ~= nil then 599 parentPos = WG['unittotals'].GetPosition() 600 elseif WG['music'] ~= nil then 601 parentPos = WG['music'].GetPosition() 602 elseif WG['advplayerlist_api'] ~= nil then 603 parentPos = WG['advplayerlist_api'].GetPosition() 604 else 605 local scale = (vsy / 880) * (1 + (Spring.GetConfigFloat('ui_scale', 1) - 1) / 1.25) 606 parentPos = {0,vsx-(220*scale),0,vsx,scale} 607 end 608 609 local parentLeft = parentPos[2] -- x 610 local parentTop = parentPos[1] -- y 611 local parentScale = parentPos[5] 612 613 if (force or 614 prevPos[1] == nil or 615 prevPos[1] ~= parentTop or 616 prevPos[2] ~= parentLeft or 617 prevPos[5] ~= parentScale) 618 then 619 positionChanged = true 620 usedImgSize = OPTIONS[currentOption]['imageSize'] * parentScale 621 xPos = parentLeft + (xOffset * parentScale) 622 yPos = parentTop + (yOffset * parentScale) 623 end 624 end 625 626 local totalTime = 0 627 628 local blinkTimer = 0 629 630 local animationInterval = 1/30 631 local animationTimer = 0 632 local updateBobRotation = false 633 634 local updatePositionTimer = 0 635 local updatePositionInterval = 2 636 637 local doConfettiAnimation = true 638 local confettiTime = 0 639 local confettiInterval = 5 640 641 function widget:Update(dt) 642 totalTime=totalTime+dt 643 644 animationTimer=animationTimer+dt 645 if animationTimer > animationInterval then 646 updateBobRotation = true 647 bob = 1.5*sin(pi*(totalTime/5.5)) 648 rot = 12 + 6*sin(pi*(totalTime/4)) 649 animationTimer=0 650 end 651 652 blinkTimer=blinkTimer+dt 653 if (not isBlinking) and (headblink ~= nil) and (blinkTimer > blinkStart) then 654 isBlinking = true 655 headTexture = headblink 656 end 657 if isBlinking and (blinkTimer > blinkEnd) then 658 isBlinking = false 659 headTexture = head 660 blinkTimer = 0 661 end 662 663 if doConfettiAnimation then 664 confettiTime=confettiTime+dt 665 if confettiTime > confettiInterval then 666 confettiTime = 0 667 extendedElements = 0 668 doConfettiAnimation = false 669 end 670 end 671 672 -- For when other advPlayerList menues are enabled/disabled or resize 673 updatePositionTimer = updatePositionTimer + dt 674 if updatePositionTimer > updatePositionInterval then 675 updatePositionTimer = 0 676 updatePosition() 677 end 678 end 679 680 function widget:UnitDestroyed(unitID, unitDefID, unitTeam) 681 local name = UnitDefs[unitDefID].name; 682 if name == 'armdecom' or name == 'coredecom' then 683 extendedElements = confettiParticleCount 684 doConfettiAnimation = true 685 end 686 end 687 688 function widget:Initialize() 689 initShader() 690 initGLBuffers() 691 loadOption() 692 updatePosition() 693 end 694 695 function widget:Shutdown() 696 if mascotShader ~= nil then 697 mascotShaderWrapper:Delete() 698 end 699 if mascotInstanceVBO ~= nil then 700 mascotInstanceVBO:Delete() 701 end 702 if mascotIndexVBO ~= nil then 703 mascotIndexVBO:Delete() 704 end 705 if mascotVBO ~= nil then 706 mascotVBO:Delete() 707 end 708 if mascotVAO ~= nil then 709 mascotVAO:Delete() 710 end 711 end 712 713 function widget:RecvLuaMsg(msg, playerID) 714 if msg:sub(1,18) == 'LobbyOverlayActive' then 715 chobbyInterface = (msg:sub(1,19) == 'LobbyOverlayActive1') 716 end 717 end 718 719 function widget:DrawScreen() 720 if chobbyInterface then return end 721 722 if bodyTexture then 723 gl_Texture(0, bodyTexture) 724 end 725 if headTexture then 726 gl_Texture(1, headTexture) 727 end 728 if hatTexture then 729 gl_Texture(2, hatTexture) 730 end 731 732 gl_UseShader(mascotShader) 733 if updateBobRotation then 734 gl_Uniform(bobRotationUniformLoc, bob, rot) 735 updateBobRotation = false 736 end 737 738 if positionChanged then 739 gl_Uniform(screenPosUniformLoc, xPos, yPos) 740 positionChanged = false 741 end 742 743 if mascotChanged then 744 gl_Uniform(imgSizeUniformLoc, usedImgSize) 745 gl_Uniform(offsetsUniformLoc, xOffset, yOffset, xHeadOffset, yHeadOffset) 746 mascotChanged = false 747 end 748 749 if doConfettiAnimation then 750 gl_Uniform(confettiTimeUniformLoc, confettiTime) 751 end 752 753 if updateViewGeometry then 754 local x, y = Spring.GetViewGeometry() 755 gl_Uniform(viewGeometryUniformLoc, x, y) 756 end 757 758 local usedElements = baseElements + extendedElements 759 if usedElements > 0 then 760 mascotVAO:DrawElements(GL_TRIANGLES, 6, 0, usedElements, 0, 0) 761 end 762 gl_UseShader(0) 763 764 gl_Texture(0, false) 765 gl_Texture(1, false) 766 gl_Texture(2, false) 767 end 768