void CLTypeEntryItem::MakeDragRegion( const STableCell& inCell, RgnHandle outGlobalDragRgn, Rect& outGlobalItemBounds) { // Validate pointers. ValidateThis_(); ValidateObject_(mOutlineTable); // Make sure this cell is visible. Rect ignore; if (!mOutlineTable->GetLocalCellRect(inCell, ignore)) return; // Find out what we're supposed to draw. SOutlineDrawContents drawInfo; GetDrawContents(inCell, drawInfo); // Create a bounds rect that starts at the upper left corner // of the icon and has the width & height of the placed item. if (drawInfo.outHasIcon && (drawInfo.outIconSuite != nil) && !::EmptyRect(&drawInfo.prIconFrame)) outGlobalItemBounds = drawInfo.prIconFrame; else outGlobalItemBounds = drawInfo.prTextFrame; SDimension32 dragSize; mTypeEntry->GetDragSize(dragSize); outGlobalItemBounds.bottom = outGlobalItemBounds.top + dragSize.height; outGlobalItemBounds.right = outGlobalItemBounds.left + dragSize.width; // Convert to global coordinates. mOutlineTable->LocalToPortPoint(topLeft(outGlobalItemBounds)); mOutlineTable->LocalToPortPoint(botRight(outGlobalItemBounds)); mOutlineTable->PortToGlobalPoint(topLeft(outGlobalItemBounds)); mOutlineTable->PortToGlobalPoint(botRight(outGlobalItemBounds)); // Item bounds have been created. Now create drag region that // is the same size. RgnHandle tempRgn = ::NewRgn(); #if PP_Target_Carbon ThrowIfNil_(tempRgn); #else ValidateHandle_((Handle) tempRgn); #endif ::RectRgn(tempRgn, &outGlobalItemBounds); ::UnionRgn(outGlobalDragRgn, tempRgn, outGlobalDragRgn); ::DisposeRgn(tempRgn); }
void LToG (Rect *r) { Point p1, p2; p1 = topLeft (*r); p2 = botRight (*r); LocalToGlobal (&p1); LocalToGlobal (&p2); Pt2Rect (p1, p2, r); }
// -------------------------------------------------------------------------------------- void DisplayHelpBalloons(WindowRef prefsWindow) { GrafPtr savedPort; Point mouseLocation; Rect hotRects[3]; short hotRectID; static int previousHotRectID = kNotInHotRect; GetPort(&savedPort); SetPortWindowPort(prefsWindow); GetMouse(&mouseLocation); GetWindowProperty(prefsWindow, kAppSignature, kHotRectsTag, 3 * sizeof(Rect), NULL, hotRects); for (hotRectID = kInList; hotRectID < kNotInHotRect; hotRectID++) { if (PtInRect(mouseLocation, &hotRects[hotRectID])) { if (hotRectID != previousHotRectID) { HMMessageRecord helpMessage; Point tips[3]; helpMessage.hmmHelpType = khmmStringRes; helpMessage.u.hmmStringRes.hmmResID = rHelpStrings; helpMessage.u.hmmStringRes.hmmIndex = hotRectID + 1; GetWindowProperty(prefsWindow, kAppSignature, kBalloonTipsTag, 3 * sizeof(Point), NULL, tips); LocalToGlobal(&tips[hotRectID]); LocalToGlobal(&topLeft(hotRects[hotRectID])); LocalToGlobal(&botRight(hotRects[hotRectID])); HMShowBalloon(&helpMessage, tips[hotRectID], &hotRects[hotRectID], NULL, kBalloonWDEFID, kTopLeftTipPointsLeftVariant, kHMRegularWindow); } break; } } previousHotRectID = hotRectID; SetPort(savedPort); }
void ofApp::setupScene(int width, int height) { /* setup camera */ double aspectRatio = static_cast<double>(width) / height; ofVec3f topLeft (-CAMERA_SIZE * aspectRatio, CAMERA_SIZE, 0.0); ofVec3f botLeft (-CAMERA_SIZE * aspectRatio, -CAMERA_SIZE, 0.0); ofVec3f botRight( CAMERA_SIZE * aspectRatio, -CAMERA_SIZE, 0.0); cam = OffAxisCamera(topLeft, botLeft, botRight); cam.setPosition(ofVec3f(0.0, 0.0, 50.0f)); /* calculate grid box dimension */ ofVec3f camWidthVec = botRight - botLeft; double camWidth = camWidthVec.length(); gridBox = GridBox(ofVec3f(-CAMERA_SIZE * aspectRatio, -CAMERA_SIZE, 0.0f), camWidth, camWidth / aspectRatio, 8.0f); }
//////////////////////////////////////////////////////////// // Helper Function for Cascade Classifier // Note: Cascade classifier is not currently used // by this application. We left the functions associated // with this method for future reference. //////////////////////////////////////////////////////////// void detectAndDisplay(Mat image, string panel_cascade_name) { CascadeClassifier panel_cascade; if (!panel_cascade.load(panel_cascade_name)){ printf("--(!)Error loading\n"); return; }; std::vector<Rect> detectedPanels; Mat frame_gray; cvtColor(image, frame_gray, CV_BGR2GRAY); equalizeHist(frame_gray, frame_gray); //-- Detect faces panel_cascade.detectMultiScale(frame_gray, detectedPanels, 1.1, 20, 0 | CV_HAAR_SCALE_IMAGE, Size(200, 200)); for (size_t i = 0; i < detectedPanels.size(); i++) { Point topLeft(detectedPanels[i].x, detectedPanels[i].y); Point botRight(detectedPanels[i].x + detectedPanels[i].width, detectedPanels[i].y + detectedPanels[i].height); rectangle(image, topLeft, botRight, Scalar(0, 0, 255), 4); } //-- Show what you got imshow("Classifier Result", image); }
Boolean VEBackdrop::CalcLocalFrameForRootObject( Rect& outFrameRect) { // Validate pointers. ValidateThis_(); // First make sure there is a root object. if (mRootObject != nil) { // There is, make sure it has a drawing agent. ValidateObject_(mRootObject.GetObject()); VEDrawingAgent* rootAgent = mRootObject->FindDrawingAgent(); if (rootAgent != nil) { // There is an agent, see if it can give us a frame. ValidateObject_(rootAgent); if (rootAgent->CalcPortFrameRect(outFrameRect)) { PortToLocalPoint(topLeft(outFrameRect)); PortToLocalPoint(botRight(outFrameRect)); return true; } } } // Nope. Root object isn't visible. return false; }
/*
//------------------------------------------------------------------------- // // DoMouseDown // //------------------------------------------------------------------------- PRBool nsMacMessagePump::DoMouseDown(EventRecord &anEvent) { WindowPtr whichWindow; WindowPartCode partCode; PRBool handled = PR_FALSE; partCode = ::FindWindow(anEvent.where, &whichWindow); switch (partCode) { case inNoWindow: break; case inCollapseBox: // we never seem to get this. case inSysWindow: if ( gRollupListener && gRollupWidget ) gRollupListener->Rollup(); break; case inMenuBar: { // If a xul popup is displayed, roll it up and don't allow the click // through to the menu code. This is how MacOS context menus work, so // I think this is a valid solution. if ( gRollupListener && gRollupWidget ) { gRollupListener->Rollup(); } else { ::MenuSelect(anEvent.where); handled = PR_TRUE; } break; } case inContent: { nsGraphicsUtils::SafeSetPortWindowPort(whichWindow); if ( IsWindowHilited(whichWindow) || (gRollupListener && gRollupWidget) ) handled = DispatchOSEventToRaptor(anEvent, whichWindow); else { nsCOMPtr<nsIWidget> topWidget; nsToolkit::GetTopWidget ( whichWindow, getter_AddRefs(topWidget) ); nsCOMPtr<nsPIWidgetMac> macWindow ( do_QueryInterface(topWidget) ); if ( macWindow ) { // a click occurred in a background window. Use WaitMouseMove() to determine if // it was a click or a drag. If it was a drag, send a drag gesture to the // background window. We don't need to rely on the ESM to track the gesture, // the OS has just told us. If it was a click, bring it to the front like normal. Boolean initiateDragFromBGWindow = ::WaitMouseMoved(anEvent.where); if ( initiateDragFromBGWindow ) { nsCOMPtr<nsIEventSink> sink ( do_QueryInterface(topWidget) ); if ( sink ) { // dispach a mousedown, an update event to paint any changes, // then the drag gesture event PRBool handled = PR_FALSE; sink->DispatchEvent ( &anEvent, &handled ); EventRecord updateEvent = anEvent; updateEvent.what = updateEvt; updateEvent.message = NS_REINTERPRET_CAST(UInt32, whichWindow); sink->DispatchEvent ( &updateEvent, &handled ); sink->DragEvent ( NS_DRAGDROP_GESTURE, anEvent.where.h, anEvent.where.v, 0L, &handled ); } } else { PRBool enabled; if (NS_SUCCEEDED(topWidget->IsEnabled(&enabled)) && !enabled) ::SysBeep(1); else macWindow->ComeToFront(); } handled = PR_TRUE; } } break; } case inDrag: { nsGraphicsUtils::SafeSetPortWindowPort(whichWindow); Point oldTopLeft = {0, 0}; ::LocalToGlobal(&oldTopLeft); // roll up popups BEFORE we start the drag if ( gRollupListener && gRollupWidget ) gRollupListener->Rollup(); Rect screenRect; ::GetRegionBounds(::GetGrayRgn(), &screenRect); ::DragWindow(whichWindow, anEvent.where, &screenRect); Point newTopLeft = {0, 0}; ::LocalToGlobal(&newTopLeft); // only activate if the command key is not down if (!(anEvent.modifiers & cmdKey)) { nsCOMPtr<nsIWidget> topWidget; nsToolkit::GetTopWidget(whichWindow, getter_AddRefs(topWidget)); nsCOMPtr<nsPIWidgetMac> macWindow ( do_QueryInterface(topWidget) ); if ( macWindow ) macWindow->ComeToFront(); } // Dispatch the event because some windows may want to know that they have been moved. anEvent.where.h += newTopLeft.h - oldTopLeft.h; anEvent.where.v += newTopLeft.v - oldTopLeft.v; handled = DispatchOSEventToRaptor(anEvent, whichWindow); break; } case inGrow: { nsGraphicsUtils::SafeSetPortWindowPort(whichWindow); Rect sizeLimit; sizeLimit.top = kMinWindowHeight; sizeLimit.left = kMinWindowWidth; sizeLimit.bottom = 0x7FFF; sizeLimit.right = 0x7FFF; Rect newSize; ::ResizeWindow(whichWindow, anEvent.where, &sizeLimit, &newSize); Point newPt = botRight(newSize); ::LocalToGlobal(&newPt); newPt.h -= 8, newPt.v -= 8; anEvent.where = newPt; // important! handled = DispatchOSEventToRaptor(anEvent, whichWindow); break; } case inGoAway: { nsGraphicsUtils::SafeSetPortWindowPort(whichWindow); if (::TrackGoAway(whichWindow, anEvent.where)) { handled = DispatchOSEventToRaptor(anEvent, whichWindow); } break; } case inZoomIn: case inZoomOut: if (::TrackBox(whichWindow, anEvent.where, partCode)) { if (partCode == inZoomOut) { nsCOMPtr<nsIWidget> topWidget; nsToolkit::GetTopWidget ( whichWindow, getter_AddRefs(topWidget) ); nsCOMPtr<nsPIWidgetMac> macWindow ( do_QueryInterface(topWidget) ); if ( macWindow ) macWindow->CalculateAndSetZoomedSize(); } // !!! Do not call ZoomWindow before calling DispatchOSEventToRaptor // otherwise nsMacEventHandler::HandleMouseDownEvent won't get // the right partcode for the click location handled = DispatchOSEventToRaptor(anEvent, whichWindow); } break; case inToolbarButton: // Mac OS X only nsGraphicsUtils::SafeSetPortWindowPort(whichWindow); handled = DispatchOSEventToRaptor(anEvent, whichWindow); break; } return handled; }
bool CFXTransExplodingCubes::LoadData(CResourceList* pResourceList) { // Create RTT Texture CVarInt::CValueInt valueInt; EvaluateVar("RenderTex Width", 0.0f, &valueInt); if(valueInt.GetValue() < 1) valueInt.SetValue(1); int nWidthPwr = MYROUND(log10f(valueInt.GetValue()) / log10f(2)); EvaluateVar("RenderTex Height", 0.0f, &valueInt); if(valueInt.GetValue() < 1) valueInt.SetValue(1); int nHeightPwr = MYROUND(log10f(valueInt.GetValue()) / log10f(2)); int nWidth = pow(2, nWidthPwr); int nHeight = pow(2, nHeightPwr); UtilGL::Texturing::STexLoadOptions texOptions; texOptions.SetDefaults(); texOptions.eFilter = UtilGL::Texturing::FILTER_LINEAR; m_textureRTT.LoadFlat(nWidth, nHeight, CVector4(0.0f, 0.0f, 0.0f, 1.0f), false, false, &texOptions); // Create cubes CVarInt::CValueInt valueXCubes; CVarInt::CValueInt valueYCubes; CVarInt::CValueInt valueSeed; CVarFloat::CValueFloat valueAngleMultiple; CVarFloat::CValueFloat valueDepth; CVarFloat::CValueFloat valueAngleStep; CVarFloat::CValueFloat valueAccelX; CVarFloat::CValueFloat valueAccelY; CVarFloat::CValueFloat valueAccelZ; CVarFloat::CValueFloat valueSpeedX; CVarFloat::CValueFloat valueSpeedY; CVarFloat::CValueFloat valueSpeedZ; CVarFloat::CValueFloat valueAssimetry; CVarFloat::CValueFloat valueMaxRotation; CVarFloat::CValueFloat valueVariation; EvaluateVar("X Cubes", 0.0f, &valueXCubes); EvaluateVar("Y Cubes", 0.0f, &valueYCubes); EvaluateVar("Seed", 0.0f, &valueSeed); EvaluateVar("Z Depth", 0.0f, &valueDepth); EvaluateVar("Angle Step", 0.0f, &valueAngleStep); EvaluateVar("Accel X", 0.0f, &valueAccelX); EvaluateVar("Accel Y", 0.0f, &valueAccelY); EvaluateVar("Accel Z", 0.0f, &valueAccelZ); EvaluateVar("Start Speed X", 0.0f, &valueSpeedX); EvaluateVar("Start Speed Y", 0.0f, &valueSpeedY); EvaluateVar("Start Speed Z", 0.0f, &valueSpeedZ); EvaluateVar("Assimetry", 0.0f, &valueAssimetry); EvaluateVar("Max Rotation", 0.0f, &valueMaxRotation); EvaluateVar("Variation", 0.0f, &valueVariation); CVector3 v3Accel(valueAccelX.GetValue(), valueAccelY.GetValue(), valueAccelZ.GetValue()); CVector3 v3Speed(valueSpeedX.GetValue(), valueSpeedY.GetValue(), valueSpeedZ.GetValue()); int xRes = valueXCubes.GetValue() > 1 ? valueXCubes.GetValue() : 1; int yRes = valueYCubes.GetValue() > 1 ? valueYCubes.GetValue() : 1; float fSizeX = 1.0f / xRes; float fSizeY = 1.0f / yRes; srand(valueSeed.GetValue()); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60.0f, 1.33f, 1.0f, 100.0f); UtilGL::Transforming::ClearMatrix(UtilGL::Transforming::MATRIX_WORLD); UtilGL::Transforming::ClearMatrix(UtilGL::Transforming::MATRIX_VIEW); for(int y = 0; y < yRes; y++) { for(int x = 0; x < xRes; x++) { SCube cube; cube.fU = x * fSizeX; cube.fV = 1.0f - (y * fSizeY); cube.fU2 = x * fSizeX + fSizeX; cube.fV2 = 1.0f - (y * fSizeY + fSizeY); CVector3 upLeft (x * fSizeX, y * fSizeY, 0.5f); CVector3 botRight(x * fSizeX + fSizeX, y * fSizeY + fSizeY, 0.5f); UtilGL::Transforming::NormViewportToLocal(&upLeft); UtilGL::Transforming::NormViewportToLocal(&botRight); float fHalfX = (botRight.X() - upLeft.X()) * 0.5f; float fHalfY = (botRight.Y() - upLeft.Y()) * 0.5f; float fHalfZ = valueDepth.GetValue() * 0.5f; cube.v1.Set(-fHalfX, -fHalfY, +fHalfZ); cube.v2.Set(-fHalfX, +fHalfY, +fHalfZ); cube.v3.Set(+fHalfX, +fHalfY, +fHalfZ); cube.v4.Set(+fHalfX, -fHalfY, +fHalfZ); cube.v5.Set(-fHalfX, -fHalfY, -fHalfZ); cube.v6.Set(-fHalfX, +fHalfY, -fHalfZ); cube.v7.Set(+fHalfX, +fHalfY, -fHalfZ); cube.v8.Set(+fHalfX, -fHalfY, -fHalfZ); cube.v3Center.Set( (x * fSizeX) + (fSizeX * 0.5f), (y * fSizeY) + (fSizeY * 0.5f), 0.5f); cube.v3Accel = v3Accel * ComputeRandWithVariation(1.0f, valueVariation.GetValue()) * ((botRight.Y() - upLeft.Y()) * xRes); cube.v3Speed = v3Speed * ComputeRandWithVariation(1.0f, valueVariation.GetValue()) * ((botRight.Y() - upLeft.Y()) * xRes); cube.fStartTime = (MYFABSF(x - (xRes / 2.0f)) / (float)(xRes / 2.0f)) * valueAssimetry.GetValue(); cube.fRotation = ComputeRand(0.0f, valueMaxRotation.GetValue()); UtilGL::Transforming::NormViewportToLocal(&cube.v3Center); cube.fTStart = 0.0f; cube.fTEnd = 1.0f; m_vecCubes.push_back(cube); } } return true; }
void sstSequence::ClampBeats() { float margin = 100.f; vsScreen *screen = vsSystem::GetScreen(); float fov = screen->GetScene(0)->GetFOV(); float screenHeight = fov; float screenWidth = screenHeight * screen->GetAspectRatio(); float topEdge = (screenHeight * -.5f) + 100.0f + margin; float botEdge = 0.f; // never go below the halfway point, because that's just not nice. :) float leftEdge = (screenWidth * -0.5f) + margin; float rightEdge = (screenWidth * 0.5f) - margin; // bool clampedSuccessfully = false; // if we're supposed to be on the right, clamp us onto the right side. if ( m_onRight ) leftEdge = 0.f; else rightEdge = 0.f; vsVector2D worldBeatPos[MAX_BEATS]; vsVector2D topLeft(10000.0f,10000.0f); // arbitrary large values vsVector2D botRight(-1000.0f,-10000.0f); // arbitrary small values for ( int i = 0; i < m_beatCount; i++ ) { vsTransform2D t = GetTransformAtTime( m_segment[i].m_time ); worldBeatPos[i] = t.ApplyTo( m_segment[i].m_position ); if ( worldBeatPos[i].x < topLeft.x ) topLeft.x = worldBeatPos[i].x; if ( worldBeatPos[i].x > botRight.x ) botRight.x = worldBeatPos[i].x; if ( worldBeatPos[i].y < topLeft.y ) topLeft.y = worldBeatPos[i].y; if ( worldBeatPos[i].y > botRight.y ) botRight.y = worldBeatPos[i].y; } float width = botRight.x - topLeft.x; float height = botRight.y - topLeft.y; float usableScreenWidth = rightEdge - leftEdge; float usableScreenHeight = botEdge - topEdge; if ( width > usableScreenWidth || height > usableScreenHeight ) { // we're never going to make this fit; make our translation smaller! //printf("Too big! Try again!\n"); return DoneAddingBeats(); } // float widthRange = usableScreenWidth - width; // float heightRange = usableScreenHeight - height; vsVector2D minAdjustment = vsVector2D::Zero; vsVector2D maxAdjustment = vsVector2D::Zero; if ( topLeft.x < leftEdge ) { minAdjustment.x = leftEdge - topLeft.x; maxAdjustment.x = rightEdge - botRight.x; } else if ( botRight.x > rightEdge ) { minAdjustment.x = rightEdge - botRight.x; maxAdjustment.x = leftEdge - topLeft.x; } if ( topLeft.y < topEdge ) { minAdjustment.y = topEdge - topLeft.y; maxAdjustment.y = botEdge - botRight.y; } else if ( botRight.y > botEdge ) { minAdjustment.y = botEdge - botRight.y; maxAdjustment.y = topEdge - topLeft.y; } vsVector2D adjustment( vsRandom::GetFloat(minAdjustment.x, maxAdjustment.x), vsRandom::GetFloat(minAdjustment.y, maxAdjustment.y) ); m_transformA.SetTranslation( m_transformA.GetTranslation() + adjustment ); m_transformB.SetTranslation( m_transformB.GetTranslation() + adjustment ); }
void gridToPolygon(phys::Collision* c, phys::RigidBody *a, phys::RigidBody *b) { c->addManifold(); c->getLastManifold()->contactCount = 0; GridShape* grid = reinterpret_cast<GridShape*>(a->getShape()); phys::PolygonShape* poly = reinterpret_cast<phys::PolygonShape*>(b->getShape()); sf::Vector2f topLeft(FLT_MAX, FLT_MAX); sf::Vector2f botRight(-FLT_MAX, -FLT_MAX); for (unsigned int i = 0; i < poly->getVertices().size(); i++) { // Retrieve a face normal from A sf::Vector2f n = poly->getNormals()[i]; sf::Vector2f nw = poly->getU() * n; // Transform face normal into B's model space phys::Mat2 buT = grid->getU().transpose( ); n = buT * nw; // Retrieve vertex on face from A, transform into // B's model space sf::Vector2f v = poly->getVertices()[i]; v = (poly->getU() * v) + b->getPosition(); v -= a->getPosition(); v = buT * v; poly->transformedVertices[i] = v; poly->transformedNormals[i] = n; if (v.x < topLeft.x) topLeft.x = v.x; if (v.y < topLeft.y) topLeft.y = v.y; if (v.x > botRight.x) botRight.x = v.x; if (v.y > botRight.y) botRight.y = v.y; } int left = floor(topLeft.x/(PTU/TILE_SIZE))-1; int top = floor(topLeft.y/(PTU/TILE_SIZE))-1; int right = ceil(botRight.x/(PTU/TILE_SIZE))+1; int bot = ceil(botRight.y/(PTU/TILE_SIZE))+1; if (!grid->getGrid()->mWrapX) { left = std::max(left, 0); right = std::min(right, grid->getGrid()->mSizeX-1); } top = std::max(top, 0); bot = std::min(bot, grid->getGrid()->mSizeY-1); // Tile size float tileSize = PTU/TILE_SIZE; // Find the tile with the least overlap in the collision sf::Vector2f tileVerts[4]; int tileVertCount; float tilePenetration = 0.f; float polyPenetration = 0.f; int tileFace; int polyFace; sf::Vector2f tileNormals[4]; sf::Vector2f usedNormals[20]; int usedNormalCount = 0; for (int y = top; y <= bot; y++) { for (int _x = left; _x <= right; _x++) { int x = _x; if (grid->getGrid()->mWrapX) x = grid->getGrid()->wrapX(x); if (!grid->getGrid()->mTiles[y][x].isSolid()) continue; int left = x-1; int right = x+1; int up = y-1; int down = y+1; if (grid->getGrid()->mWrapX) { left = grid->getGrid()->wrapX(left); right = grid->getGrid()->wrapX(right); } bool leftT = false; bool rightT = false; bool upT = false; bool downT = false; if (left >= 0 && grid->getGrid()->mTiles[y][left].isSolid()) leftT = true; if (right < grid->getGrid()->mSizeX && grid->getGrid()->mTiles[y][right].isSolid()) rightT = true; if (up >= 0 && grid->getGrid()->mTiles[up][x].isSolid()) upT = true; if (down < grid->getGrid()->mSizeY && grid->getGrid()->mTiles[down][x].isSolid()) downT = true; sf::Vector2f start(_x*tileSize, y*tileSize); if (!leftT && !rightT && !upT && downT) { tileVertCount = 3; tileVerts[0] = start + sf::Vector2f(tileSize/2, 0); tileVerts[1] = start + sf::Vector2f(0, tileSize); tileVerts[2] = start + sf::Vector2f(tileSize, tileSize); tileNormals[0] = normalize(sf::Vector2f(-0.5, -1.f)); tileNormals[1] = sf::Vector2f(0, 1); tileNormals[2] = normalize(sf::Vector2f(0.5, -1.f)); } else if (!leftT && rightT && !upT && downT) { tileVertCount = 3; tileVerts[0] = start + sf::Vector2f(tileSize, 0); tileVerts[1] = start + sf::Vector2f(0, tileSize); tileVerts[2] = start + sf::Vector2f(tileSize, tileSize); tileNormals[0] = normalize(sf::Vector2f(-1.f, -1.f)); tileNormals[1] = sf::Vector2f(0, 1); tileNormals[2] = sf::Vector2f(1.f, 0.f); } else if (leftT && !rightT && !upT && downT) { tileVertCount = 3; tileVerts[0] = start; tileVerts[1] = start + sf::Vector2f(0, tileSize); tileVerts[2] = start + sf::Vector2f(tileSize, tileSize); tileNormals[0] = sf::Vector2f(-1.f, 0.f); tileNormals[1] = sf::Vector2f(0, 1); tileNormals[2] = normalize(sf::Vector2f(1.f, -1.f)); } else { tileVertCount = 4; tileVerts[0] = start; tileVerts[1] = start + sf::Vector2f(0, tileSize); tileVerts[2] = start + sf::Vector2f(tileSize, tileSize); tileVerts[3] = start + sf::Vector2f(tileSize, 0); tileNormals[0] = sf::Vector2f(-1, 0); tileNormals[1] = sf::Vector2f(0, 1); tileNormals[2] = sf::Vector2f(1, 0); tileNormals[3] = sf::Vector2f(0, -1); } // Check for a separating axis with A's face planes int faceA; float penetrationA = findAxisLeastPenetration(&faceA, poly->transformedVertices.data(), poly->transformedNormals.data(), poly->transformedVertices.size(), tileVerts, tileVertCount); if(penetrationA >= 0.0f || phys::equal(penetrationA, 0.f)) continue; // Check for a separating axis with B's face planes int faceB; float penetrationB = findAxisLeastPenetration(&faceB, tileVerts, tileNormals, tileVertCount, poly->transformedVertices.data(), poly->transformedVertices.size()); if(penetrationB >= 0.0f || phys::equal(penetrationB, 0.f)) continue; tilePenetration = penetrationB; polyPenetration = penetrationA; tileFace = faceB; polyFace = faceA; sf::Uint32 referenceIndex; bool flip; // Always point from a to b phys::RigidBody* ref; sf::Vector2f* refVerts; sf::Vector2f* refNormals; int refCount; phys::RigidBody* inc; sf::Vector2f* incVerts; sf::Vector2f* incNormals; int incCount; // Determine which shape contains reference face if(phys::biasGreaterThan( tilePenetration, polyPenetration )) { ref = a; refVerts = tileVerts; refNormals = tileNormals; refCount = tileVertCount; inc = b; incVerts = poly->transformedVertices.data(); incNormals = poly->transformedNormals.data(); incCount = poly->transformedVertices.size(); referenceIndex = tileFace; flip = false; } else { ref = b; refVerts = poly->transformedVertices.data(); refNormals = poly->transformedNormals.data(); refCount = poly->transformedVertices.size(); inc = a; incVerts = tileVerts; incNormals = tileNormals; incCount = tileVertCount; referenceIndex = polyFace; flip = true; } bool used = false; for (int i = 0; i < usedNormalCount; i++) { if (refNormals[referenceIndex] == usedNormals[i]) { used = true; break; } } if (used) continue; usedNormals[usedNormalCount] = refNormals[referenceIndex]; usedNormalCount++; // World space incident face sf::Vector2f incidentFace[2]; findIncidentFace(incidentFace, refVerts, refNormals, refCount, incVerts, incNormals, incCount, referenceIndex); // y // ^ ->n ^ // +---c ------posPlane-- // x < | i |\ // +---+ c-----negPlane-- // \ v // r // // r : reference face // i : incident poly // c : clipped point // n : incident normal // Setup reference face vertices sf::Vector2f v1 = refVerts[referenceIndex]; referenceIndex = referenceIndex + 1 == refCount ? 0 : referenceIndex + 1; sf::Vector2f v2 = refVerts[referenceIndex]; // Calculate reference face side normal in world space sf::Vector2f sidePlaneNormal = (v2 - v1); sidePlaneNormal = phys::normalize(sidePlaneNormal); // Orthogonalize sf::Vector2f refFaceNormal( sidePlaneNormal.y, -sidePlaneNormal.x ); // ax + by = c // c is distance from origin float refC = phys::dot( refFaceNormal, v1 ); float negSide = -phys::dot( sidePlaneNormal, v1 ); float posSide = phys::dot( sidePlaneNormal, v2 ); // Clip incident face to reference face side planes if(clip( -sidePlaneNormal, negSide, incidentFace ) < 2) return; // Due to floating point error, possible to not have required points if(clip( sidePlaneNormal, posSide, incidentFace ) < 2) return; // Due to floating point error, possible to not have required points // Flip c->getLastManifold()->normal = flip ? -refFaceNormal : refFaceNormal; // Keep points behind reference face sf::Uint32 cp = 0; // clipped points behind reference face float separation = phys::dot( refFaceNormal, incidentFace[0] ) - refC; if(separation <= 0.0f) { c->getLastManifold()->contacts[cp] = incidentFace[0]; c->getLastManifold()->penetration = -separation; ++cp; } else c->getLastManifold()->penetration = 0; separation = phys::dot( refFaceNormal, incidentFace[1] ) - refC; if(separation <= 0.0f) { c->getLastManifold()->contacts[cp] = incidentFace[1]; c->getLastManifold()->penetration += -separation; ++cp; // Average penetration c->getLastManifold()->penetration /= (float)cp; } c->getLastManifold()->contactCount = cp; c->addManifold(); c->getLastManifold()->contactCount = 0; } } }
void circleToGrid(phys::Collision* c, phys::RigidBody *a, phys::RigidBody *b) { GridShape* grid = reinterpret_cast<GridShape*>(b->getShape()); phys::CircleShape* circle = reinterpret_cast<phys::CircleShape*>(a->getShape()); // Transform circle center to Polygon model space sf::Vector2f center = a->getPosition(); center = grid->getU().transpose() * (center - b->getPosition()); sf::Vector2f topLeft(center.x-circle->getRadius(), center.y-circle->getRadius()); sf::Vector2f botRight(center.x+circle->getRadius(), center.y+circle->getRadius()); int left = floor(topLeft.x/(PTU/TILE_SIZE))-1; int top = floor(topLeft.y/(PTU/TILE_SIZE))-1; int right = ceil(botRight.x/(PTU/TILE_SIZE))+1; int bot = ceil(botRight.y/(PTU/TILE_SIZE))+1; if (!grid->getGrid()->getWrapX()) { left = std::max(left, 0); right = std::min(right, grid->getGrid()->getSizeX()-1); } top = std::max(top, 0); bot = std::min(bot, grid->getGrid()->getSizeY()-1); // Tile size float tileSize = PTU/TILE_SIZE; // Find the tile with the least overlap in the collision sf::Vector2f tileVerts[4]; int tileVertCount; sf::Vector2f tileNormals[4]; sf::Vector2f usedNormals[20]; int usedNormalCount = 0; for (int y = top; y <= bot; y++) { for (int _x = left; _x <= right; _x++) { c->addManifold(); c->getLastManifold()->contactCount = 0; int x = _x; if (grid->getGrid()->getWrapX()) x = grid->getGrid()->wrapX(x); if (!grid->getGrid()->mTiles[y][x].isSolid()) continue; int left = x-1; int right = x+1; int up = y-1; int down = y+1; if (grid->getGrid()->mWrapX) { left = grid->getGrid()->wrapX(left); right = grid->getGrid()->wrapX(right); } bool leftT = false; bool rightT = false; bool upT = false; bool downT = false; if (left >= 0 && grid->getGrid()->mTiles[y][left].isSolid()) leftT = true; if (right < grid->getGrid()->mSizeX && grid->getGrid()->mTiles[y][right].isSolid()) rightT = true; if (up >= 0 && grid->getGrid()->mTiles[up][x].isSolid()) upT = true; if (down < grid->getGrid()->mSizeY && grid->getGrid()->mTiles[down][x].isSolid()) downT = true; sf::Vector2f start(_x*tileSize, y*tileSize); if (!leftT && !rightT && !upT && downT) { tileVertCount = 3; tileVerts[0] = start + sf::Vector2f(tileSize/2, 0); tileVerts[1] = start + sf::Vector2f(0, tileSize); tileVerts[2] = start + sf::Vector2f(tileSize, tileSize); tileNormals[0] = normalize(sf::Vector2f(-0.5, -1.f)); tileNormals[1] = sf::Vector2f(0, 1); tileNormals[2] = normalize(sf::Vector2f(0.5, -1.f)); } else if (!leftT && rightT && !upT && downT) { tileVertCount = 3; tileVerts[0] = start + sf::Vector2f(tileSize, 0); tileVerts[1] = start + sf::Vector2f(0, tileSize); tileVerts[2] = start + sf::Vector2f(tileSize, tileSize); tileNormals[0] = normalize(sf::Vector2f(-1.f, -1.f)); tileNormals[1] = sf::Vector2f(0, 1); tileNormals[2] = sf::Vector2f(1.f, 0.f); } else if (leftT && !rightT && !upT && downT) { tileVertCount = 3; tileVerts[0] = start; tileVerts[1] = start + sf::Vector2f(0, tileSize); tileVerts[2] = start + sf::Vector2f(tileSize, tileSize); tileNormals[0] = sf::Vector2f(-1.f, 0.f); tileNormals[1] = sf::Vector2f(0, 1); tileNormals[2] = normalize(sf::Vector2f(1.f, -1.f)); } else { tileVertCount = 4; tileVerts[0] = start; tileVerts[1] = start + sf::Vector2f(0, tileSize); tileVerts[2] = start + sf::Vector2f(tileSize, tileSize); tileVerts[3] = start + sf::Vector2f(tileSize, 0); tileNormals[0] = sf::Vector2f(-1, 0); tileNormals[1] = sf::Vector2f(0, 1); tileNormals[2] = sf::Vector2f(1, 0); tileNormals[3] = sf::Vector2f(0, -1); } // Find edge with minimum penetration // Exact concept as using support points in Polygon vs Polygon float separation = -FLT_MAX; sf::Uint32 faceNormal = 0; bool done = false; for(sf::Uint32 i = 0; i < tileVertCount; ++i) { float s = dot( tileNormals[i], center - tileVerts[i] ); if(s > circle->getRadius()) { done = true; break; } if(s > separation) { separation = s; faceNormal = i; } } if (done) continue; /*bool used = false; for (int i = 0; i < usedNormalCount; i++) { if (tileNormals[faceNormal] == usedNormals[i]) { used = true; break; } } if (used) continue; usedNormals[usedNormalCount] = tileNormals[faceNormal]; usedNormalCount++;*/ // Grab face's vertices sf::Vector2f v1 = tileVerts[faceNormal]; sf::Uint32 i2 = faceNormal + 1 < tileVertCount ? faceNormal + 1 : 0; sf::Vector2f v2 = tileVerts[i2]; // Check to see if center is within polygon if(separation < EPSILON) { c->getLastManifold()->contactCount = 1; c->getLastManifold()->normal = -(grid->getU() * tileNormals[faceNormal]); c->getLastManifold()->contacts[0] = c->getLastManifold()->normal * circle->getRadius() + b->getPosition(); c->getLastManifold()->penetration = circle->getRadius(); continue; } // Determine which voronoi region of the edge center of circle lies within float dot1 = dot( center - v1, v2 - v1 ); float dot2 = dot( center - v2, v1 - v2 ); c->getLastManifold()->penetration = circle->getRadius() - separation; // Closest to v1 if(dot1 <= 0.0f) { if(lengthSqr( center - v1 ) > circle->getRadius() * circle->getRadius()) continue; c->getLastManifold()->contactCount = 1; sf::Vector2f n = v1 - center; n = grid->getU() * n; n = normalize(n); c->getLastManifold()->normal = n; v1 = grid->getU() * v1 + a->getPosition(); c->getLastManifold()->contacts[0] = v1; } // Closest to v2 else if(dot2 <= 0.0f) { if(lengthSqr( center - v2 ) > circle->getRadius() * circle->getRadius()) continue; c->getLastManifold()->contactCount = 1; sf::Vector2f n = v2 - center; v2 = grid->getU() * v2 + a->getPosition(); c->getLastManifold()->contacts[0] = v2; n = grid->getU() * n; n = normalize(n); c->getLastManifold()->normal = n; } // Closest to face else { sf::Vector2f n = tileNormals[faceNormal]; if(dot( center - v1, n ) > circle->getRadius()) continue; n = grid->getU() * n; c->getLastManifold()->normal = -n; c->getLastManifold()->contacts[0] = c->getLastManifold()->normal * circle->getRadius() + b->getPosition(); c->getLastManifold()->contactCount = 1; } } } }
MTV Collision::getCollision(const sf::Sprite& object1,Entity::ENTITY_SHAPE shape1,const sf::Sprite& object2,Entity::ENTITY_SHAPE shape2){ //Use Separating Axis Theorem to determine whether two objects are overlapping //See documentation for full explanation of this algorithm //Get the oriented bounding box in world coordinates (includes rotation) of objects OBB obb1 = getOBB(object1); OBB obb2 = getOBB(object2); float rot = object1.getRotation(); double overlap = LONG_MAX; maths::Vector2 smallest(0,0); std::vector<maths::Vector2> axis1; std::vector<maths::Vector2> axis2; maths::Vector2 circleCentre1; maths::Vector2 circleCentre2; sf::FloatRect gbounds1 = object1.getGlobalBounds(); sf::FloatRect gbounds2 = object2.getGlobalBounds(); //Find all the axes to check using SAT based on shapes of objects //Works with squares/rectangles or circles //Rectangles only need 2 axes because they have 2 sets of parallel lines if(shape1 == Entity::SHAPE_CIRCLE && shape2 == Entity::SHAPE_CIRCLE){ //If both shapes are circles, the only axis needed is the axis between centres of circles circleCentre1 = maths::Vector2(gbounds1.left + gbounds1.width / 2, gbounds1.top + gbounds1.height / 2); circleCentre2 = maths::Vector2(gbounds2.left + gbounds2.width / 2, gbounds2.top + gbounds2.height / 2); axis1.push_back(maths::Vector2(circleCentre1 - circleCentre2).normalise()); }else if(shape1 != shape2){ //if one shape is circle and one shape is rectangle maths::Vector2 circleCentre; sf::FloatRect squareRect; float rotation; //First get the unrotated bounding box and centre of the circle of the 2 objects if(shape1 == Entity::SHAPE_CIRCLE){ circleCentre = maths::Vector2(gbounds1.left + gbounds1.width / 2, gbounds1.top + gbounds1.height / 2); circleCentre1 = circleCentre; squareRect = getOriginalBoundingBox(object2); rotation = object2.getRotation(); }else if(shape2 == Entity::SHAPE_CIRCLE){ circleCentre = maths::Vector2(gbounds2.left + gbounds2.width / 2, gbounds2.top + gbounds2.height / 2); circleCentre2 = circleCentre; squareRect = getOriginalBoundingBox(object1); rotation = object1.getRotation(); } maths::Vector2 squareCentre(squareRect.left + squareRect.width / 2, squareRect.top + squareRect.height / 2); OBB* square = (shape1 == Entity::SHAPE_SQUARE ? &obb1 : &obb2); maths::Vector2 relativeCircleCentre = circleCentre.rotate(-rotation, squareCentre); //get circle centre in relation to the rotated square bool vertice = false; maths::Vector2 axis; maths::Vector2 topLeft(squareRect.left, squareRect.top); maths::Vector2 topRight(squareRect.left + squareRect.width, squareRect.top); maths::Vector2 botLeft(squareRect.left, squareRect.top + squareRect.height); maths::Vector2 botRight(squareRect.left + squareRect.width, squareRect.top + squareRect.height); //Get the closest vertex of the rectangle to the circle centre. //The axis to check is the vector between these 2 points. if(circleCentre.x < topLeft.x){ if(circleCentre.y < topLeft.y){ vertice = true; axis = topLeft; }else if(circleCentre.y > botLeft.y){ vertice = true; axis = botLeft; }else{ axis = maths::Vector2(topLeft - botLeft).normalise(); } }else if(circleCentre.x > topRight.x){ if(circleCentre.y < topLeft.y){ vertice = true; axis = topRight; }else if(circleCentre.y > botLeft.y){ vertice = true; axis = botRight; }else{ axis = maths::Vector2(topRight - botRight).normalise(); } }else{ if(circleCentre.y < topLeft.y){ axis = maths::Vector2(topRight - topLeft).normalise(); }else if(circleCentre.y > botLeft.y){ axis = maths::Vector2(botLeft - botRight).normalise(); }else{ //contains point! } } if(vertice){ axis1.push_back(maths::Vector2(circleCentre - axis).normalise()); }else{ axis1.push_back(maths::Vector2(topRight - topLeft).normalise()); axis1.push_back(maths::Vector2(topRight - botRight).normalise()); } }else{ //If both shapes are rectangles //Get vectors for sides of shapes maths::Vector2 Xside1(obb1.bot_left - obb1.bot_right); maths::Vector2 Yside1(obb1.top_left - obb1.bot_left); maths::Vector2 Xside2(obb2.bot_left - obb2.bot_right); maths::Vector2 Yside2(obb2.top_left - obb2.bot_left); //Axes requires are perpendicular to the sides of the shape //Vector2.perpendicular() normalises for greater accuracy axis1.push_back(Xside1.perpendicular()); axis1.push_back(Yside1.perpendicular()); axis2.push_back(Xside2.perpendicular()); axis2.push_back(Yside2.perpendicular()); } //We have all the axes to check. //Now find details on collisions with projections. for(int i=0;i<axis1.size();i++){ //Get projection of axis for both shapes maths::Vector2 axis = axis1[i]; Projection projection1 = project(obb1, axis); if(shape1 == Entity::SHAPE_CIRCLE){ float radius = gbounds1.width / 2; projection1 = projectCircle(circleCentre1, radius, axis); } Projection projection2 = project(obb2, axis); if (shape2 == Entity::SHAPE_CIRCLE){ float radius = gbounds2.width / 2; projection2 = projectCircle(circleCentre2, radius, axis); } //If a projection does not overlap, we know the objects do not collide so we can exit the function. //Otherwise, the MTV (minimum translation vector required to make the objects not collide) is calculated. if(!projection1.overlap(projection2)){ return MTV::NONE; }else{ //The axis with the smallest overlap is the axis used to calculate MTV, so record it. double o = projection1.getOverlap(projection2); if(o < overlap){ overlap = o; //set smallest overlap smallest = axis; //set smallest separation vector } } } //Repeat the same process as above with the other set of axes. for(int i=0;i<axis2.size();i++){ maths::Vector2 axis = axis2[i]; Projection projection1 = project(obb1, axis); if(shape1 == Entity::SHAPE_CIRCLE){ float radius = gbounds1.width/2; projection1 = projectCircle(circleCentre1, radius, axis); } Projection projection2 = project(obb2,axis); if(shape2 == Entity::SHAPE_CIRCLE){ float radius = gbounds2.width / 2; projection2 = projectCircle(circleCentre2, radius, axis); } if(!projection1.overlap(projection2)){ return MTV::NONE; }else{ double o = projection1.getOverlap(projection2); if(o < overlap){ overlap = o; smallest = axis; } } } //Get the vector from the centre of object 2 to the centre of object 1 maths::Vector2 centre1 = maths::Vector2(gbounds1.left + gbounds1.width / 2, gbounds1.top + gbounds1.height / 2); maths::Vector2 centre2 = maths::Vector2(gbounds2.left + gbounds2.width / 2, gbounds2.top + gbounds2.height / 2); maths::Vector2 between = centre1 - centre2; //If the separation vector is in the opposite direction of 'between', flip it round by negating it if(between.dot(smallest) < 0){ smallest = -smallest; } MTV mtv(overlap, smallest); return mtv; }