forked from gamealgorithms/defense
-
Notifications
You must be signed in to change notification settings - Fork 0
/
PhysicsManager.cs
148 lines (127 loc) · 4.69 KB
/
PhysicsManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
//-----------------------------------------------------------------------------
// The PhysicsManager caches the model space bounding spheres and AABBs
// for all 3D models used in the game.
//
// __Defense Sample for Game Programming Algorithms and Techniques
// Copyright (C) Sanjay Madhav. All rights reserved.
//
// Released under the Microsoft Permissive License.
// See LICENSE.txt for full details.
//-----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace defense
{
public class PhysicsManager : Patterns.Singleton<PhysicsManager>
{
Game m_Game;
SortedList<string, BoundingBox> m_AABBList = new SortedList<string, BoundingBox>();
SortedList<string, BoundingSphere> m_SphereList = new SortedList<string, BoundingSphere>();
public void Start(Game game)
{
m_Game = game;
}
// Get the cached AABB for this model, if it exists. Otherwise generate it.
public BoundingBox GetBoundingBox(string modelName)
{
if (m_AABBList.ContainsKey(modelName))
{
return m_AABBList[modelName];
}
BoundingBox bb = GenerateBoundingBox(modelName);
m_AABBList[modelName] = bb;
return bb;
}
BoundingBox GenerateBoundingBox(string modelName)
{
if (m_Game.Content == null)
{
throw new System.InvalidOperationException("No content manager for BB :(");
}
Model model = m_Game.Content.Load<Model>(modelName);
Matrix[] ModelBones = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(ModelBones);
// Initialize minimum and maximum corners of the bounding box to max and min values
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
// For each mesh of the model
foreach (ModelMesh mesh in model.Meshes)
{
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
// Vertex buffer parameters
int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
int vertexBufferSize = meshPart.NumVertices * vertexStride;
// Get vertex data as float
float[] vertexData = new float[vertexBufferSize / sizeof(float)];
meshPart.VertexBuffer.GetData<float>(vertexData);
// Iterate through each vertex
for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
{
// Transform this by any sub-mesh transform information
Vector3 transformedPosition =
Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]),
ModelBones[mesh.ParentBone.Index]);
min = Vector3.Min(min, transformedPosition);
max = Vector3.Max(max, transformedPosition);
}
}
}
// Create and return bounding box
return new BoundingBox(min, max);
}
// Get the cached BoundingSphere for this model, if it exists. Otherwise generate it.
public BoundingSphere GetBoundingSphere(string modelName)
{
if (m_SphereList.ContainsKey(modelName))
{
return m_SphereList[modelName];
}
BoundingSphere sphere = GenerateBoundingSphere(modelName);
m_SphereList[modelName] = sphere;
return sphere;
}
BoundingSphere GenerateBoundingSphere(string modelName)
{
BoundingSphere modelBounds = new BoundingSphere();
Model model = m_Game.Content.Load<Model>(modelName);
Matrix[] ModelBones = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(ModelBones);
// Initialize initial radius
float radius = 0.0f;
// For each mesh of the model
foreach (ModelMesh mesh in model.Meshes)
{
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
// Vertex buffer parameters
int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
int vertexBufferSize = meshPart.NumVertices * vertexStride;
// Get vertex data as float
float[] vertexData = new float[vertexBufferSize / sizeof(float)];
meshPart.VertexBuffer.GetData<float>(vertexData);
// Iterate through each vertex
for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
{
// Transform this by any sub-mesh transform information
Vector3 transformedPosition =
Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]),
ModelBones[mesh.ParentBone.Index]);
// Get the distance from center to this point, and see if it's a new radius
float dist = Vector3.Distance(Vector3.Zero, transformedPosition);
if (dist > radius)
{
radius = dist;
}
}
}
}
modelBounds.Radius = radius;
return modelBounds;
}
}
}