⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 model.c

📁 3D游戏场景编辑器
💻 C
📖 第 1 页 / 共 3 页
字号:
/****************************************************************************************/
/*  Model.c                                                                             */
/*                                                                                      */
/*  Author:       Jim Mischel                                                           */
/*  Description:  GenEdit editor model management module                                 */
/*                                                                                      */
/*  The contents of this file are subject to the Genesis3D Public License               */
/*  Version 1.01 (the "License"); you may not use this file except in                   */
/*  compliance with the License. You may obtain a copy of the License at                */
/*  http://www.genesis3d.com                                                            */
/*                                                                                      */
/*  Software distributed under the License is distributed on an "AS IS"                 */
/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */
/*  the License for the specific language governing rights and limitations              */
/*  under the License.                                                                  */
/*                                                                                      */
/*  The Original Code is Genesis3D, released March 25, 1999.                            */
/*Genesis3D Version 1.1 released November 15, 1999                            */
/*  Copyright (C) 1999 WildTangent, Inc. All Rights Reserved           */
/*                                                                                      */
/*  Prepared for GenEdit-Classic ver. 0.5, Dec. 15, 2000								*/
/****************************************************************************************/
#include "model.h"
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include "TypeIO.h"
#include <float.h>
#include "units.h"
#include "ram.h"
#include "util.h"
#include "node.h"
#include "brush.h"
#include <vfile.h>

// Major/minor versions at which motions were introduced
#define MODEL_MOTION_VERSION_MAJOR 1
#define MODEL_MOTION_VERSION_MINOR 5

typedef struct tag_BrushList BrushList;

static const char MODEL_PATH_NAME[] = "PathInfo";

struct tag_Model
{
	int Id;
	char *Name;
	geMotion *pMotion;
	geXForm3d XfmObjectToWorld;
	geBoolean Locked;
	geFloat CurrentKeyTime;

	// information above here is persistent (i.e. stored in file)
	Node *ModelTree;	// mini bsp tree for the model
	geBoolean Animating;
	geBoolean RotationLocked;
};


static Model *Model_Create
	(
	  int id,
	  char const *Name
	)
{
	Model *pModel;

	pModel = (Model *)geRam_Allocate (sizeof (Model));
	if (pModel != NULL)
	{
		pModel->Id = id;
		pModel->Name = Util_Strdup (Name);
		pModel->pMotion = NULL;
		pModel->ModelTree = NULL;
		geXForm3d_SetIdentity (&(pModel->XfmObjectToWorld));
		pModel->Locked = GE_TRUE;
		pModel->CurrentKeyTime = 0.0f;
		pModel->Animating = GE_FALSE;
		pModel->RotationLocked = GE_FALSE;
	}
	return pModel;
}

void Model_CopyStuff
	(
	  Model *pDest,
	  Model const *pSrc
	)
{
	gePath *pSrcPath;
	gePath *pDestPath;
	int iKey;

	assert (pDest != NULL);
	assert (pSrc != NULL);

	pDest->XfmObjectToWorld = pSrc->XfmObjectToWorld;
	pDest->CurrentKeyTime = pSrc->CurrentKeyTime;
		
	// this will force creation of a path
	pDestPath = Model_GetPath (pDest);
	pSrcPath = Model_GetPath ((Model *)pSrc);

	// now get keys for source model and create in destination
	for (iKey = 0; iKey < gePath_GetKeyframeCount (pSrcPath, GE_PATH_TRANSLATION_CHANNEL); ++iKey)
	{
		geXForm3d XfmXlate;
		geXForm3d XfmRotate;
		geFloat Time;

		// get the rotation element
		gePath_GetKeyframe (pSrcPath, iKey, GE_PATH_ROTATION_CHANNEL, &Time, &XfmRotate);

		// get the translation element
		gePath_GetKeyframe (pSrcPath, iKey, GE_PATH_TRANSLATION_CHANNEL, &Time, &XfmXlate);

		XfmRotate.Translation = XfmXlate.Translation;

		gePath_InsertKeyframe (pDestPath, GE_PATH_ALL_CHANNELS, Time, &XfmRotate);
	}

	pDest->RotationLocked = (Model_GetNumKeys (pDest) > 1);
}

