Jian's profile星舞PhotosBlogListsMore Tools Help

Blog


    11/14/2008

    XNA学习笔记2

    <描述>载入3D模型,用上下左右方向键操作一个摄像机,已3D模型的中心为圆点的一个球面为运行轨迹,全方位的观察该3D物体。同时在屏幕上显示X,Y,Z三条坐标轴

    /* INFR 1350U Photographic and Image Processing Techniques
    * Assignment Two
    * Submit by: Jian Sun
    * Student ID Number: 100285100
    */

    using System;
    using System.Collections.Generic;
    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Audio;
    using Microsoft.Xna.Framework.Content;
    using Microsoft.Xna.Framework.GamerServices;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;
    using Microsoft.Xna.Framework.Net;
    using Microsoft.Xna.Framework.Storage;

    namespace Sun_as2
    {
        /// <summary>
        /// This is the main type for your game
        /// </summary>
        public class Game1 : Microsoft.Xna.Framework.Game
        {
            GraphicsDeviceManager graphics;
            SpriteBatch spriteBatch;

            Model helicopter;
            Vector3 helicopterPosition = Vector3.Zero;//set the helicopter at the origin of the coordinate system

            Vector3 cameraPosition = new Vector3(0.0f, 0.0f, 45.0f);
            Vector3 cameraLookAt = new Vector3(0.0f, 0.0f, 0.0f); //set the camera's orientation
            Vector3 tempPostition; //this will be stored the camera position after rotate

            Matrix cameraProjectionMatrix; //a projection matrix
            Matrix cameraViewMatrix; //a view matrix

            static float currentVerAng = 0; //set the current vertical angle equals 0
            static float currentHorAng = 0; //set the current horizontal angle equals 0

            //an array to store all points that will be used to draw three lines
            VertexPositionColor[] vertices;
            BasicEffect basicEffect;
            public Game1()
            {
                graphics = new GraphicsDeviceManager(this);
                Content.RootDirectory = "Content";
            }

            /// <summary>
            /// Allows the game to perform any initialization it needs to before starting to run.
            /// This is where it can query for any required services and load any non-graphic
            /// related content.  Calling base.Initialize will enumerate through any components
            /// and initialize them as well.
            /// </summary>
            protected override void Initialize()
            {
               // TODO: Add your initialization logic here

                base.Initialize();
            }

            /// <summary>
            /// LoadContent will be called once per game and is the place to load
            /// all of your content.
            /// </summary>
            protected override void LoadContent()
            {
                // Create a new SpriteBatch, which can be used to draw textures.
                spriteBatch = new SpriteBatch(GraphicsDevice);

                // TODO: use this.Content to load your game content here
                helicopter = Content.Load<Model>("Models\\bell47");//load the model into XNA

               //initialize the camera view matrix
                cameraViewMatrix = Matrix.CreateLookAt(cameraPosition,
                                                      cameraLookAt,
                                                      Vector3.Up);

                //initialize the camera projection matrix
                cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45.0f),  //set the field of view to 45 degree
                    graphics.GraphicsDevice.Viewport.AspectRatio,
                    1.0f,
                    10000.0f);

               //load the vertices, there are total 6 points
                vertices = new VertexPositionColor[6];
                vertices[0] = new VertexPositionColor(Vector3.Zero, Color.Red);
                vertices[1] = new VertexPositionColor(new Vector3(400,0,0), Color.Red); //x-axis is red
                vertices[2] = new VertexPositionColor(Vector3.Zero, Color.Green);
                vertices[3] = new VertexPositionColor(new Vector3(0,400,0), Color.Green); //y-axis is green
                vertices[4] = new VertexPositionColor(Vector3.Zero, Color.Blue);
                vertices[5] = new VertexPositionColor(new Vector3(0,0,400), Color.Blue); //z-axis is blue

                //initalize the basicEffect
              
    basicEffect = new BasicEffect(graphics.GraphicsDevice, null);
                //enable the color
                basicEffect.VertexColorEnabled = true;

            }

           /// <summary>
            /// UnloadContent will be called once per game and is the place to unload
            /// all content.
            /// </summary>
            protected override void UnloadContent()
            {
                // TODO: Unload any non ContentManager content here
            }

            /// <summary>
            /// Allows the game to run logic such as updating the world,
            /// checking for collisions, gathering input, and playing audio.
            /// </summary>
            /// <param name="gameTime">Provides a snapshot of timing values.</param>
            protected override void Update(GameTime gameTime)
            {
                // Allows the game to exit
                if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                    this.Exit();

                // TODO: Add your update logic here
                // Allows the game to exit by pressing 'Q' and 'q' on keyborad

                KeyboardState keys;
                keys = Keyboard.GetState();
                if (keys.IsKeyDown(Keys.Q))
                    this.Exit(); //use a key 'Q' to exit
                if (keys.IsKeyDown(Keys.Up))
                {
                    //if the current vertical angle is large than -80 degree
                    if (currentVerAng >= -80)
                    {
                        currentVerAng -= 5; //update the current vertical angle
                        updateCameraPosition();
                    }
                }
                if (keys.IsKeyDown(Keys.Left))
                {
                    currentHorAng -= 5; //decrease the current horizontal angle means turn left
                    if (currentHorAng < 0 || currentHorAng > 360) //the current horizontal angle must in the range[0,360]
                    {
                        if (currentHorAng < 0)
                            currentHorAng += 360; //if current horizontal angle is negative, plus 360 degree
                        else
                            currentHorAng -= 360; //if current horizontal angle is positive, minus 360 degree
                    }
                    updateCameraPosition();
                }
                if (keys.IsKeyDown(Keys.Right))
                {
                    currentHorAng += 5; //increase the current horizontal angle means turn right
                    if (currentHorAng < 0 || currentHorAng > 360) //the current horizontal angle must in the range[0,360]
                    {
                        if (currentHorAng < 0)
                            currentHorAng += 360; //if current horizontal angle is negative, plus 360 degree
                        else
                            currentHorAng -= 360; //if current horizontal angle is positive, minus 360 degree
                    }
                    updateCameraPosition();
                }
                if (keys.IsKeyDown(Keys.Down))
                {
                   //if the current vertial angle is small than 80
                    if (currentVerAng <= 80)
                    {
                        currentVerAng += 5;
                        updateCameraPosition();
                    }

                }
                base.Update(gameTime);
            }

            //update the position of camera
            void updateCameraPosition()
            {
                tempPostition = Vector3.Transform(cameraPosition, Matrix.CreateRotationX(MathHelper.ToRadians(currentVerAng)));
                tempPostition = Vector3.Transform(tempPostition, Matrix.CreateRotationY(MathHelper.ToRadians(currentHorAng)));
                cameraViewMatrix = Matrix.CreateLookAt(tempPostition, helicopterPosition, Vector3.Up);
            }

            /// <summary>
            /// This is called when the game should draw itself.
            /// </summary>
            /// <param name="gameTime">Provides a snapshot of timing values.</param>
            protected override void Draw(GameTime gameTime)
            {
                graphics.GraphicsDevice.Clear(Color.WhiteSmoke);

                // TODO: Add your drawing code here
                //set up the cameraViewMatrix
                DrawLine();
                DrawModel(helicopter, helicopterPosition);//draw the model
                base.Draw(gameTime);
            }

            //this function is used to draw a 3D cooridnate system
            void DrawLine()
            {
                basicEffect.Begin();//start to draw the 3D coordinate
                foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    basicEffect.World = Matrix.CreateTranslation(Vector3.Zero);
                    basicEffect.View = cameraViewMatrix;
                    basicEffect.Projection = cameraProjectionMatrix;
                    graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(graphics.GraphicsDevice, VertexPositionColor.VertexElements);
                    graphics.GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, vertices, 0, 3);
                    pass.End();
                }
                basicEffect.End();
            }

           //this funtion is used to draw the model and the model's effects
            //it's from the XNA creators online club, 3D game tutorial
            //website link:
    http://creators.xna.com/en-us/education/gettingstarted/bg3d/chapter4
            void DrawModel(Model model, Vector3 modelPosition)
            {
                foreach (ModelMesh mesh in model.Meshes)
                {
                    foreach (BasicEffect effect in mesh.Effects)
                    {
                        effect.EnableDefaultLighting();
                        effect.PreferPerPixelLighting = true;

                        //becasue the origin model is too big, therefore I make it smaller,the rate is 0.05
                        effect.World = Matrix.CreateScale(0.05f) * Matrix.CreateTranslation(modelPosition);
                        effect.Projection = cameraProjectionMatrix;
                        effect.View = cameraViewMatrix;
                    }
                    mesh.Draw();
                }
            }
        }
    }

    Keyframe System

    <描述>动画中插入关键帧,smooth关键帧间的路径

    Keyframe system中运用的vector math:

    <VectorMath.h>

    vector math的实现

    <VectorMath.cpp>

    Keyframe system的头文件

    <Keyframe.h>

    Keyframe system的实现

    <Keyframe.cpp>

    <Keyframe.cpp>

    #include "Keyframe.h"
    #include <iostream>
    #include <math.h>
    using namespace std;

    Keyframe_t *Keyframe_new(vector3_t *position)
    {
        Keyframe_t *key = new Keyframe_t;
        vector3_copy(position, &key->info.position);
        return key;
    }

    /*copy the Keyframe_t k to Keyframe_t result*/
    void Keyframe_copy(Keyframe_t *k, Keyframe_t *result)
    {
        result->info = k->info;
        result->durationMS = k->durationMS;
        result->startMS = k->startMS;   
    }

    void Keyframe_interpolateLinear(Keyframe_t *k1, Keyframe_t *k2, float t, Keyframe_t *result)
    {
        vector3_lerp(&k1->info.position,&k2->info.position,t,&result->info.position); //call a vector3_lerp function to do interpolate linear
    }

    void Keyframe_interpolateCatmullRom(Keyframe_t *k1, Keyframe_t *k2, Keyframe_t *k3, Keyframe_t *k4, float t, Keyframe_t *result)
    {
        vector3_catmullRom(&k1->info.position,&k2->info.position,&k3->info.position,&k4->info.position,t,&result->info.position); //call a vector3_catmullRom to do catmull rom splines interpolation
    }

    KeyframeAnimationSystem_t *KAS_new()
    {
        KeyframeAnimationSystem_t *kas = new KeyframeAnimationSystem_t;
        /* other initialization here */
        kas->currentKeyframe = 0; //initialize the currentKeyframe is 0
        kas->loopFlag = true;
        kas->interpolationMode = INTERPOLATION_CATMULL_ROM;
        kas->isAnimating = false;

        return kas;
    }

    void KAS_toggleInterpolationMode(KeyframeAnimationSystem_t *kas)
    {
       //change the interpolation mode
        if (kas->interpolationMode == INTERPOLATION_LINEAR)
            kas->interpolationMode = INTERPOLATION_CATMULL_ROM;
        else
            kas->interpolationMode = INTERPOLATION_LINEAR;
    }

    void KAS_addKeyframe(KeyframeAnimationSystem_t *kas, Keyframe_t *key)
    {
        kas->keys.push_back(key); //add a keyframe_t key into the vector in keyframeAnimationSystem_t
    }

    void KAS_update(KeyframeAnimationSystem_t *kas, float timeMS)
    {
        kas->currentTimeMS = timeMS;
        //determine the current time is between in which two keys   
        if (kas->keys[kas->currentKeyframe]->startMS <= timeMS && timeMS < kas->keys[kas->currentKeyframe]->startMS+kas->keys[kas->currentKeyframe]->durationMS)
        {
            KAS_interpolate(kas,timeMS,&kas->currentValues);
        }

        else
        {
            //while the current time is out of the range, it means the current key is finished, so switch to next keyframe
            if (kas->currentKeyframe < kas->keys.size()-1) //make sure the currentKeyframe is not over the size of vector list
            {
                KAS_switchToNextKeyframe(kas);
            }
            else
            {
                kas->isAnimating = false;//when the time is finish,the sprite is in the end position, therefore, the isAnimating is false
            }
        }
    }

    void KAS_interpolate(KeyframeAnimationSystem_t *kas, float timeMS, Keyframe_t *result)
    {
        float t;
        t = (timeMS - kas->keys[kas->currentKeyframe]->startMS)/kas->keys[kas->currentKeyframe]->durationMS; //transfer the current time into [0,1]]
        //if the interpolation mode is linear
        if (kas->interpolationMode == INTERPOLATION_LINEAR)
            Keyframe_interpolateLinear(KAS_getCurrentKeyframe(kas),KAS_getNextKeyframe(kas),t,result);
        else
        {
            //recaluate the index value of four points in order to get catmull rom value
            int p0,p1,p2,p3;
            p1 = kas->currentKeyframe;
            p0 = kas->currentKeyframe-1;
            if (p0<0)
                p0 = p1;
            p2 = kas->currentKeyframe+1;
            if (p2 == kas->keys.size())
                p2 = p1;
            p3 = kas->currentKeyframe+2;
            if (p3>=kas->keys.size())
                p3 = p2;

            Keyframe_interpolateCatmullRom(KAS_getKeyframeAtIndex(kas,p0), //the four points in the curve
                                           KAS_getKeyframeAtIndex(kas,p1),
                                           KAS_getKeyframeAtIndex(kas,p2),
                                           KAS_getKeyframeAtIndex(kas,p3),
                                           t,
                                           result);
        }
    }

    void KAS_switchToNextKeyframe(KeyframeAnimationSystem_t *kas)
    {
        kas->currentKeyframe++; //switch to next keyframe
    }

    Keyframe_t *KAS_getNextKeyframe(KeyframeAnimationSystem_t *kas)
    {
        return kas->keys[kas->currentKeyframe+1];//return the pointer of next keyframe   
    }
    Keyframe_t *KAS_getCurrentKeyframe(KeyframeAnimationSystem_t *kas)
    {
        return kas->keys[kas->currentKeyframe];//reture the pointer of current keyframe
    }
    Keyframe_t *KAS_getKeyframeAtIndex(KeyframeAnimationSystem_t *kas, int ind)
    {
        return kas->keys[ind];//return the pointer of keyframe at index ind
    }

    void KAS_setInterpolationMode(KeyframeAnimationSystem_t *kas, int interpolationMode)
    {
        kas->interpolationMode = interpolationMode; //set the interpolation mode equals int interpolationMode
    }

    void KAS_startAnimation(KeyframeAnimationSystem_t *kas, float timeMS)
    {
        kas->startTimeMS = timeMS; //set the start time in the keyframeAnimationSystem_t
    }
    void KAS_stopAnimation(KeyframeAnimationSystem_t *kas)
    {
        kas->isAnimating = false; //stop the animation
    }
    void KAS_toggleAnimation(KeyframeAnimationSystem_t *kas, float timeMS)
    {
        kas->currentTimeMS = timeMS;//set the current time = timeMS
        if (kas->isAnimating)
            kas->isAnimating = false;
        else
            kas->isAnimating = true;//toggle animation
    }

    void KAS_clearAllKeyframes(KeyframeAnimationSystem_t *kas)
    {
        kas->keys.clear(); //clear all elements in the vector keys
    }

    <Keyframe.h>

    #ifndef _KEYFRAME_H
    #define _KEYFRAME_H
    #include <vector>
    #include <algorithm>
    #include "VectorMath.h"
    using namespace std;
    /* this file contains the declarations for functions in a keyframe animation system */
    enum {INTERPOLATION_LINEAR=0, INTERPOLATION_CATMULL_ROM};

    /* the KeyframeInfo struct contains information that is to be used in a single keyframe
       - i.e. note it may contain many types of things */
    typedef struct _KeyframeInfo_t
    {
        vector3_t position;
    }KeyframeInfo_t;

    /* the keyframe contains the information plus other variables you would need
       to define a keyframe animation system
       */
    typedef struct _Keyframe_t
    {
        KeyframeInfo_t info;
        float durationMS;
        float startMS; // set when changing the keyframe to this one
    }Keyframe_t;

    /* The Keyframe Animation System contains a list of keyframes
    * and any other information that is necessary
    * You may add anything else you need to this structure.
    */

    typedef struct _KeyframeAnimationSystem_t
    {
        vector<Keyframe_t*> keys;
        bool loopFlag;  // does the system loop back to the beginning or not
        int currentKeyframe;
        int interpolationMode;
        bool isAnimating;

        float deltaTimeMS; // delta since previous update
        float startTimeMS;
        float currentTimeMS;
        float previousTimeMS; // the previous time update

        Keyframe_t currentValues; // the current interpolated values to be used for drawing purposes
    }KeyframeAnimationSystem_t;

    /* functions needed to implement a keyframe animation system or KAS */

    /* this returns a new keyframe with given position */
    Keyframe_t *Keyframe_new(vector3_t *position);

    /* this returns a new initialized KeyframeAnimationSystem */
    KeyframeAnimationSystem_t *KAS_new();

    /****************************/
    /* Keyframe functions */
    /****************************/

    /*copy keyframe_t k to the keyframe_t result*/
    void Keyframe_copy(Keyframe_t *k, Keyframe_t *result);

    /* interpolation routines for keyframes */
    void Keyframe_interpolateLinear(Keyframe_t *k1, Keyframe_t *k2, float timeMS, Keyframe_t *result);
    void Keyframe_interpolateCatmullRom(Keyframe_t *k1, Keyframe_t *k2, Keyframe_t *k3, Keyframe_t *k4, float timeMS, Keyframe_t *result);

    /***************************/
    /* Keyframe animation system functions */
    /***************************/

    /*switch the current interpolation mode from Linear to Catmull-rom or from Catmull-rom to Linear interpolation*/
    void KAS_toggleInterpolationMode(KeyframeAnimationSystem_t *kas);

    /* add a keyframe to the system */
    void KAS_addKeyframe(KeyframeAnimationSystem_t *kas, Keyframe_t *key);

    /* this updates the keyframe animation given the current time in milliseconds */
    void KAS_update(KeyframeAnimationSystem_t *kas, float timeMS);

    /* this calls the appropriate interpolation routines and returns the interpolated values in result */
    void KAS_interpolate(KeyframeAnimationSystem_t *kas, float timeMS, Keyframe_t *result);

    /* returns the next keyframe in the sequence */
    Keyframe_t *KAS_getNextKeyframe(KeyframeAnimationSystem_t *kas);

    /* this returns the current keyframe */
    Keyframe_t *KAS_getCurrentKeyframe(KeyframeAnimationSystem_t *kas);

    /* this returns a particular keyframe given an index into the array/list */
    Keyframe_t *KAS_getKeyframeAtIndex(KeyframeAnimationSystem_t *kas, int ind);

    /* this just switches the animation to the next keyframe */
    void KAS_switchToNextKeyframe(KeyframeAnimationSystem_t *kas);

    /* easy functions to round out the functionality */

    /* this sets the interpolation mode to be either linear or catmull rom */
    void KAS_setInterpolationMode(KeyframeAnimationSystem_t *kas, int interpolationMode);

    /* this tells the system to start animating and passes in the current time in milliseconds */
    void KAS_startAnimation(KeyframeAnimationSystem_t *kas, float timeMS);

    /* this stops the animation */
    void KAS_stopAnimation(KeyframeAnimationSystem_t *kas);

    /* this toggles the animation, if it was animating, it is now stopped */
    void KAS_toggleAnimation(KeyframeAnimationSystem_t *kas, float timeMS);

    /* this clears all keyframes from the KAS */
    void KAS_clearAllKeyframes(KeyframeAnimationSystem_t *kas);
    #endif

    <VectorMath.cpp>

    #include "VectorMath.h"
    #include <string>
    #include <iostream>
    using namespace std;
    vector3_t *vector3_new(float x, float y, float z)
    {
        vector3_t *v = new vector3_t;
        vector3_set(v,x,y,z);
        return v;
    }

    /* set up a new vector with appropriate values */
    void vector3_set(vector3_t *v, float x, float y, float z)
    {
        v->x = x; //set the float x equals the x value of vector v
        v->y = y; //set the float y equals the y value of vector v
        v->z = z; //set the float z equals the z value of vector v   
    }

    /* vector copy, result = v1 */
    void vector3_copy(vector3_t *v1, vector3_t *result)
    {
        result->x = v1->x; //set the x value in vector result equals the x value of vector v1
        result->y = v1->y; //set the y value in vector result equals the y value of vector v1
        result->z = v1->z; //set the z value in vector result equals the z value of vector v1
    }

    /* returns v1 dot v2 */
    float vector3_dot(vector3_t *v1, vector3_t *v2)
    {
        return v1->x*v2->x+v1->y*v2->y+v1->z*v2->z;//the formula of dot product is x1x2+y1y2+z1z2   
    }

    /* result = v1 x v2 */
    void vector3_cross(vector3_t *v1, vector3_t *v2, vector3_t *result)
    {
        //the formula for corss product is v1 x v2 = <v1y*v2z - v1z*v2y, v1z*v2x - v1x*v2z, v1x*v2y - v1y*v2x>
        result->x = v1->y*v2->z - v1->z*v2->y;
        result->y = v1->z*v2->x - v1->x*v2->z;
        result->z = v1->x*v2->y - v1->y*v2->x;   
    }

    /* result = v1+v2 */
    void vector3_add(vector3_t *v1, vector3_t *v2, vector3_t *result)
    {
        //the formula is result = <v1x+v2x, v1y+v2y, v1z+v2z>
        result->x = v1->x+v2->x;
        result->y = v1->y+v2->y;
        result->z = v1->z+v2->z;
    }

    /* result = v1-v2 */
    void vector3_subtract(vector3_t *v1, vector3_t *v2, vector3_t *result)
    {
       //the formula is result = <v1x-v2x, v1y-v2y, v1z-v2z>
        result->x = v1->x-v2->x;
        result->y = v1->y-v2->y;
        result->z = v1->z-v2->z;
    }

    /* INTERPOLATION ROUTINES */
    void vector3_lerp(vector3_t *v1, vector3_t *v2, float t, vector3_t *result)
    {
        //the formula is result = (1-t)v1 + t*v2
        float t2 = 1 - t;
        result->x = v1->x*t2 + v2->x*t;
        result->y = v1->y*t2 + v2->y*t;
        result->z = v1->z*t2 + v2->z*t;   
    }

    void vector3_catmullRom(vector3_t *v1, vector3_t *v2, vector3_t *v3, vector3_t *v4, float t, vector3_t *result)
    {
        //the formula is p(t) = [t~3,t~2,t,1]*0.5*M*[v1,v2,v3,v4]~t
        result->x = catmullRom1D(-1,2,-1,0,t)*v1->x + catmullRom1D(3,-5,0,2,t)*v2->x + catmullRom1D(-3,4,1,0,t)*v3->x + catmullRom1D(1,-1,0,0,t)*v4->x;
        result->y = catmullRom1D(-1,2,-1,0,t)*v1->y + catmullRom1D(3,-5,0,2,t)*v2->y + catmullRom1D(-3,4,1,0,t)*v3->y + catmullRom1D(1,-1,0,0,t)*v4->y;
        result->z = catmullRom1D(-1,2,-1,0,t)*v1->z + catmullRom1D(3,-5,0,2,t)*v2->z + catmullRom1D(-3,4,1,0,t)*v3->z + catmullRom1D(1,-1,0,0,t)*v4->z;
    }

    float catmullRom1D(float p0, float p1, float p2, float p3, float t)
    {
        //this formula is [t~3, t~2, t, 1] dot product [p0, p1, p2, p3]~t
        return (t*t*t*p0+t*t*p1+t*p2+p3)*0.5f;   
    }
    void vector3_print(vector3_t *v, char *s)
    {
        cout << s<< "["<<v->x<<","<<v->y<<","<<v->z<<"]"<<endl;
    }

    <VectorMath.h>

    #ifndef _VECTOR_MATH_H
    #define _VECTOR_MATH_H
    /* this file contains the function declarations for 3D vector math routines */

    /* a vector contains an x,y,z */
    typedef struct _vector3_t
    {
        float x,y,z;
    }vector3_t;

    /* create a new vector with values (x,y,z) */
    vector3_t *vector3_new(float x, float y, float z);

    /* print a vector to the console */
    void vector3_print(vector3_t *v, char *s);

    /* set values in a vector with (x,y,z) */
    void vector3_set(vector3_t *v, float x, float y, float z);

    /* vector copy, result = v1 */
    void vector3_copy(vector3_t *v1, vector3_t *result);

    /* the scalar/inner/dot product returns v1 dot v2 */
    float vector3_dot(vector3_t *v1, vector3_t *v2);

    /* the cross product, result = v1 x v2 */
    void vector3_cross(vector3_t *v1, vector3_t *v2, vector3_t *result);

    /* vector addition, result = v1+v2 */
    void vector3_add(vector3_t *v1, vector3_t *v2, vector3_t *result);

    /* vector subtraction, result = v1-v2 */
    void vector3_subtract(vector3_t *v1, vector3_t *v2, vector3_t *result);

    /* INTERPOLATION ROUTINES */

    /* lerp is linear interpolation given 2 vectors and a value t betwen 0..1
       result is the linearly interpolated vector
    */

    void vector3_lerp(vector3_t *v1, vector3_t *v2, float t, vector3_t *result);

    /* catmull rom spline interpolation.  Given 4 vectors, and a t-value (between 0..1) result is the interpolated result */
    void vector3_catmullRom(vector3_t *v1, vector3_t *v2, vector3_t *v3, vector3_t *v4, float t, vector3_t *result);

    /* this is a helper function that might be useful for you
       and would compute a single value for a single catmull rom spline
    */
    float catmullRom1D(float p1, float p2, float p3, float p4, float t);

    #endif