~cpp
// static function
/*
Func - LoadAse
Desc - 지정된 Ase 파일을 읽어들이고 그 파일의 월드 좌표계상으로 저장된 정점들을 로컬 좌표계로 변환하며
각 노드마다 자신의 상위 노드에 좌표계에 기준해서 자신의 좌표계로 이동시켜주는 메트릭스를 생성한다.( -> AniTM)
*/
bool CHS_GObject::LoadAse (char* filename)
{
FILE *s;
DWORD max_time = 0;
bool bResult;
if (!(s = fopen (filename, "r"))) {
char ds[255];
sprintf (ds, "# %s not found\n", filename);
OutputDebugString (ds);
return false;
}
else
bResult = GetAseAllInfo (s);
// 0번 모델을 스키닝 통짜 모델이라 가정
pNodeList [0]->bIsSkinModel = TRUE;
// 모델의 메모리 할당.
for (int i=0; i<nNodeNum; i++)
{
//pNodeList [i]->ModelAlloc ();
aseAllocate2CHS_Model (pNodeList [i]);
}
// 하이어라키 정보 생성 -----------------------------------------------
// : 루트 리스트에 트리 구조로이루어진 모델들을 링크 한다.
for (int i1=0; i1<nNodeNum; i1++)
{
if (strcmp (pNodeList [i1]->ParentName, "")) {
for (int i2=0; i2<nNodeNum; i2++)
{
if (pNodeList [i1] != pNodeList [i2] &&
!strcmp (pNodeList [i1]->ParentName, pNodeList [i2]->Name))
{
pNodeList [i1]->SetParent (pNodeList [i2]); // 자식에게 부모가 누구인지 지정
pNodeList [i2]->AddChildNum (); // 부모의 자식수 카운트를 1 늘림
CHS_Model** pChildTmp = pNodeList [i2]->GetChildPointer (); // 임시 보관
CHS_Model** pDest = new CHS_Model* [pNodeList [i2]->GetChildNum ()]; // 새 메모리 할당
memcpy (pDest, pChildTmp, sizeof (CHS_Model*) * (pNodeList [i2]->GetChildNum ()-1)); // 복사
pDest[pNodeList [i2]->GetChildNum ()-1] = pNodeList [i1]; // 부모에게 추가된 새 자식 저장
pNodeList [i2]->SetChildPointer (pDest); // 새 메모리를 자식 포인터로 지정
delete [] pChildTmp; // 임시 보관 장소 삭제
}
}
}
}
// 정점 데이타 읽기 ---------------------------------------------------
CHS_GObject::GetAseAllData (s, &max_time);
// 정점을 wcs -> lcs로 변환 -------------------------------------------
// ani_tm 최초 update -------------------------------------------------
for (i=0; i<nNodeNum; i++) {
pNodeList[i]->InitObject (0);
if (i!=0) pNodeList[i]->MulMatInverse (FALSE);
// pNodeList[i]->MulMatInverse (FALSE);
pNodeList[i]->UpdateAniTM (FALSE);
// BoundingVolumn 계산
pNodeList[i]->CreateVolumn (pNodeList[i]->verts, pNodeList[i]->numVertex);
}
// 텍스쳐 데이타 읽기 -------------------------------------------------
// : 미구현
// 루트 노드 리스트 갱신 ----------------------------------------------
// : 루트 노드만 가지고 있는 리스트를 만든다.
// StlLink* pRL = &(s_RootList);
// for(StlListItor itorAll = pSL->begin (); itorAll!= pSL->end (); ++itorAll) {
for (i=0; i<nNodeNum; i++) {
CHS_Model* pTmp = pNodeList[i];
if (!strcmp(pTmp->ParentName, "")) {
//pRL->push_back ((void*)pTmp);
pTmp->SetTimeSkip (800);
pTmp->SetMaxTime (max_time);
pRootList [nRootNum] = pTmp;
nRootNum++;
char debug_buf[255];
sprintf (debug_buf,"\n#ROOT NODE: %s", pTmp->Name);
OutputDebugString (debug_buf);
}
}
fclose (s);
return true;
}
// static function
// 픽킹을 위해 클릭 된 점의 좌표를 계산한다.
// 입력값: 마우스 클릭된 포인트
void CHS_GObject::UpdatePickedPoint (int &cl_x, int &cl_y, int &width, int &height)
{
// 시점 계산
PickedPoint [0][0] = float(cl_x)*2.0f/float(width) - 1.0f;
PickedPoint [0][1] = float(cl_y)*2.0f/float(height) - 1.0f;
PickedPoint [0][1] = -PickedPoint [0][1];
PickedPoint [0][2] = 5.0f;
mat44_t mat_mv, inv_mat_mv;
glGetFloatv (GL_PROJECTION_MATRIX, mat_mv);
matrix44_inverse (inv_mat_mv, mat_mv);
vectorCopy (PickedPoint[0], PickedPoint[1]);
PickedPoint[1][2] -= 10.0;
matrixMultiplyVector3 (inv_mat_mv, PickedPoint[0]);
matrixMultiplyVector3 (inv_mat_mv, PickedPoint[1]);
}
// static function
// s_AllList상의 모든 노드를 삭제한다.
void CHS_GObject::ReleaseModels ()
{
/*
StlLink* pSL = &(CHS_GObject::s_AllList);
for(StlListItor itor=pSL->begin (); itor!=pSL->end ();++itor) {
delete (*itor);
itor = pSL->erase(itor);
}
*/
for (int i=0; i<nNodeNum; i++)
{
delete pNodeList[i];
}
}
// static function
bool CHS_GObject::GetAseAllInfo (FILE *s)
{
char data[255];
rewind (s); //파일포인터를 맨 앞으로..
CHS_Model* pM;
while (!feof (s)) //파일 스트림이 끝났는지 check!
{
fscanf (s, "%s", &data);
if (!strcmp (data, OBJECT_BEGIN))
{
pM = new CHS_Model;
//pLink->AddTail(pModel);
//CHS_GObject::s_AllList.push_back ((void*)pM);
pNodeList [nNodeNum] = pM;
nNodeNum++;
}
else if (!strcmp (data, OBJECT_NAME))
{ // 자기 노드 이름
char temp[128];
int c_index = 0;
while (fgetc (s) != '"') {}
while (1) {
temp [c_index++] = (char) fgetc (s);
if (temp [c_index-1] == '"') {
temp [c_index-1] = '\0';
break;
}
}
memcpy (pM->Name, temp, strlen(temp));
}
else if (!strcmp (data, OBJECT_PARENT))
{ // 부모 노드 이름
char temp[128];
int c_index = 0;
while (fgetc (s) != '"') {}
while (1) {
temp [c_index++] = (char) fgetc (s);
if (temp [c_index-1] == '"') {
temp [c_index-1] = '\0';
break;
}
}
memcpy (pM->ParentName, temp, strlen(temp));
}
else if (!strcmp (data, OBJECT_POS))
{
// 일반적인 ascii export plug in을 사용했을 경우
// 이 pos 값은 월드 좌표로 계산되어 지는듯함. *MESH에 들어있는 vertex 좌표들은
// 모두 월드 좌표들이었습니다. 모델 각각의 위치로 Translate 나 Rotate를
// 할 필요는 없었음.
fscanf (s, "%f %f %f", &pM->Pos[0]
, &pM->Pos[2]
, &pM->Pos[1]);
pM->Pos[2] = -pM->Pos[2];
}
else if (!strcmp (data, OBJECT_ROTAXIS))
{
fscanf (s, "%f %f %f", &pM->Axis[0]
, &pM->Axis[2]
, &pM->Axis[1]);
pM->Axis[2] = -pM->Axis[2];
}
else if (!strcmp (data, OBJECT_ROTANGLE)) {
vec_t x;
fscanf (s, "%f", &x);
// pM->Angle = -x;
pM->Angle = x;
matrix_t tmp_trans, tmp_rot;
matrixIdentity (tmp_trans);
matrixIdentity (tmp_rot);
matrixIdentity (pM->tm);
matrixTranslate (tmp_trans, pM->Pos);
AngleAxis2Matrix (tmp_rot, pM->Axis, pM->Angle);
matrixMultiply (tmp_rot, tmp_trans, pM->tm);
matrix44_inverse (pM->inv_tm, pM->tm);
}
else if (!strcmp (data, OBJECT_ROW0))
{
fscanf (s, "%f %f %f", &pM->tm[0]
, &pM->tm[2]
, &pM->tm[1]);
pM->tm[2] = -pM->tm[2];
pM->tm[3] = 0.0f;
}
else if (!strcmp (data, OBJECT_ROW1))
{
fscanf (s, "%f %f %f", &pM->tm[8]
, &pM->tm[10]
, &pM->tm[9]);
pM->tm[10] = -pM->tm[10];
pM->tm[11] = 0.0f;
}
else if (!strcmp (data, OBJECT_ROW2))
{
fscanf (s, "%f %f %f", &pM->tm[4]
, &pM->tm[6]
, &pM->tm[5]);
pM->tm[6] = -pM->tm[6];
pM->tm[7] = 0.0f;
}
else if (!strcmp (data, OBJECT_ROW3))
{
fscanf (s, "%f %f %f", &pM->tm[12]
, &pM->tm[14]
, &pM->tm[13]);
pM->tm[14] = -pM->tm[14];
pM->tm[15] = 1.0f;
// matrix44_inverse (pM->inv_tm, pM->tm);
}
else if (!strcmp (data, NUM_VERTEX))
fscanf (s, "%d", &pM->numVertex);
else if (!strcmp (data, NUM_FACES))
fscanf (s, "%d", &pM->numFaces);
else if (!strcmp (data, NUM_TVERTEX)) //texture mapped vertex?
{
fscanf (s, "%d", &pM->numTexVertex);
pM->bTexture_on = 1; //만약 텍스쳐 버텍스들이 존재한다면 모델객체의 텍스쳐 플래그 온
}
else if (!strcmp (data, NUM_TFACES)) //texture mapped face?
fscanf (s, "%d", &pM->numTexFaces);
else if (!strcmp (data, NUM_TEXTURE))
{
// 일단 텍스쳐 정보 부분은 삭제
/*
int n = (int) aseGetFloatVal(s);
pTex = new char*[n]; //pTex 는 이중 포인터
app_con.numTex = n;
*/
}
else if (!strcmp (data, NORMALS))
pM->bNormals = true;
else if (!strcmp (data, TEXTURE))
{
// 일단 텍스쳐 정보 부분은 삭제
/*
aseGetTextureName1 (s);
*/
}
else if (!strcmp (data, OBJECT_ANI))
{ // rotate sample이 존재함을 표시.
//pM->bRotKey = TRUE;
}
else if (!strcmp (data, OBJECT_ROT_EXIST))
{
pM->bRotKey = TRUE;
}
else if (!strcmp (data, OBJECT_POS_EXIST))
{
pM->bPosKey = TRUE;
}
else if (!strcmp (data, OBJECT_ROT_SAMPLE))
{
// pM->AddKeyNum (); // == pM->keyNum++
pM->rotkeyNum++;
}
else if (!strcmp (data, OBJECT_POS_SAMPLE))
{
pM->poskeyNum++;
}
else
fgets (data, sizeof (data), s);
}
// 각각의 본에 할당되는 PV의 개수 count
rewind (s);
while (!feof (s)) //파일 스트림이 끝났는지 check!
{
int x;
vec_t w;
char tmp_name[255];
char name[255];
fscanf (s, "%s", &data);
if (!strcmp (data, PV_NONBLEND)) {
fscanf (s, "%d ", &x);
int c_index = 0;
while (fgetc (s) != '"') {}
while (1) {
tmp_name [c_index++] = (char) fgetc (s);
if (tmp_name [c_index-1] == '"') {
tmp_name [c_index-1] = '\0';
break;
}
}
memcpy (name, tmp_name, strlen(tmp_name)+1);
for (int i=0;i<nNodeNum;i++) {
if (!strcmp (pNodeList [i]->Name, name))
pNodeList [i]->GetPSQInfo()->nPVertexCount++;
}
}
else if (!strcmp (data, PV_BLEND_ASSIGN)) {
fscanf (s, "%d %f ", &x, &w);
int c_index = 0;
while (fgetc (s) != '"') {}
while (1) {
tmp_name [c_index++] = (char) fgetc (s);
if (tmp_name [c_index-1] == '"') {
tmp_name [c_index-1] = '\0';
break;
}
}
memcpy (name, tmp_name, strlen(tmp_name)+1);
for (int i=0;i<nNodeNum;i++) {
if (!strcmp (pNodeList [i]->Name, name))
pNodeList [i]->GetPSQInfo()->nPVertexCount++;
}
}
else
fgets (data, sizeof (data), s);
}
// 전체 키 설정
for (int i=0;i<nNodeNum;i++) {
pNodeList [i]->SetKeyNum (1);
if (!pNodeList [i]->bPosKey)
pNodeList [i]->poskeyNum = 1;
if (!pNodeList [i]->bRotKey)
pNodeList [i]->rotkeyNum = 1;
if (pNodeList [i]->rotkeyNum > 1)
pNodeList [i]->SetKeyNum (pNodeList [i]->rotkeyNum);
if (pNodeList [i]->poskeyNum > pNodeList [i]->rotkeyNum)
pNodeList [i]->SetKeyNum (pNodeList [i]->poskeyNum);
}
return true;
}
// 모델에 메모리 할당.
void CHS_GObject::ModelAlloc (CHS_GObject* pO)
{
}
// static
vec_t CHS_GObject::GetFloatVal (FILE *s)
{
vec_t v;
fscanf (s, " %f", &v);
return v;
}
// 모델에 정점 정보 입력
void CHS_GObject::GetAseAllData (FILE *s, DWORD *max_time)
{
char data[255];
int count = 0;
int pv_count[50] = {0,};
int nBlendAssignIndex;
CHS_Model* pM = 0;
// StlListItor itor = s_AllList.begin ();
// pM = (CHS_Model*)*itor;
pM = pNodeList[0];
rewind (s);
while (!feof (s))
{
fscanf (s, "%s", &data);
if (strcmp (data, OBJECT_BEGIN) == 0)
{
if (count == 0)
//itor = CHS_GObject::s_AllList.begin ();
pM = pNodeList [0];
else
//itor++;
pM = pNodeList [count];
count++;
//pM = (CHS_Model*)*itor;
}
else if (strcmp (data, VERTEX) == 0)
{
//CHS_GObject::GetVertex (s, pM);
int index;
fscanf (s, "%d", &index);
// swap y and z cause 3dsm likes too
fscanf (s, "%f %f %f",
&pM->verts[index][0],
&pM->verts[index][2],
&pM->verts[index][1]);
// in 3dsm negative z goes out of the screen, we want it to go in
pM->verts[index][2] = -(pM->verts[index][2]);
}
else if (strcmp (data, TVERTEX) == 0)
{
//CHS_GObject::GetTVertex (s, pM);
int index;
fscanf (s, "%d", &index);
fscanf (s, "%f %f", &pM->texVerts[index][0], &pM->texVerts[index][1]);
}
else if (strcmp (data, NVERTEX) == 0)
{
//CHS_GObject::GetNVertex (s, pM);
int index;
fscanf (s, "%d", &index);
fscanf (s, "%f %f %f",
&pM->vertNorms[index][0],
&pM->vertNorms[index][2],
&pM->vertNorms[index][1]);
pM->vertNorms[index][2] = -pM->vertNorms[index][2];
}
else if (strcmp (data, FACE_NORMAL) == 0)
{
//CHS_GObject::GetFaceNormal (s, pM);
int index;
fscanf (s, "%d", &index);
fscanf (s, "%f %f %f",
&pM->faces[index].normal[0],
&pM->faces[index].normal[2],
&pM->faces[index].normal[1]);
pM->faces[index].normal[2] = -pM->faces[index].normal[2];
}
else if (strcmp (data, FACE) == 0)
{
//CHS_GObject::GetFace (s, pM);
int index;
fscanf (s, "%d:", &index);
fscanf (s, "\tA:\t%d B:\t%d C:\t%d",
&pM->faces[index].vertIndex[0],
&pM->faces[index].vertIndex[1],
&pM->faces[index].vertIndex[2]);
/* &pM->faces[index].vertIndex[2],
&pM->faces[index].vertIndex[1]);*/
}
else if (strcmp (data, TFACE) == 0)
{
//CHS_GObject::GetTFace (s, pM);
int index;
fscanf (s, "%d:", &index);
fscanf (s, "%d %d %d",
&pM->faces[index].coordIndex[0],
&pM->faces[index].coordIndex[1],
&pM->faces[index].coordIndex[2]);
}
/*
else if (strcmp (data, TEXTURE) == 0)
{
aseGetTextureName (s, p); //모델t 구조체에 들어가는 텍스쳐 네임은 사용x
//textureLink 에 들거나는 네임 사용
}
*/
else if (!strcmp (data, OBJECT_ROT_SAMPLE))
{
// animation - rotate sampling
static int nTmpCount = 0;
vec3_t v;
vec_t t;
// 파싱한 angular displacement?? 로 추정되는 것을..
// fscanf (s, "%d", &(pM->pRotKey[nTmpCount].time)); fgetchar ();
// fscanf (s, "%f", &v[0]); fgetchar ();
// fscanf (s, "%f", &v[2]); fgetchar ();
// fscanf (s, "%f", &v[1]); fgetchar ();
// fscanf (s, "%f", &t);
fscanf (s, "%d", &(pM->pRotKey[nTmpCount].time)); fgetchar ();
fscanf (s, "%f", &v[0]); fgetchar ();
fscanf (s, "%f", &v[2]); fgetchar ();
fscanf (s, "%f", &v[1]); fgetchar ();
fscanf (s, "%f", &t);
// max_time 값 업데이트
if (pM->pRotKey[nTmpCount].time > *max_time) *max_time = pM->pRotKey[nTmpCount].time;
v[2] = -v[2];
// -----------------------------------------------------------
// 180도 이상되는 회전각을 가진 키에 대한 처리
// : 회전축을 뒤집고 회전각은 '각 = 360-각'으로 처리해준다.
// -----------------------------------------------------------
if (t >= degToRad(180)) {
t = degToRad(360) - t;
vectorScale (v, -1.0);
}
// 쿼터니언으로 변환해서 저장.
// !! 여기서.. angle은 왼손 좌표계를 기준으로 한다고 함..
// 오픈지엘은 오른손 좌표계이므로 부호를 반대로.. (-t)
// AngleAxis2Quat (&pM->pRotKey[nTmpCount].q, v, -t);
AngleAxis2Quat (&pM->pRotKey[nTmpCount].q, v, t);
nTmpCount++;
if (nTmpCount == pM->rotkeyNum)
nTmpCount = 0;
}
else if (!strcmp (data, OBJECT_POS_SAMPLE))
{
// animation - position sampling
static int nTmpCount2 = 0;
vec3_t p;
fscanf (s, "%d", &(pM->pPosKey[nTmpCount2].time)); fgetchar ();
fscanf (s, "%f", &p[0]); fgetchar ();
fscanf (s, "%f", &p[2]); fgetchar ();
fscanf (s, "%f", &p[1]);
p[2] = -p[2];
// max_time 값 업데이트
if (pM->pPosKey[nTmpCount2].time > *max_time) *max_time = pM->pPosKey[nTmpCount2].time;
memcpy (&pM->pPosKey[nTmpCount2].p, p, sizeof (vec3_t));
nTmpCount2++;
if (nTmpCount2 == pM->poskeyNum)
nTmpCount2 = 0;
}
else if (!strcmp (data, PV_NONBLEND))
{
int index;
char tmp_name[255];
char name[255];
fscanf (s, "%d ", &index);
int c_index = 0;
while (fgetc (s) != '"') {}
while (1) {
tmp_name [c_index++] = (char) fgetc (s);
if (tmp_name [c_index-1] == '"') {
tmp_name [c_index-1] = '\0';
break;
}
}
// memcpy (name, tmp_name+1, strlen(tmp_name)-2);
memcpy (name, tmp_name, strlen(tmp_name)+1);
// name [strlen(tmp_name)-2] = '\0';
for (int i=0;i<nNodeNum;i++) {
if (!strcmp (pNodeList [i]->Name, name))
{
pNodeList [i]->GetPSQInfo()->pV[pv_count[i]].nVIndex = index;
pNodeList [i]->GetPSQInfo()->pV[pv_count[i]].weight = 1.0;
pv_count[i]++;
}
}
}
else if (!strcmp (data, PV_BLEND_ASSIGNMODE))
{
fscanf (s, "%d", &nBlendAssignIndex);
}
else if (!strcmp (data, PV_BLEND_ASSIGN))
{
int index;
vec_t w;
char tmp_name[255];
char name[255];
//fscanf (s, "%d %f %s", &index, &w, &tmp_name);
fscanf (s, "%d %f ", &index, &w);
int c_index = 0;
while (fgetc (s) != '"') {}
while (1) {
tmp_name [c_index++] = (char) fgetc (s);
if (tmp_name [c_index-1] == '"') {
tmp_name [c_index-1] = '\0';
break;
}
}
memcpy (name, tmp_name, strlen(tmp_name)+1);
// memcpy (name, tmp_name+1, strlen(tmp_name)-2);
// name [strlen(tmp_name)-2] = '\0';
for (int i=0;i<nNodeNum;i++) {
if (!strcmp (pNodeList [i]->Name, name))
{
pNodeList [i]->GetPSQInfo()->pV[pv_count[i]].nVIndex = nBlendAssignIndex;
pNodeList [i]->GetPSQInfo()->pV[pv_count[i]].weight = w;
pv_count[i]++;
}
}
}
else if (strcmp (data, TEXTURE_ID) == 0)
{
pM->texture.texId = (int) GetFloatVal (s);
}
// 아래 부분은 없애두 될듯.. 그리고 texture는 모델과는 별도로 관리하는 것이 좋을 것 같다.
// 모델에는 텍스쳐의 참조 번호 정도만 저장하면 될 것 같다.
else if (strcmp (data, UTILE) == 0)
{
pM->texture.uTile = GetFloatVal (s);
}
else if (strcmp (data, VTILE) == 0)
{
pM->texture.vTile = GetFloatVal (s);
}
else if (strcmp (data, UOFFSET) == 0)
{
pM->texture.uOffset = GetFloatVal (s);
}
else if (strcmp (data, VOFFSET) == 0)
{
pM->texture.vOffset = GetFloatVal (s);
}
else
fgets (data, sizeof (data), s);
}
mat44_t parent_inv, tmp_out;
for (int i=0;i<nNodeNum;i++) {
if (!pNodeList [i]->bPosKey) {
matrixIdentity (parent_inv);
matrixIdentity (tmp_out);
pNodeList[i]->pPosKey[0].time = 0;
// 하이어라키 정보를 생성한 후이므로..
if (pNodeList [i]->RetParent ()) matrix44_inverse (parent_inv, pNodeList [i]->RetParent ()->tm);
matrixMultiply (pNodeList [i]->tm, parent_inv, tmp_out);
pNodeList[i]->pPosKey[0].p[0] = tmp_out[12];
pNodeList[i]->pPosKey[0].p[1] = tmp_out[13];
pNodeList[i]->pPosKey[0].p[2] = tmp_out[14];
}
if (!pNodeList [i]->bRotKey) {
pNodeList[i]->pRotKey[0].time = 0;
AngleAxis2Quat (&pNodeList[i]->pRotKey[0].q, pNodeList[i]->Axis, pNodeList[i]->Angle);
}
}
}