70
OpenRA.FileFormats/Graphics/HvaReader.cs
Normal file
70
OpenRA.FileFormats/Graphics/HvaReader.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public class HvaReader
|
||||
{
|
||||
public readonly uint FrameCount;
|
||||
public readonly uint LimbCount;
|
||||
float[] Transforms;
|
||||
|
||||
public HvaReader(Stream s)
|
||||
{
|
||||
// Index swaps for transposing a matrix
|
||||
var ids = new byte[]{0,4,8,12,1,5,9,13,2,6,10,14};
|
||||
|
||||
s.Seek(16, SeekOrigin.Begin);
|
||||
FrameCount = s.ReadUInt32();
|
||||
LimbCount = s.ReadUInt32();
|
||||
|
||||
// Skip limb names
|
||||
s.Seek(16*LimbCount, SeekOrigin.Current);
|
||||
Transforms = new float[16*FrameCount*LimbCount];
|
||||
for (var j = 0; j < FrameCount; j++)
|
||||
for (var i = 0; i < LimbCount; i++)
|
||||
{
|
||||
// Convert to column-major matrices and add the final matrix row
|
||||
var c = 16*(LimbCount*j + i);
|
||||
Transforms[c + 3] = 0;
|
||||
Transforms[c + 7] = 0;
|
||||
Transforms[c + 11] = 0;
|
||||
Transforms[c + 15] = 1;
|
||||
|
||||
for (var k = 0; k < 12; k++)
|
||||
Transforms[c + ids[k]] = s.ReadFloat();
|
||||
}
|
||||
}
|
||||
|
||||
public float[] TransformationMatrix(uint limb, uint frame)
|
||||
{
|
||||
if (frame >= FrameCount)
|
||||
throw new ArgumentOutOfRangeException("frame", "Only {0} frames exist.".F(FrameCount));
|
||||
if (limb >= LimbCount)
|
||||
throw new ArgumentOutOfRangeException("limb", "Only {1} limbs exist.".F(LimbCount));
|
||||
|
||||
var t = new float[16];
|
||||
Array.Copy(Transforms, 16*(LimbCount*frame + limb), t, 0, 16);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
public static HvaReader Load(string filename)
|
||||
{
|
||||
using (var s = File.OpenRead(filename))
|
||||
return new HvaReader(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,12 @@ namespace OpenRA.FileFormats.Graphics
|
||||
void SetLineWidth( float width );
|
||||
void EnableScissor( int left, int top, int width, int height );
|
||||
void DisableScissor();
|
||||
|
||||
void EnableDepthBuffer();
|
||||
void DisableDepthBuffer();
|
||||
|
||||
void EnableStencilBuffer();
|
||||
void DisableStencilBuffer();
|
||||
}
|
||||
|
||||
public interface IVertexBuffer<T>
|
||||
@@ -60,8 +66,11 @@ namespace OpenRA.FileFormats.Graphics
|
||||
|
||||
public interface IShader
|
||||
{
|
||||
void SetVec(string name, float x);
|
||||
void SetVec(string name, float x, float y);
|
||||
void SetVec(string name, float[] vec, int length);
|
||||
void SetTexture(string param, ITexture texture);
|
||||
void SetMatrix(string param, float[] mtx);
|
||||
void Render(Action a);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,5 +24,12 @@ namespace OpenRA.FileFormats.Graphics
|
||||
this.u = uv.X; this.v = uv.Y;
|
||||
this.p = pc.X; this.c = pc.Y;
|
||||
}
|
||||
|
||||
public Vertex(float[] xyz, float2 uv, float2 pc)
|
||||
{
|
||||
this.x = xyz[0]; this.y = xyz[1]; this.z = xyz[2];
|
||||
this.u = uv.X; this.v = uv.Y;
|
||||
this.p = pc.X; this.c = pc.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
158
OpenRA.FileFormats/Graphics/VxlReader.cs
Normal file
158
OpenRA.FileFormats/Graphics/VxlReader.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace OpenRA.FileFormats
|
||||
{
|
||||
public enum NormalType { TiberianSun = 2, RedAlert2 = 4 }
|
||||
public class VxlElement
|
||||
{
|
||||
public byte Color;
|
||||
public byte Normal;
|
||||
}
|
||||
|
||||
public class VxlLimb
|
||||
{
|
||||
public string Name;
|
||||
public float Scale;
|
||||
public float[] Bounds;
|
||||
public byte[] Size;
|
||||
public NormalType Type;
|
||||
|
||||
public uint VoxelCount;
|
||||
public Dictionary<byte, VxlElement>[,] VoxelMap;
|
||||
}
|
||||
|
||||
public class VxlReader
|
||||
{
|
||||
public readonly uint LimbCount;
|
||||
public VxlLimb[] Limbs;
|
||||
|
||||
uint BodySize;
|
||||
|
||||
void ReadVoxelData(Stream s, VxlLimb l)
|
||||
{
|
||||
var baseSize = l.Size[0]*l.Size[1];
|
||||
var colStart = new int[baseSize];
|
||||
for (var i = 0; i < baseSize; i++)
|
||||
colStart[i] = s.ReadInt32();
|
||||
s.Seek(4*baseSize, SeekOrigin.Current);
|
||||
var dataStart = s.Position;
|
||||
|
||||
// Count the voxels in this limb
|
||||
l.VoxelCount = 0;
|
||||
for (var i = 0; i < baseSize; i++)
|
||||
{
|
||||
// Empty column
|
||||
if (colStart[i] == -1)
|
||||
continue;
|
||||
|
||||
s.Seek(dataStart + colStart[i], SeekOrigin.Begin);
|
||||
var z = 0;
|
||||
do
|
||||
{
|
||||
z += s.ReadUInt8();
|
||||
var count = s.ReadUInt8();
|
||||
z += count;
|
||||
l.VoxelCount += count;
|
||||
s.Seek(2*count + 1, SeekOrigin.Current);
|
||||
} while (z < l.Size[2]);
|
||||
}
|
||||
|
||||
// Read the data
|
||||
l.VoxelMap = new Dictionary<byte, VxlElement>[l.Size[0],l.Size[1]];
|
||||
for (var i = 0; i < baseSize; i++)
|
||||
{
|
||||
// Empty column
|
||||
if (colStart[i] == -1)
|
||||
continue;
|
||||
|
||||
s.Seek(dataStart + colStart[i], SeekOrigin.Begin);
|
||||
|
||||
byte x = (byte)(i % l.Size[0]);
|
||||
byte y = (byte)(i / l.Size[0]);
|
||||
byte z = 0;
|
||||
l.VoxelMap[x,y] = new Dictionary<byte, VxlElement>();
|
||||
do
|
||||
{
|
||||
z += s.ReadUInt8();
|
||||
var count = s.ReadUInt8();
|
||||
for (var j = 0; j < count; j++)
|
||||
{
|
||||
var v = new VxlElement();
|
||||
v.Color = s.ReadUInt8();
|
||||
v.Normal = s.ReadUInt8();
|
||||
|
||||
l.VoxelMap[x,y].Add(z, v);
|
||||
z++;
|
||||
}
|
||||
// Skip duplicate count
|
||||
s.ReadUInt8();
|
||||
} while (z < l.Size[2]);
|
||||
}
|
||||
}
|
||||
|
||||
public VxlReader(Stream s)
|
||||
{
|
||||
|
||||
if (!s.ReadASCII(16).StartsWith("Voxel Animation"))
|
||||
throw new InvalidDataException("Invalid vxl header");
|
||||
|
||||
s.ReadUInt32();
|
||||
LimbCount = s.ReadUInt32();
|
||||
s.ReadUInt32();
|
||||
BodySize = s.ReadUInt32();
|
||||
s.Seek(770, SeekOrigin.Current);
|
||||
|
||||
// Read Limb headers
|
||||
Limbs = new VxlLimb[LimbCount];
|
||||
for (var i = 0; i < LimbCount; i++)
|
||||
{
|
||||
Limbs[i] = new VxlLimb();
|
||||
Limbs[i].Name = s.ReadASCII(16);
|
||||
s.Seek(12, SeekOrigin.Current);
|
||||
}
|
||||
|
||||
// Skip to the Limb footers
|
||||
s.Seek(802 + 28*LimbCount + BodySize, SeekOrigin.Begin);
|
||||
|
||||
var LimbDataOffset = new uint[LimbCount];
|
||||
for (var i = 0; i < LimbCount; i++)
|
||||
{
|
||||
LimbDataOffset[i] = s.ReadUInt32();
|
||||
s.Seek(8, SeekOrigin.Current);
|
||||
Limbs[i].Scale = s.ReadFloat();
|
||||
s.Seek(48, SeekOrigin.Current);
|
||||
|
||||
Limbs[i].Bounds = new float[6];
|
||||
for (var j = 0; j < 6; j++)
|
||||
Limbs[i].Bounds[j] = s.ReadFloat();
|
||||
Limbs[i].Size = s.ReadBytes(3);
|
||||
Limbs[i].Type = (NormalType)s.ReadByte();
|
||||
}
|
||||
|
||||
for (var i = 0; i < LimbCount; i++)
|
||||
{
|
||||
s.Seek(802 + 28*LimbCount + LimbDataOffset[i], SeekOrigin.Begin);
|
||||
ReadVoxelData(s, Limbs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static VxlReader Load(string filename)
|
||||
{
|
||||
using (var s = File.OpenRead(filename))
|
||||
return new VxlReader(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ namespace OpenRA.FileFormats
|
||||
{
|
||||
public readonly string[]
|
||||
Mods, Folders, Rules, ServerTraits,
|
||||
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
|
||||
Sequences, VoxelSequences, Cursors, Chrome, Assemblies, ChromeLayout,
|
||||
Weapons, Voices, Notifications, Music, Movies, TileSets,
|
||||
ChromeMetrics, PackageContents;
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace OpenRA.FileFormats
|
||||
Rules = YamlList(yaml, "Rules");
|
||||
ServerTraits = YamlList(yaml, "ServerTraits");
|
||||
Sequences = YamlList(yaml, "Sequences");
|
||||
VoxelSequences = YamlList(yaml, "VoxelSequences");
|
||||
Cursors = YamlList(yaml, "Cursors");
|
||||
Chrome = YamlList(yaml, "Chrome");
|
||||
Assemblies = YamlList(yaml, "Assemblies");
|
||||
|
||||
@@ -141,6 +141,8 @@
|
||||
<Compile Include="Graphics\ShpTSReader.cs" />
|
||||
<Compile Include="FileFormats\XccLocalDatabase.cs" />
|
||||
<Compile Include="FileFormats\XccGlobalDatabase.cs" />
|
||||
<Compile Include="Graphics\VxlReader.cs" />
|
||||
<Compile Include="Graphics\HvaReader.cs" />
|
||||
<Compile Include="StreamExts.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace OpenRA.Graphics
|
||||
public SpriteRenderer WorldSpriteRenderer { get; private set; }
|
||||
public QuadRenderer WorldQuadRenderer { get; private set; }
|
||||
public LineRenderer WorldLineRenderer { get; private set; }
|
||||
public VoxelRenderer WorldVoxelRenderer { get; private set; }
|
||||
public LineRenderer LineRenderer { get; private set; }
|
||||
public SpriteRenderer RgbaSpriteRenderer { get; private set; }
|
||||
public SpriteRenderer SpriteRenderer { get; private set; }
|
||||
@@ -46,6 +47,7 @@ namespace OpenRA.Graphics
|
||||
|
||||
WorldSpriteRenderer = new SpriteRenderer(this, device.CreateShader("shp"));
|
||||
WorldLineRenderer = new LineRenderer(this, device.CreateShader("line"));
|
||||
WorldVoxelRenderer = new VoxelRenderer(this, device.CreateShader("vxl"), device.CreateShader("vxlshadow"));
|
||||
LineRenderer = new LineRenderer(this, device.CreateShader("line"));
|
||||
WorldQuadRenderer = new QuadRenderer(this, device.CreateShader("line"));
|
||||
RgbaSpriteRenderer = new SpriteRenderer(this, device.CreateShader("rgba"));
|
||||
@@ -71,6 +73,7 @@ namespace OpenRA.Graphics
|
||||
WorldLineRenderer.SetViewportParams(Resolution, zoom, scroll);
|
||||
WorldQuadRenderer.SetViewportParams(Resolution, zoom, scroll);
|
||||
LineRenderer.SetViewportParams(Resolution, 1f, float2.Zero);
|
||||
WorldVoxelRenderer.SetViewportParams(Resolution, zoom, scroll);
|
||||
}
|
||||
|
||||
ITexture currentPaletteTexture;
|
||||
@@ -85,6 +88,7 @@ namespace OpenRA.Graphics
|
||||
RgbaSpriteRenderer.SetPalette(currentPaletteTexture);
|
||||
SpriteRenderer.SetPalette(currentPaletteTexture);
|
||||
WorldSpriteRenderer.SetPalette(currentPaletteTexture);
|
||||
WorldVoxelRenderer.SetPalette(currentPaletteTexture);
|
||||
}
|
||||
|
||||
public void EndFrame(IInputHandler inputHandler)
|
||||
@@ -186,5 +190,29 @@ namespace OpenRA.Graphics
|
||||
Flush();
|
||||
Device.DisableScissor();
|
||||
}
|
||||
|
||||
public void EnableDepthBuffer()
|
||||
{
|
||||
Flush();
|
||||
Device.EnableDepthBuffer();
|
||||
}
|
||||
|
||||
public void DisableDepthBuffer()
|
||||
{
|
||||
Flush();
|
||||
Device.DisableDepthBuffer();
|
||||
}
|
||||
|
||||
public void EnableStencilBuffer()
|
||||
{
|
||||
Flush();
|
||||
Device.EnableStencilBuffer();
|
||||
}
|
||||
|
||||
public void DisableStencilBuffer()
|
||||
{
|
||||
Flush();
|
||||
Device.DisableStencilBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,5 +53,181 @@ namespace OpenRA.Graphics
|
||||
destOffset += destSkip;
|
||||
}
|
||||
}
|
||||
|
||||
public static float[] IdentityMatrix()
|
||||
{
|
||||
return Exts.MakeArray(16, j => (j % 5 == 0) ? 1.0f : 0);
|
||||
}
|
||||
|
||||
public static float[] ScaleMatrix(float sx, float sy, float sz)
|
||||
{
|
||||
var mtx = IdentityMatrix();
|
||||
mtx[0] = sx;
|
||||
mtx[5] = sy;
|
||||
mtx[10] = sz;
|
||||
return mtx;
|
||||
}
|
||||
|
||||
public static float[] TranslationMatrix(float x, float y, float z)
|
||||
{
|
||||
var mtx = IdentityMatrix();
|
||||
mtx[12] = x;
|
||||
mtx[13] = y;
|
||||
mtx[14] = z;
|
||||
return mtx;
|
||||
}
|
||||
|
||||
public static float[] MatrixMultiply(float[] lhs, float[] rhs)
|
||||
{
|
||||
var mtx = new float[16];
|
||||
for (var i = 0; i < 4; i++)
|
||||
for (var j = 0; j < 4; j++)
|
||||
{
|
||||
mtx[4*i + j] = 0;
|
||||
for (var k = 0; k < 4; k++)
|
||||
mtx[4*i + j] += lhs[4*k + j]*rhs[4*i + k];
|
||||
}
|
||||
|
||||
return mtx;
|
||||
}
|
||||
|
||||
public static float[] MatrixVectorMultiply(float[] mtx, float[] vec)
|
||||
{
|
||||
var ret = new float[4];
|
||||
for (var j = 0; j < 4; j++)
|
||||
{
|
||||
ret[j] = 0;
|
||||
for (var k = 0; k < 4; k++)
|
||||
ret[j] += mtx[4*k + j]*vec[k];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static float[] MatrixInverse(float[] m)
|
||||
{
|
||||
var mtx = new float[16];
|
||||
|
||||
mtx[0] = m[5]*m[10]*m[15] -
|
||||
m[5]*m[11]*m[14] -
|
||||
m[9]*m[6]*m[15] +
|
||||
m[9]*m[7]*m[14] +
|
||||
m[13]*m[6]*m[11] -
|
||||
m[13]*m[7]*m[10];
|
||||
|
||||
mtx[4] = -m[4]*m[10]*m[15] +
|
||||
m[4]*m[11]*m[14] +
|
||||
m[8]*m[6]*m[15] -
|
||||
m[8]*m[7]*m[14] -
|
||||
m[12]*m[6]*m[11] +
|
||||
m[12]*m[7]*m[10];
|
||||
|
||||
mtx[8] = m[4]*m[9]*m[15] -
|
||||
m[4]*m[11]*m[13] -
|
||||
m[8]*m[5]*m[15] +
|
||||
m[8]*m[7]*m[13] +
|
||||
m[12]*m[5]*m[11] -
|
||||
m[12]*m[7]*m[9];
|
||||
|
||||
mtx[12] = -m[4]*m[9]*m[14] +
|
||||
m[4]*m[10]*m[13] +
|
||||
m[8]*m[5]*m[14] -
|
||||
m[8]*m[6]*m[13] -
|
||||
m[12]*m[5]*m[10] +
|
||||
m[12]*m[6]*m[9];
|
||||
|
||||
mtx[1] = -m[1]*m[10]*m[15] +
|
||||
m[1]*m[11]*m[14] +
|
||||
m[9]*m[2]*m[15] -
|
||||
m[9]*m[3]*m[14] -
|
||||
m[13]*m[2]*m[11] +
|
||||
m[13]*m[3]*m[10];
|
||||
|
||||
mtx[5] = m[0]*m[10]*m[15] -
|
||||
m[0]*m[11]*m[14] -
|
||||
m[8]*m[2]*m[15] +
|
||||
m[8]*m[3]*m[14] +
|
||||
m[12]*m[2]*m[11] -
|
||||
m[12]*m[3]*m[10];
|
||||
|
||||
mtx[9] = -m[0]*m[9]*m[15] +
|
||||
m[0]*m[11]*m[13] +
|
||||
m[8]*m[1]*m[15] -
|
||||
m[8]*m[3]*m[13] -
|
||||
m[12]*m[1]*m[11] +
|
||||
m[12]*m[3]*m[9];
|
||||
|
||||
mtx[13] = m[0]*m[9]*m[14] -
|
||||
m[0]*m[10]*m[13] -
|
||||
m[8]*m[1]*m[14] +
|
||||
m[8]*m[2]*m[13] +
|
||||
m[12]*m[1]*m[10] -
|
||||
m[12]*m[2]*m[9];
|
||||
|
||||
mtx[2] = m[1]*m[6]*m[15] -
|
||||
m[1]*m[7]*m[14] -
|
||||
m[5]*m[2]*m[15] +
|
||||
m[5]*m[3]*m[14] +
|
||||
m[13]*m[2]*m[7] -
|
||||
m[13]*m[3]*m[6];
|
||||
|
||||
mtx[6] = -m[0]*m[6]*m[15] +
|
||||
m[0]*m[7]*m[14] +
|
||||
m[4]*m[2]*m[15] -
|
||||
m[4]*m[3]*m[14] -
|
||||
m[12]*m[2]*m[7] +
|
||||
m[12]*m[3]*m[6];
|
||||
|
||||
mtx[10] = m[0]*m[5]*m[15] -
|
||||
m[0]*m[7]*m[13] -
|
||||
m[4]*m[1]*m[15] +
|
||||
m[4]*m[3]*m[13] +
|
||||
m[12]*m[1]*m[7] -
|
||||
m[12]*m[3]*m[5];
|
||||
|
||||
mtx[14] = -m[0]*m[5]*m[14] +
|
||||
m[0]*m[6]*m[13] +
|
||||
m[4]*m[1]*m[14] -
|
||||
m[4]*m[2]*m[13] -
|
||||
m[12]*m[1]*m[6] +
|
||||
m[12]*m[2]*m[5];
|
||||
|
||||
mtx[3] = -m[1]*m[6]*m[11] +
|
||||
m[1]*m[7]*m[10] +
|
||||
m[5]*m[2]*m[11] -
|
||||
m[5]*m[3]*m[10] -
|
||||
m[9]*m[2]*m[7] +
|
||||
m[9]*m[3]*m[6];
|
||||
|
||||
mtx[7] = m[0]*m[6]*m[11] -
|
||||
m[0]*m[7]*m[10] -
|
||||
m[4]*m[2]*m[11] +
|
||||
m[4]*m[3]*m[10] +
|
||||
m[8]*m[2]*m[7] -
|
||||
m[8]*m[3]*m[6];
|
||||
|
||||
mtx[11] = -m[0]*m[5]*m[11] +
|
||||
m[0]*m[7]*m[9] +
|
||||
m[4]*m[1]*m[11] -
|
||||
m[4]*m[3]*m[9] -
|
||||
m[8]*m[1]*m[7] +
|
||||
m[8]*m[3]*m[5];
|
||||
|
||||
mtx[15] = m[0]*m[5]*m[10] -
|
||||
m[0]*m[6]*m[9] -
|
||||
m[4]*m[1]*m[10] +
|
||||
m[4]*m[2]*m[9] +
|
||||
m[8]*m[1]*m[6] -
|
||||
m[8]*m[2]*m[5];
|
||||
|
||||
var det = m[0]*mtx[0] + m[1]*mtx[4] + m[2]*mtx[8] + m[3]*mtx[12];
|
||||
if (det == 0)
|
||||
return null;
|
||||
|
||||
for (var i = 0; i < 16; i++)
|
||||
mtx[i] *= 1/det;
|
||||
|
||||
return mtx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
161
OpenRA.Game/Graphics/Voxel.cs
Normal file
161
OpenRA.Game/Graphics/Voxel.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
struct Limb
|
||||
{
|
||||
public float Scale;
|
||||
public float[] Bounds;
|
||||
public byte[] Size;
|
||||
public VoxelRenderData RenderData;
|
||||
}
|
||||
|
||||
public class Voxel
|
||||
{
|
||||
Limb[] limbs;
|
||||
HvaReader hva;
|
||||
VoxelLoader loader;
|
||||
|
||||
float[][] transform, lightDirection, groundNormal;
|
||||
float[] groundZ;
|
||||
|
||||
public Voxel(VoxelLoader loader, VxlReader vxl, HvaReader hva)
|
||||
{
|
||||
this.hva = hva;
|
||||
this.loader = loader;
|
||||
|
||||
limbs = new Limb[vxl.LimbCount];
|
||||
for (var i = 0; i < vxl.LimbCount; i++)
|
||||
{
|
||||
var vl = vxl.Limbs[i];
|
||||
var l = new Limb();
|
||||
l.Scale = vl.Scale;
|
||||
l.Bounds = (float[])vl.Bounds.Clone();
|
||||
l.Size = (byte[])vl.Size.Clone();
|
||||
l.RenderData = loader.GenerateRenderData(vxl.Limbs[i]);
|
||||
limbs[i] = l;
|
||||
}
|
||||
|
||||
transform = new float[vxl.LimbCount][];
|
||||
lightDirection = new float[vxl.LimbCount][];
|
||||
groundNormal = new float[vxl.LimbCount][];
|
||||
groundZ = new float[vxl.LimbCount];
|
||||
}
|
||||
|
||||
// Extract the rotation components from a matrix and apply them to a vector
|
||||
static float[] ExtractRotationVector(float[] mtx, WVec vec)
|
||||
{
|
||||
var tVec = Util.MatrixVectorMultiply(mtx, new float[] {vec.X, vec.Y, vec.Z, 1});
|
||||
var tOrigin = Util.MatrixVectorMultiply(mtx, new float[] {0,0,0,1});
|
||||
tVec[0] -= tOrigin[0]*tVec[3]/tOrigin[3];
|
||||
tVec[1] -= tOrigin[1]*tVec[3]/tOrigin[3];
|
||||
tVec[2] -= tOrigin[2]*tVec[3]/tOrigin[3];
|
||||
|
||||
// Renormalize
|
||||
var w = (float)Math.Sqrt(tVec[0]*tVec[0] + tVec[1]*tVec[1] + tVec[2]*tVec[2]);
|
||||
tVec[0] /= w;
|
||||
tVec[1] /= w;
|
||||
tVec[2] /= w;
|
||||
tVec[3] = 1f;
|
||||
|
||||
return tVec;
|
||||
}
|
||||
|
||||
static float[] MakeFloatMatrix(int[] imtx)
|
||||
{
|
||||
var fmtx = new float[16];
|
||||
for (var i = 0; i < 16; i++)
|
||||
fmtx[i] = imtx[i]*1f / imtx[15];
|
||||
return fmtx;
|
||||
}
|
||||
|
||||
public void Draw(VoxelRenderer r, float[] lightAmbientColor, float[] lightDiffuseColor,
|
||||
int colorPalette, int normalsPalette)
|
||||
{
|
||||
for (var i = 0; i < limbs.Length; i++)
|
||||
r.Render(loader, limbs[i].RenderData, transform[i], lightDirection[i],
|
||||
lightAmbientColor, lightDiffuseColor, colorPalette, normalsPalette);
|
||||
}
|
||||
|
||||
public void DrawShadow(VoxelRenderer r, int shadowPalette)
|
||||
{
|
||||
for (var i = 0; i < limbs.Length; i++)
|
||||
r.RenderShadow(loader, limbs[i].RenderData, transform[i], lightDirection[i],
|
||||
groundNormal[i], groundZ[i], shadowPalette);
|
||||
}
|
||||
|
||||
static readonly WVec forward = new WVec(1024,0,0);
|
||||
static readonly WVec up = new WVec(0,0,1024);
|
||||
public void PrepareForDraw(WorldRenderer wr, WPos pos, IEnumerable<WRot> rotations,
|
||||
WRot camera, uint frame, float scale, WRot lightSource)
|
||||
{
|
||||
// Calculate the shared view matrix components
|
||||
var pxPos = wr.ScreenPosition(pos);
|
||||
|
||||
// Rotations
|
||||
var rot = rotations.Reverse().Aggregate(MakeFloatMatrix(camera.AsMatrix()),
|
||||
(a,b) => Util.MatrixMultiply(a, MakeFloatMatrix(b.AsMatrix())));
|
||||
|
||||
// Each limb has its own transformation matrix
|
||||
for (uint i = 0; i < limbs.Length; i++)
|
||||
{
|
||||
Limb l = limbs[i];
|
||||
var t = Util.MatrixMultiply(Util.ScaleMatrix(1,-1,1),
|
||||
hva.TransformationMatrix(i, frame));
|
||||
// Fix limb position
|
||||
t[12] *= l.Scale*(l.Bounds[3] - l.Bounds[0]) / l.Size[0];
|
||||
t[13] *= l.Scale*(l.Bounds[4] - l.Bounds[1]) / l.Size[1];
|
||||
t[14] *= l.Scale*(l.Bounds[5] - l.Bounds[2]) / l.Size[2];
|
||||
t = Util.MatrixMultiply(t, Util.TranslationMatrix(l.Bounds[0], l.Bounds[1], l.Bounds[2]));
|
||||
|
||||
// Apply view matrix
|
||||
transform[i] = Util.MatrixMultiply(Util.TranslationMatrix(pxPos.X, pxPos.Y, pxPos.Y),
|
||||
Util.ScaleMatrix(scale*l.Scale, scale*l.Scale, scale*l.Scale));
|
||||
transform[i] = Util.MatrixMultiply(transform[i], rot);
|
||||
transform[i] = Util.MatrixMultiply(transform[i], t);
|
||||
|
||||
// Transform light direction into limb-space
|
||||
var undoPitch = MakeFloatMatrix(new WRot(camera.Pitch, WAngle.Zero, WAngle.Zero).AsMatrix());
|
||||
var lightTransform = Util.MatrixMultiply(Util.MatrixInverse(transform[i]), undoPitch);
|
||||
|
||||
lightDirection[i] = ExtractRotationVector(lightTransform, forward.Rotate(lightSource));
|
||||
groundNormal[i] = ExtractRotationVector(Util.MatrixInverse(t), up);
|
||||
|
||||
// Hack: Extract the ground z position independently of y.
|
||||
groundZ[i] = (wr.ScreenPosition(pos).Y - wr.ScreenZPosition(pos, 0)) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
public uint Frames { get { return hva.FrameCount; }}
|
||||
public uint LimbCount { get { return (uint)limbs.Length; }}
|
||||
|
||||
public float[] Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return limbs.Select(a => a.Size.Select(b => a.Scale*b).ToArray())
|
||||
.Aggregate((a,b) => new float[]
|
||||
{
|
||||
Math.Max(a[0], b[0]),
|
||||
Math.Max(a[1], b[1]),
|
||||
Math.Max(a[2], b[2])
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
OpenRA.Game/Graphics/VoxelAnimation.cs
Normal file
35
OpenRA.Game/Graphics/VoxelAnimation.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public struct VoxelAnimation
|
||||
{
|
||||
public readonly Voxel Voxel;
|
||||
public readonly Func<WVec> OffsetFunc;
|
||||
public readonly Func<IEnumerable<WRot>> RotationFunc;
|
||||
public readonly Func<bool> DisableFunc;
|
||||
public readonly Func<uint> FrameFunc;
|
||||
|
||||
public VoxelAnimation(Voxel voxel, Func<WVec> offset, Func<IEnumerable<WRot>> rotation, Func<bool> disable, Func<uint> frame)
|
||||
{
|
||||
Voxel = voxel;
|
||||
OffsetFunc = offset;
|
||||
RotationFunc = rotation;
|
||||
DisableFunc = disable;
|
||||
FrameFunc = frame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
208
OpenRA.Game/Graphics/VoxelLoader.cs
Normal file
208
OpenRA.Game/Graphics/VoxelLoader.cs
Normal file
@@ -0,0 +1,208 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public struct VoxelRenderData
|
||||
{
|
||||
public readonly int Start;
|
||||
public readonly int Count;
|
||||
public readonly Sheet Sheet;
|
||||
|
||||
public VoxelRenderData(int start, int count, Sheet sheet)
|
||||
{
|
||||
Start = start;
|
||||
Count = count;
|
||||
Sheet = sheet;
|
||||
}
|
||||
}
|
||||
|
||||
public class VoxelLoader
|
||||
{
|
||||
SheetBuilder sheetBuilder;
|
||||
|
||||
Cache<Pair<string,string>, Voxel> voxels;
|
||||
IVertexBuffer<Vertex> vertexBuffer;
|
||||
List<Vertex[]> vertices;
|
||||
int totalVertexCount;
|
||||
int cachedVertexCount;
|
||||
|
||||
public VoxelLoader()
|
||||
{
|
||||
voxels = new Cache<Pair<string,string>, Voxel>(LoadFile);
|
||||
vertices = new List<Vertex[]>();
|
||||
totalVertexCount = 0;
|
||||
cachedVertexCount = 0;
|
||||
|
||||
sheetBuilder = new SheetBuilder(SheetType.DualIndexed);
|
||||
}
|
||||
|
||||
static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f };
|
||||
Vertex[] GenerateSlicePlane(int su, int sv, Func<int,int,VxlElement> first, Func<int,int,VxlElement> second, Func<int, int, float[]> coord)
|
||||
{
|
||||
var colors = new byte[su*sv];
|
||||
var normals = new byte[su*sv];
|
||||
|
||||
var c = 0;
|
||||
for (var v = 0; v < sv; v++)
|
||||
for (var u = 0; u < su; u++)
|
||||
{
|
||||
var voxel = first(u,v) ?? second(u,v);
|
||||
colors[c] = voxel == null ? (byte)0 : voxel.Color;
|
||||
normals[c] = voxel == null ? (byte)0 : voxel.Normal;
|
||||
c++;
|
||||
}
|
||||
|
||||
Sprite s = sheetBuilder.Allocate(new Size(su, sv), false);
|
||||
Util.FastCopyIntoChannel(s, 0, colors);
|
||||
Util.FastCopyIntoChannel(s, 1, normals);
|
||||
s.sheet.MakeDirty();
|
||||
|
||||
var channels = new float2(channelSelect[(int)s.channel], channelSelect[(int)s.channel + 1]);
|
||||
return new Vertex[4]
|
||||
{
|
||||
new Vertex(coord(0, 0), s.FastMapTextureCoords(0), channels),
|
||||
new Vertex(coord(su, 0), s.FastMapTextureCoords(1), channels),
|
||||
new Vertex(coord(su, sv), s.FastMapTextureCoords(3), channels),
|
||||
new Vertex(coord(0, sv), s.FastMapTextureCoords(2), channels)
|
||||
};
|
||||
}
|
||||
|
||||
IEnumerable<Vertex[]> GenerateSlicePlanes(VxlLimb l)
|
||||
{
|
||||
Func<int,int,int,VxlElement> get = (x,y,z) =>
|
||||
{
|
||||
if (x < 0 || y < 0 || z < 0)
|
||||
return null;
|
||||
|
||||
if (x >= l.Size[0] || y >= l.Size[1] || z >= l.Size[2])
|
||||
return null;
|
||||
|
||||
var v = l.VoxelMap[(byte)x,(byte)y];
|
||||
if (v == null || !v.ContainsKey((byte)z))
|
||||
return null;
|
||||
|
||||
return l.VoxelMap[(byte)x,(byte)y][(byte)z];
|
||||
};
|
||||
|
||||
// Cull slices without any visible faces
|
||||
var xPlanes = new bool[l.Size[0]+1];
|
||||
var yPlanes = new bool[l.Size[1]+1];
|
||||
var zPlanes = new bool[l.Size[2]+1];
|
||||
for (var x = 0; x < l.Size[0]; x++)
|
||||
{
|
||||
for (var y = 0; y < l.Size[1]; y++)
|
||||
{
|
||||
for (var z = 0; z < l.Size[2]; z++)
|
||||
{
|
||||
if (get(x,y,z) == null)
|
||||
continue;
|
||||
|
||||
// Only generate a plane if it is actually visible
|
||||
if (!xPlanes[x] && get(x-1,y,z) == null)
|
||||
xPlanes[x] = true;
|
||||
if (!xPlanes[x+1] && get(x+1,y,z) == null)
|
||||
xPlanes[x+1] = true;
|
||||
|
||||
if (!yPlanes[y] && get(x,y-1,z) == null)
|
||||
yPlanes[y] = true;
|
||||
if (!yPlanes[y+1] && get(x,y+1,z) == null)
|
||||
yPlanes[y+1] = true;
|
||||
|
||||
if (!zPlanes[z] && get(x,y,z-1) == null)
|
||||
zPlanes[z] = true;
|
||||
if (!zPlanes[z+1] && get(x,y,z+1) == null)
|
||||
zPlanes[z+1] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var x = 0; x <= l.Size[0]; x++)
|
||||
if (xPlanes[x])
|
||||
yield return GenerateSlicePlane(l.Size[1], l.Size[2],
|
||||
(u,v) => get(x, u, v),
|
||||
(u,v) => get(x - 1, u, v),
|
||||
(u,v) => new float[] {x, u, v});
|
||||
|
||||
for (var y = 0; y <= l.Size[1]; y++)
|
||||
if (yPlanes[y])
|
||||
yield return GenerateSlicePlane(l.Size[0], l.Size[2],
|
||||
(u,v) => get(u, y, v),
|
||||
(u,v) => get(u, y - 1, v),
|
||||
(u,v) => new float[] {u, y, v});
|
||||
|
||||
for (var z = 0; z <= l.Size[2]; z++)
|
||||
if (zPlanes[z])
|
||||
yield return GenerateSlicePlane(l.Size[0], l.Size[1],
|
||||
(u,v) => get(u, v, z),
|
||||
(u,v) => get(u, v, z - 1),
|
||||
(u,v) => new float[] {u, v, z});
|
||||
}
|
||||
|
||||
public VoxelRenderData GenerateRenderData(VxlLimb l)
|
||||
{
|
||||
Vertex[] v;
|
||||
try
|
||||
{
|
||||
v = GenerateSlicePlanes(l).SelectMany(x => x).ToArray();
|
||||
}
|
||||
catch (SheetOverflowException)
|
||||
{
|
||||
// Sheet overflow - allocate a new sheet and try once more
|
||||
Log.Write("debug", "Voxel sheet overflow! Generating new sheet");
|
||||
sheetBuilder = new SheetBuilder(SheetType.DualIndexed);
|
||||
v = GenerateSlicePlanes(l).SelectMany(x => x).ToArray();
|
||||
}
|
||||
|
||||
vertices.Add(v);
|
||||
|
||||
var start = totalVertexCount;
|
||||
var count = v.Length;
|
||||
totalVertexCount += count;
|
||||
return new VoxelRenderData(start, count, sheetBuilder.Current);
|
||||
}
|
||||
|
||||
public void RefreshBuffer()
|
||||
{
|
||||
vertexBuffer = Game.Renderer.Device.CreateVertexBuffer(totalVertexCount);
|
||||
vertexBuffer.SetData(vertices.SelectMany(v => v).ToArray(), totalVertexCount);
|
||||
cachedVertexCount = totalVertexCount;
|
||||
}
|
||||
|
||||
public IVertexBuffer<Vertex> VertexBuffer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (cachedVertexCount != totalVertexCount)
|
||||
RefreshBuffer();
|
||||
return vertexBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
Voxel LoadFile(Pair<string,string> files)
|
||||
{
|
||||
var vxl = new VxlReader(FileSystem.OpenWithExts(files.First, ".vxl"));
|
||||
var hva = new HvaReader(FileSystem.OpenWithExts(files.Second, ".hva"));
|
||||
return new Voxel(this, vxl, hva);
|
||||
}
|
||||
|
||||
public Voxel Load(string vxl, string hva)
|
||||
{
|
||||
return voxels[Pair.New(vxl, hva)];
|
||||
}
|
||||
}
|
||||
}
|
||||
88
OpenRA.Game/Graphics/VoxelProvider.cs
Normal file
88
OpenRA.Game/Graphics/VoxelProvider.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public static class VoxelProvider
|
||||
{
|
||||
static Dictionary<string, Dictionary<string, Voxel>> units;
|
||||
|
||||
public static void Initialize(string[] voxelFiles, List<MiniYamlNode> voxelNodes)
|
||||
{
|
||||
units = new Dictionary<string, Dictionary<string, Voxel>>();
|
||||
|
||||
var sequences = voxelFiles
|
||||
.Select(s => MiniYaml.FromFile(s))
|
||||
.Aggregate(voxelNodes, MiniYaml.MergeLiberal);
|
||||
|
||||
foreach (var s in sequences)
|
||||
LoadVoxelsForUnit(s.Key, s.Value);
|
||||
|
||||
Game.modData.VoxelLoader.RefreshBuffer();
|
||||
}
|
||||
|
||||
static Voxel LoadVoxel(string unit, string name, MiniYaml info)
|
||||
{
|
||||
var vxl = unit;
|
||||
var hva = unit;
|
||||
if (info.Value != null)
|
||||
{
|
||||
var fields = info.Value.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (fields.Length >= 1)
|
||||
vxl = hva = fields[0].Trim();
|
||||
|
||||
if (fields.Length >= 2)
|
||||
hva = fields[1].Trim();
|
||||
}
|
||||
|
||||
return Game.modData.VoxelLoader.Load(vxl, hva);
|
||||
}
|
||||
|
||||
static void LoadVoxelsForUnit(string unit, MiniYaml sequences)
|
||||
{
|
||||
Game.modData.LoadScreen.Display();
|
||||
try
|
||||
{
|
||||
var seq = sequences.NodesDict.ToDictionary(x => x.Key, x => LoadVoxel(unit,x.Key,x.Value));
|
||||
units.Add(unit, seq);
|
||||
}
|
||||
catch (FileNotFoundException) {} // Do nothing; we can crash later if we actually wanted art
|
||||
}
|
||||
|
||||
public static Voxel GetVoxel(string unitName, string voxelName)
|
||||
{
|
||||
try { return units[unitName][voxelName]; }
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
if (units.ContainsKey(unitName))
|
||||
throw new InvalidOperationException(
|
||||
"Unit `{0}` does not have a voxel `{1}`".F(unitName, voxelName));
|
||||
else
|
||||
throw new InvalidOperationException(
|
||||
"Unit `{0}` does not have any voxels defined.".F(unitName));
|
||||
}
|
||||
}
|
||||
|
||||
public static bool HasVoxel(string unit, string seq)
|
||||
{
|
||||
if (!units.ContainsKey(unit))
|
||||
throw new InvalidOperationException(
|
||||
"Unit `{0}` does not have any voxels defined.".F(unit));
|
||||
|
||||
return units[unit].ContainsKey(seq);
|
||||
}
|
||||
}
|
||||
}
|
||||
106
OpenRA.Game/Graphics/VoxelRenderable.cs
Normal file
106
OpenRA.Game/Graphics/VoxelRenderable.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public struct VoxelRenderable : IRenderable
|
||||
{
|
||||
readonly IEnumerable<VoxelAnimation> voxels;
|
||||
readonly WPos pos;
|
||||
readonly int zOffset;
|
||||
readonly WRot camera;
|
||||
readonly WRot lightSource;
|
||||
readonly float[] lightAmbientColor;
|
||||
readonly float[] lightDiffuseColor;
|
||||
readonly PaletteReference palette;
|
||||
readonly PaletteReference normalsPalette;
|
||||
readonly PaletteReference shadowPalette;
|
||||
readonly float scale;
|
||||
|
||||
public VoxelRenderable(IEnumerable<VoxelAnimation> voxels, WPos pos, int zOffset, WRot camera, float scale,
|
||||
WRot lightSource, float[] lightAmbientColor, float[] lightDiffuseColor,
|
||||
PaletteReference color, PaletteReference normals, PaletteReference shadow)
|
||||
{
|
||||
this.voxels = voxels;
|
||||
this.pos = pos;
|
||||
this.zOffset = zOffset;
|
||||
this.scale = scale;
|
||||
this.camera = camera;
|
||||
this.lightSource = lightSource;
|
||||
this.lightAmbientColor = lightAmbientColor;
|
||||
this.lightDiffuseColor = lightDiffuseColor;
|
||||
this.palette = color;
|
||||
this.normalsPalette = normals;
|
||||
this.shadowPalette = shadow;
|
||||
}
|
||||
|
||||
public WPos Pos { get { return pos; } }
|
||||
public float Scale { get { return scale; } }
|
||||
public PaletteReference Palette { get { return palette; } }
|
||||
public int ZOffset { get { return zOffset; } }
|
||||
|
||||
public IRenderable WithScale(float newScale)
|
||||
{
|
||||
return new VoxelRenderable(voxels, pos, zOffset, camera, newScale,
|
||||
lightSource, lightAmbientColor, lightDiffuseColor,
|
||||
palette, normalsPalette, shadowPalette);
|
||||
}
|
||||
|
||||
public IRenderable WithPalette(PaletteReference newPalette)
|
||||
{
|
||||
return new VoxelRenderable(voxels, pos, zOffset, camera, scale,
|
||||
lightSource, lightAmbientColor, lightDiffuseColor,
|
||||
newPalette, normalsPalette, shadowPalette);
|
||||
}
|
||||
|
||||
public IRenderable WithZOffset(int newOffset)
|
||||
{
|
||||
return new VoxelRenderable(voxels, pos, newOffset, camera, scale,
|
||||
lightSource, lightAmbientColor, lightDiffuseColor,
|
||||
palette, normalsPalette, shadowPalette);
|
||||
}
|
||||
|
||||
public IRenderable WithPos(WPos newPos)
|
||||
{
|
||||
return new VoxelRenderable(voxels, newPos, zOffset, camera, scale,
|
||||
lightSource, lightAmbientColor, lightDiffuseColor,
|
||||
palette, normalsPalette, shadowPalette);
|
||||
}
|
||||
|
||||
public void Render(WorldRenderer wr)
|
||||
{
|
||||
// Depth and shadow buffers are cleared between actors so that
|
||||
// overlapping units and shadows behave like overlapping sprites.
|
||||
var vr = Game.Renderer.WorldVoxelRenderer;
|
||||
var draw = voxels.Where(v => v.DisableFunc == null || !v.DisableFunc());
|
||||
|
||||
foreach (var v in draw)
|
||||
v.Voxel.PrepareForDraw(wr, pos + v.OffsetFunc(), v.RotationFunc(), camera,
|
||||
v.FrameFunc(), scale, lightSource);
|
||||
|
||||
Game.Renderer.EnableDepthBuffer();
|
||||
Game.Renderer.EnableStencilBuffer();
|
||||
foreach (var v in draw)
|
||||
v.Voxel.DrawShadow(vr, shadowPalette.Index);
|
||||
Game.Renderer.DisableStencilBuffer();
|
||||
Game.Renderer.DisableDepthBuffer();
|
||||
|
||||
Game.Renderer.EnableDepthBuffer();
|
||||
foreach (var v in draw)
|
||||
v.Voxel.Draw(vr, lightAmbientColor, lightDiffuseColor, palette.Index, normalsPalette.Index);
|
||||
Game.Renderer.DisableDepthBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
88
OpenRA.Game/Graphics/VoxelRenderer.cs
Normal file
88
OpenRA.Game/Graphics/VoxelRenderer.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.FileFormats.Graphics;
|
||||
|
||||
namespace OpenRA.Graphics
|
||||
{
|
||||
public class VoxelRenderer
|
||||
{
|
||||
Renderer renderer;
|
||||
IShader shader;
|
||||
IShader shadowShader;
|
||||
|
||||
public VoxelRenderer(Renderer renderer, IShader shader, IShader shadowShader)
|
||||
{
|
||||
this.renderer = renderer;
|
||||
this.shader = shader;
|
||||
this.shadowShader = shadowShader;
|
||||
}
|
||||
|
||||
public void Render(VoxelLoader loader, VoxelRenderData renderData,
|
||||
float[] t, float[] lightDirection,
|
||||
float[] ambientLight, float[] diffuseLight,
|
||||
int colorPalette, int normalsPalette)
|
||||
{
|
||||
shader.SetTexture("DiffuseTexture", renderData.Sheet.Texture);
|
||||
shader.SetVec("PaletteRows", (colorPalette + 0.5f) / HardwarePalette.MaxPalettes,
|
||||
(normalsPalette + 0.5f) / HardwarePalette.MaxPalettes);
|
||||
shader.SetMatrix("TransformMatrix", t);
|
||||
shader.SetVec("LightDirection", lightDirection, 4);
|
||||
shader.SetVec("AmbientLight", ambientLight, 3);
|
||||
shader.SetVec("DiffuseLight", diffuseLight, 3);
|
||||
shader.Render(() => renderer.DrawBatch(loader.VertexBuffer, renderData.Start, renderData.Count, PrimitiveType.QuadList));
|
||||
}
|
||||
|
||||
public void RenderShadow(VoxelLoader loader, VoxelRenderData renderData,
|
||||
float[] t, float[] lightDirection, float[] groundNormal, float groundZ, int colorPalette)
|
||||
{
|
||||
shadowShader.SetTexture("DiffuseTexture", renderData.Sheet.Texture);
|
||||
shadowShader.SetVec("PaletteRows", (colorPalette + 0.5f) / HardwarePalette.MaxPalettes, 0);
|
||||
shadowShader.SetMatrix("TransformMatrix", t);
|
||||
shadowShader.SetVec("LightDirection", lightDirection, 4);
|
||||
shadowShader.SetVec("GroundNormal", groundNormal, 3);
|
||||
shadowShader.SetVec("GroundZ", groundZ);
|
||||
shadowShader.Render(() => renderer.DrawBatch(loader.VertexBuffer, renderData.Start, renderData.Count, PrimitiveType.QuadList));
|
||||
}
|
||||
|
||||
public void SetPalette(ITexture palette)
|
||||
{
|
||||
shader.SetTexture("Palette", palette);
|
||||
shadowShader.SetTexture("Palette", palette);
|
||||
}
|
||||
|
||||
public void SetViewportParams(Size screen, float zoom, float2 scroll)
|
||||
{
|
||||
// Construct projection matrix
|
||||
// Clip planes are set at -height and +2*height
|
||||
|
||||
var tiw = 2*zoom / screen.Width;
|
||||
var tih = 2*zoom / screen.Height;
|
||||
var view = new float[]
|
||||
{
|
||||
tiw, 0, 0, 0,
|
||||
0, -tih, 0, 0,
|
||||
0, 0, -tih/3, 0,
|
||||
-1 - tiw*scroll.X,
|
||||
1 + tih*scroll.Y,
|
||||
1 + tih*scroll.Y/3,
|
||||
1
|
||||
};
|
||||
|
||||
shader.SetMatrix("View", view);
|
||||
shadowShader.SetMatrix("View", view);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ namespace OpenRA
|
||||
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Rules = new List<MiniYamlNode>();
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Sequences = new List<MiniYamlNode>();
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> VoxelSequences = new List<MiniYamlNode>();
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Weapons = new List<MiniYamlNode>();
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Voices = new List<MiniYamlNode>();
|
||||
[FieldLoader.Ignore] public List<MiniYamlNode> Notifications = new List<MiniYamlNode>();
|
||||
@@ -150,6 +151,7 @@ namespace OpenRA
|
||||
|
||||
Rules = NodesOrEmpty(yaml, "Rules");
|
||||
Sequences = NodesOrEmpty(yaml, "Sequences");
|
||||
VoxelSequences = NodesOrEmpty(yaml, "VoxelSequences");
|
||||
Weapons = NodesOrEmpty(yaml, "Weapons");
|
||||
Voices = NodesOrEmpty(yaml, "Voices");
|
||||
Notifications = NodesOrEmpty(yaml, "Notifications");
|
||||
@@ -206,6 +208,7 @@ namespace OpenRA
|
||||
root.Add(new MiniYamlNode("Smudges", MiniYaml.FromList<SmudgeReference>( Smudges.Value )));
|
||||
root.Add(new MiniYamlNode("Rules", null, Rules));
|
||||
root.Add(new MiniYamlNode("Sequences", null, Sequences));
|
||||
root.Add(new MiniYamlNode("VoxelSequences", null, VoxelSequences));
|
||||
root.Add(new MiniYamlNode("Weapons", null, Weapons));
|
||||
root.Add(new MiniYamlNode("Voices", null, Voices));
|
||||
root.Add(new MiniYamlNode("Notifications", null, Notifications));
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace OpenRA
|
||||
public ILoadScreen LoadScreen = null;
|
||||
public SheetBuilder SheetBuilder;
|
||||
public SpriteLoader SpriteLoader;
|
||||
public VoxelLoader VoxelLoader;
|
||||
|
||||
public ModData(params string[] mods)
|
||||
{
|
||||
@@ -55,6 +56,7 @@ namespace OpenRA
|
||||
ChromeProvider.Initialize(Manifest.Chrome);
|
||||
SheetBuilder = new SheetBuilder(SheetType.Indexed);
|
||||
SpriteLoader = new SpriteLoader(new string[] { ".shp" }, SheetBuilder);
|
||||
VoxelLoader = new VoxelLoader();
|
||||
CursorProvider.Initialize(Manifest.Cursors);
|
||||
}
|
||||
|
||||
@@ -76,7 +78,7 @@ namespace OpenRA
|
||||
SpriteLoader = new SpriteLoader(Rules.TileSets[map.Tileset].Extensions, SheetBuilder);
|
||||
// TODO: Don't load the sequences for assets that are not used in this tileset. Maybe use the existing EditorTilesetFilters.
|
||||
SequenceProvider.Initialize(Manifest.Sequences, map.Sequences);
|
||||
|
||||
VoxelProvider.Initialize(Manifest.VoxelSequences, map.VoxelSequences);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,13 @@
|
||||
<Compile Include="Widgets\ClientTooltipRegionWidget.cs" />
|
||||
<Compile Include="Graphics\Renderable.cs" />
|
||||
<Compile Include="Traits\Render\RenderSprites.cs" />
|
||||
<Compile Include="Graphics\Voxel.cs" />
|
||||
<Compile Include="Graphics\VoxelRenderer.cs" />
|
||||
<Compile Include="Graphics\VoxelLoader.cs" />
|
||||
<Compile Include="Graphics\VoxelProvider.cs" />
|
||||
<Compile Include="Traits\BodyOrientation.cs" />
|
||||
<Compile Include="Graphics\VoxelAnimation.cs" />
|
||||
<Compile Include="Graphics\VoxelRenderable.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
@@ -27,12 +27,12 @@ namespace OpenRA.Mods.RA
|
||||
[Desc("Allows you to attach weapons to the unit (use @IdentifierSuffix for > 1)")]
|
||||
public class ArmamentInfo : ITraitInfo, Requires<AttackBaseInfo>
|
||||
{
|
||||
public readonly string Name = "primary";
|
||||
|
||||
[WeaponReference]
|
||||
[Desc("Has to be defined here and in weapons.yaml.")]
|
||||
public readonly string Weapon = null;
|
||||
public readonly string Turret = "primary";
|
||||
[Desc("Move the turret backwards when firing.")]
|
||||
public readonly int LegacyRecoil = 0;
|
||||
[Desc("Time (in frames) until the weapon can fire again.")]
|
||||
public readonly int FireDelay = 0;
|
||||
|
||||
|
||||
@@ -439,6 +439,12 @@
|
||||
<Compile Include="Render\WithTurret.cs" />
|
||||
<Compile Include="Widgets\Logic\AssetBrowserLogic.cs" />
|
||||
<Compile Include="Widgets\Logic\ConvertGameFilesLogic.cs" />
|
||||
<Compile Include="VoxelNormalsPalette.cs" />
|
||||
<Compile Include="Render\RenderVoxels.cs" />
|
||||
<Compile Include="Render\WithVoxelTurret.cs" />
|
||||
<Compile Include="Render\WithVoxelBody.cs" />
|
||||
<Compile Include="Render\WithVoxelBarrel.cs" />
|
||||
<Compile Include="Render\WithVoxelWalkerBody.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
|
||||
|
||||
85
OpenRA.Mods.RA/Render/RenderVoxels.cs
Executable file
85
OpenRA.Mods.RA/Render/RenderVoxels.cs
Executable file
@@ -0,0 +1,85 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
public class RenderVoxelsInfo : ITraitInfo, Requires<IBodyOrientationInfo>
|
||||
{
|
||||
[Desc("Defaults to the actor name.")]
|
||||
public readonly string Image = null;
|
||||
|
||||
[Desc("Custom palette name")]
|
||||
public readonly string Palette = null;
|
||||
|
||||
[Desc("Custom PlayerColorPalette: BaseName")]
|
||||
public readonly string PlayerPalette = "player";
|
||||
public readonly string NormalsPalette = "normals";
|
||||
|
||||
[Desc("Change the image size.")]
|
||||
public readonly float Scale = 10;
|
||||
|
||||
public readonly WAngle LightPitch = new WAngle(170); // 60 degrees
|
||||
public readonly WAngle LightYaw = new WAngle(739); // 260 degrees
|
||||
public readonly float[] LightAmbientColor = new float[] {0.6f, 0.6f, 0.6f};
|
||||
public readonly float[] LightDiffuseColor = new float[] {0.4f, 0.4f, 0.4f};
|
||||
|
||||
public virtual object Create(ActorInitializer init) { return new RenderVoxels(init.self, this); }
|
||||
}
|
||||
|
||||
public class RenderVoxels : IRender, INotifyOwnerChanged
|
||||
{
|
||||
Actor self;
|
||||
RenderVoxelsInfo info;
|
||||
List<VoxelAnimation> components = new List<VoxelAnimation>();
|
||||
IBodyOrientation body;
|
||||
WRot camera;
|
||||
WRot lightSource;
|
||||
|
||||
public RenderVoxels(Actor self, RenderVoxelsInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
this.info = info;
|
||||
body = self.Trait<IBodyOrientation>();
|
||||
camera = new WRot(WAngle.Zero, body.CameraPitch - new WAngle(256), new WAngle(256));
|
||||
lightSource = new WRot(WAngle.Zero, info.LightPitch, info.LightYaw - new WAngle(256));
|
||||
}
|
||||
|
||||
bool initializePalettes = true;
|
||||
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) { initializePalettes = true; }
|
||||
|
||||
protected PaletteReference colorPalette, normalsPalette, shadowPalette;
|
||||
public IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
|
||||
{
|
||||
if (initializePalettes)
|
||||
{
|
||||
var paletteName = info.Palette ?? info.PlayerPalette + self.Owner.InternalName;
|
||||
colorPalette = wr.Palette(paletteName);
|
||||
normalsPalette = wr.Palette(info.NormalsPalette);
|
||||
shadowPalette = wr.Palette("shadow");
|
||||
initializePalettes = false;
|
||||
}
|
||||
|
||||
yield return new VoxelRenderable(components, self.CenterPosition, 0, camera, info.Scale,
|
||||
lightSource, info.LightAmbientColor, info.LightDiffuseColor,
|
||||
colorPalette, normalsPalette, shadowPalette);
|
||||
}
|
||||
|
||||
public string Image { get { return info.Image ?? self.Info.Name; } }
|
||||
public void Add(VoxelAnimation v) { components.Add(v); }
|
||||
public void Remove(VoxelAnimation v) { components.Remove(v); }
|
||||
}
|
||||
}
|
||||
75
OpenRA.Mods.RA/Render/WithVoxelBarrel.cs
Executable file
75
OpenRA.Mods.RA/Render/WithVoxelBarrel.cs
Executable file
@@ -0,0 +1,75 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
public class WithVoxelBarrelInfo : ITraitInfo, Requires<RenderVoxelsInfo>
|
||||
{
|
||||
[Desc("Voxel sequence name to use")]
|
||||
public readonly string Sequence = "barrel";
|
||||
[Desc("Armament to use for recoil")]
|
||||
public readonly string Armament = "primary";
|
||||
[Desc("Visual offset")]
|
||||
public readonly WVec LocalOffset = WVec.Zero;
|
||||
|
||||
public object Create(ActorInitializer init) { return new WithVoxelBarrel(init.self, this); }
|
||||
}
|
||||
|
||||
public class WithVoxelBarrel
|
||||
{
|
||||
WithVoxelBarrelInfo info;
|
||||
Actor self;
|
||||
Armament armament;
|
||||
Turreted turreted;
|
||||
IBodyOrientation body;
|
||||
|
||||
public WithVoxelBarrel(Actor self, WithVoxelBarrelInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
this.info = info;
|
||||
body = self.Trait<IBodyOrientation>();
|
||||
armament = self.TraitsImplementing<Armament>()
|
||||
.First(a => a.Info.Name == info.Armament);
|
||||
turreted = self.TraitsImplementing<Turreted>()
|
||||
.First(tt => tt.Name == armament.Info.Turret);
|
||||
|
||||
var rv = self.Trait<RenderVoxels>();
|
||||
rv.Add(new VoxelAnimation(VoxelProvider.GetVoxel(rv.Image, info.Sequence),
|
||||
() => BarrelOffset(), () => BarrelRotation(),
|
||||
() => false, () => 0));
|
||||
}
|
||||
|
||||
WVec BarrelOffset()
|
||||
{
|
||||
var localOffset = info.LocalOffset + new WVec(-armament.Recoil, WRange.Zero, WRange.Zero);
|
||||
var turretOffset = turreted != null ? turreted.Position(self) : WVec.Zero;
|
||||
var turretOrientation = turreted != null ? turreted.LocalOrientation(self) : WRot.Zero;
|
||||
|
||||
var quantizedBody = body.QuantizeOrientation(self, self.Orientation);
|
||||
var quantizedTurret = body.QuantizeOrientation(self, turretOrientation);
|
||||
return turretOffset + body.LocalToWorld(localOffset.Rotate(quantizedTurret).Rotate(quantizedBody));
|
||||
}
|
||||
|
||||
IEnumerable<WRot> BarrelRotation()
|
||||
{
|
||||
var b = self.Orientation;
|
||||
var qb = body.QuantizeOrientation(self, b);
|
||||
yield return turreted.LocalOrientation(self) + WRot.FromYaw(b.Yaw - qb.Yaw);
|
||||
yield return qb;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
OpenRA.Mods.RA/Render/WithVoxelBody.cs
Executable file
47
OpenRA.Mods.RA/Render/WithVoxelBody.cs
Executable file
@@ -0,0 +1,47 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
public class WithVoxelBodyInfo : ITraitInfo, Requires<RenderVoxelsInfo>
|
||||
{
|
||||
public object Create(ActorInitializer init) { return new WithVoxelBody(init.self); }
|
||||
}
|
||||
|
||||
public class WithVoxelBody : IAutoSelectionSize
|
||||
{
|
||||
int2 size;
|
||||
|
||||
public WithVoxelBody(Actor self)
|
||||
{
|
||||
var body = self.Trait<IBodyOrientation>();
|
||||
var rv = self.Trait<RenderVoxels>();
|
||||
|
||||
var voxel = VoxelProvider.GetVoxel(rv.Image, "idle");
|
||||
rv.Add(new VoxelAnimation(voxel, () => WVec.Zero,
|
||||
() => new[]{ body.QuantizeOrientation(self, self.Orientation) },
|
||||
() => false, () => 0));
|
||||
|
||||
// Selection size
|
||||
var rvi = self.Info.Traits.Get<RenderVoxelsInfo>();
|
||||
var s = (int)(rvi.Scale*voxel.Size.Aggregate(Math.Max));
|
||||
size = new int2(s, s);
|
||||
}
|
||||
|
||||
public int2 SelectionSize(Actor self) { return size; }
|
||||
}
|
||||
}
|
||||
58
OpenRA.Mods.RA/Render/WithVoxelTurret.cs
Executable file
58
OpenRA.Mods.RA/Render/WithVoxelTurret.cs
Executable file
@@ -0,0 +1,58 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
public class WithVoxelTurretInfo : ITraitInfo, Requires<RenderVoxelsInfo>
|
||||
{
|
||||
[Desc("Voxel sequence name to use")]
|
||||
public readonly string Sequence = "turret";
|
||||
|
||||
[Desc("Turreted 'Turret' key to display")]
|
||||
public readonly string Turret = "primary";
|
||||
|
||||
public object Create(ActorInitializer init) { return new WithVoxelTurret(init.self, this); }
|
||||
}
|
||||
|
||||
public class WithVoxelTurret
|
||||
{
|
||||
Actor self;
|
||||
Turreted turreted;
|
||||
IBodyOrientation body;
|
||||
|
||||
public WithVoxelTurret(Actor self, WithVoxelTurretInfo info)
|
||||
{
|
||||
this.self = self;
|
||||
body = self.Trait<IBodyOrientation>();
|
||||
turreted = self.TraitsImplementing<Turreted>()
|
||||
.First(tt => tt.Name == info.Turret);
|
||||
|
||||
var rv = self.Trait<RenderVoxels>();
|
||||
rv.Add(new VoxelAnimation(VoxelProvider.GetVoxel(rv.Image, info.Sequence),
|
||||
() => turreted.Position(self), () => TurretRotation(),
|
||||
() => false, () => 0));
|
||||
}
|
||||
|
||||
IEnumerable<WRot> TurretRotation()
|
||||
{
|
||||
var b = self.Orientation;
|
||||
var qb = body.QuantizeOrientation(self, b);
|
||||
yield return turreted.LocalOrientation(self) + WRot.FromYaw(b.Yaw - qb.Yaw);
|
||||
yield return qb;
|
||||
}
|
||||
}
|
||||
}
|
||||
69
OpenRA.Mods.RA/Render/WithVoxelWalkerBody.cs
Executable file
69
OpenRA.Mods.RA/Render/WithVoxelWalkerBody.cs
Executable file
@@ -0,0 +1,69 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.RA.Move;
|
||||
using OpenRA.Traits;
|
||||
|
||||
namespace OpenRA.Mods.RA.Render
|
||||
{
|
||||
public class WithVoxelWalkerBodyInfo : ITraitInfo, Requires<RenderVoxelsInfo>, Requires<MobileInfo>
|
||||
{
|
||||
public readonly int TickRate = 5;
|
||||
public object Create(ActorInitializer init) { return new WithVoxelWalkerBody(init.self, this); }
|
||||
}
|
||||
|
||||
public class WithVoxelWalkerBody : IAutoSelectionSize, ITick
|
||||
{
|
||||
WithVoxelWalkerBodyInfo info;
|
||||
Mobile mobile;
|
||||
int2 size;
|
||||
uint tick, frame, frames;
|
||||
|
||||
public WithVoxelWalkerBody(Actor self, WithVoxelWalkerBodyInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
mobile = self.Trait<Mobile>();
|
||||
|
||||
var body = self.Trait<IBodyOrientation>();
|
||||
var rv = self.Trait<RenderVoxels>();
|
||||
|
||||
var voxel = VoxelProvider.GetVoxel(rv.Image, "idle");
|
||||
frames = voxel.Frames;
|
||||
rv.Add(new VoxelAnimation(voxel, () => WVec.Zero,
|
||||
() => new[]{ body.QuantizeOrientation(self, self.Orientation) },
|
||||
() => false, () => frame));
|
||||
|
||||
// Selection size
|
||||
var rvi = self.Info.Traits.Get<RenderVoxelsInfo>();
|
||||
var s = (int)(rvi.Scale*voxel.Size.Aggregate(Math.Max));
|
||||
size = new int2(s, s);
|
||||
}
|
||||
|
||||
public int2 SelectionSize(Actor self) { return size; }
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (mobile.IsMoving)
|
||||
tick++;
|
||||
|
||||
if (tick < info.TickRate)
|
||||
return;
|
||||
|
||||
tick = 0;
|
||||
if (++frame == frames)
|
||||
frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
347
OpenRA.Mods.RA/VoxelNormalsPalette.cs
Normal file
347
OpenRA.Mods.RA/VoxelNormalsPalette.cs
Normal file
@@ -0,0 +1,347 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
|
||||
* This file is part of OpenRA, which is free software. It is made
|
||||
* available to you under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation. For more information,
|
||||
* see COPYING.
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Traits;
|
||||
using OpenRA.Graphics;
|
||||
|
||||
namespace OpenRA.Mods.RA
|
||||
{
|
||||
public class VoxelNormalsPaletteInfo : ITraitInfo
|
||||
{
|
||||
public readonly string Name = "normals";
|
||||
public readonly NormalType Type = NormalType.TiberianSun;
|
||||
|
||||
public object Create(ActorInitializer init) { return new VoxelNormalsPalette(this); }
|
||||
}
|
||||
|
||||
public class VoxelNormalsPalette : IPalette
|
||||
{
|
||||
readonly VoxelNormalsPaletteInfo info;
|
||||
|
||||
public VoxelNormalsPalette(VoxelNormalsPaletteInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public void InitPalette(WorldRenderer wr)
|
||||
{
|
||||
// Rotate vectors to expected orientation
|
||||
// Voxel coordinates are x=forward, y=right, z=up
|
||||
var channel = new int[] {2,1,0};
|
||||
var n = info.Type == NormalType.RedAlert2 ? RA2Normals : TSNormals;
|
||||
|
||||
// Map normals into color range
|
||||
// Introduces a maximum error of ~0.5%
|
||||
var data = new uint[256];
|
||||
for (var i = 0; i < n.Length / 3; i++)
|
||||
{
|
||||
data[i] = 0xFF000000;
|
||||
for (int j = 0; j < 3; j++)
|
||||
{
|
||||
var t = (n[3*i + j] + 1) / 2;
|
||||
data[i] |= (uint)((byte)(t*0xFF + 0.5) << (8*channel[j]));
|
||||
}
|
||||
}
|
||||
|
||||
wr.AddPalette(info.Name, new Palette(data), false);
|
||||
}
|
||||
|
||||
// Normal vector tables from http://www.sleipnirstuff.com/forum/viewtopic.php?t=8048
|
||||
static readonly float[] TSNormals =
|
||||
{
|
||||
0.671214f, 0.198492f, -0.714194f,
|
||||
0.269643f, 0.584394f, -0.765360f,
|
||||
-0.040546f, 0.096988f, -0.994459f,
|
||||
-0.572428f, -0.091914f, -0.814787f,
|
||||
-0.171401f, -0.572710f, -0.801639f,
|
||||
0.362557f, -0.302999f, -0.881331f,
|
||||
0.810347f, -0.348972f, -0.470698f,
|
||||
0.103962f, 0.938672f, -0.328767f,
|
||||
-0.324047f, 0.587669f, -0.741376f,
|
||||
-0.800865f, 0.340461f, -0.492647f,
|
||||
-0.665498f, -0.590147f, -0.456989f,
|
||||
0.314767f, -0.803002f, -0.506073f,
|
||||
0.972629f, 0.151076f, -0.176550f,
|
||||
0.680291f, 0.684236f, -0.262727f,
|
||||
-0.520079f, 0.827777f, -0.210483f,
|
||||
-0.961644f, -0.179001f, -0.207847f,
|
||||
-0.262714f, -0.937451f, -0.228401f,
|
||||
0.219707f, -0.971301f, 0.091125f,
|
||||
0.923808f, -0.229975f, 0.306087f,
|
||||
-0.082489f, 0.970660f, 0.225866f,
|
||||
-0.591798f, 0.696790f, 0.405289f,
|
||||
-0.925296f, 0.366601f, 0.097111f,
|
||||
-0.705051f, -0.687775f, 0.172828f,
|
||||
0.732400f, -0.680367f, -0.026305f,
|
||||
0.855162f, 0.374582f, 0.358311f,
|
||||
0.473006f, 0.836480f, 0.276705f,
|
||||
-0.097617f, 0.654112f, 0.750072f,
|
||||
-0.904124f, -0.153725f, 0.398658f,
|
||||
-0.211916f, -0.858090f, 0.467732f,
|
||||
0.500227f, -0.674408f, 0.543091f,
|
||||
0.584539f, -0.110249f, 0.803841f,
|
||||
0.437373f, 0.454644f, 0.775889f,
|
||||
-0.042441f, 0.083318f, 0.995619f,
|
||||
-0.596251f, 0.220132f, 0.772028f,
|
||||
-0.506455f, -0.396977f, 0.765449f,
|
||||
0.070569f, -0.478474f, 0.875262f
|
||||
};
|
||||
|
||||
static readonly float[] RA2Normals =
|
||||
{
|
||||
0.526578f, -0.359621f, -0.770317f,
|
||||
0.150482f, 0.435984f, 0.887284f,
|
||||
0.414195f, 0.738255f, -0.532374f,
|
||||
0.075152f, 0.916249f, -0.393498f,
|
||||
-0.316149f, 0.930736f, -0.183793f,
|
||||
-0.773819f, 0.623334f, -0.112510f,
|
||||
-0.900842f, 0.428537f, -0.069568f,
|
||||
-0.998942f, -0.010971f, 0.044665f,
|
||||
-0.979761f, -0.157670f, -0.123324f,
|
||||
-0.911274f, -0.362371f, -0.195620f,
|
||||
-0.624069f, -0.720941f, -0.301301f,
|
||||
-0.310173f, -0.809345f, -0.498752f,
|
||||
0.146613f, -0.815819f, -0.559414f,
|
||||
-0.716516f, -0.694356f, -0.066888f,
|
||||
0.503972f, -0.114202f, -0.856137f,
|
||||
0.455491f, 0.872627f, -0.176211f,
|
||||
-0.005010f, -0.114373f, -0.993425f,
|
||||
-0.104675f, -0.327701f, -0.938965f,
|
||||
0.560412f, 0.752589f, -0.345756f,
|
||||
-0.060576f, 0.821628f, -0.566796f,
|
||||
-0.302341f, 0.797007f, -0.522847f,
|
||||
-0.671543f, 0.670740f, -0.314863f,
|
||||
-0.778401f, -0.128357f, 0.614505f,
|
||||
-0.924050f, 0.278382f, -0.261985f,
|
||||
-0.699773f, -0.550491f, -0.455278f,
|
||||
-0.568248f, -0.517189f, -0.640008f,
|
||||
0.054098f, -0.932864f, -0.356143f,
|
||||
0.758382f, 0.572893f, -0.310888f,
|
||||
0.003620f, 0.305026f, -0.952337f,
|
||||
-0.060850f, -0.986886f, -0.149511f,
|
||||
0.635230f, 0.045478f, -0.770983f,
|
||||
0.521705f, 0.241309f, -0.818287f,
|
||||
0.269404f, 0.635425f, -0.723641f,
|
||||
0.045676f, 0.672754f, -0.738455f,
|
||||
-0.180511f, 0.674657f, -0.715719f,
|
||||
-0.397131f, 0.636640f, -0.661042f,
|
||||
-0.552004f, 0.472515f, -0.687038f,
|
||||
-0.772170f, 0.083090f, -0.629960f,
|
||||
-0.669819f, -0.119533f, -0.732840f,
|
||||
-0.540455f, -0.318444f, -0.778782f,
|
||||
-0.386135f, -0.522789f, -0.759994f,
|
||||
-0.261466f, -0.688567f, -0.676395f,
|
||||
-0.019412f, -0.696103f, -0.717680f,
|
||||
0.303569f, -0.481844f, -0.821993f,
|
||||
0.681939f, -0.195129f, -0.704900f,
|
||||
-0.244889f, -0.116562f, -0.962519f,
|
||||
0.800759f, -0.022979f, -0.598546f,
|
||||
-0.370275f, 0.095584f, -0.923991f,
|
||||
-0.330671f, -0.326578f, -0.885440f,
|
||||
-0.163220f, -0.527579f, -0.833679f,
|
||||
0.126390f, -0.313146f, -0.941257f,
|
||||
0.349548f, -0.272226f, -0.896498f,
|
||||
0.239918f, -0.085825f, -0.966992f,
|
||||
0.390845f, 0.081537f, -0.916838f,
|
||||
0.255267f, 0.268697f, -0.928785f,
|
||||
0.146245f, 0.480438f, -0.864749f,
|
||||
-0.326016f, 0.478456f, -0.815349f,
|
||||
-0.469682f, -0.112519f, -0.875636f,
|
||||
0.818440f, -0.258520f, -0.513151f,
|
||||
-0.474318f, 0.292238f, -0.830433f,
|
||||
0.778943f, 0.395842f, -0.486371f,
|
||||
0.624094f, 0.393773f, -0.674870f,
|
||||
0.740886f, 0.203834f, -0.639953f,
|
||||
0.480217f, 0.565768f, -0.670297f,
|
||||
0.380930f, 0.424535f, -0.821378f,
|
||||
-0.093422f, 0.501124f, -0.860318f,
|
||||
-0.236485f, 0.296198f, -0.925387f,
|
||||
-0.131531f, 0.093959f, -0.986849f,
|
||||
-0.823562f, 0.295777f, -0.484006f,
|
||||
0.611066f, -0.624304f, -0.486664f,
|
||||
0.069496f, -0.520330f, -0.851133f,
|
||||
0.226522f, -0.664879f, -0.711775f,
|
||||
0.471308f, -0.568904f, -0.673957f,
|
||||
0.388425f, -0.742624f, -0.545560f,
|
||||
0.783675f, -0.480729f, -0.393385f,
|
||||
0.962394f, 0.135676f, -0.235349f,
|
||||
0.876607f, 0.172034f, -0.449406f,
|
||||
0.633405f, 0.589793f, -0.500941f,
|
||||
0.182276f, 0.800658f, -0.570721f,
|
||||
0.177003f, 0.764134f, 0.620297f,
|
||||
-0.544016f, 0.675515f, -0.497721f,
|
||||
-0.679297f, 0.286467f, -0.675642f,
|
||||
-0.590391f, 0.091369f, -0.801929f,
|
||||
-0.824360f, -0.133124f, -0.550189f,
|
||||
-0.715794f, -0.334542f, -0.612961f,
|
||||
0.174286f, -0.892484f, 0.416049f,
|
||||
-0.082528f, -0.837123f, -0.540753f,
|
||||
0.283331f, -0.880874f, -0.379189f,
|
||||
0.675134f, -0.426627f, -0.601817f,
|
||||
0.843720f, -0.512335f, -0.160156f,
|
||||
0.977304f, -0.098556f, -0.187520f,
|
||||
0.846295f, 0.522672f, -0.102947f,
|
||||
0.677141f, 0.721325f, -0.145501f,
|
||||
0.320965f, 0.870892f, -0.372194f,
|
||||
-0.178978f, 0.911533f, -0.370236f,
|
||||
-0.447169f, 0.826701f, -0.341474f,
|
||||
-0.703203f, 0.496328f, -0.509081f,
|
||||
-0.977181f, 0.063563f, -0.202674f,
|
||||
-0.878170f, -0.412938f, 0.241455f,
|
||||
-0.835831f, -0.358550f, -0.415728f,
|
||||
-0.499174f, -0.693433f, -0.519592f,
|
||||
-0.188789f, -0.923753f, -0.333225f,
|
||||
0.192254f, -0.969361f, -0.152896f,
|
||||
0.515940f, -0.783907f, -0.345392f,
|
||||
0.905925f, -0.300952f, -0.297871f,
|
||||
0.991112f, -0.127746f, 0.037107f,
|
||||
0.995135f, 0.098424f, -0.004383f,
|
||||
0.760123f, 0.646277f, 0.067367f,
|
||||
0.205221f, 0.959580f, -0.192591f,
|
||||
-0.042750f, 0.979513f, -0.196791f,
|
||||
-0.438017f, 0.898927f, 0.008492f,
|
||||
-0.821994f, 0.480785f, -0.305239f,
|
||||
-0.899917f, 0.081710f, -0.428337f,
|
||||
-0.926612f, -0.144618f, -0.347096f,
|
||||
-0.793660f, -0.557792f, -0.242839f,
|
||||
-0.431350f, -0.847779f, -0.308558f,
|
||||
-0.005492f, -0.965000f, 0.262193f,
|
||||
0.587905f, -0.804026f, -0.088940f,
|
||||
0.699493f, -0.667686f, -0.254765f,
|
||||
0.889303f, 0.359795f, -0.282291f,
|
||||
0.780972f, 0.197037f, 0.592672f,
|
||||
0.520121f, 0.506696f, 0.687557f,
|
||||
0.403895f, 0.693961f, 0.596060f,
|
||||
-0.154983f, 0.899236f, 0.409090f,
|
||||
-0.657338f, 0.537168f, 0.528543f,
|
||||
-0.746195f, 0.334091f, 0.575827f,
|
||||
-0.624952f, -0.049144f, 0.779115f,
|
||||
0.318141f, -0.254715f, 0.913185f,
|
||||
-0.555897f, 0.405294f, 0.725752f,
|
||||
-0.794434f, 0.099406f, 0.599160f,
|
||||
-0.640361f, -0.689463f, 0.338495f,
|
||||
-0.126713f, -0.734095f, 0.667120f,
|
||||
0.105457f, -0.780817f, 0.615795f,
|
||||
0.407993f, -0.480916f, 0.776055f,
|
||||
0.695136f, -0.545120f, 0.468647f,
|
||||
0.973191f, -0.006489f, 0.229908f,
|
||||
0.946894f, 0.317509f, -0.050799f,
|
||||
0.563583f, 0.825612f, 0.027183f,
|
||||
0.325773f, 0.945423f, 0.006949f,
|
||||
-0.171821f, 0.985097f, -0.007815f,
|
||||
-0.670441f, 0.739939f, 0.054769f,
|
||||
-0.822981f, 0.554962f, 0.121322f,
|
||||
-0.966193f, 0.117857f, 0.229307f,
|
||||
-0.953769f, -0.294704f, 0.058945f,
|
||||
-0.864387f, -0.502728f, -0.010015f,
|
||||
-0.530609f, -0.842006f, -0.097366f,
|
||||
-0.162618f, -0.984075f, 0.071772f,
|
||||
0.081447f, -0.996011f, 0.036439f,
|
||||
0.745984f, -0.665963f, 0.000762f,
|
||||
0.942057f, -0.329269f, -0.064106f,
|
||||
0.939702f, -0.281090f, 0.194803f,
|
||||
0.771214f, 0.550670f, 0.319363f,
|
||||
0.641348f, 0.730690f, 0.234021f,
|
||||
0.080682f, 0.996691f, 0.009879f,
|
||||
-0.046725f, 0.976643f, 0.209725f,
|
||||
-0.531076f, 0.821001f, 0.209562f,
|
||||
-0.695815f, 0.655990f, 0.292435f,
|
||||
-0.976122f, 0.216709f, -0.014913f,
|
||||
-0.961661f, -0.144129f, 0.233314f,
|
||||
-0.772084f, -0.613647f, 0.165299f,
|
||||
-0.449600f, -0.836060f, 0.314426f,
|
||||
-0.392700f, -0.914616f, 0.096247f,
|
||||
0.390589f, -0.919470f, 0.044890f,
|
||||
0.582529f, -0.799198f, 0.148127f,
|
||||
0.866431f, -0.489812f, 0.096864f,
|
||||
0.904587f, 0.111498f, 0.411450f,
|
||||
0.953537f, 0.232330f, 0.191806f,
|
||||
0.497311f, 0.770803f, 0.398177f,
|
||||
0.194066f, 0.956320f, 0.218611f,
|
||||
0.422876f, 0.882276f, 0.206797f,
|
||||
-0.373797f, 0.849566f, 0.372174f,
|
||||
-0.534497f, 0.714023f, 0.452200f,
|
||||
-0.881827f, 0.237160f, 0.407598f,
|
||||
-0.904948f, -0.014069f, 0.425289f,
|
||||
-0.751827f, -0.512817f, 0.414458f,
|
||||
-0.501015f, -0.697917f, 0.511758f,
|
||||
-0.235190f, -0.925923f, 0.295555f,
|
||||
0.228983f, -0.953940f, 0.193819f,
|
||||
0.734025f, -0.634898f, 0.241062f,
|
||||
0.913753f, -0.063253f, -0.401316f,
|
||||
0.905735f, -0.161487f, 0.391875f,
|
||||
0.858930f, 0.342446f, 0.380749f,
|
||||
0.624486f, 0.607581f, 0.490777f,
|
||||
0.289264f, 0.857479f, 0.425508f,
|
||||
0.069968f, 0.902169f, 0.425671f,
|
||||
-0.286180f, 0.940700f, 0.182165f,
|
||||
-0.574013f, 0.805119f, -0.149309f,
|
||||
0.111258f, 0.099718f, -0.988776f,
|
||||
-0.305393f, -0.944228f, -0.123160f,
|
||||
-0.601166f, -0.789576f, 0.123163f,
|
||||
-0.290645f, -0.812140f, 0.505919f,
|
||||
-0.064920f, -0.877163f, 0.475785f,
|
||||
0.408301f, -0.862216f, 0.299789f,
|
||||
0.566097f, -0.725566f, 0.391264f,
|
||||
0.839364f, -0.427387f, 0.335869f,
|
||||
0.818900f, -0.041305f, 0.572448f,
|
||||
0.719784f, 0.414997f, 0.556497f,
|
||||
0.881744f, 0.450270f, 0.140659f,
|
||||
0.401823f, -0.898220f, -0.178152f,
|
||||
-0.054020f, 0.791344f, 0.608980f,
|
||||
-0.293774f, 0.763994f, 0.574465f,
|
||||
-0.450798f, 0.610347f, 0.651351f,
|
||||
-0.638221f, 0.186694f, 0.746873f,
|
||||
-0.872870f, -0.257127f, 0.414708f,
|
||||
-0.587257f, -0.521710f, 0.618828f,
|
||||
-0.353658f, -0.641974f, 0.680291f,
|
||||
0.041649f, -0.611273f, 0.790323f,
|
||||
0.348342f, -0.779183f, 0.521087f,
|
||||
0.499167f, -0.622441f, 0.602826f,
|
||||
0.790019f, -0.303831f, 0.532500f,
|
||||
0.660118f, 0.060733f, 0.748702f,
|
||||
0.604921f, 0.294161f, 0.739960f,
|
||||
0.385697f, 0.379346f, 0.841032f,
|
||||
0.239693f, 0.207876f, 0.948332f,
|
||||
0.012623f, 0.258532f, 0.965920f,
|
||||
-0.100557f, 0.457147f, 0.883688f,
|
||||
0.046967f, 0.628588f, 0.776319f,
|
||||
-0.430391f, -0.445405f, 0.785097f,
|
||||
-0.434291f, -0.196228f, 0.879139f,
|
||||
-0.256637f, -0.336867f, 0.905902f,
|
||||
-0.131372f, -0.158910f, 0.978514f,
|
||||
0.102379f, -0.208767f, 0.972592f,
|
||||
0.195687f, -0.450129f, 0.871258f,
|
||||
0.627319f, -0.423148f, 0.653771f,
|
||||
0.687439f, -0.171583f, 0.705682f,
|
||||
0.275920f, -0.021255f, 0.960946f,
|
||||
0.459367f, 0.157466f, 0.874178f,
|
||||
0.285395f, 0.583184f, 0.760556f,
|
||||
-0.812174f, 0.460303f, 0.358461f,
|
||||
-0.189068f, 0.641223f, 0.743698f,
|
||||
-0.338875f, 0.476480f, 0.811252f,
|
||||
-0.920994f, 0.347186f, 0.176727f,
|
||||
0.040639f, 0.024465f, 0.998874f,
|
||||
-0.739132f, -0.353747f, 0.573190f,
|
||||
-0.603512f, -0.286615f, 0.744060f,
|
||||
-0.188676f, -0.547059f, 0.815554f,
|
||||
-0.026045f, -0.397820f, 0.917094f,
|
||||
0.267897f, -0.649041f, 0.712023f,
|
||||
0.518246f, -0.284891f, 0.806386f,
|
||||
0.493451f, -0.066533f, 0.867225f,
|
||||
-0.328188f, 0.140251f, 0.934143f,
|
||||
-0.328188f, 0.140251f, 0.934143f,
|
||||
-0.328188f, 0.140251f, 0.934143f,
|
||||
-0.328188f, 0.140251f, 0.934143f
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -75,11 +75,44 @@ namespace OpenRA.Renderer.Cg
|
||||
Tao.Cg.CgGl.cgGLSetupSampler(param, texture.texture);
|
||||
}
|
||||
|
||||
public void SetVec(string name, float x)
|
||||
{
|
||||
var param = Tao.Cg.Cg.cgGetNamedEffectParameter(effect, name);
|
||||
if (param != IntPtr.Zero)
|
||||
Tao.Cg.CgGl.cgGLSetParameter1f(param, x);
|
||||
}
|
||||
|
||||
public void SetVec(string name, float x, float y)
|
||||
{
|
||||
var param = Tao.Cg.Cg.cgGetNamedEffectParameter(effect, name);
|
||||
if (param != IntPtr.Zero)
|
||||
Tao.Cg.CgGl.cgGLSetParameter2f(param, x, y);
|
||||
}
|
||||
|
||||
public void SetVec(string name, float[] vec, int length)
|
||||
{
|
||||
var param = Tao.Cg.Cg.cgGetNamedEffectParameter(effect, name);
|
||||
if (param == IntPtr.Zero)
|
||||
return;
|
||||
|
||||
switch(length)
|
||||
{
|
||||
case 1: Tao.Cg.CgGl.cgGLSetParameter1fv(param, vec); break;
|
||||
case 2: Tao.Cg.CgGl.cgGLSetParameter2fv(param, vec); break;
|
||||
case 3: Tao.Cg.CgGl.cgGLSetParameter3fv(param, vec); break;
|
||||
case 4: Tao.Cg.CgGl.cgGLSetParameter4fv(param, vec); break;
|
||||
default: throw new InvalidDataException("Invalid vector length");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetMatrix(string name, float[] mtx)
|
||||
{
|
||||
if (mtx.Length != 16)
|
||||
throw new InvalidDataException("Invalid 4x4 matrix");
|
||||
|
||||
var param = Tao.Cg.Cg.cgGetNamedEffectParameter(effect, name);
|
||||
if (param != IntPtr.Zero)
|
||||
Tao.Cg.CgGl.cgGLSetMatrixParameterfr(param, mtx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,6 +141,16 @@ namespace OpenRA.Renderer.Glsl
|
||||
textures[texUnit] = t;
|
||||
}
|
||||
|
||||
public void SetVec(string name, float x)
|
||||
{
|
||||
Gl.glUseProgramObjectARB(program);
|
||||
ErrorHandler.CheckGlError();
|
||||
int param = Gl.glGetUniformLocationARB(program, name);
|
||||
ErrorHandler.CheckGlError();
|
||||
Gl.glUniform1fARB(param,x);
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
|
||||
public void SetVec(string name, float x, float y)
|
||||
{
|
||||
Gl.glUseProgramObjectARB(program);
|
||||
@@ -150,5 +160,33 @@ namespace OpenRA.Renderer.Glsl
|
||||
Gl.glUniform2fARB(param,x,y);
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
|
||||
public void SetVec(string name, float[] vec, int length)
|
||||
{
|
||||
int param = Gl.glGetUniformLocationARB(program, name);
|
||||
ErrorHandler.CheckGlError();
|
||||
switch(length)
|
||||
{
|
||||
case 1: Gl.glUniform1fv(param, 1, vec); break;
|
||||
case 2: Gl.glUniform2fv(param, 1, vec); break;
|
||||
case 3: Gl.glUniform3fv(param, 1, vec); break;
|
||||
case 4: Gl.glUniform4fv(param, 1, vec); break;
|
||||
default: throw new InvalidDataException("Invalid vector length");
|
||||
}
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
|
||||
public void SetMatrix(string name, float[] mtx)
|
||||
{
|
||||
if (mtx.Length != 16)
|
||||
throw new InvalidDataException("Invalid 4x4 matrix");
|
||||
|
||||
Gl.glUseProgramObjectARB(program);
|
||||
ErrorHandler.CheckGlError();
|
||||
int param = Gl.glGetUniformLocationARB(program, name);
|
||||
ErrorHandler.CheckGlError();
|
||||
Gl.glUniformMatrix4fv(param, 1, Gl.GL_FALSE, mtx);
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,12 @@ namespace OpenRA.Renderer.Null
|
||||
public void EnableScissor(int left, int top, int width, int height) { }
|
||||
public void DisableScissor() { }
|
||||
|
||||
public void EnableDepthBuffer() { }
|
||||
public void DisableDepthBuffer() { }
|
||||
|
||||
public void EnableStencilBuffer() { }
|
||||
public void DisableStencilBuffer() { }
|
||||
|
||||
public void Clear() { }
|
||||
public void Present() { }
|
||||
|
||||
@@ -58,8 +64,11 @@ namespace OpenRA.Renderer.Null
|
||||
|
||||
public class NullShader : IShader
|
||||
{
|
||||
public void SetVec(string name, float x) { }
|
||||
public void SetVec(string name, float x, float y) { }
|
||||
public void SetVec(string name, float[] vec, int length) { }
|
||||
public void SetTexture(string param, ITexture texture) { }
|
||||
public void SetMatrix(string param, float[] mtx) { }
|
||||
public void Commit() { }
|
||||
public void Render(Action a) { }
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace OpenRA.Renderer.SdlCommon
|
||||
Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_GREEN_SIZE, 8 );
|
||||
Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_BLUE_SIZE, 8 );
|
||||
Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_ALPHA_SIZE, 0 );
|
||||
Sdl.SDL_GL_SetAttribute( Sdl.SDL_GL_STENCIL_SIZE, 1 );
|
||||
|
||||
int windowFlags = 0;
|
||||
switch (window)
|
||||
@@ -133,6 +134,38 @@ namespace OpenRA.Renderer.SdlCommon
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
|
||||
public void EnableStencilBuffer()
|
||||
{
|
||||
Gl.glClear(Gl.GL_STENCIL_BUFFER_BIT);
|
||||
ErrorHandler.CheckGlError();
|
||||
Gl.glEnable(Gl.GL_STENCIL_TEST);
|
||||
ErrorHandler.CheckGlError();
|
||||
Gl.glStencilFunc(Gl.GL_NOTEQUAL, 1, 1);
|
||||
ErrorHandler.CheckGlError();
|
||||
Gl.glStencilOp(Gl.GL_KEEP, Gl.GL_KEEP, Gl.GL_INCR);
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
|
||||
public void DisableStencilBuffer()
|
||||
{
|
||||
Gl.glDisable(Gl.GL_STENCIL_TEST);
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
|
||||
public void EnableDepthBuffer()
|
||||
{
|
||||
Gl.glClear(Gl.GL_DEPTH_BUFFER_BIT);
|
||||
ErrorHandler.CheckGlError();
|
||||
Gl.glEnable(Gl.GL_DEPTH_TEST);
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
|
||||
public void DisableDepthBuffer()
|
||||
{
|
||||
Gl.glDisable(Gl.GL_DEPTH_TEST);
|
||||
ErrorHandler.CheckGlError();
|
||||
}
|
||||
|
||||
public void EnableScissor(int left, int top, int width, int height)
|
||||
{
|
||||
if (width < 0) width = 0;
|
||||
|
||||
86
cg/vxl.fx
Normal file
86
cg/vxl.fx
Normal file
@@ -0,0 +1,86 @@
|
||||
mat4x4 View;
|
||||
mat4x4 TransformMatrix;
|
||||
float2 PaletteRows;
|
||||
|
||||
float4 LightDirection;
|
||||
float3 AmbientLight, DiffuseLight;
|
||||
|
||||
sampler2D DiffuseTexture = sampler_state {
|
||||
MinFilter = Nearest;
|
||||
MagFilter = Nearest;
|
||||
WrapS = Repeat;
|
||||
WrapT = Repeat;
|
||||
};
|
||||
|
||||
sampler2D Palette = sampler_state {
|
||||
MinFilter = Nearest;
|
||||
MagFilter = Nearest;
|
||||
WrapS = Repeat;
|
||||
WrapT = Repeat;
|
||||
};
|
||||
|
||||
struct VertexIn {
|
||||
float4 Position: POSITION;
|
||||
float4 Tex0: TEXCOORD0;
|
||||
};
|
||||
|
||||
struct VertexOut {
|
||||
float4 Position: POSITION;
|
||||
float2 Tex0: TEXCOORD0;
|
||||
float4 ColorChannel: TEXCOORD1;
|
||||
float4 NormalsChannel: TEXCOORD2;
|
||||
};
|
||||
|
||||
float4 DecodeChannelMask(float x)
|
||||
{
|
||||
if (x > 0)
|
||||
return (x > 0.5f) ? float4(1,0,0,0) : float4(0,1,0,0);
|
||||
else
|
||||
return (x <-0.5f) ? float4(0,0,0,1) : float4(0,0,1,0);
|
||||
}
|
||||
|
||||
VertexOut Simple_vp(VertexIn v) {
|
||||
VertexOut o;
|
||||
o.Position = mul(mul(v.Position, TransformMatrix), View);
|
||||
o.Tex0 = v.Tex0.xy;
|
||||
o.ColorChannel = DecodeChannelMask(v.Tex0.z);
|
||||
o.NormalsChannel = DecodeChannelMask(v.Tex0.w);
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 Simple_fp(VertexOut f) : COLOR0 {
|
||||
float4 x = tex2D(DiffuseTexture, f.Tex0.xy);
|
||||
vec4 color = tex2D(Palette, float2(dot(x, f.ColorChannel), PaletteRows.x));
|
||||
if (color.a < 0.01)
|
||||
discard;
|
||||
|
||||
float4 normal = (2.0*tex2D(Palette, vec2(dot(x, f.NormalsChannel), PaletteRows.y)) - 1.0);
|
||||
float3 intensity = AmbientLight + DiffuseLight*max(dot(normal, LightDirection), 0.0);
|
||||
return float4(intensity*color.rgb, color.a);
|
||||
}
|
||||
|
||||
technique high_quality {
|
||||
pass p0 {
|
||||
BlendEnable = true;
|
||||
DepthTestEnable = true;
|
||||
CullFaceEnable = false;
|
||||
VertexProgram = compile latest Simple_vp();
|
||||
FragmentProgram = compile latest Simple_fp();
|
||||
|
||||
BlendEquation = FuncAdd;
|
||||
BlendFunc = int2(SrcAlpha, OneMinusSrcAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
technique high_quality_cg21 {
|
||||
pass p0 {
|
||||
BlendEnable = true;
|
||||
DepthTestEnable = true;
|
||||
CullFaceEnable = false;
|
||||
VertexProgram = compile arbvp1 Simple_vp();
|
||||
FragmentProgram = compile arbfp1 Simple_fp();
|
||||
|
||||
BlendEquation = FuncAdd;
|
||||
BlendFunc = int2(SrcAlpha, OneMinusSrcAlpha);
|
||||
}
|
||||
}
|
||||
90
cg/vxlshadow.fx
Normal file
90
cg/vxlshadow.fx
Normal file
@@ -0,0 +1,90 @@
|
||||
mat4x4 View;
|
||||
mat4x4 TransformMatrix;
|
||||
float4 LightDirection;
|
||||
float GroundZ;
|
||||
float3 GroundNormal;
|
||||
|
||||
float2 PaletteRows;
|
||||
float3 AmbientLight, DiffuseLight;
|
||||
|
||||
sampler2D DiffuseTexture = sampler_state {
|
||||
MinFilter = Nearest;
|
||||
MagFilter = Nearest;
|
||||
WrapS = Repeat;
|
||||
WrapT = Repeat;
|
||||
};
|
||||
|
||||
sampler2D Palette = sampler_state {
|
||||
MinFilter = Nearest;
|
||||
MagFilter = Nearest;
|
||||
WrapS = Repeat;
|
||||
WrapT = Repeat;
|
||||
};
|
||||
|
||||
struct VertexIn {
|
||||
float4 Position: POSITION;
|
||||
float4 Tex0: TEXCOORD0;
|
||||
};
|
||||
|
||||
struct VertexOut {
|
||||
float4 Position: POSITION;
|
||||
float2 Tex0: TEXCOORD0;
|
||||
float4 ColorChannel: TEXCOORD1;
|
||||
float4 NormalsChannel: TEXCOORD2;
|
||||
};
|
||||
|
||||
float4 DecodeChannelMask(float x)
|
||||
{
|
||||
if (x > 0)
|
||||
return (x > 0.5f) ? float4(1,0,0,0) : float4(0,1,0,0);
|
||||
else
|
||||
return (x <-0.5f) ? float4(0,0,0,1) : float4(0,0,1,0);
|
||||
}
|
||||
|
||||
VertexOut Simple_vp(VertexIn v) {
|
||||
// Distance between vertex and ground
|
||||
float d = dot(v.Position.xyz - float3(0.0,0.0,GroundZ), GroundNormal) / dot(LightDirection.xyz, GroundNormal);
|
||||
float3 shadow = v.Position.xyz - d*LightDirection.xyz;
|
||||
|
||||
VertexOut o;
|
||||
o.Position = mul(mul(vec4(shadow, 1), TransformMatrix), View);
|
||||
o.Tex0 = v.Tex0.xy;
|
||||
o.ColorChannel = DecodeChannelMask(v.Tex0.z);
|
||||
o.NormalsChannel = DecodeChannelMask(v.Tex0.w);
|
||||
return o;
|
||||
}
|
||||
|
||||
float4 Simple_fp(VertexOut f) : COLOR0 {
|
||||
float4 x = tex2D(DiffuseTexture, f.Tex0.xy);
|
||||
vec4 color = tex2D(Palette, float2(dot(x, f.ColorChannel), PaletteRows.x));
|
||||
if (color.a < 0.01)
|
||||
discard;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
technique high_quality {
|
||||
pass p0 {
|
||||
BlendEnable = true;
|
||||
DepthTestEnable = true;
|
||||
CullFaceEnable = false;
|
||||
VertexProgram = compile latest Simple_vp();
|
||||
FragmentProgram = compile latest Simple_fp();
|
||||
|
||||
BlendEquation = FuncAdd;
|
||||
BlendFunc = int2(SrcAlpha, OneMinusSrcAlpha);
|
||||
}
|
||||
}
|
||||
|
||||
technique high_quality_cg21 {
|
||||
pass p0 {
|
||||
BlendEnable = true;
|
||||
DepthTestEnable = true;
|
||||
CullFaceEnable = false;
|
||||
VertexProgram = compile arbvp1 Simple_vp();
|
||||
FragmentProgram = compile arbfp1 Simple_fp();
|
||||
|
||||
BlendEquation = FuncAdd;
|
||||
BlendFunc = int2(SrcAlpha, OneMinusSrcAlpha);
|
||||
}
|
||||
}
|
||||
17
glsl/vxl.frag
Normal file
17
glsl/vxl.frag
Normal file
@@ -0,0 +1,17 @@
|
||||
uniform sampler2D Palette, DiffuseTexture;
|
||||
uniform vec2 PaletteRows;
|
||||
|
||||
uniform vec4 LightDirection;
|
||||
uniform vec3 AmbientLight, DiffuseLight;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 x = texture2D(DiffuseTexture, gl_TexCoord[0].st);
|
||||
vec4 color = texture2D(Palette, vec2(dot(x, gl_TexCoord[1]), PaletteRows.x));
|
||||
if (color.a < 0.01)
|
||||
discard;
|
||||
|
||||
vec4 normal = (2.0*texture2D(Palette, vec2(dot(x, gl_TexCoord[2]), PaletteRows.y)) - 1.0);
|
||||
vec3 intensity = AmbientLight + DiffuseLight*max(dot(normal, LightDirection), 0.0);
|
||||
gl_FragColor = vec4(intensity*color.rgb, color.a);
|
||||
}
|
||||
18
glsl/vxl.vert
Normal file
18
glsl/vxl.vert
Normal file
@@ -0,0 +1,18 @@
|
||||
uniform mat4 View;
|
||||
uniform mat4 TransformMatrix;
|
||||
|
||||
vec4 DecodeChannelMask(float x)
|
||||
{
|
||||
if (x > 0.0)
|
||||
return (x > 0.5) ? vec4(1,0,0,0) : vec4(0,1,0,0);
|
||||
else
|
||||
return (x < -0.5) ? vec4(0,0,0,1) : vec4(0,0,1,0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = View*TransformMatrix*gl_Vertex;
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
gl_TexCoord[1] = DecodeChannelMask(gl_MultiTexCoord0.z);
|
||||
gl_TexCoord[2] = DecodeChannelMask(gl_MultiTexCoord0.w);
|
||||
}
|
||||
12
glsl/vxlshadow.frag
Normal file
12
glsl/vxlshadow.frag
Normal file
@@ -0,0 +1,12 @@
|
||||
uniform sampler2D Palette, DiffuseTexture;
|
||||
uniform vec2 PaletteRows;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 x = texture2D(DiffuseTexture, gl_TexCoord[0].st);
|
||||
vec4 color = texture2D(Palette, vec2(dot(x, gl_TexCoord[1]), PaletteRows.x));
|
||||
if (color.a < 0.01)
|
||||
discard;
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
26
glsl/vxlshadow.vert
Normal file
26
glsl/vxlshadow.vert
Normal file
@@ -0,0 +1,26 @@
|
||||
uniform mat4 View;
|
||||
uniform mat4 TransformMatrix;
|
||||
uniform vec4 LightDirection;
|
||||
uniform float GroundZ;
|
||||
uniform vec3 GroundNormal;
|
||||
|
||||
vec4 DecodeChannelMask(float x)
|
||||
{
|
||||
if (x > 0.0)
|
||||
return (x > 0.5) ? vec4(1,0,0,0) : vec4(0,1,0,0);
|
||||
else
|
||||
return (x < -0.5) ? vec4(0,0,0,1) : vec4(0,0,1,0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Distance between vertex and ground
|
||||
float d = dot(gl_Vertex.xyz - vec3(0.0,0.0,GroundZ), GroundNormal) / dot(LightDirection.xyz, GroundNormal);
|
||||
|
||||
// Project onto ground plane
|
||||
vec3 shadow = gl_Vertex.xyz - d*LightDirection.xyz;
|
||||
gl_Position = View*TransformMatrix*vec4(shadow, 1);
|
||||
gl_TexCoord[0] = gl_MultiTexCoord0;
|
||||
gl_TexCoord[1] = DecodeChannelMask(gl_MultiTexCoord0.z);
|
||||
gl_TexCoord[2] = DecodeChannelMask(gl_MultiTexCoord0.w);
|
||||
}
|
||||
Reference in New Issue
Block a user