void ExplainCanvas::OnMouseMotion(wxMouseEvent &ev) { ev.Skip(true); if (ev.Dragging()) return; wxClientDC dc(this); PrepareDC(dc); wxPoint logPos(ev.GetLogicalPosition(dc)); double x, y; x = (double) logPos.x; y = (double) logPos.y; // Find the nearest object int attachment = 0; ExplainShape *nearestObj = dynamic_cast<ExplainShape *>(FindShape(x, y, &attachment)); if (nearestObj) { ShowPopup(nearestObj); } }
BoundingBoxf KDTree::GetBound( uint32_t idx ) const { uint32_t meshIdx = FindShape(idx); const Mesh* mesh = mShapes[idx]->GetTriangleMesh(); if (mesh) { return mesh->GetWorldBound(idx); } else return mShapes[meshIdx]->GetWorldBound(); }
/* * Try to find a sensitive object, working up the hierarchy of composites. * */ wxShape *wxShapeCanvas::FindFirstSensitiveShape(double x, double y, int *new_attachment, int op) { wxShape *image = FindShape(x, y, new_attachment); if (!image) return NULL; wxShape *actualImage = FindFirstSensitiveShape1(image, op); if (actualImage) { double dist; // Find actual attachment actualImage->HitTest(x, y, new_attachment, &dist); } return actualImage; }
void vHavokShapeFactory::RemoveShape(const char *szShapeID) { VASSERT(m_pShapeCacheTable != NULL); if (szShapeID == NULL) return; hkpShape* pShape = FindShape(szShapeID); if (pShape == NULL) return; if (pShape->m_referenceCount == 1) { m_pShapeCacheTable->remove(szShapeID); pShape->removeReference(); } }
// Expands all the classes/fonts in the shape individually to build // a ShapeTable. int ShapeTable::BuildFromShape(const Shape& shape, const ShapeTable& master_shapes) { int num_masters = 0; for (int u_ind = 0; u_ind < shape.size(); ++u_ind) { for (int f_ind = 0; f_ind < shape[u_ind].font_ids.size(); ++f_ind) { int c = shape[u_ind].unichar_id; int f = shape[u_ind].font_ids[f_ind]; if (FindShape(c, f) < 0) { int shape_id = AddShape(c, f); int master_id = master_shapes.FindShape(c, f); if (master_id >= 0 && shape.size() > 1) { const Shape& master = master_shapes.GetShape(master_id); if (master.IsSubsetOf(shape) && !shape.IsSubsetOf(master)) { // Add everything else from the master shape. shape_table_[shape_id]->AddShape(master); ++num_masters; } } } } } return num_masters; }
// Expands all the classes/fonts in the shape individually to build // a ShapeTable. int ShapeTable::BuildFromShape(const Shape& shape, const ShapeTable& master_shapes) { BitVector shape_map(master_shapes.NumShapes()); for (int u_ind = 0; u_ind < shape.size(); ++u_ind) { for (int f_ind = 0; f_ind < shape[u_ind].font_ids.size(); ++f_ind) { int c = shape[u_ind].unichar_id; int f = shape[u_ind].font_ids[f_ind]; int master_id = master_shapes.FindShape(c, f); if (master_id >= 0) { shape_map.SetBit(master_id); } else if (FindShape(c, f) < 0) { AddShape(c, f); } } } int num_masters = 0; for (int s = 0; s < master_shapes.NumShapes(); ++s) { if (shape_map[s]) { AddShape(master_shapes.GetShape(s)); ++num_masters; } } return num_masters; }
void wxShapeCanvas::OnMouseEvent(wxMouseEvent& event) { wxClientDC dc(this); PrepareDC(dc); wxPoint logPos(event.GetLogicalPosition(dc)); double x, y; x = (double) logPos.x; y = (double) logPos.y; int keys = 0; if (event.ShiftDown()) keys = keys | KEY_SHIFT; if (event.ControlDown()) keys = keys | KEY_CTRL; bool dragging = event.Dragging(); // Check if we're within the tolerance for mouse movements. // If we're very close to the position we started dragging // from, this may not be an intentional drag at all. if (dragging) { int dx = abs(dc.LogicalToDeviceX((long) (x - m_firstDragX))); int dy = abs(dc.LogicalToDeviceY((long) (y - m_firstDragY))); if (m_checkTolerance && (dx <= GetDiagram()->GetMouseTolerance()) && (dy <= GetDiagram()->GetMouseTolerance())) { return; } else // If we've ignored the tolerance once, then ALWAYS ignore // tolerance in this drag, even if we come back within // the tolerance range. m_checkTolerance = false; } // Dragging - note that the effect of dragging is left entirely up // to the object, so no movement is done unless explicitly done by // object. if (dragging && m_draggedShape && m_dragState == StartDraggingLeft) { m_dragState = ContinueDraggingLeft; // If the object isn't m_draggable, transfer message to canvas if (m_draggedShape->Draggable()) m_draggedShape->GetEventHandler()->OnBeginDragLeft((double)x, (double)y, keys, m_draggedAttachment); else { m_draggedShape = NULL; OnBeginDragLeft((double)x, (double)y, keys); } m_oldDragX = x; m_oldDragY = y; } else if (dragging && m_draggedShape && m_dragState == ContinueDraggingLeft) { // Continue dragging m_draggedShape->GetEventHandler()->OnDragLeft(false, m_oldDragX, m_oldDragY, keys, m_draggedAttachment); m_draggedShape->GetEventHandler()->OnDragLeft(true, (double)x, (double)y, keys, m_draggedAttachment); m_oldDragX = x; m_oldDragY = y; } else if (event.LeftUp() && m_draggedShape && m_dragState == ContinueDraggingLeft) { m_dragState = NoDragging; m_checkTolerance = true; m_draggedShape->GetEventHandler()->OnDragLeft(false, m_oldDragX, m_oldDragY, keys, m_draggedAttachment); m_draggedShape->GetEventHandler()->OnEndDragLeft((double)x, (double)y, keys, m_draggedAttachment); m_draggedShape = NULL; } else if (dragging && m_draggedShape && m_dragState == StartDraggingRight) { m_dragState = ContinueDraggingRight; if (m_draggedShape->Draggable()) m_draggedShape->GetEventHandler()->OnBeginDragRight((double)x, (double)y, keys, m_draggedAttachment); else { m_draggedShape = NULL; OnBeginDragRight((double)x, (double)y, keys); } m_oldDragX = x; m_oldDragY = y; } else if (dragging && m_draggedShape && m_dragState == ContinueDraggingRight) { // Continue dragging m_draggedShape->GetEventHandler()->OnDragRight(false, m_oldDragX, m_oldDragY, keys, m_draggedAttachment); m_draggedShape->GetEventHandler()->OnDragRight(true, (double)x, (double)y, keys, m_draggedAttachment); m_oldDragX = x; m_oldDragY = y; } else if (event.RightUp() && m_draggedShape && m_dragState == ContinueDraggingRight) { m_dragState = NoDragging; m_checkTolerance = true; m_draggedShape->GetEventHandler()->OnDragRight(false, m_oldDragX, m_oldDragY, keys, m_draggedAttachment); m_draggedShape->GetEventHandler()->OnEndDragRight((double)x, (double)y, keys, m_draggedAttachment); m_draggedShape = NULL; } // All following events sent to canvas, not object else if (dragging && !m_draggedShape && m_dragState == StartDraggingLeft) { m_dragState = ContinueDraggingLeft; OnBeginDragLeft((double)x, (double)y, keys); m_oldDragX = x; m_oldDragY = y; } else if (dragging && !m_draggedShape && m_dragState == ContinueDraggingLeft) { // Continue dragging OnDragLeft(false, m_oldDragX, m_oldDragY, keys); OnDragLeft(true, (double)x, (double)y, keys); m_oldDragX = x; m_oldDragY = y; } else if (event.LeftUp() && !m_draggedShape && m_dragState == ContinueDraggingLeft) { m_dragState = NoDragging; m_checkTolerance = true; OnDragLeft(false, m_oldDragX, m_oldDragY, keys); OnEndDragLeft((double)x, (double)y, keys); m_draggedShape = NULL; } else if (dragging && !m_draggedShape && m_dragState == StartDraggingRight) { m_dragState = ContinueDraggingRight; OnBeginDragRight((double)x, (double)y, keys); m_oldDragX = x; m_oldDragY = y; } else if (dragging && !m_draggedShape && m_dragState == ContinueDraggingRight) { // Continue dragging OnDragRight(false, m_oldDragX, m_oldDragY, keys); OnDragRight(true, (double)x, (double)y, keys); m_oldDragX = x; m_oldDragY = y; } else if (event.RightUp() && !m_draggedShape && m_dragState == ContinueDraggingRight) { m_dragState = NoDragging; m_checkTolerance = true; OnDragRight(false, m_oldDragX, m_oldDragY, keys); OnEndDragRight((double)x, (double)y, keys); m_draggedShape = NULL; } // Non-dragging events else if (event.IsButton()) { m_checkTolerance = true; // Find the nearest object int attachment = 0; wxShape *nearest_object = FindShape(x, y, &attachment); if (nearest_object) // Object event { if (event.LeftDown()) { m_draggedShape = nearest_object; m_draggedAttachment = attachment; m_dragState = StartDraggingLeft; m_firstDragX = x; m_firstDragY = y; } else if (event.LeftUp()) { // N.B. Only register a click if the same object was // identified for down *and* up. if (nearest_object == m_draggedShape) nearest_object->GetEventHandler()->OnLeftClick((double)x, (double)y, keys, attachment); m_draggedShape = NULL; m_dragState = NoDragging; } else if (event.LeftDClick()) { nearest_object->GetEventHandler()->OnLeftDoubleClick((double)x, (double)y, keys, attachment); m_draggedShape = NULL; m_dragState = NoDragging; } else if (event.RightDown()) { m_draggedShape = nearest_object; m_draggedAttachment = attachment; m_dragState = StartDraggingRight; m_firstDragX = x; m_firstDragY = y; } else if (event.RightUp()) { if (nearest_object == m_draggedShape) nearest_object->GetEventHandler()->OnRightClick((double)x, (double)y, keys, attachment); m_draggedShape = NULL; m_dragState = NoDragging; } } else // Canvas event (no nearest object) { if (event.LeftDown()) { m_draggedShape = NULL; m_dragState = StartDraggingLeft; m_firstDragX = x; m_firstDragY = y; } else if (event.LeftUp()) { OnLeftClick((double)x, (double)y, keys); m_draggedShape = NULL; m_dragState = NoDragging; } else if (event.RightDown()) { m_draggedShape = NULL; m_dragState = StartDraggingRight; m_firstDragX = x; m_firstDragY = y; } else if (event.RightUp()) { OnRightClick((double)x, (double)y, keys); m_draggedShape = NULL; m_dragState = NoDragging; } } } }
void MyCanvas::OnMouseEvent(wxMouseEvent& event) { if (event.LeftDown()) { DragShape* shape = FindShape(event.GetPosition()); if (shape) { // We tentatively start dragging, but wait for // mouse movement before dragging properly. m_dragMode = TEST_DRAG_START; m_dragStartPos = event.GetPosition(); m_draggedShape = shape; } } else if (event.LeftUp() && m_dragMode != TEST_DRAG_NONE) { // Finish dragging m_dragMode = TEST_DRAG_NONE; if (!m_draggedShape || !m_dragImage) return; m_draggedShape->SetPosition(m_draggedShape->GetPosition() + event.GetPosition() - m_dragStartPos); m_dragImage->Hide(); m_dragImage->EndDrag(); delete m_dragImage; m_dragImage = NULL; wxClientDC dc(this); if (m_currentlyHighlighted) { m_currentlyHighlighted->Draw(dc); } m_draggedShape->SetShow(true); m_draggedShape->Draw(dc); m_currentlyHighlighted = (DragShape*) NULL; m_draggedShape = (DragShape*) NULL; } else if (event.Dragging() && m_dragMode != TEST_DRAG_NONE) { if (m_dragMode == TEST_DRAG_START) { // We will start dragging if we've moved beyond a couple of pixels int tolerance = 2; int dx = abs(event.GetPosition().x - m_dragStartPos.x); int dy = abs(event.GetPosition().y - m_dragStartPos.y); if (dx <= tolerance && dy <= tolerance) return; // Start the drag. m_dragMode = TEST_DRAG_DRAGGING; if (m_dragImage) delete m_dragImage; // Erase the dragged shape from the canvas m_draggedShape->SetShow(false); wxClientDC dc(this); EraseShape(m_draggedShape, dc); DrawShapes(dc); switch (m_draggedShape->GetDragMethod()) { case SHAPE_DRAG_BITMAP: { m_dragImage = new wxDragImage(m_draggedShape->GetBitmap(), wxCursor(wxCURSOR_HAND)); break; } case SHAPE_DRAG_TEXT: { m_dragImage = new wxDragImage(wxString(_T("Dragging some test text")), wxCursor(wxCURSOR_HAND)); break; } case SHAPE_DRAG_ICON: { m_dragImage = new wxDragImage(wxICON(dragicon), wxCursor(wxCURSOR_HAND)); break; } } bool fullScreen = wxGetApp().GetUseScreen(); // The offset between the top-left of the shape image and the current shape position wxPoint beginDragHotSpot = m_dragStartPos - m_draggedShape->GetPosition(); // Now we do this inside the implementation: always assume // coordinates relative to the capture window (client coordinates) //if (fullScreen) // beginDragHotSpot -= ClientToScreen(wxPoint(0, 0)); if (!m_dragImage->BeginDrag(beginDragHotSpot, this, fullScreen)) { delete m_dragImage; m_dragImage = (wxDragImage*) NULL; m_dragMode = TEST_DRAG_NONE; } else { m_dragImage->Move(event.GetPosition()); m_dragImage->Show(); } } else if (m_dragMode == TEST_DRAG_DRAGGING) { // We're currently dragging. See if we're over another shape. DragShape* onShape = FindShape(event.GetPosition()); bool mustUnhighlightOld = false; bool mustHighlightNew = false; if (m_currentlyHighlighted) { if ((onShape == (DragShape*) NULL) || (m_currentlyHighlighted != onShape)) mustUnhighlightOld = true; } if (onShape && (onShape != m_currentlyHighlighted) && onShape->IsShown()) mustHighlightNew = true; if (mustUnhighlightOld || mustHighlightNew) m_dragImage->Hide(); // Now with the drag image switched off, we can change the window contents. if (mustUnhighlightOld) { wxClientDC clientDC(this); m_currentlyHighlighted->Draw(clientDC); m_currentlyHighlighted = (DragShape*) NULL; } if (mustHighlightNew) { wxClientDC clientDC(this); m_currentlyHighlighted = onShape; m_currentlyHighlighted->Draw(clientDC, wxINVERT); } // Move and show the image again m_dragImage->Move(event.GetPosition()); if (mustUnhighlightOld || mustHighlightNew) m_dragImage->Show(); } } }
void CGraphView::OnMouseEvent(wxMouseEvent &event) { if(m_nMode==ARROW) { wxShapeCanvas::OnMouseEvent(event); return; } wxClientDC dc(this); PrepareDC(dc); int ch,cw; dc.GetSize(&cw,&ch); wxPoint logPos(event.GetLogicalPosition(dc)); double x, y; x = (double) logPos.x; y = (double) logPos.y; int keys = 0; if (event.ShiftDown()) keys = keys | KEY_SHIFT; if (event.ControlDown()) keys = keys | KEY_CTRL; bool dragging = event.Dragging(); // Find the nearest object if(event.IsButton()) { if(event.RightDown()) { if(m_pHoverShape) { CNodeEvent evt; evt.SetEventType(GV_NODE_MENU); evt.SetNode(m_pHoverShape->GetId()); evt.SetPosition(event.GetPosition()); AddPendingEvent(evt); } } else if(event.LeftDClick()) { if(m_pHoverShape) { CNodeEvent evt; evt.SetEventType(GV_NODE_ACTIVATED); evt.SetNode(m_pHoverShape->GetId()); evt.SetPosition(event.GetPosition()); AddPendingEvent(evt); } } else if(event.LeftDown()) { if(m_pHoverShape) { m_pClickShape=m_pHoverShape; return; } else { m_pClickShape=NULL; if(event.ShiftDown()) { //m_bZooming=true; //m_ptGrab=event.GetPosition(); //UpdateCursor(); //CaptureMouse(); } else { m_bGrabbing=true; m_ptGrab=event.GetPosition(); int vx,vy; GetViewStart(&vx,&vy); m_ptGrabLogical=wxPoint(vx,vy); UpdateCursor(); CaptureMouse(); } return; } } else if(event.LeftUp()) { if(m_pClickShape && (m_pClickShape==m_pHoverShape)) { CNodeEvent evt; evt.SetEventType(GV_NODE_SELECTED); evt.SetNode(m_pHoverShape->GetId()); evt.SetPosition(event.GetPosition()); AddPendingEvent(evt); return; } if(m_bGrabbing || m_bZooming) { ReleaseMouse(); } m_bZooming=false; m_bGrabbing=false; UpdateCursor(); } // if(nearest_object) { // } return; } else if(event.Moving()) { if(m_bGrabbing) { int nx,ny; event.GetPosition(&nx,&ny); nx=nx-m_ptGrab.x; ny=ny-m_ptGrab.y; int vx,vy; vx=m_ptGrabLogical.x-nx; vy=m_ptGrabLogical.y-ny; Scroll(vx,vy); UpdateCursor(); } else if(m_bZooming) { /* int nx,ny; event.GetPosition(&nx,&ny); nx=nx-m_ptGrab.x; ny=ny-m_ptGrab.y; double scale; if(ny>0.0) { scale=1.0+3.0*(ny/(ch/2.0)); } else { scale=1.0-0.75*(-ny/(ch/2.0)); } int vsx,vsy; GetViewStart(&vsx,&vsy); vsx=vsx*scale/m_diag.GetZoomFactor(); vsy=vsy*scale/m_diag.GetZoomFactor(); m_diag.SetZoomFactor(scale); SetScrollbars(1,1,m_nGraphWidth*scale,m_nGraphHeight*scale,vsx,vsy,true); Refresh(true); */ } else { int attachment=0; wxShape *shape=FindShape(x,y,&attachment,NULL,NULL,CLASSINFO(wxLineShape)); if(shape!=m_pHoverShape) { m_pHoverShape=shape; UpdateCursor(); } } } else if(event.Entering()) { UpdateCursor(); } }
hkRefNew<hkpShape> vHavokShapeFactory::CreateConvexHullShapeFromMesh(VBaseMesh *pMesh, const hkvVec3& vScaleIn, const char **szShapeCacheId, int iCreationFlags) { VVERIFY_OR_RET_VAL(pMesh != NULL, NULL); const bool bAllowStaticMeshCaching = vHavokPhysicsModule_GetDefaultWorldRuntimeSettings().m_bEnableShapeCaching==TRUE; const bool bCacheShape = iCreationFlags & VShapeCreationFlags_CACHE_SHAPE; const vHavokPhysicsModule *pModule = vHavokPhysicsModule::GetInstance(); VASSERT(pModule != NULL); const bool bForceHktShapeCaching = pModule->IsHktShapeCachingEnforced(); const bool bShrinkShape = iCreationFlags & VShapeCreationFlags_SHRINK; char szShapeId[512]; if (bCacheShape) { VASSERT(szShapeCacheId != NULL); // Check whether shape has been already cached for this model with the respective scaling. vHavokShapeFactory::GetIDStringForConvexShape(szShapeId, pMesh->GetFilename(), vScaleIn, bShrinkShape); hkpShape *pCachedShape = FindShape(szShapeId, szShapeCacheId); if (pCachedShape) { pCachedShape->addReference(); return pCachedShape; } // Check if shape is already cached on disk if (bAllowStaticMeshCaching) { pCachedShape = vHavokCachedShape::LoadConvexShape(pMesh, vScaleIn, bShrinkShape); if (pCachedShape) { *szShapeCacheId = AddShape(szShapeId, pCachedShape); #ifdef HK_DEBUG_SLOW const hkClass* loadedClassType = hkVtableClassRegistry::getInstance().getClassFromVirtualInstance(pCachedShape); HK_ASSERT2(0x695cc897, loadedClassType && (hkString::strCmp( loadedClassType->getName(), "hkvConvexVerticesShape" ) == 0), "Serialized in a unexpected cached Havok shape type!"); #endif return pCachedShape; } else if(!Vision::Editor.IsInEditor() && !bForceHktShapeCaching) { Vision::Error.Warning("Cached HKT file for %s is missing. Please generate HKT file (see documentation for details).", pMesh->GetFilename()); } } } // Get the collision mesh for the specified mesh const IVCollisionMesh *pColMesh = (iCreationFlags & VShapeCreationFlags_USE_VCOLMESH) ? pMesh->GetCollisionMesh(true, true) : pMesh->GetTraceMesh(true, true); VASSERT(pColMesh != NULL); hkvMat4 tranform; tranform.setScalingMatrix(vScaleIn); hkGeometry geom; const int iNumColMeshes = hkvMath::Max(pColMesh->GetSubmeshCount(), 1); for (int i=0;i<iNumColMeshes;i++) BuildGeomFromCollisionMesh(pColMesh, i, tranform, true, geom); VVERIFY_OR_RET_VAL(geom.m_vertices.getSize() > 0, NULL); // Set the build configuration to set planes equations and connectivity automatically hkpConvexVerticesShape::BuildConfig config; config.m_createConnectivity = true; config.m_shrinkByConvexRadius = bShrinkShape; hkStridedVertices stridedVerts; stridedVerts.m_numVertices = geom.m_vertices.getSize(); stridedVerts.m_striding = sizeof(hkVector4); stridedVerts.m_vertices = (const hkReal*)geom.m_vertices.begin(); // Create convex shape hkvConvexVerticesShape *pConvexShape = new hkvConvexVerticesShape(pColMesh->GetFileTime(), stridedVerts, config); // Add shape to cache if (bCacheShape) *szShapeCacheId = AddShape(szShapeId, pConvexShape); // Only cache shape to HKT file when inside vForge or when enforced. if ((Vision::Editor.IsInEditor() && bAllowStaticMeshCaching && bCacheShape) || bForceHktShapeCaching) vHavokCachedShape::SaveConvexShape(pMesh, vScaleIn, bShrinkShape, pConvexShape); return pConvexShape; }
hkRefNew<hkpShape> vHavokShapeFactory::CreateShapeFromStaticMeshInstances(const VisStaticMeshInstCollection &meshInstances, int iCreationFlags, const char **szShapeCacheId) { int iCount = meshInstances.GetLength(); VVERIFY_OR_RET_VAL(iCount>0 && szShapeCacheId!=NULL, NULL); // Actual mesh scale, which is only used for caching. hkvVec3 vScale(hkvNoInitialization); ExtractScaling(meshInstances[0]->GetTransform(), vScale); char szShapeId[512]; const bool bAllowStaticMeshCaching = vHavokPhysicsModule_GetDefaultWorldRuntimeSettings().m_bEnableShapeCaching==TRUE; const vHavokPhysicsModule *pModule = vHavokPhysicsModule::GetInstance(); VASSERT(pModule != NULL); const bool bForceHktShapeCaching = pModule->IsHktShapeCachingEnforced(); // For single mesh instances the per instance welding type is used. For merged mesh instances the global merged welding type is used. VisWeldingType_e eWeldingType = (iCount==1) ? meshInstances[0]->GetWeldingType() : (VisWeldingType_e)vHavokPhysicsModule_GetWorldSetupSettings().m_iMergedStaticWeldingType; const bool bAllowPerTriCollisionInfo = iCreationFlags & VShapeCreationFlags_ALLOW_PERTRICOLINFO; const bool bShrinkByCvxRadius = iCreationFlags & VShapeCreationFlags_SHRINK; // Check whether shape has been already cached for this mesh with the respective scaling. // We are just caching single static mesh instances and no static mesh collections. hkpShape *pCachedShape = HK_NULL; if (iCount == 1) { // first, find the convex version GetIDStringForConvexShape(szShapeId, meshInstances[0]->GetMesh()->GetFilename(), vScale, bShrinkByCvxRadius); pCachedShape = FindShape(szShapeId, szShapeCacheId); if (!pCachedShape) { // then find the mesh version GetIDStringForMeshShape(szShapeId, meshInstances[0]->GetMesh()->GetFilename(), vScale, meshInstances[0]->GetCollisionBehavior(), eWeldingType); pCachedShape = FindShape(szShapeId, szShapeCacheId); } if (pCachedShape) { pCachedShape->addReference(); return pCachedShape; } if (bAllowStaticMeshCaching) { // first, find the convex version pCachedShape = vHavokCachedShape::LoadConvexShape(meshInstances[0]->GetMesh(), vScale, bShrinkByCvxRadius); if (pCachedShape) { *szShapeCacheId = AddShape(szShapeId, pCachedShape); #ifdef HK_DEBUG_SLOW const hkClass* loadedClassType = hkVtableClassRegistry::getInstance().getClassFromVirtualInstance(pCachedShape); HK_ASSERT2(0x5432c902, loadedClassType && (hkString::strCmp( loadedClassType->getName(), "hkvConvexVerticesShape" ) == 0), "Serialized in a unexpected cached Havok shape type!"); #endif return pCachedShape; } else { // then find the mesh version pCachedShape = vHavokCachedShape::LoadMeshShape(meshInstances[0]->GetMesh(), vScale, meshInstances[0]->GetCollisionBehavior(), eWeldingType); } if (pCachedShape ) { *szShapeCacheId = AddShape(szShapeId, pCachedShape); #ifdef HK_DEBUG_SLOW const hkClass* loadedClassType = hkVtableClassRegistry::getInstance().getClassFromVirtualInstance(pCachedShape); HK_ASSERT2(0x5432c902, loadedClassType && (hkString::strCmp( loadedClassType->getName(), "hkvBvCompressedMeshShape" ) == 0), "Serialized in a unexpected cached Havok shape type!"); #endif hkvBvCompressedMeshShape *pCompressedMeshShape = reinterpret_cast<hkvBvCompressedMeshShape*>(pCachedShape); pCompressedMeshShape->SetupMaterials(); return pCachedShape; } else if(!Vision::Editor.IsInEditor() && !bForceHktShapeCaching) { Vision::Error.Warning("Cached HKT file for %s is missing. Please generate HKT file (see documentation for details).", meshInstances[0]->GetMesh()->GetFilename()); } } } // Get the reference transformation. We use the first static mesh as reference // transformation, and thus as the position of the corresponding rigid body. hkvMat4 referenceTransform = meshInstances[0]->GetTransform(); // Remove any scaling from the reference matrix. This one has to be applied to // the Havok shapes, and thus needs to be part of the mesh transforms. referenceTransform.setScalingFactors(hkvVec3 (1)); // We need the inverse referenceTransform to transform each instance into reference space referenceTransform.invert(); referenceTransform.setRow (3, hkvVec4 (0, 0, 0, 1)); // Determine collision type from first static mesh instance. const VisStaticMeshInstance_cl *pMeshInstance = meshInstances[0]; VisStaticMesh_cl *pMesh = pMeshInstance->GetMesh(); IVCollisionMesh *pColMesh = pMesh->GetCollisionMesh(true, true); const bool bIsConvex = pColMesh->GetType()==VIS_COLMESH_GEOTYPE_CONVEXHULL; // Only create a convex shape if a single mesh instance is used, since otherwise merging multiple mesh instances in one single convex hull // will provide in most cases not the desired behavior. Moreover we can only create either a convex hull or a concave mesh shape, therefore // mesh instances with different collision type can't be merged into one shape. hkpShape *pShape = (bIsConvex && iCount==1) ? CreateConvexShapeFromStaticMeshInstances(meshInstances, referenceTransform, bShrinkByCvxRadius) : CreateMeshShapeFromStaticMeshInstances(meshInstances, referenceTransform, bAllowPerTriCollisionInfo, eWeldingType); // We are just caching single static mesh instances and no static mesh collections. if (iCount == 1) { *szShapeCacheId = AddShape(szShapeId, pShape); // Only cache shape to HKT file when inside vForge or when enforced. if ((Vision::Editor.IsInEditor() && bAllowStaticMeshCaching) || bForceHktShapeCaching) { if (bIsConvex) vHavokCachedShape::SaveConvexShape(meshInstances[0]->GetMesh(), vScale, bShrinkByCvxRadius, (hkvConvexVerticesShape*)pShape); else vHavokCachedShape::SaveMeshShape(meshInstances[0]->GetMesh(), vScale, meshInstances[0]->GetCollisionBehavior(), eWeldingType, (hkvBvCompressedMeshShape*)pShape); } } return pShape; }
// -------------------------------------------------------------------------- // // Havok Shape - Mesh // // -------------------------------------------------------------------------- // hkRefNew<hkpShape> vHavokShapeFactory::CreateShapeFromMesh(VBaseMesh* pMesh, const hkvVec3& vScale, const char **szShapeCacheId, int iCreationFlags, VisWeldingType_e eWeldingType) { VVERIFY_OR_RET_VAL(pMesh != NULL, NULL); const bool bAllowStaticMeshCaching = vHavokPhysicsModule_GetDefaultWorldRuntimeSettings().m_bEnableShapeCaching==TRUE; const bool bCacheShape = iCreationFlags & VShapeCreationFlags_CACHE_SHAPE; const vHavokPhysicsModule *pModule = vHavokPhysicsModule::GetInstance(); VASSERT(pModule != NULL); const bool bForceHktShapeCaching = pModule->IsHktShapeCachingEnforced(); char szShapeId[512]; if (bCacheShape) { VASSERT(szShapeCacheId != NULL); // Check whether shape has been already cached for this model with the respective scaling vHavokShapeFactory::GetIDStringForMeshShape(szShapeId, pMesh->GetFilename(), vScale, VisStaticMeshInstance_cl::VIS_COLLISION_BEHAVIOR_CUSTOM, eWeldingType); hkpShape *pCachedShape = FindShape(szShapeId, szShapeCacheId); if (pCachedShape) { pCachedShape->addReference(); return pCachedShape; } // Check if shape is already cached on disk if (bAllowStaticMeshCaching ) { pCachedShape = vHavokCachedShape::LoadMeshShape(pMesh, vScale, VisStaticMeshInstance_cl::VIS_COLLISION_BEHAVIOR_CUSTOM, eWeldingType); if (pCachedShape) { *szShapeCacheId = AddShape(szShapeId, pCachedShape); #ifdef HK_DEBUG_SLOW const hkClass* loadedClassType = hkVtableClassRegistry::getInstance().getClassFromVirtualInstance(pCachedShape); HK_ASSERT2(0x695cc897, loadedClassType && (hkString::strCmp( loadedClassType->getName(), "hkvBvCompressedMeshShape" ) == 0), "Serialized in a unexpected cached Havok shape type!"); #endif hkvBvCompressedMeshShape* pCompressedMeshShape = reinterpret_cast<hkvBvCompressedMeshShape*>(pCachedShape); pCompressedMeshShape->SetupMaterials(); // just to be sure we don't try to access it as material ptr ever return pCompressedMeshShape; } else if(!Vision::Editor.IsInEditor() && !bForceHktShapeCaching) { Vision::Error.Warning("Cached HKT file for %s is missing. Please generate HKT file (see documentation for details).", pMesh->GetFilename()); } } } hkGeometry geom; // Get the collision mesh for the specified mesh IVCollisionMesh *pColMesh = (iCreationFlags & VShapeCreationFlags_USE_VCOLMESH) ? pMesh->GetCollisionMesh(true, true) : pMesh->GetTraceMesh(true, true); VASSERT(pColMesh != NULL); hkvMat4 tranform; tranform.setScalingMatrix(vScale); int iNumColMeshes = hkvMath::Max(pColMesh->GetSubmeshCount(), 1); for (int i=0;i<iNumColMeshes;i++) BuildGeomFromCollisionMesh(pColMesh, i, tranform, false, geom); VVERIFY_OR_RET_VAL(geom.m_vertices.getSize() > 0, NULL); ///XX A DynamicMesh can be animated. We are treating it as static here. hkpDefaultBvCompressedMeshShapeCinfo ci( &geom ); ci.m_collisionFilterInfoMode = hkpBvCompressedMeshShape::PER_PRIMITIVE_DATA_NONE; // Collision info ci.m_userDataMode = hkpBvCompressedMeshShape::PER_PRIMITIVE_DATA_NONE; // Materials ci.m_weldingType = vHavokConversionUtils::VisToHkWeldingType(eWeldingType); hkvBvCompressedMeshShape* pCompressedMeshShape = new hkvBvCompressedMeshShape(ci, pColMesh->GetFileTime()); if (pCompressedMeshShape->getNumChildShapes() <= 0) { pCompressedMeshShape->removeReference(); const char *szMeshFilename = (pMesh->GetFilename() != NULL) ? pMesh->GetFilename() : "UnnamedMesh"; Vision::Error.Warning("Physics Shape for [%s] is empty. Volume too small?", szMeshFilename); return NULL; } if (bCacheShape) *szShapeCacheId = AddShape(szShapeId, pCompressedMeshShape); // Only cache shape to HKT file when inside vForge or when enforced. if ((Vision::Editor.IsInEditor() && bAllowStaticMeshCaching && bCacheShape) || bForceHktShapeCaching) vHavokCachedShape::SaveMeshShape(pMesh, vScale, VisStaticMeshInstance_cl::VIS_COLLISION_BEHAVIOR_CUSTOM, eWeldingType, pCompressedMeshShape); return pCompressedMeshShape; }