Model *Model_Clone 
	(
	  Model *OldModel
	)
{
	Model *NewModel;

	assert (OldModel != NULL);

	NewModel = Model_Create (OldModel->Id, OldModel->Name);
	if (NewModel != NULL)
	{
		Model_CopyStuff (NewModel, OldModel);
	}

	return NewModel;
}

static void Model_Destroy
	(
	  Model **ppModel
	)
{
	Model *pModel;

	assert (ppModel != NULL);
	assert (*ppModel != NULL);

	pModel = *ppModel;
	if (pModel->Name != NULL)
	{
		geRam_Free (pModel->Name);
	}
	if (pModel->pMotion != NULL)
	{
		geMotion_Destroy (&pModel->pMotion);
	}
	if (pModel->ModelTree != NULL)
	{
		Node_ClearBsp(pModel->ModelTree);
	}

	geRam_Free (pModel);
	*ppModel = NULL;
}

geMotion *Model_GetMotion
	(
	  Model const *pModel
	)
{
	assert (pModel != NULL);

	return pModel->pMotion;
}

gePath *Model_GetPath
	(
	  Model *pModel
	)
/*
  Get the path associated with this model.
  Currently, models can have only one path.
  If there's no motion, create it.  If no path, create it.
*/
{
	gePath *pPath;

	assert (pModel != NULL);

	pPath = NULL;

	if (pModel->pMotion == NULL)
	{
		pModel->pMotion = geMotion_Create (GE_TRUE);
	}
	
	if (pModel->pMotion != NULL)
	{
		pPath = geMotion_GetPathNamed (pModel->pMotion, MODEL_PATH_NAME);	// single path, for now
		if (pPath == NULL)
		{
			pPath = gePath_Create (
				GE_PATH_INTERPOLATE_HERMITE, // translational
				GE_PATH_INTERPOLATE_SLERP,	 // rotational
				GE_FALSE);					 // looped flag

			if (pPath != NULL)
			{
				int Index;
				geBoolean rslt;

				rslt = geMotion_AddPath (pModel->pMotion, pPath, MODEL_PATH_NAME, &Index);
				// Path is reference counted, so we have to destroy it.
				gePath_Destroy (&pPath);

				if (rslt != GE_FALSE)
				{
					pPath = geMotion_GetPath (pModel->pMotion, Index);
				}
			}
		}
	}
	return pPath;
}

void Model_AddKeyframe
	(
	  Model *pModel,
	  geFloat Time,
	  geXForm3d const *pXfm
	)
{
	gePath *pPath;

	assert (pModel != NULL);
	assert (pXfm != NULL);

	pPath = Model_GetPath (pModel);
	gePath_InsertKeyframe (pPath, GE_PATH_ALL_CHANNELS, Time, pXfm);
}

void Model_DeleteKeyframe
	(
	  Model *pModel,
	  geFloat Time
	)
{
	gePath *pPath;
	int iKey;
	int KeyframeCount;

	assert (pModel != NULL);

	pPath = Model_GetPath (pModel);


	// Since there's no Path function to get the keyframe for a particular time,
	// we'll iterate the path's keyframes looking for it.  If it doesn't exist,
	// then we'll return GE_FALSE.
	// 
	// Probably should make the search into a utility function at some point.
	KeyframeCount = gePath_GetKeyframeCount (pPath, GE_PATH_ROTATION_CHANNEL);
	for (iKey = 0; iKey < KeyframeCount; ++iKey)
	{
		geFloat kTime;
		geXForm3d XfmRotate;

		gePath_GetKeyframe (pPath, iKey, GE_PATH_ROTATION_CHANNEL, &kTime, &XfmRotate);
		if (fabs (kTime - Time) < 0.0001f)
		{
			gePath_DeleteKeyframe (pPath, iKey, GE_PATH_ALL_CHANNELS);
			return;
		}
	}
}

