bool CKinematics:: PickBone (const Fmatrix &parent_xform, Fvector& normal, float& dist, const Fvector& start, const Fvector& dir, u16 bone_id) { Fvector S,D;//normal = {0,0,0} // transform ray from world to model Fmatrix P; P.invert (parent_xform); P.transform_tiny (S,start); P.transform_dir (D,dir); for (u32 i=0; i<children.size(); i++) if (LL_GetChild(i)->PickBone(normal,dist,S,D,bone_id)) { parent_xform.transform_dir (normal); return true; } return false; }
void CKinematics::Copy(IRender_Visual *P) { inherited::Copy (P); CKinematics* pFrom = (CKinematics*)P; PCOPY(pUserData ); PCOPY(bones ); PCOPY(iRoot ); PCOPY(bone_map_N); PCOPY(bone_map_P); PCOPY(visimask ); IBoneInstances_Create (); for (u32 i=0; i<children.size(); i++) LL_GetChild(i)->SetParent(this); CalculateBones_Invalidate (); m_lod = (pFrom->m_lod)?::Render->model_Duplicate (pFrom->m_lod):0; }
void CKinematics::Copy(dxRender_Visual *P) { inherited::Copy (P); CKinematics* pFrom = dynamic_cast<CKinematics*>(P); VERIFY(pFrom); pUserData = pFrom->pUserData; bones = pFrom->bones; iRoot = pFrom->iRoot; bone_map_N = pFrom->bone_map_N; bone_map_P = pFrom->bone_map_P; visimask = pFrom->visimask; IBoneInstances_Create (); for (u32 i=0; i<children.size(); i++) LL_GetChild(i)->SetParent(this); CalculateBones_Invalidate (); m_lod = (pFrom->m_lod)?(dxRender_Visual*)::Render->model_Duplicate (pFrom->m_lod):0; }
void CKinematics::AddWallmark(const Fmatrix* parent_xform, const Fvector3& start, const Fvector3& dir, ref_shader shader, float size) { Fvector S,D,normal = {0,0,0}; // transform ray from world to model Fmatrix P; P.invert (*parent_xform); P.transform_tiny (S,start); P.transform_dir (D,dir); // find pick point float dist = flt_max; BOOL picked = FALSE; DEFINE_VECTOR (Fobb,OBBVec,OBBVecIt); OBBVec cache_obb; cache_obb.resize (LL_BoneCount()); for (u16 k=0; k<LL_BoneCount(); k++){ CBoneData& BD = LL_GetData(k); if (LL_GetBoneVisible(k)&&!BD.shape.flags.is(SBoneShape::sfNoPickable)){ Fobb& obb = cache_obb[k]; obb.transform (BD.obb,LL_GetBoneInstance(k).mTransform); if (CDB::TestRayOBB(S,D, obb)) for (u32 i=0; i<children.size(); i++) if (LL_GetChild(i)->PickBone(normal,dist,S,D,k)) picked=TRUE; } } if (!picked) return; // calculate contact point Fvector cp; cp.mad (S,D,dist); // collect collide boxes Fsphere test_sphere; test_sphere.set (cp,size); U16Vec test_bones; test_bones.reserve (LL_BoneCount()); for (k=0; k<LL_BoneCount(); k++){ CBoneData& BD = LL_GetData(k); if (LL_GetBoneVisible(k)&&!BD.shape.flags.is(SBoneShape::sfNoPickable)){ Fobb& obb = cache_obb[k]; if (CDB::TestSphereOBB(test_sphere, obb)) test_bones.push_back(k); } } // find similar wm for (u32 wm_idx=0; wm_idx<wallmarks.size(); wm_idx++){ intrusive_ptr<CSkeletonWallmark>& wm = wallmarks[wm_idx]; if (wm->Similar(shader,cp,0.02f)){ if (wm_idx<wallmarks.size()-1) wm = wallmarks.back(); wallmarks.pop_back(); break; } } // ok. allocate wallmark intrusive_ptr<CSkeletonWallmark> wm = xr_new<CSkeletonWallmark>(this,parent_xform,shader,cp,Device.fTimeGlobal); wm->m_LocalBounds.set (cp,size*2.f); wm->XFORM()->transform_tiny (wm->m_Bounds.P,cp); wm->m_Bounds.R = wm->m_Bounds.R; Fvector tmp; tmp.invert (D); normal.add(tmp).normalize (); // build UV projection matrix Fmatrix mView,mRot; BuildMatrix (mView,1/(0.9f*size),normal,cp); mRot.rotateZ (::Random.randF(deg2rad(-20.f),deg2rad(20.f))); mView.mulA_43 (mRot); // fill vertices for (u32 i=0; i<children.size(); i++){ CSkeletonX* S = LL_GetChild(i); for (U16It b_it=test_bones.begin(); b_it!=test_bones.end(); b_it++) S->FillVertices (mView,*wm,normal,size,*b_it); } wallmarks.push_back (wm); }
void CKinematics::EnumBoneVertices (SEnumVerticesCallback &C, u16 bone_id) { for ( u32 i=0; i<children.size(); i++ ) LL_GetChild( i )->EnumBoneVertices( C, bone_id ); }
void CKinematics::Load(const char* N, IReader *data, u32 dwFlags) { //Msg ("skeleton: %s",N); inherited::Load (N, data, dwFlags); pUserData = NULL; m_lod = NULL; // loading lods IReader* LD = data->open_chunk(OGF_S_LODS); if (LD) { string_path short_name; strcpy_s (short_name,sizeof(short_name),N); if (strext(short_name)) *strext(short_name)=0; // From stream { string_path lod_name; LD->r_string (lod_name, sizeof(lod_name)); //. strconcat (sizeof(name_load),name_load, short_name, ":lod:", lod_name.c_str()); m_lod = ::Render->model_CreateChild(lod_name, NULL); VERIFY3(m_lod,"Cant create LOD model for", N); //. VERIFY2 (m_lod->Type==MT_HIERRARHY || m_lod->Type==MT_PROGRESSIVE || m_lod->Type==MT_NORMAL,lod_name.c_str()); /* strconcat (name_load, short_name, ":lod:1"); m_lod = ::Render->model_CreateChild(name_load,LD); VERIFY (m_lod->Type==MT_SKELETON_GEOMDEF_PM || m_lod->Type==MT_SKELETON_GEOMDEF_ST); */ } LD->close (); } #ifndef _EDITOR // User data IReader* UD = data->open_chunk(OGF_S_USERDATA); pUserData = UD?xr_new<CInifile>(UD,FS.get_path("$game_config$")->m_Path):0; if (UD) UD->close(); #endif // Globals bone_map_N = xr_new<accel> (); bone_map_P = xr_new<accel> (); bones = xr_new<vecBones> (); bone_instances = NULL; // Load bones #pragma todo("container is created in stack!") xr_vector<shared_str> L_parents; R_ASSERT (data->find_chunk(OGF_S_BONE_NAMES)); visimask.zero (); int dwCount = data->r_u32(); // Msg ("!!! %d bones",dwCount); // if (dwCount >= 64) Msg ("!!! More than 64 bones is a crazy thing! (%d), %s",dwCount,N); VERIFY3 (dwCount < 64, "More than 64 bones is a crazy thing!",N); for (; dwCount; dwCount--) { string256 buf; // Bone u16 ID = u16(bones->size()); data->r_stringZ (buf,sizeof(buf)); strlwr(buf); CBoneData* pBone = CreateBoneData(ID); pBone->name = shared_str(buf); pBone->child_faces.resize (children.size()); bones->push_back (pBone); bone_map_N->push_back (mk_pair(pBone->name,ID)); bone_map_P->push_back (mk_pair(pBone->name,ID)); // It's parent data->r_stringZ (buf,sizeof(buf)); strlwr(buf); L_parents.push_back (buf); data->r (&pBone->obb,sizeof(Fobb)); visimask.set (u64(1)<<ID,TRUE); } std::sort (bone_map_N->begin(),bone_map_N->end(),pred_sort_N); std::sort (bone_map_P->begin(),bone_map_P->end(),pred_sort_P); // Attach bones to their parents iRoot = BI_NONE; for (u32 i=0; i<bones->size(); i++) { shared_str P = L_parents[i]; CBoneData* B = (*bones)[i]; if (!P||!P[0]) { // no parent - this is root bone R_ASSERT (BI_NONE==iRoot); iRoot = u16(i); B->SetParentID(BI_NONE); continue; } else { u16 ID = LL_BoneID(P); R_ASSERT (ID!=BI_NONE); (*bones)[ID]->children.push_back(B); B->SetParentID(ID); } } R_ASSERT (BI_NONE != iRoot); // Free parents L_parents.clear(); // IK data IReader* IKD = data->open_chunk(OGF_S_IKDATA); if (IKD){ for (u32 i=0; i<bones->size(); i++) { CBoneData* B = (*bones)[i]; u16 vers = (u16)IKD->r_u32(); IKD->r_stringZ (B->game_mtl_name); IKD->r (&B->shape,sizeof(SBoneShape)); B->IK_data.Import(*IKD,vers); Fvector vXYZ,vT; IKD->r_fvector3 (vXYZ); IKD->r_fvector3 (vT); B->bind_transform.setXYZi(vXYZ); B->bind_transform.translate_over(vT); B->mass = IKD->r_float(); IKD->r_fvector3 (B->center_of_mass); } // calculate model to bone converting matrix (*bones)[LL_GetBoneRoot()]->CalculateM2B(Fidentity); IKD->close(); } // after load process { for (u16 child_idx=0; child_idx<(u16)children.size(); child_idx++) LL_GetChild(child_idx)->AfterLoad (this,child_idx); } // unique bone faces { for (u32 bone_idx=0; bone_idx<bones->size(); bone_idx++) { CBoneData* B = (*bones)[bone_idx]; for (u32 child_idx=0; child_idx<children.size(); child_idx++){ CBoneData::FacesVec faces = B->child_faces[child_idx]; std::sort (faces.begin(),faces.end()); CBoneData::FacesVecIt new_end = std::unique(faces.begin(),faces.end()); faces.erase (new_end,faces.end()); B->child_faces[child_idx].clear_and_free(); B->child_faces[child_idx] = faces; } } } // reset update_callback Update_Callback = NULL; // reset update frame wm_frame = u32(-1); LL_Validate (); }