Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ode/ode-0.9/contrib/OdeModelProcessor/OdeModelProcessor/OdeModelProcessor.cs @ 216

Last change on this file since 216 was 216, checked in by mathiask, 17 years ago

[Physik] add ode-0.9

File size: 12.0 KB
Line 
1/*
2 * The ODE Model Processor
3 * -----------------------
4 *
5 * Copyright 2007, Department of Information Science,
6 * University of Otago, Dunedin, New Zealand.
7 *
8 * Author: Richard Barrington <barri662@student.otago.ac.nz>
9 *
10 * This is a Content Processor and Tag library written for use with
11 * Microsoft Visual C# 2005 Express Edition and Microsoft XNA Game
12 * Studio Express 1.0.
13 *
14 * It can be used to read .x model vertex and index data before
15 * insertion into the content pipeline. This is used to build ODE
16 * Triangle Meshes which are then used for collision detection that
17 * is more accurate than the default XNA bounding boxes or spheres.
18 *
19 * Usage is simple:
20 * Build the library and reference the DLL in your project.
21 * Add the DLL to the Content Pipeline
22 * Set the content processor for you .x models to OdeModelProcessor.
23 *
24 * Create triangle meshes as follows:
25 * 1) Create a space, but only one for all of models.
26 * 2) Create a triangle data.
27 * 3) Load the model.
28 * 4) Retreive the tag from the model.
29 * 6) Build the triangle mesh by calling d.GeomTriMeshDataBuildSimple.
30 *
31 * Eg:
32 * IntPtr space = d.SimpleSpaceCreate(IntPtr.Zero);
33 * IntPtr triangleData = d.GeomTriMeshDataCreate();
34 * Model obj = content.Load<Model>("Content\\mycube");
35 * OdeTag tag = (OdeTag)obj.Tag;
36 * IntPtr vertexArray = tag.getVertices();
37 * IntPtr indexArray = tag.getIndices();
38 * d.GeomTriMeshDataBuildSimple
39 * (
40 *     triangleData,
41 *     vertexArray, tag.getVertexStride(), tag.getVertexCount(),
42 *     indexArray, tag.getIndexCount(), tag.getIndexStride()
43 * );
44 * IntPtr triangleMesh = d.CreateTriMesh(space, triangleData, null, null, null);
45 *
46 * You can load multiple models and test for collisions with something
47 * like this in the update method:
48 *
49 * d.GeomSetPosition(odeTri1, obj1Position.X, obj1Position.Y, obj1Position.Z);
50 * d.GeomSetPosition(odeTri2, obj2Position.X, obj2Position.Y, obj2Position.Z);
51 * int numberOfContacts = d.Collide(odeTri1, odeTri2, ODE_CONTACTS,
52 *     contactGeom, d.ContactGeom.SizeOf);
53 *
54 * Where odeTri1 and odeTri2 are triangle meshes you've created, obj1Position
55 * and obj2Position are the positions of your rendered models in the scene,
56 * ODE_CONTACTS is a constant defining the maximum number of contacts
57 * to test for, contactGeom is a d.ContactGeom[] of length ODE_CONTACTS.
58 *
59 * If numberOfContacts is greater than 0, you have a collision.
60 *
61 * Other ODE functions such as d.SpaceCollide() also work; see ODE.NET BoxTest.cs.
62 *
63 * This library is free software; you can redistribute it and/or
64 * modify it under the same terms as the ODE and ODE.Net libraries.
65 * Specifically, the terms are one of EITHER:
66 *
67 *   (1) The GNU Lesser General Public License as published by the Free
68 *       Software Foundation; either version 2.1 of the License, or (at
69 *       your option) any later version. The text of the GNU Lesser
70 *       General Public License is included with this library in the
71 *       file LICENSE.TXT.
72 *
73 *   (2) The BSD-style license that is included with this library in
74 *       the file LICENSE-BSD.TXT.
75 *
76 * This library is distributed in the hope that it will be useful,
77 * but WITHOUT ANY WARRANTY; without even the implied warranty of
78 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
79 * LICENSE.TXT and LICENSE-BSD.TXT for more details.
80 *
81 */
82
83using System;
84using System.Collections.Generic;
85using System.Text;
86using Microsoft.Xna.Framework;
87using Microsoft.Xna.Framework.Content;
88using Microsoft.Xna.Framework.Graphics;
89using Microsoft.Xna.Framework.Design;
90using Microsoft.Xna.Framework.Content.Pipeline;
91using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
92using Microsoft.Xna.Framework.Content.Pipeline.Processors;
93using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
94using Ode.NET;
95using System.Runtime.InteropServices;
96
97namespace OdeModelProcessor
98{
99    /*
100     * Container for vertex and index data in a format
101     * that ODE.Net can use
102     */
103    public class OdeTag
104    {
105
106        private float[] vertexData;
107        private int[] indexData;
108        private const int indexStride = (sizeof(int));
109        private const int vertexStride = (3 * sizeof(float));
110
111        /* Constructors */
112        public OdeTag()
113        {
114            vertexData = new float[0];
115            indexData = new int[0];
116        }
117       
118        public OdeTag(float[] vertexData, int[] indexData)
119        {
120            this.vertexData = vertexData;
121            this.indexData = indexData;
122        }
123       
124        /* Data setter */
125        public void setData(float[] vertexData, int[] indexData)
126        {
127            this.vertexData = vertexData;
128            this.indexData = indexData;
129        }
130
131        /* Data appenders */
132        public void appendVertexData(float[] vertexData)
133        {
134            int newVertexDataLength = vertexData.Length;
135            float[] tempVertexArray = new float[newVertexDataLength + this.vertexData.Length];
136            this.vertexData.CopyTo(tempVertexArray, 0);
137            vertexData.CopyTo(tempVertexArray, this.vertexData.Length);
138            this.vertexData = tempVertexArray;
139        }
140
141        public void appendIndexData(int[] indexData)
142        {
143            int newIndexDataLength = indexData.Length;
144            int[] tempIndexArray = new int[newIndexDataLength + this.indexData.Length];
145            this.indexData.CopyTo(tempIndexArray, 0);
146            indexData.CopyTo(tempIndexArray, this.indexData.Length);
147            this.indexData = tempIndexArray;
148        }
149
150        /* Data getters */
151        public float[] getVertexData()
152        {
153            return this.vertexData;
154        }
155
156        public int[] getIndexData()
157        {
158            return this.indexData;
159        }
160
161        /* Native data getters */
162        public IntPtr getVertices()
163        {
164            int count = getVertexData().Length;
165            int memsize = count * Marshal.SizeOf(getVertexData()[0].GetType());
166            IntPtr pointer = Marshal.AllocCoTaskMem(memsize);
167            Marshal.Copy(getVertexData(), 0, pointer, count);
168            return pointer;
169        }
170
171        public IntPtr getIndices()
172        {
173            int count = getIndexData().Length;
174            int memsize = count * Marshal.SizeOf(getIndexData()[0].GetType());
175            IntPtr pointer = Marshal.AllocCoTaskMem(memsize);
176            Marshal.Copy(getIndexData(), 0, pointer, count);
177            return pointer;
178        }
179
180        /* Count getters */
181        public int getVertexCount()
182        {
183            return vertexData.Length/3;
184        }
185
186        public int getIndexCount()
187        {
188            return indexData.Length;
189        }
190
191        /* Stride getters */
192        public int getVertexStride()
193        {
194            return vertexStride;
195        }
196
197        public int getIndexStride()
198        {
199            return indexStride;
200        }
201
202        /*
203         * Convienience method to build the mesh and return it. The triangleData
204         * is passed in to allow the calling application to delete it afterwards.
205         *
206         * Be sure to destroy the returned TriangleMesh in the client application.
207         *
208         * Can't destroy the index and vertex arrays here though, so best to handle
209         * this manually - only use this method if nothing else makes sense.
210         */ 
211        public IntPtr getTriangleMesh(IntPtr space, IntPtr triangleData)
212        {
213            d.GeomTriMeshDataBuildSimple(
214                triangleData,
215                getVertices(), getVertexStride(), getVertexCount(),
216                getIndices(), getIndexCount(), getIndexStride()
217            );
218            return d.CreateTriMesh(space, triangleData, null, null, null);
219        }
220
221    }
222
223    /*
224     * Subclass of the XNA .x model processor, which creates and appends a tag
225     * containing vertex and index data for ODE.Net to use.
226     */ 
227    [ContentProcessor]
228    public class OdeModelProcessor : ModelProcessor
229    {
230        private OdeTag tag;
231        private int indexOffset = 0;
232
233        public override ModelContent Process(NodeContent input, ContentProcessorContext context)
234        {
235            tag = new OdeTag();
236            GenerateVerticesRecursive( input );
237            ModelContent model = base.Process(input, context);
238            model.Tag = tag;
239            indexOffset = 0;
240            return model;
241        }
242
243        public void GenerateVerticesRecursive(NodeContent input)
244        {
245           
246            MeshContent mesh = input as MeshContent;
247           
248            if (mesh != null)
249            {
250                GeometryContentCollection gc = mesh.Geometry;
251                foreach (GeometryContent g in gc)
252                {
253                    VertexContent vc = g.Vertices;
254                    IndirectPositionCollection ipc = vc.Positions;
255                    IndexCollection ic = g.Indices;
256
257                    float[] vertexData = new float[ipc.Count * 3];
258                    for (int i = 0; i < ipc.Count; i++)
259                    {
260                       
261                        Vector3 v0 = ipc[i];
262                        vertexData[(i * 3) + 0] = v0.X;
263                        vertexData[(i * 3) + 1] = v0.Y;
264                        vertexData[(i * 3) + 2] = v0.Z;                       
265                       
266                    }
267
268                    int[] indexData = new int[ic.Count];
269                    for (int j = 0; j < ic.Count; j ++)
270                    {
271
272                        indexData[j] = ic[j] + indexOffset;
273
274                    }
275
276                    tag.appendVertexData(vertexData);
277                    tag.appendIndexData(indexData);
278                    indexOffset += ipc.Count;
279                }
280               
281            }
282
283            foreach (NodeContent child in input.Children)
284            {
285                GenerateVerticesRecursive(child);
286            }
287
288        }
289
290    }
291
292    /* Writer for the OdeTag class */
293    [ContentTypeWriter]
294    public class OdeTagWriter : ContentTypeWriter<OdeTag>
295    {
296
297        protected override void Write(ContentWriter output, OdeTag value)
298        {
299            float[] vertexData = value.getVertexData();
300            int[] indexData = value.getIndexData();
301            output.Write(vertexData.Length);
302            output.Write(indexData.Length);
303            for (int j = 0; j < vertexData.Length; j++)
304            {
305                output.Write(vertexData[j]);
306            }
307            for (int i = 0; i < indexData.Length; i++)
308            {
309                output.Write(indexData[i]);
310            }
311        }
312
313        public override string GetRuntimeType(TargetPlatform targetPlatform)
314        {
315            return typeof(OdeTag).AssemblyQualifiedName;
316        }
317
318        public override string GetRuntimeReader(TargetPlatform targetPlatform)
319        {
320            return "OdeModelProcessor.OdeTagReader, OdeModelProcessor, Version=1.0.0.0, Culture=neutral";
321        }
322
323    }
324
325    /* Reader for the OdeTag class */
326    public class OdeTagReader : ContentTypeReader<OdeTag>
327    {
328        protected override OdeTag Read(ContentReader input, OdeTag existingInstance)
329        {
330            float[] vertexData = new float[input.ReadInt32()];
331            int[] indexData = new int[input.ReadInt32()];
332            for (int j = 0; j < vertexData.Length; j++)
333            {
334                vertexData[j] = input.ReadSingle();
335            }
336            for (int i = 0; i < indexData.Length; i++)
337            {
338                indexData[i] = input.ReadInt32();
339            }
340
341            OdeTag tag = null;
342            if (existingInstance == null)
343            {
344                tag = new OdeTag(vertexData, indexData);
345            }
346            else
347            {
348                tag = existingInstance;
349                tag.setData(vertexData, indexData);
350            }
351            return tag;
352        }
353    }
354}
Note: See TracBrowser for help on using the repository browser.