void Model_AddEvent
	(
	  Model *pModel,
	  geFloat Time,
	  char const *EventString
	)
{
	geMotion *pMotion;

	assert (pModel != NULL);
	assert (EventString != NULL);

	pMotion = Model_GetMotion (pModel);
	assert (pMotion != NULL);		// This has to exist...

	geMotion_InsertEvent (pMotion, Time, EventString);
}

void Model_DeleteEvent
	(
	  Model *pModel,
	  geFloat Time
	)
{
	geMotion *pMotion;

	assert (pModel != NULL);
	
	pMotion = Model_GetMotion (pModel);
	assert (pMotion != NULL);

	geMotion_DeleteEvent (pMotion, Time);
}

int Model_GetId
	(
	  Model const *pModel
	)
{
	assert (pModel != NULL);

	return pModel->Id;
}


const char *Model_GetName
	(
	  Model const *pModel
	)
{
	assert (pModel != NULL);

	return pModel->Name;
}

void Model_SetName
	(
	  Model *pModel,
	  const char *pName
	)
{
	assert (pModel != NULL);
	assert (pName != NULL);

	if (pModel->Name != NULL)
	{
		geRam_Free (pModel->Name);
	}
	pModel->Name = Util_Strdup (pName);
}


// Returns a pointer to the model's mini bsp tree
Node *Model_GetModelTree
	(
	  Model const *pModel
	)
{
	assert (pModel != NULL);

	return pModel->ModelTree;
}


// sets the model's mini bsp tree pointer
void Model_SetModelTree
	(
	  Model *pModel,
	  Node *n
	)
{
	assert (pModel != NULL);

	pModel->ModelTree	=n;
}

// determine if all of the model's brushes are selected
geBoolean Model_IsSelected
	(
	  Model const *pModel,
	  SelBrushList *pSelList,
	  BrushList *pList
	)
{
	int i;
	int SelCount;
	int SelBrushCount;
	Brush *pBrush;

	assert (pModel != NULL);
	assert (pList != NULL);
	
	SelBrushCount = SelBrushList_GetSize (pSelList);
	SelCount = 0;
	// count the number of selected brushes that have this model id
	for (i = 0; i < SelBrushCount; i++)
	{
		pBrush = SelBrushList_GetBrush (pSelList, i);
		if (Brush_GetModelId (pBrush) == pModel->Id)
		{
			++SelCount;
		}
	}

	
	if (SelCount > 0)
	{
		// now count number of model brushes in the entire list...
		int ModelBrushCount;
		Brush *pBrush;
		BrushIterator bi;

		ModelBrushCount = 0;
		pBrush = BrushList_GetFirst (pList, &bi);
		while (pBrush != NULL)
		{
			if (Brush_GetModelId (pBrush) == pModel->Id)
			{
				++ModelBrushCount;
			}
			pBrush = BrushList_GetNext (&bi);
		}
		if (ModelBrushCount == SelCount)
		{
			return GE_TRUE;
		}		
	}
	return GE_FALSE;
}


geBoolean Model_IsLocked
	(
	  Model const *pModel
	)
{
	assert (pModel != NULL);

	return pModel->Locked;
}


void Model_SetLock
	(
	  Model *pModel,
	  geBoolean Locked
	)
{
	assert (pModel != NULL);

	pModel->Locked = Locked;
}

int Model_GetNumKeys
	(
	  Model const *pModel
	)
{
	gePath *pPath;
	int nKeys;

	assert (pModel != NULL);

	nKeys = 0;
	pPath = Model_GetPath ((Model *)pModel);
	if (pPath != NULL)
	{
		nKeys = gePath_GetKeyframeCount (pPath, GE_PATH_ROTATION_CHANNEL);
	}
	return nKeys;
}

geBoolean Model_IsRotationLocked
	(
	  Model const *pModel
	)
{
	assert (pModel != NULL);

	return (pModel->RotationLocked && (Model_GetNumKeys (pModel) > 1));
}

