RenameThisPage - 적저한 이름과 하는 일이 필요할것 같아서. 궁리중 --["1002"] {{{~cpp //#define OBJECT_BEGIN "*NODE_TM" #define OBJECT_BEGIN "*GEOMOBJECT" #define OBJECT_NAME "*NODE_NAME" #define OBJECT_POS "*TM_POS" #define NUM_VERTEX "*MESH_NUMVERTEX" #define NUM_FACES "*MESH_NUMFACES" #define NUM_TVERTEX "*MESH_NUMTVERTEX" #define NUM_TFACES "*MESH_NUMTVFACES" #define NUM_TEXTURE "*MATERIAL_COUNT" #define VERTEX_LIST "*MESH_VERTEX_LIST" #define VERTEX "*MESH_VERTEX" #define FACE_LIST "*MESH_FACE_LIST" #define FACE "*MESH_FACE" #define NORMALS "*MESH_NORMALS" #define FACE_NORMAL "*MESH_FACENORMAL" #define NVERTEX "*MESH_VERTEXNORMAL" #define TVERTEX "*MESH_TVERT" #define TFACE "*MESH_TFACE" #define TEXTURE "*BITMAP" #define TEXTURE_ID "*MATERIAL_REF" #define UTILE "*UVW_U_TILING" #define VTILE "*UVW_V_TILING" #define UOFFSET "*UVW_U_OFFSET" #define VOFFSET "*UVW_V_OFFSET" #define WIREFRAME_COLOR "*WIREFRAME_COLOR" //- 2002/01 추가.. ---------------------------------------------- #define OBJECT_PARENT "*NODE_PARENT" #define OBJECT_ROW0 "*TM_ROW0" #define OBJECT_ROW1 "*TM_ROW1" #define OBJECT_ROW2 "*TM_ROW2" #define OBJECT_ROW3 "*TM_ROW3" #define OBJECT_ROTAXIS "*TM_ROTAXIS" #define OBJECT_ROTANGLE "*TM_ROTANGLE" #define OBJECT_ANI "*TM_ANIMATION" #define OBJECT_ROT_EXIST "*CONTROL_ROT_TRACK" #define OBJECT_POS_EXIST "*CONTROL_POS_TRACK" #define OBJECT_ROT_SAMPLE "*CONTROL_ROT_SAMPLE" #define OBJECT_POS_SAMPLE "*CONTROL_POS_SAMPLE" //--------------------------------------------------------------- // - 피지크 관련 정보 ------------------------------------------- // pv : physique vertex 의 의미 #define PV_NUM "*PHYSIQUE_NUMVERTEXASSIGNMENT" // 전체 PV 개수. 별로 의미 없다.. 본 개개에 할당된 PV수가 필요하므로.. #define PV_NONBLEND "*PHYSIQUE_NONBLENDED_RIGIDTYPE" #define PV_BLEND_ASSIGNMODE "*PHYSIQUE_BLENDED_RIGIDTYPE_LIST" #define PV_BLEND_ASSIGN "*PHYSIQUE_VERTEXASSIGNMENT_NODE" //--------------------------------------------------------------- // a triangle in the model typedef struct { int vertIndex[3]; // indicies for the verts that make up this triangle int coordIndex[3]; // indicies for the tex coords to texture this face vec3_t normal; // face normal } triangle_t; // texture information for the model typedef struct { char texName[51]; // texture name int texId; // texture id vec_t uTile; // u tiling of texture vec_t vTile; // v tiling of " vec_t uOffset; // u offset of " vec_t vOffset; // v offset of " } texture_t; }}} {{{~cpp class CHS_GObject { protected: // ------------------------------------- public: /* // 원래 STL 리스트로 전체 노드를 관리했는데 지금은 사용안함. 전체 노드 리스트는 이 모듈의 cpp 파일에 전역으로 선언. static StlLink s_RootList; static StlLink s_AllList; */ // ------------------------------------- CHS_GObject(); virtual ~CHS_GObject(); virtual void Render (void* pArg) {}; virtual void InitObject (void* pArg) {}; // ------------------------------------- // static member // ------------------------------------- static vec_t GetFloatVal (FILE *s); // 파일에서 Float형 값을 하나 읽는다. static bool LoadAse (char* filename); // ASE 파일을 읽어들인다. static void ModelAlloc (CHS_GObject* pO); // 쓰이지 않음. j_ase 모듈에 있는 aseAllocate2CHS_Model을 사용 static bool GetAseAllInfo (FILE *s); // 각 노드의 헤더정보와, 연결된 피지크 정점 개수를 카운트하고 에니메이션 키가 없는 노드의 에니메이션 키를 1로 초기화한다. static void GetAseAllData (FILE *s, DWORD *max_time); // 각 노드의 나머지 정보를 읽는다. 정점, 페이스, 노멀, 에니메이션 키(위치, 회전), 피지크의 weight 등등. static void ReleaseModels (); // s_AllList상의 모든 노드를 삭제한다. static void UpdatePickedPoint (int &cl_x, int &cl_y, int &width, int &height); // Picking을 위해 윈도우 상의 클릭된 점의 좌표가 월드 좌표계 상에서 얼마인지 계산한다. static vec3_t PickedPoint[2]; // 위의 함수에서 계산한 결과가 저장된다. }; }}} {{{~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; iModelAlloc (); aseAllocate2CHS_Model (pNodeList [i]); } // 하이어라키 정보 생성 ----------------------------------------------- // : 루트 리스트에 트리 구조로이루어진 모델들을 링크 한다. for (int i1=0; i1ParentName, "")) { for (int i2=0; i2ParentName, 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; iInitObject (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; iParentName, "")) { //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; iAddTail(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;iName, 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;iName, name)) pNodeList [i]->GetPSQInfo()->nPVertexCount++; } } else fgets (data, sizeof (data), s); } // 전체 키 설정 for (int i=0;iSetKeyNum (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;iName, 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;iName, 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;ibPosKey) { 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); } } } }}}