Exemple #1
0
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);
	}
}
Exemple #2
0
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();
  }
}
Exemple #5
0
// 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;
}
Exemple #6
0
// 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;
      }
    }
  }
}
Exemple #8
0
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;
}