void Model_SetRotationLock
	(
	  Model *pModel,
	  geBoolean Locked
	)
{
	assert (pModel != NULL);

	pModel->RotationLocked = Locked;
}


geBoolean Model_IsAnimating
	(
	  Model const *pModel
	)
{
	assert (pModel != NULL);

	return pModel->Animating;
}

void Model_SetAnimating
	(
	  Model *pModel, 
	  geBoolean Anim
	)
{
	assert (pModel != NULL);

	pModel->Animating = Anim;
}

/*
static void OrientationFromPoints
	(
	  const geVec3d *p0,
	  const geVec3d *p1,
	  const geVec3d *p2,
	  const geVec3d *p3,
	  geXForm3d *XForm
	)
{
	geVec3d	V1, V2, V3;
	geVec3d	Left, Up, In;

	geVec3d_Subtract(p1, p0, &V1);
	geVec3d_Subtract(p2, p0, &V2);
	geVec3d_Subtract(p3, p0, &V3);

	geVec3d_Normalize(&V1);
	geVec3d_Normalize(&V2);
	geVec3d_Normalize(&V3);
	geVec3d_CrossProduct(&V2, &V1, &Up);
	// make sure it's a right-handed coordinate system...
	if	(geVec3d_DotProduct(&Up, &V3) >= 0.0f)
	{
		geVec3d_CrossProduct(&Up, &V1, &Left);
	}
	else
	{
		geVec3d_CrossProduct(&V1, &V2, &Up);
		geVec3d_CrossProduct(&Up, &V2, &Left);
	}

	geVec3d_CrossProduct(&Left, &Up, &In);

	geVec3d_Normalize (&Left);
	geVec3d_Normalize (&Up);
	geVec3d_Normalize (&In);

	geXForm3d_SetFromLeftUpIn(XForm, &Left, &Up, &In);
}
*/

void Model_GetCenter
	(
	  Model const *pModel,
	  BrushList *pList,
	  geVec3d *pVecCenter
	)
{
	// compute geometric center of model brushes
	Box3d Box;
	BrushIterator bi;
	Brush *pBrush;
	geBoolean First;

	assert (pModel != NULL);
	assert (pVecCenter != NULL);

	First = GE_FALSE;
	pBrush = BrushList_GetFirst (pList, &bi);

	while (pBrush != NULL)
	{
		if (Brush_GetModelId (pBrush) == pModel->Id)
		{
			Box3d const *pBrushBox;

			pBrushBox = Brush_GetBoundingBox (pBrush);
			if (!First)
			{
				Box = *pBrushBox;
				First = GE_TRUE;
			}
			else
			{
				// Update bounding box from brush's bounding box
				Box3d_Union (&Box, pBrushBox, &Box);
			}
		}
		pBrush = BrushList_GetNext (&bi);
	}

	Box3d_GetCenter (&Box, pVecCenter);
}

static void Model_ComputeObjectToWorldXfm
	(
	  Model const *pModel,
	  BrushList *pList,
	  geXForm3d *pXfm
	)
/*
  Computes the model's position and orientation relative
  to the world origin.

  This occurs in two parts.  First we compute the geometric
  "center" of the model by averaging the centers of all
  the brushes.

  Then, we pick the first face of the first brush in the model
  compute its orientation, and set the model's orientation from
  that.  The final step is to apply the translation computed
  in step 1 above.
*/
{
	geVec3d Pos;

	assert (pModel != NULL);
	assert (pList != NULL);
	assert (pXfm != NULL);

	Model_GetCenter (pModel, pList, &Pos);

	geXForm3d_SetTranslation (pXfm, Pos.X, Pos.Y, Pos.Z);
}

void Model_Transform
	(
	  Model const *pModel,
	  const geXForm3d *pXfm,
	  BrushList *pList
	)
// apply the given transformation to all brushes in the model
{
	Brush *pBrush;
	BrushIterator bi;

	assert (pModel != NULL);
	assert (pXfm != NULL);

	pBrush = BrushList_GetFirst (pList, &bi);
	while (pBrush != NULL)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -