Skip to content

Instantly share code, notes, and snippets.

@lhog
Created May 13, 2018 21:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lhog/75602b39a2ee3c8e658571dd31d21446 to your computer and use it in GitHub Desktop.
Save lhog/75602b39a2ee3c8e658571dd31d21446 to your computer and use it in GitHub Desktop.
Geometry Shader Instancing in Spring/ZK
-- $Id: gui_metal_features.lua 3171 2008-11-06 09:06:29Z det $
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--
-- file: gui_metal_features.lua
-- brief: highlights features with metal in metal-map viewmode
-- author: Dave Rodgers
--
-- Copyright (C) 2007.
-- Licensed under the terms of the GNU GPL, v2 or later.
--
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function widget:GetInfo()
return {
name = "MetalFeatures",
desc = "Highlights features with metal in the metal-map viewmode",
author = "trepan",
date = "Aug 05, 2007", --May 6, 2013
license = "GNU GPL, v2 or later",
layer = 0,
enabled = true, -- loaded by default?
}
end
local spGetMapDrawMode = Spring.GetMapDrawMode
local spGetActiveCommand = Spring.GetActiveCommand
local spGetActiveCmdDesc = Spring.GetActiveCmdDesc
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local hilite = false
local geometryShaderCode = [[
#version 150 compatibility
#extension GL_EXT_geometry_shader4 : enable
#define MAX_VERTICES _MAX_VERT_
layout(triangles) in;
layout(triangle_strip, max_vertices = 1024) out;
uniform float transformVector[(3 + 4) * MAX_VERTICES];
uniform int maxObjects;
//uniform float alpha;
uniform mat4 projMat;
uniform mat4 viewMat;
//varying mat4 modMat;
flat out vec3 rgb;
mat4 translationMatrix(in vec3 t)
{
return mat4(1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
t.x, t.y, t.z, 1.0);
}
mat4 scaleMatrix(vec3 s)
{
return mat4(s.x, 0.0, 0.0, 0.0,
0.0, s.y, 0.0, 0.0,
0.0, 0.0, s.z, 0.0,
0.0, 0.0, 0.0, 1.0);
}
mat4 rotationMatrix(vec3 axis, float angle)
{
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;
return mat4(oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s, 0.0,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s, 0.0,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c, 0.0,
0.0, 0.0, 0.0, 1.0);
}
#define QuarternionConjugate(q) vec4(-q.x, -q.y, -q.z, q.w)
vec4 QuarternionFromAxisAngle(vec3 axis, float angle)
{
vec4 qr;
float half_angle = (angle * 0.5);
qr.x = axis.x * sin(half_angle);
qr.y = axis.y * sin(half_angle);
qr.z = axis.z * sin(half_angle);
qr.w = cos(half_angle);
return qr;
}
vec4 QuarternionMult(vec4 q1, vec4 q2)
{
vec4 qr;
qr.x = (q1.w * q2.x) + (q1.x * q2.w) + (q1.y * q2.z) - (q1.z * q2.y);
qr.y = (q1.w * q2.y) - (q1.x * q2.z) + (q1.y * q2.w) + (q1.z * q2.x);
qr.z = (q1.w * q2.z) + (q1.x * q2.y) - (q1.y * q2.x) + (q1.z * q2.w);
qr.w = (q1.w * q2.w) - (q1.x * q2.x) - (q1.y * q2.y) - (q1.z * q2.z);
return qr;
}
vec3 RotateVertex(vec3 position, vec3 axis, float angle)
{
vec4 q = QuarternionFromAxisAngle(axis, angle);
vec3 v = position.xyz;
return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
}
void main()
{
for (int k = 0; k < MAX_VERTICES; ++k) {
if (k < maxObjects) {
for(int i = 0; i < 3; ++i) {
vec3 trmVec = vec3(transformVector[7 * k + 0], transformVector[7 * k + 1] + 0.0, transformVector[7 * k + 2]);
vec3 rotVec = vec3(transformVector[7 * k + 3], transformVector[7 * k + 4], transformVector[7 * k + 5]);
float pitch = transformVector[7 * k + 3];
float yaw = transformVector[7 * k + 4];
float roll = transformVector[7 * k + 5];
mat4 trm = translationMatrix(trmVec);
mat4 sm = scaleMatrix(vec3(1.05));
#if 0
mat4 rmz = rotationMatrix(vec3(0.0, 0.0, 1.0), roll);
mat4 rmy = rotationMatrix(vec3(0.0, 1.0, 0.0), yaw);
mat4 rmx = rotationMatrix(vec3(1.0, 0.0, 0.0), pitch);
mat4 rm = rmx * rmy * rmz;
//mat4 rm = rmz * rmx * rmy;
vec4 pos = trm * rm * sm * gl_in[i].gl_Position;
#else
vec3 P = (sm * gl_in[i].gl_Position).xyz;
//rotate
//P = RotateVertex(vec3(0.0), vec3(1.0, 0.0, 0.0), -rotVec[1]);
//P = RotateVertex(vec3(0.0), vec3(0.0, 1.0, 0.0), -rotVec[0]);
//P = RotateVertex(vec3(0.0), vec3(0.0, 0.0, 1.0), -rotVec[2]);
P = RotateVertex(P, vec3(0.0, 0.0, -1.0), roll);
P = RotateVertex(P, vec3(0.0, -1.0, 0.0), yaw);
P = RotateVertex(P, vec3(-1.0, 0.0, 0.0), pitch);
//transform
P += trmVec;
vec4 pos = vec4(P, 1.0);
#endif
float metal = transformVector[7 * k + 6];
float x100 = 100.0 / (100.0 + metal);
float x1000 = 1000.0 / (1000.0 + metal);
float r = 1.0 - x1000;
float g = x1000 - x100;
float b = x100;
rgb = vec3(r, g, b);
gl_Position = projMat * viewMat * pos;
EmitVertex();
}
EndPrimitive();
}
}
}
]]
local vertexShaderCode = [[
#version 150 compatibility
uniform mat4 projMat;
uniform mat4 viewMat;
void main(void)
{
//gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
//gl_Position = projMat * gl_ModelViewMatrix * gl_Vertex;
gl_Position = gl_Vertex;
}
]]
local fragShaderCode = [[
#version 150 compatibility
flat in vec3 rgb;
uniform float alpha;
void main()
{
gl_FragColor = vec4(rgb, alpha);
gl_FragColor = vec4(vec3(0.3), 1.0);
}
]]
local shaderObj
local transformVectorUniform
local maxObjectsUniform
local alphaUniform
local projMatUniform
local viewMatUniform
local modelMatUniform
local function DrawWorldFunc()
if (not hilite) and (spGetMapDrawMode() ~= 'metal') and (not WG.showeco) then
return
end
gl.DepthTest(true)
--gl.PolygonOffset(-2, -2)
gl.Blending(GL.SRC_ALPHA, GL.ONE)
local timer = widgetHandler:GetHourTimer()
local alpha = 0.25 + (0.75 * math.abs(1 - (timer * 2) % 2))
local myAllyTeam = Spring.GetMyAllyTeamID()
local featureArray = {}
local features = Spring.GetAllFeatures()
--[[
for _, fID in pairs(features) do
local metal = Spring.GetFeatureResources(fID)
if (metal and (metal > 1)) then
-- local aTeam = Spring.GetFeatureAllyTeam(fID)
-- if (aTeam ~= myAllyTeam) then
local x100 = 100 / (100 + metal)
local x1000 = 1000 / (1000 + metal)
local r = 1 - x1000
local g = x1000 - x100
local b = x100
--gl.Color(r, g, b, alpha)
--gl.Feature(fID, true)
--gl.PushMatrix()
local x,y,z = Spring.GetFeaturePosition(fID)
--gl.Translate(x,y,z)
--gl.Color(r, g, b, alpha)
gl.UseShader(shaderObj)
gl.FeatureShape(Spring.GetFeatureDefID(fID), -1, true, true, true)
gl.UseShader(0)
--gl.PopMatrix()
-- end
end
end
]]--
for _, fID in pairs(features) do
local fDefId = Spring.GetFeatureDefID(fID)
if not featureArray[fDefId] then
featureArray[fDefId] = {}
end
local x, y, z = Spring.GetFeaturePosition(fID)
local pi, ya, ro = Spring.GetFeatureRotation(fID)
local metal = Spring.GetFeatureResources(fID)
local arrLen = #featureArray[fDefId]
featureArray[fDefId][arrLen + 1] = x
featureArray[fDefId][arrLen + 2] = y
featureArray[fDefId][arrLen + 3] = z
featureArray[fDefId][arrLen + 4] = pi
featureArray[fDefId][arrLen + 5] = ya
featureArray[fDefId][arrLen + 6] = ro
featureArray[fDefId][arrLen + 7] = metal
end
for fDefId, array in pairs(featureArray) do
gl.UseShader(shaderObj)
gl.UniformInt(maxObjectsUniform, math.floor(#array / 7))
gl.UniformArray(transformVectorUniform, 2, featureArray[fDefId])
gl.Uniform(alphaUniform, alpha)
gl.UniformMatrix(projMatUniform, "projection")
gl.UniformMatrix(viewMatUniform, "view")
gl.FeatureShape(fDefId, -1, true, false, true)
gl.UseShader(0)
end
gl.Blending(GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA)
--gl.PolygonOffset(false)
gl.DepthTest(false)
end
function widget:DrawWorld()
DrawWorldFunc()
end
function widget:DrawWorldRefraction()
DrawWorldFunc()
end
function widget:Initialize()
local GL_MAX_GEOMETRY_OUTPUT_VERTICES = 0x8DE0
local GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS = 0x8DE1
local GL_MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB
local GL_MAX_GEOMETRY_UNIFORM_COMPONENTS = 0x8DDF
local GL_MAX_TEXTURE_COORDS = 0x8871
Spring.Echo("GL_MAX_GEOMETRY_OUTPUT_VERTICES", gl.GetNumber(GL_MAX_GEOMETRY_OUTPUT_VERTICES))
Spring.Echo("GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS", gl.GetNumber(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS))
Spring.Echo("GL_MAX_VERTEX_UNIFORM_VECTORS", gl.GetNumber(GL_MAX_VERTEX_UNIFORM_VECTORS))
Spring.Echo("GL_MAX_GEOMETRY_UNIFORM_COMPONENTS", gl.GetNumber(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS))
Spring.Echo("GL_MAX_TEXTURE_COORDS", gl.GetNumber(GL_MAX_TEXTURE_COORDS))
--[[
local maxVertices = math.min(
gl.GetNumber(GL_MAX_GEOMETRY_OUTPUT_VERTICES),
math.floor(gl.GetNumber(GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS) / 12), --4 floats X 3 vertexes per triangle = 12
math.floor(gl.GetNumber(GL_MAX_VERTEX_UNIFORM_VECTORS) * 4 / (3 + 4) ), --Number of 4 floats vectors in array. We will use 3 + 4 floats: 3 translation, 3 rotation, 1 metal value
math.floor(gl.GetNumber(GL_MAX_GEOMETRY_UNIFORM_COMPONENTS) / (7 * 4) - ) -- 7 components ^^^^ each 4 bytes
)
]]--
maxVertices = 32
Spring.Echo("maxVertices", maxVertices)
geometryShaderCode = string.gsub(geometryShaderCode, "_MAX_VERT_", tostring(maxVertices))
shaderObj = gl.CreateShader({
vertex = vertexShaderCode,
geometry = geometryShaderCode,
fragment = fragShaderCode,
})
Spring.Echo("GL_EXT_geometry_shader4", gl.HasExtension("GL_EXT_geometry_shader4"))
local shLog = gl.GetShaderLog()
if (shaderObj == nil or string.len(shLog or "") > 0) then
Spring.Echo("MetalFeatures->Shader: shader warnings & errors: "..shLog)
return false
end
transformVectorUniform = gl.GetUniformLocation(shaderObj, 'transformVector')
maxObjectsUniform = gl.GetUniformLocation(shaderObj, 'maxObjects')
alphaUniform = gl.GetUniformLocation(shaderObj, 'alpha')
projMatUniform = gl.GetUniformLocation(shaderObj, 'projMat')
viewMatUniform = gl.GetUniformLocation(shaderObj, 'viewMat')
end
function widget:Shutdown()
gl.DeleteShader(shaderObj)
end
local currCmd = spGetActiveCommand() --remember current command
function widget:Update()
if currCmd == spGetActiveCommand() then --if detect no change in command selection: --skip whole thing
return
end --else (command selection has change): perform check/automated-map-view-change
currCmd = spGetActiveCommand() --update active command
local activeCmd = spGetActiveCmdDesc(currCmd)
hilite = (activeCmd and (activeCmd.name == "Reclaim" or activeCmd.name == "Resurrect"))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment