continued…
public class Prism
{
#region Variables
/// <summary>
/// Number of prism faces
/// </summary>
private int prismSides;
/// <summary>
/// Height of the prism
/// </summary>
private float prismHeight;
/// <summary>
/// Diameter of the prism
/// </summary>
private float prismRadius;
/// <summary>
/// Placeholder for the texture on the sides
/// </summary>
private Texture2D prismSideTexture;
/// <summary>
/// prism BasicEffect
/// </summary>
public BasicEffect effect;
/// <summary>
/// The World Matrix somewhat redundant being here.
/// Now if anything we should provide accessors to set the effect view and projection.
/// </summary>
private Matrix worldMatrix;
#endregion
// Requisite for draw user indexed primitives.
private VertexPositionTexture[] nverts;
private short[] nIndexs;
// Requisite for draw primitives.
private VertexBuffer vertexBuffer;
private IndexBuffer indexBuffer;
/// <summary>
/// Creates and initializes a prism class object at load time.
/// Returns it as desired by the users specifications.
/// this method is static so that you call it like so... Prism p = Prism.Load(..) .
/// </summary>
public static Prism Load(GraphicsDevice device, int nSides, float height, float radius, Texture2D sideTexture)
{
var t = new Prism();
t.prismSides = nSides;
t.prismHeight = height;
t.prismRadius = radius;
t.prismSideTexture = sideTexture;
if (nSides < 3)
t.prismSides = 3;
// you might want decimals and you can probably do this with a scaling matrix in your own vertex shader.
if (height < 1f)
t.prismHeight = 1f;
if (radius < 1f)
t.prismRadius = 1f;
// __________________________________
// moved this all to this load method
//
// All common stuff set up the effect initially.
//
t.effect = new BasicEffect(device);
t.effect.LightingEnabled = false;
t.effect.TextureEnabled = true;
t.effect.Texture = t.prismSideTexture;
// The game itself is really responsible for this not some arbitrary game object.
if (t.worldMatrix == null) { t.worldMatrix = Matrix.Identity; }
float aspectRatio = (float)device.Viewport.Width / device.Viewport.Height;
t.effect.View = Matrix.CreateLookAt(new Vector3(0f, 4f, 0f), Vector3.Zero, Vector3.Up);
t.effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 1.0f, 10.0f);
//
// build the prism
//
t.BuildPrism(device, t.prismSides, t.prismHeight, (int)(t.prismRadius));
// i made this a static load to sort of be like blah forget the constructor.
// so now its time to return the new prism object.
return t;
}
/// <summary>
/// Build the prism
/// </summary>
private void BuildPrism(GraphicsDevice gd, int sides, float height, float radius)
{
//
// Get the vertices into a vertex array.
// Note drawuserindexed primitives can use this.
// However its not really using the vertex buffer this way.
//
nverts = GetPrismVertices(radius, height, sides);
//
// Send a vertex buffer to the device.
// create the buffer, set the vertice array to that buffer, send the buffer to the device.
//
vertexBuffer = new VertexBuffer(gd, VertexPositionTexture.VertexDeclaration, nverts.Length, BufferUsage.None);
vertexBuffer.SetData(nverts);
gd.SetVertexBuffer(vertexBuffer);
//
// set up the index buffer
//
nIndexs = new short[sides * 3 * 2];
int offset = 0;
// first set
for (int i = 2; i < nverts.Length; i++)
{
int i0 = offset + 0;
int i1 = offset + 1;
int i2 = offset + 2;
offset += 3;
short v0 = (short)(0); // vertice [0] holds the up prism point.
short v1 = (short)(i); // each side has 2 points other then top or bottom.
short v2 = (short)(i + 1); // we know all our side points are from 2 to the end.
//
// now towards the end of this loop.
// well wrap that second side vertice around back to vertice [2]
//
if (v2 >= nverts.Length)
{
v2 = 2;
}
// we can control our initial culling order.
// i.e. the way vertices use backface or frontface culling right here.
// So here ill set it to use counter clockwise winding (ccw)
nIndexs[i0] = v0;
nIndexs[i1] = v1;
nIndexs[i2] = v2;
}
// second set
for (int i = 2; i < nverts.Length; i++)
{
int i0 = offset + 0;
int i1 = offset + 1;
int i2 = offset + 2;
offset += 3;
short v0 = (short)(1); // vertice [1] holds the down prism point
short v1 = (short)(i);
short v2 = (short)(i + 1);
if (v2 >= nverts.Length)
{
v2 = 2;
}
// reverse the input ordering to keep the winding counter clockwise
nIndexs[i0] = v1;
nIndexs[i1] = v2;
nIndexs[i2] = v0;
}
indexBuffer = new IndexBuffer(gd, IndexElementSize.SixteenBits, offset + 1, BufferUsage.None);
indexBuffer.SetData(nIndexs);
gd.Indices = indexBuffer;
}
/// <summary>
/// Returns all the vertices the first two indices are the top then bottom points.
/// Followed by all the other vertices points.
/// </summary>
public VertexPositionTexture[] GetPrismVertices(float radius, float height, float nPositions)
{
VertexPositionTexture[] result = new VertexPositionTexture[(int)(nPositions) + 2];
float degrees = 0;
float radians = 0f;
float x;
float z;
float textureU = .5f;
float textureV = 0f;
result[0] = new VertexPositionTexture(Vector3.Up * height, new Vector2(textureU, textureV));
textureV = 1f;
result[1] = new VertexPositionTexture(Vector3.Down * height, new Vector2(textureU, textureV));
textureV = .5f;
for (int i = 0; i < nPositions; i++)
{
degrees = i * (360 / nPositions);
radians = (degrees * ((float)Math.PI / 180));
float sin = (float)(Math.Sin(radians));
float cos = (float)(Math.Cos(radians));
x = radius * sin;
z = radius * cos;
textureU = (i) / (nPositions - 1);
result[i + 2] = new VertexPositionTexture(new Vector3(x, 0f, z), new Vector2(textureU, textureV ));
}
return result;
}
public void Draw(GraphicsDevice device)
{
float aspectRatio = (float)device.Viewport.Width / device.Viewport.Height;
effect.World = worldMatrix;
effect.View = Matrix.CreateLookAt(new Vector3(0f, 0f, 1f), Vector3.Zero, Vector3.Up);
effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(65.0f), aspectRatio, .5f, 1000.0f);
Draw(device, effect.World, effect.View, effect.Projection, true);
}
public void Draw(GraphicsDevice device, Matrix world, Matrix view, Matrix projection, bool useingUserIndexedPrims)
{
int triangleCount = nIndexs.Length / 3;
//World Matrix
effect.World = world;
effect.View = view;
effect.Projection = projection;
effect.CurrentTechnique.Passes[0].Apply();
if (useingUserIndexedPrims)
{
// With DrawUserIndexedPrimitives we can work with the arrays themselves by passing them each frame.
device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, nverts, 0, nverts.Length, nIndexs, 0, triangleCount, VertexPositionTexture.VertexDeclaration);
}
else
{
// set buffers on device
device.Indices = indexBuffer;
device.SetVertexBuffer(vertexBuffer);
// this way actually uses these buffers that we already set onto the device.
device.DrawPrimitives(PrimitiveType.TriangleList, 0, triangleCount);
}
}
}
/// <summary>
/// simple camera class
/// Add one of these objects to your class.
/// </summary>
public class WorldSpaceObject
{
public Matrix world = Matrix.Identity;
/// <summary>
/// This returns the orientation matrix without the translations.
/// I.E this is the local rotations.
/// Typically ignored, it is here for convienience for a shaders.
/// </summary>
public Matrix LocalOrientationMatrix
{
get
{
Matrix m = Matrix.Identity;
m.Forward = world.Forward;
m.Right = world.Right;
m.Up = world.Up;
return m;
}
}
/// <summary>
/// While the rotations are in fact axis angle rotations.
/// About the current objects orientation, we still have a multiplication order.
/// </summary>
public bool UseYawPitchRollToRotate
{
get;
set;
}
public Vector3 Position
{
get { return world.Translation; }
set { world.Translation = value; }
}
public Vector3 Forward
{
get { return world.Forward; }
set { world = Matrix.CreateWorld(world.Translation, value, world.Up); }
}
/// <summary>
/// Move on a dimensional vector axis of the object itself. Note, we dont use the system vectors for this.
/// </summary>
public void Move(Vector3 moveSpeedInEachAxis)
{
var motion =
moveSpeedInEachAxis.X * world.Right +
moveSpeedInEachAxis.Y * world.Up +
moveSpeedInEachAxis.Z * world.Forward
;
Position += motion;
}
/// <summary>
/// We designate the dimensional speed of rotation in dimension x y or z upon a perpendicular axis.
/// We may change the cw or ccw of rotation by using the reverse inverted axis vector. or just negating
/// </summary>
public void Rotate(Vector3 turnSpeedInDimension)
{
Vector3 temp = world.Translation;
if (UseYawPitchRollToRotate)
{
world *=
Matrix.CreateFromAxisAngle(world.Right, turnSpeedInDimension.Y) *
Matrix.CreateFromAxisAngle(world.Up, turnSpeedInDimension.X) *
Matrix.CreateFromAxisAngle(world.Forward, turnSpeedInDimension.Z)
;
Forward = world.Forward;
}
else
{
world *=
Matrix.CreateFromAxisAngle(world.Forward, turnSpeedInDimension.Z) *
Matrix.CreateFromAxisAngle(world.Up, turnSpeedInDimension.X) *
Matrix.CreateFromAxisAngle(world.Right, turnSpeedInDimension.Y)
;
Forward = world.Forward;
}
world.Translation = temp;
}
}
/// <summary>
/// This class takes a world space object to create a view camera. Via CreateCameraViewSpace.
/// You then get a combined world view projection matrix from GetWorldViewProjection.
/// </summary>
public class ViewSpaceCameraObjTransformer
{
private Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, GraphicsDeviceManager.DefaultBackBufferWidth / GraphicsDeviceManager.DefaultBackBufferHeight, .5f, 1000);
private Matrix viewSpace = Matrix.Identity;
private Matrix combinedViewProjection;
/// <summary>
/// This can be used as a camera offset such as for a chase view.
/// </summary>
public Vector3 OffsetPosition
{
get;
set;
}
/// <summary>
/// Creates a camera view space, matrice and stores it.
/// </summary>
public void CreateCameraViewSpace(WorldSpaceObject worldObjectToUseAsCamera)
{
viewSpace = Matrix.CreateLookAt
(
worldObjectToUseAsCamera.Position + OffsetPosition,
worldObjectToUseAsCamera.Forward + (worldObjectToUseAsCamera.Position + OffsetPosition),
worldObjectToUseAsCamera.world.Up
);
combinedViewProjection = viewSpace * projection;
}
/// <summary>
/// Takes a world space object matrice and transforms it.
/// By the view and projection matrixs into screen space.
/// </summary>
public Matrix GetWorldViewProjection(WorldSpaceObject worldObject)
{
return worldObject.world * combinedViewProjection;
}
/// <summary>
/// Get a default projection matrix or set a new one
/// </summary>
public Matrix Projection
{
get
{
return projection;
}
set
{
projection = value;
combinedViewProjection = viewSpace * projection;
}
}
/// <summary>
/// Get a view and projection matrix combined
/// Note you normally use GetWorldViewProjection
/// </summary>
public Matrix ViewProjection
{
get
{
return combinedViewProjection;
}
}
/// <summary>
/// Get a view matrix alone
/// Note you normally use GetWorldViewProjection
/// </summary>
public Matrix View
{
get
{
return viewSpace;
}
}
}
/// <summary>
/// Use keys mouse or what not To move WorldSpaceObjects Around.
/// This could probably be better.
/// </summary>
public class UserInputToOrientWorldObject
{
Vector3 turnOnAxis = Vector3.Zero;
Vector3 moveInAxis = Vector3.Zero;
public float SpeedMovement = .01f;
public float SpeedRotational = .01f;
bool didAnyChangeOccur = false;
public bool HasChangeOccured { get { return didAnyChangeOccur; } }
Vector2 windowcenter = new Vector2(GraphicsDeviceManager.DefaultBackBufferWidth * .5f, GraphicsDeviceManager.DefaultBackBufferHeight * .5f);
KeyboardState keyStates;
MouseState mouseStates;
public Keys KeyMoveRight = Keys.D;
public Keys KeyMoveLeft = Keys.A;
public Keys KeyMoveUp = Keys.W;
public Keys KeyMoveDown = Keys.S;
public Keys KeyMoveForward = Keys.E;
public Keys KeyMoveBack = Keys.Q;
public Keys KeyLookRight = Keys.Right;
public Keys KeyLookLeft = Keys.Left;
public Keys KeyLookUp = Keys.Up;
public Keys KeyLookDown = Keys.Down;
public Keys KeySpinCW = Keys.Z;
public Keys KeySpinCCW = Keys.C;
private bool useMouseLook = false;
// if this is never called will just use the default key assignments
public bool UseMouseLook
{
get { return useMouseLook; }
set
{
if (value)
{
KeyMoveForward = Keys.W;
KeyMoveBack = Keys.S;
// just move them out of the way
KeyMoveUp = Keys.Home;
KeyMoveDown = Keys.PageUp;
}
else
{
KeyMoveRight = Keys.D;
KeyMoveLeft = Keys.A;
KeyMoveUp = Keys.W;
KeyMoveDown = Keys.S;
KeyMoveForward = Keys.E;
KeyMoveBack = Keys.Q;
}
useMouseLook = value;
}
}
public void SetWindowSizeRequiredForMouseLook(GraphicsDevice g)
{
windowcenter = new Vector2(g.Viewport.Width * .5f, g.Viewport.Height * .5f);
}
public void SetWindowSizeRequiredForMouseLook(int width, int height)
{
windowcenter = new Vector2(width * .5f, height * .5f);
}
public WorldSpaceObject UpdateOrientation(WorldSpaceObject worldObj)
{
didAnyChangeOccur = false;
keyStates = Keyboard.GetState();
mouseStates = Mouse.GetState();
if (useMouseLook)
{
MouseLook();
Move();
}
else
{
Rotate();
Move();
}
if (didAnyChangeOccur)
{
worldObj.Move(moveInAxis);
worldObj.Rotate(turnOnAxis);
}
return worldObj;
}
private void Rotate()
{
turnOnAxis = Vector3.Zero;
if (keyStates.IsKeyDown(KeySpinCCW)) // roll ccw
{
turnOnAxis.Z = -SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeySpinCW)) // roll cw
{
turnOnAxis.Z = SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyLookLeft)) // r ccw
{
turnOnAxis.X = SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyLookRight)) // r cw
{
turnOnAxis.X = -SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyLookUp)) // u cw
{
turnOnAxis.Y = SpeedRotational;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyLookDown)) // d ccw
{
turnOnAxis.Y = -SpeedRotational;
didAnyChangeOccur = true;
}
}
private void Move()
{
moveInAxis = Vector3.Zero;
if (keyStates.IsKeyDown(KeyMoveForward)) // Forward
{
moveInAxis.Z = SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveBack)) // back
{
moveInAxis.Z = -SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveLeft)) // left
{
moveInAxis.X = -SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveRight)) // right
{
moveInAxis.X = SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveDown)) // down
{
moveInAxis.Y = -SpeedMovement;
didAnyChangeOccur = true;
}
if (keyStates.IsKeyDown(KeyMoveUp)) // up
{
moveInAxis.Y = SpeedMovement;
didAnyChangeOccur = true;
}
}
private void MouseLook()
{
turnOnAxis = Vector3.Zero;
Vector2 mousePos = new Vector2(mouseStates.Position.X, mouseStates.Position.Y) - windowcenter;
Vector2 mouseAngle = Vector2.Normalize(mousePos);
//if (mouseStates.LeftButton == ButtonState.Pressed)
//{
Matrix r = Matrix.Identity;
mousePos.Normalize();
if (mousePos.Y > 5f)
{
turnOnAxis.Y = SpeedRotational * mouseAngle.Y;
didAnyChangeOccur = true;
}
if (mousePos.Y < 5f)
{
turnOnAxis.Y = SpeedRotational * mouseAngle.Y;
didAnyChangeOccur = true;
}
if (mousePos.X > 5f)
{
turnOnAxis.X = SpeedRotational * mouseAngle.X;
didAnyChangeOccur = true;
}
if (mousePos.X < 5f)
{
turnOnAxis.X = SpeedRotational * mouseAngle.X;
didAnyChangeOccur = true;
}
}
}
} // ends the namespace