/// <summary>
/// Render Primitive
/// </summary>
/// <param name="pass">Which pass are we currently in</param>
/// <param name="pickingID">ID used to identify which object was picked</param>
/// <param name="scene">Main scene renderer</param>
/// <param name="time">Time it took to render the last frame</param>
public override void Render(RenderPass pass, int pickingID, SceneWindow scene, float time)
{
if (!RenderSettings.AvatarRenderingEnabled && Attached) return;
// Individual prim matrix
GL.PushMatrix();
// Prim roation and position and scale
GL.MultMatrix(Math3D.CreateSRTMatrix(Prim.Scale, RenderRotation, RenderPosition));
// Do we have animated texture on this face
bool animatedTexture = false;
// Initialise flags tracking what type of faces this prim has
if (pass == RenderPass.Simple)
{
HasSimpleFaces = false;
}
else if (pass == RenderPass.Alpha)
{
HasAlphaFaces = false;
}
else if (pass == RenderPass.Invisible)
{
HasInvisibleFaces = false;
}
// Draw the prim faces
for (int j = 0; j < Faces.Count; j++)
{
Primitive.TextureEntryFace teFace = Prim.Textures.GetFace((uint)j);
Face face = Faces[j];
FaceData data = (FaceData)face.UserData;
if (data == null)
continue;
if (teFace == null)
continue;
// Don't render transparent faces
Color4 RGBA = teFace.RGBA;
if (data.TextureInfo.FullAlpha || RGBA.A <= 0.01f) continue;
bool switchedLightsOff = false;
if (pass == RenderPass.Picking)
{
data.PickingID = pickingID;
var primNrBytes = Utils.UInt16ToBytes((ushort)pickingID);
var faceColor = new byte[] { primNrBytes[0], primNrBytes[1], (byte)j, 255 };
GL.Color4(faceColor);
}
else if (pass == RenderPass.Invisible)
{
if (!data.TextureInfo.IsInvisible) continue;
HasInvisibleFaces = true;
}
else
{
if (data.TextureInfo.IsInvisible) continue;
bool belongToAlphaPass = (RGBA.A < 0.99f) || (data.TextureInfo.HasAlpha && !data.TextureInfo.IsMask);
if (belongToAlphaPass && pass != RenderPass.Alpha) continue;
if (!belongToAlphaPass && pass == RenderPass.Alpha) continue;
if (pass == RenderPass.Simple)
{
HasSimpleFaces = true;
}
else if (pass == RenderPass.Alpha)
{
HasAlphaFaces = true;
}
if (teFace.Fullbright)
{
GL.Disable(EnableCap.Lighting);
switchedLightsOff = true;
}
float shiny = 0f;
switch (teFace.Shiny)
{
case Shininess.High:
shiny = 0.96f;
break;
case Shininess.Medium:
shiny = 0.64f;
break;
case Shininess.Low:
shiny = 0.24f;
break;
}
if (shiny > 0f)
{
scene.StartShiny();
}
GL.Material(MaterialFace.Front, MaterialParameter.Shininess, shiny);
var faceColor = new float[] { RGBA.R, RGBA.G, RGBA.B, RGBA.A };
GL.Color4(faceColor);
GL.Material(MaterialFace.Front, MaterialParameter.Specular, new float[] { 0.5f, 0.5f, 0.5f, 1f });
if (data.TextureInfo.TexturePointer == 0)
{
TextureInfo teInfo;
if (scene.TryGetTextureInfo(teFace.TextureID, out teInfo))
{
data.TextureInfo = teInfo;
}
}
if (data.TextureInfo.TexturePointer == 0)
{
GL.Disable(EnableCap.Texture2D);
if (!data.TextureInfo.FetchFailed)
{
scene.DownloadTexture(new TextureLoadItem()
{
Prim = this.Prim,
TeFace = teFace,
Data = data
}, false);
}
}
else
{
// Is this face using texture animation
if ((Prim.TextureAnim.Flags & Primitive.TextureAnimMode.ANIM_ON) != 0
&& (Prim.TextureAnim.Face == j || Prim.TextureAnim.Face == 255))
{
if (data.AnimInfo == null)
{
data.AnimInfo = new TextureAnimationInfo();
}
data.AnimInfo.PrimAnimInfo = Prim.TextureAnim;
data.AnimInfo.Step(time);
animatedTexture = true;
}
else if (data.AnimInfo != null) // Face texture not animated. Do we have previous anim setting?
{
data.AnimInfo = null;
}
GL.Enable(EnableCap.Texture2D);
GL.BindTexture(TextureTarget.Texture2D, data.TextureInfo.TexturePointer);
}
}
if (!RenderSettings.UseVBO || data.VBOFailed)
{
Vertex[] verts = face.Vertices.ToArray();
ushort[] indices = face.Indices.ToArray();
unsafe
{
fixed (float* normalPtr = &verts[0].Normal.X)
fixed (float* texPtr = &verts[0].TexCoord.X)
{
GL.NormalPointer(NormalPointerType.Float, FaceData.VertexSize, (IntPtr)normalPtr);
GL.TexCoordPointer(2, TexCoordPointerType.Float, FaceData.VertexSize, (IntPtr)texPtr);
GL.VertexPointer(3, VertexPointerType.Float, FaceData.VertexSize, verts);
GL.DrawElements(BeginMode.Triangles, indices.Length, DrawElementsType.UnsignedShort, indices);
}
}
}
else
{
if (data.CheckVBO(face))
{
Compat.BindBuffer(BufferTarget.ArrayBuffer, data.VertexVBO);
Compat.BindBuffer(BufferTarget.ElementArrayBuffer, data.IndexVBO);
GL.NormalPointer(NormalPointerType.Float, FaceData.VertexSize, (IntPtr)12);
GL.TexCoordPointer(2, TexCoordPointerType.Float, FaceData.VertexSize, (IntPtr)(24));
GL.VertexPointer(3, VertexPointerType.Float, FaceData.VertexSize, (IntPtr)(0));
GL.DrawElements(BeginMode.Triangles, face.Indices.Count, DrawElementsType.UnsignedShort, IntPtr.Zero);
}
Compat.BindBuffer(BufferTarget.ArrayBuffer, 0);
Compat.BindBuffer(BufferTarget.ElementArrayBuffer, 0);
}
if (switchedLightsOff)
{
GL.Enable(EnableCap.Lighting);
switchedLightsOff = false;
}
}
GL.BindTexture(TextureTarget.Texture2D, 0);
RHelp.ResetMaterial();
// Reset texture coordinates if we modified them in texture animation
if (animatedTexture)
{
GL.MatrixMode(MatrixMode.Texture);
GL.LoadIdentity();
GL.MatrixMode(MatrixMode.Modelview);
}
// Pop the prim matrix
GL.PopMatrix();
base.Render(pass, pickingID, scene, time);
}