attribute vec4 aPosition; attribute vec2 aTexCoord; attribute vec4 aColor; varying vec4 vTexCoord; varying vec4 vColor; #ifndef SIMPLE // we do not need these for simple shaders attribute vec4 aVertex2; attribute vec4 aNormal; attribute vec4 aNormal2; #if __VERSION__ >= 300 attribute vec4 aBoneWeight; attribute uvec4 aBoneSelector; #endif varying vec4 pixelpos; varying vec3 glowdist; varying vec3 gradientdist; varying vec4 vWorldNormal; varying vec4 vEyeNormal; #endif #ifdef NO_CLIPDISTANCE_SUPPORT varying vec4 ClipDistanceA; varying vec4 ClipDistanceB; #endif struct BonesResult { vec3 Normal; vec4 Position; }; BonesResult ApplyBones(); void main() { float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4; vec2 parmTexCoord; vec4 parmPosition; BonesResult bones = ApplyBones(); parmTexCoord = aTexCoord; parmPosition = bones.Position; #ifndef SIMPLE vec4 worldcoord = ModelMatrix * mix(parmPosition, aVertex2, uInterpolationFactor); #else vec4 worldcoord = ModelMatrix * parmPosition; #endif vec4 eyeCoordPos = ViewMatrix * worldcoord; #ifdef HAS_UNIFORM_VERTEX_DATA if ((useVertexData & 1) == 0) vColor = uVertexColor; else vColor = aColor; #else vColor = aColor; #endif #ifndef SIMPLE pixelpos.xyz = worldcoord.xyz; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; if (uGlowTopColor.a > 0.0 || uGlowBottomColor.a > 0.0) { float topatpoint = (uGlowTopPlane.w + uGlowTopPlane.x * worldcoord.x + uGlowTopPlane.y * worldcoord.z) * uGlowTopPlane.z; float bottomatpoint = (uGlowBottomPlane.w + uGlowBottomPlane.x * worldcoord.x + uGlowBottomPlane.y * worldcoord.z) * uGlowBottomPlane.z; glowdist.x = topatpoint - worldcoord.y; glowdist.y = worldcoord.y - bottomatpoint; glowdist.z = clamp(glowdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); } if (uObjectColor2.a != 0.0) { float topatpoint = (uGradientTopPlane.w + uGradientTopPlane.x * worldcoord.x + uGradientTopPlane.y * worldcoord.z) * uGradientTopPlane.z; float bottomatpoint = (uGradientBottomPlane.w + uGradientBottomPlane.x * worldcoord.x + uGradientBottomPlane.y * worldcoord.z) * uGradientBottomPlane.z; gradientdist.x = topatpoint - worldcoord.y; gradientdist.y = worldcoord.y - bottomatpoint; gradientdist.z = clamp(gradientdist.x / (topatpoint - bottomatpoint), 0.0, 1.0); } if (uSplitBottomPlane.z != 0.0) { ClipDistance3 = ((uSplitTopPlane.w + uSplitTopPlane.x * worldcoord.x + uSplitTopPlane.y * worldcoord.z) * uSplitTopPlane.z) - worldcoord.y; ClipDistance4 = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); } vWorldNormal = NormalModelMatrix * vec4(normalize(bones.Normal), 1.0); vEyeNormal = NormalViewMatrix * vWorldNormal; #endif #ifdef SPHEREMAP vec3 u = normalize(eyeCoordPos.xyz); vec4 n = normalize(NormalViewMatrix * vec4(parmTexCoord.x, 0.0, parmTexCoord.y, 0.0)); vec3 r = reflect(u, n.xyz); float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) ); vec2 sst = vec2(r.x/m + 0.5, r.y/m + 0.5); vTexCoord.xy = sst; #else vTexCoord = TextureMatrix * vec4(parmTexCoord, 0.0, 1.0); #endif if (uClipHeightDirection != 0.0) // clip planes used for reflective flats { ClipDistance0 = (worldcoord.y - uClipHeight) * uClipHeightDirection; } else if (uClipLine.x > -1000000.0) // and for line portals - this will never be active at the same time as the reflective planes clipping so it can use the same hardware clip plane. { ClipDistance0 = -( (worldcoord.z - uClipLine.y) * uClipLine.z + (uClipLine.x - worldcoord.x) * uClipLine.w ) + 1.0/32768.0; // allow a tiny bit of imprecisions for colinear linedefs. } else { ClipDistance0 = 1.0; } // clip planes used for translucency splitting ClipDistance1 = worldcoord.y - uClipSplit.x; ClipDistance2 = uClipSplit.y - worldcoord.y; if (uSplitTopPlane == vec4(0.0)) { ClipDistance3 = 1.0; ClipDistance4 = 1.0; } ClipDistanceA = vec4(ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3); ClipDistanceB = vec4(ClipDistance4, 0.0, 0.0, 0.0); gl_Position = ProjectionMatrix * eyeCoordPos; } #if !defined(SIMPLE) vec3 GetAttrNormal() { #ifdef HAS_UNIFORM_VERTEX_DATA if ((useVertexData & 2) == 0) return uVertexNormal.xyz; else return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor); #else return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor); #endif } #if __VERSION__ >= 300 void AddWeightedBone(uint boneIndex, float weight, inout vec4 position, inout vec3 normal) { if (weight != 0.0) { mat4 transform = bones[uBoneIndexBase + int(boneIndex)]; mat3 rotation = mat3(transform); position += (transform * aPosition) * weight; normal += (rotation * aNormal.xyz) * weight; } } BonesResult ApplyBones() { BonesResult result; if (uBoneIndexBase >= 0 && aBoneWeight != vec4(0.0)) { result.Position = vec4(0.0); result.Normal = vec3(0.0); // We use low precision input for our bone weights. Rescale so the sum still is 1.0 float totalWeight = aBoneWeight.x + aBoneWeight.y + aBoneWeight.z + aBoneWeight.w; float weightMultiplier = 1.0 / totalWeight; vec4 boneWeight = aBoneWeight * weightMultiplier; AddWeightedBone(aBoneSelector.x, boneWeight.x, result.Position, result.Normal); AddWeightedBone(aBoneSelector.y, boneWeight.y, result.Position, result.Normal); AddWeightedBone(aBoneSelector.z, boneWeight.z, result.Position, result.Normal); AddWeightedBone(aBoneSelector.w, boneWeight.w, result.Position, result.Normal); result.Position.w = 1.0; // For numerical stability } else { result.Position = aPosition; result.Normal = GetAttrNormal(); } return result; } #else BonesResult ApplyBones() { BonesResult result; result.Position = aPosition; result.Normal = GetAttrNormal(); return result; } #endif #else // SIMPLE BonesResult ApplyBones() { BonesResult result; result.Position = aPosition; return result; } #endif