I've been experimenting in a tool I made, and eventually found out that one of the reasons rendering wasn't working correctly in my client was because when done between a call to SpriteBatch.Begin() and SpriteBatch.End(), meshes end up being transparent.
I fixed this in the client, but meshes were still rendered transparently!
So after messing about some more in the tool I made, it would appear as though having SpriteBatch.Being() and SpriteBatch.End() in the drawingloop at all seems to fuck up rendering... does anyone have any ideas?
And going to XNA 4.0 isn't an option, because XNA 4.0 doesn't support loading BMPs from memory.
Correctly formatted source listing
[color="#0000ff"][color="#0000ff"]
using
System;
using System.Collections.Generic;
using
System.ComponentModel;
using System.Data;
using System.Drawing;
using
System.Text;
using System.Windows.Forms;
using System.IO;
using XNA =
Microsoft.Xna.Framework;
using Microsoft.Xna.Framework;
using
Microsoft.Xna.Framework.Graphics;
using Microsoft.Win32;
namespace XNAWinForms
{
///
<summary>
/// Windows form that inherits from
XNAWinForms and adds the rendering of a simple rotating
triangle
///
/// Author: Iñaki
Ayucar (http://graphicdna.blogspot.com)
/// Date: 14/11/2007
///
/// This
software is distributed "for free" for any non-commercial usage. The software is
provided “as-is.”
/// You bear the risk of using it. The
contributors give no express warranties, guarantees or
conditions.
/// </summary>
public partial class Form1 : XNAWinForm
{
private Outfit
m_CurrentOutfit;
private
Appearance m_CurrentAppearance;
private Skeleton m_Skeleton;
//Defaults to 'adult.skel' unless we are dealing with a dog or
cat.
private Mesh
m_CurrentMesh;
private Texture2D
m_Tex;
bool m_LoadComplete =
false;
private float mRotation =
0f;
private Matrix mViewMat,
mWorldMat, mProjectionMat;
private
BasicEffect mSimpleEffect;
private
VertexPositionNormalTexture[] m_NormVerticies;
private SpriteBatch
m_SBatch;
private Texture2D
m_BackgroundTex;
///
<summary>
///
///
</summary>
public
Form1()
{
InitializeComponent();
this.DeviceResetting += new
XNAWinForm.EmptyEventHandler(mWinForm_DeviceResetting);
this.DeviceReset += new
XNAWinForm.GraphicsDeviceDelegate(mWinForm_DeviceReset);
this.OnFrameRender += new
XNAWinForm.GraphicsDeviceDelegate(mWinForm_OnFrameRender);
this.OnFrameMove += new GraphicsDeviceDelegate(Form1_OnFrameMove);
mViewMat =
mWorldMat = mProjectionMat = Matrix.Identity;
//Check
for the existence of TSO on the user's machine, and get the correct
installation-path.
RegistryKey softwareKey =
Registry.LocalMachine.OpenSubKey("SOFTWARE");
if (Array.Exists(softwareKey.GetSubKeyNames(), delegate(string s) { return
s.CompareTo("Maxis") == 0;
}))
{
RegistryKey maxisKey =
softwareKey.OpenSubKey("Maxis");
if (Array.Exists(maxisKey.GetSubKeyNames(), delegate(string s) { return
s.CompareTo("The Sims Online") == 0;
}))
{
RegistryKey tsoKey = maxisKey.OpenSubKey("The Sims
Online");
string installDir =
(string)tsoKey.GetValue("InstallDir");
installDir += "\\TSOClient\\";
GlobalSettings.Default.StartupPath =
installDir;
}
else
{
MessageBox.Show("Error TSO was not found on your
system.");
Application.Exit();
//TODO: Let user select path
manually...
}
}
else
{
MessageBox.Show("Error: No Maxis products were found on your
system.");
Application.Exit();
}
foreach
(KeyValuePair<ulong, string> Pair in
ContentManager.Resources)
{
if
(Pair.Value.Contains(".po"))
LstHeads.Items.Add(Pair.Value);
}
m_Skeleton
= new Skeleton(ContentManager.GetResourceFromLongID(0x100000005));
LstHeads.SelectedIndexChanged += new
EventHandler(LstHeads_SelectedIndexChanged);
}
///
<summary>
/// User clicked
on an item in the list containing available heads and
bodies.
///
</summary>
private void
LstHeads_SelectedIndexChanged(object sender, EventArgs
e)
{
foreach(KeyValuePair<ulong, string> Pair in
ContentManager.Resources)
{
if ((string)LstHeads.SelectedItem ==
Pair.Value)
{
PurchasableObject PO = new
PurchasableObject(ContentManager.GetResourceFromLongID(Pair.Key));
m_CurrentOutfit = new
Outfit(ContentManager.GetResourceFromLongID(PO.OutfitID));
m_CurrentAppearance = new
Appearance(
ContentManager.GetResourceFromLongID(m_CurrentOutfit.LightAppearanceID));
List<Binding> Bindings = new List<Binding>();
foreach (ulong BindingID in
m_CurrentAppearance.BindingIDs)
Bindings.Add(new Binding(ContentManager.GetResourceFromLongID(BindingID)));
m_Tex = Texture2D.FromFile(this.Device, new
MemoryStream(
ContentManager.GetResourceFromLongID(Bindings[0].TextureAssetID)));
m_CurrentMesh = new
Mesh(ContentManager.GetResourceFromLongID(Bindings[0].MeshAssetID));
LoadMesh(m_CurrentMesh);
//The file selected was most likely a body-mesh, so apply the adult skeleton to
it.
if
(Pair.Value.Contains("bodies"))
{
foreach (Bone Bne in
m_Skeleton.Bones)
{
VertexPositionNormalTexture[] TransformedVerticies =
new VertexPositionNormalTexture[m_CurrentMesh.VertexCount];
foreach (BoneBinding Bnd in
m_CurrentMesh.BoneBindings)
{
if (Bne.ID ==
Bnd.BoneIndex)
{
int Counter = 0;
if (Bnd.FirstVertex !=
-1)
{
for (int i = Bnd.FirstVertex; i < Bnd.VertexCount;
i++)
{
Vector3 TransformedVector =
Vector3.Transform(
m_NormVerticies.Position, new
Quaternion(Bne.Quaternions[0],
Bne.Quaternions[1], Bne.Quaternions[2],
Bne.Quaternions[3]));
TransformedVerticies[Counter].Position = TransformedVector;
//I think these should be transformed as
well.
Vector3 TransformedNormal =
Vector3.Transform(
m_NormVerticies.Normal, new
Quaternion(Bne.Quaternions[0],
Bne.Quaternions[1], Bne.Quaternions[2],
Bne.Quaternions[3]));
TransformedNormal.Normalize();
TransformedVerticies[Counter].Normal = TransformedNormal;
//But you never need to blend the 2d texture coordinates, they are always
the
//same. i.e. some mesh vertices straddle two bones, so they are the weighted
//average of a the vertex attached to one bone, and the vertex attached to the
//other bone. But the texture coordinate of that blended vertex always
//comes from the original, and is not blended.
/*Vector2 TransformedUV =
Vector2.Transform(m_NormVerticies.TextureCoordinate,
new Quaternion(Bne.Quaternions[0], Bne.Quaternions[1],
Bne.Quaternions[2],
Bne.Quaternions[3]));
TransformedVerticies[Counter].TextureCoordinate = TransformedUV;*/
if (m_CurrentMesh.BlendCount >
0)
{
for (int j = Bnd.FirstBlendedVert; j < Bnd.BlendedVertexCount;
j++)
{
m_CurrentMesh.Blend(TransformedVerticies[m_CurrentMesh.Blends[j].OtherVertexIndex].Position,
TransformedVerticies[j +
m_CurrentMesh.TexVertexCount].Position,
ref TransformedVerticies[m_CurrentMesh.Blends[j].OtherVertexIndex], Bne.Quaternions[3]);
}
}
m_NormVerticies = TransformedVerticies[Counter];
Counter++;
}
}
}
}
}
}
m_LoadComplete =
true;
}
}
}
///
<summary>
///
///
</summary>
/// <param
name="pDevice"></param>
private void Form1_OnFrameMove(Microsoft.Xna.Framework.Graphics.GraphicsDevice
pDevice)
{
mRotation +=
0.05f;
this.mWorldMat =
Matrix.CreateRotationY(mRotation);
}
///
<summary>
///
///
</summary>
/// <param
name="pDevice"></param>
private void mWinForm_OnFrameRender(GraphicsDevice
pDevice)
{
m_SBatch.Begin();
m_SBatch.Draw(m_BackgroundTex, new Microsoft.Xna.Framework.Rectangle(0, 0,
m_BackgroundTex.Width,
m_BackgroundTex.Height), Microsoft.Xna.Framework.Graphics.Color.White);
m_SBatch.End();
Device.RenderState.DepthBufferEnable =
true;
Device.RenderState.DepthBufferWriteEnable =
true;
Device.RenderState.AlphaBlendEnable = false;
//
Configure
effect
mSimpleEffect.World =
this.mWorldMat;
mSimpleEffect.View =
this.mViewMat;
mSimpleEffect.Projection = this.mProjectionMat;
if (m_Tex
!= null)
{
mSimpleEffect.Texture =
m_Tex;
mSimpleEffect.TextureEnabled = true;
mSimpleEffect.EnableDefaultLighting();
}
mSimpleEffect.CommitChanges();
//
Draw
mSimpleEffect.Begin();
mSimpleEffect.Techniques[0].Passes[0].Begin();
if
(m_NormVerticies !=
null)
{
if
(m_LoadComplete)
{
foreach (Face Fce in
m_CurrentMesh.Faces)
{
VertexPositionNormalTexture[] Vertex = new
VertexPositionNormalTexture[3];
Vertex[0] =
m_NormVerticies[Fce.AVertexIndex];
Vertex[1] =
m_NormVerticies[Fce.BVertexIndex];
Vertex[2] = m_NormVerticies[Fce.CVertexIndex];
Vertex[0].TextureCoordinate =
m_NormVerticies[Fce.AVertexIndex].TextureCoordinate;
Vertex[1].TextureCoordinate =
m_NormVerticies[Fce.BVertexIndex].TextureCoordinate;
Vertex[2].TextureCoordinate =
m_NormVerticies[Fce.CVertexIndex].TextureCoordinate;
pDevice.DrawUserPrimitives<VertexPositionNormalTexture>(PrimitiveType.TriangleList,
Vertex, 0,
1);
}
}
}
mSimpleEffect.Techniques[0].Passes[0].End();
mSimpleEffect.End();
}
private DepthStencilBuffer
CreateDepthStencil(RenderTarget2D
target)
{
return
new DepthStencilBuffer(target.GraphicsDevice,
target.Width,
target.Height,
target.GraphicsDevice.DepthStencilBuffer.Format,
target.MultiSampleType,
target.MultiSampleQuality);
}
///
<summary>
///
///
</summary>
/// <param
name="pDevice"></param>
private void mWinForm_DeviceReset(GraphicsDevice
pDevice)
{
//
Re-Create
effect
mSimpleEffect = new BasicEffect(pDevice, null);
//
Configure
device
pDevice.VertexDeclaration = new VertexDeclaration(pDevice,
VertexPositionNormalTexture.VertexElements);
//Should this be set to another
setting?
pDevice.RenderState.CullMode = CullMode.None;
// Create
camera and projection
matrix
mWorldMat =
Matrix.Identity;
mViewMat = Matrix.CreateLookAt(Vector3.Right * 5,Vector3.Zero,
Vector3.Forward);
mProjectionMat = Matrix.CreatePerspectiveFieldOfView(MathHelper.Pi /
4.0f,
(float)pDevice.PresentationParameters.BackBufferWidth /
(float)pDevice.PresentationParameters.BackBufferHeight,
1.0f, 100.0f);
m_SBatch =
new
SpriteBatch(Device);
m_BackgroundTex = Texture2D.FromFile(Device, File.Open("sims-online-1.jpg",
FileMode.Open));
}
///
<summary>
///
///
</summary>
private void
mWinForm_DeviceResetting()
{
//
Dispose
all
if
(mSimpleEffect !=
null)
mSimpleEffect.Dispose();
}
private void
openToolStripMenuItem_Click(object sender, EventArgs
e)
{
OpenFileDialog OpenFDiag = new
OpenFileDialog();
OpenFDiag.Filter = "Mesh
file|*.mesh";
OpenFDiag.Title = "Select a mesh to open...";
if
(OpenFDiag.ShowDialog() ==
DialogResult.OK)
{
m_CurrentMesh = new
Mesh(OpenFDiag.FileName);
LoadMesh(m_CurrentMesh);
string TextureName = OpenFDiag.FileName.Replace("meshes",
"textures").Replace("mesh",
"jpg").
Replace("fah", "").Replace("fa", "falgt").Replace("-head-head", "");
m_Tex = Texture2D.FromFile(this.Device,
TextureName);
m_LoadComplete =
true;
}
}
private void LoadMesh(Mesh
MeshToLoad)
{
m_NormVerticies = new VertexPositionNormalTexture[MeshToLoad.VertexCount];
for (int i
= 0; i < MeshToLoad.VertexCount;
i++)
{
m_NormVerticies = new
VertexPositionNormalTexture();
m_NormVerticies.Position.X = MeshToLoad.VertexData[i,
0];
m_NormVerticies.Position.Y = MeshToLoad.VertexData[i,
1];
m_NormVerticies.Position.Z = MeshToLoad.VertexData[i,
2];
m_NormVerticies.Normal.X = MeshToLoad.VertexData[i,
3];
m_NormVerticies.Normal.Y = MeshToLoad.VertexData[i,
4];
m_NormVerticies.Normal.Z = MeshToLoad.VertexData[i, 5];
//Not really sure why this is important, but I think it has something to
do
//with being able to see the
texture.
//m_NormVerticies.Normal.Normalize();
}
for (int i
= 0; i < MeshToLoad.TexVertexCount;
i++)
{
m_NormVerticies.TextureCoordinate.X = MeshToLoad.TextureVertData[i,
1];
m_NormVerticies.TextureCoordinate.Y = MeshToLoad.TextureVertData[i,
2];
}
}
private void
exitToolStripMenuItem_Click(object sender, EventArgs
e)
{
Application.Exit();
}
}
}