void CC3Billboard::populateAsBoundingRectangle() { CC3Vector* vertices; // Array of simple vertex location data // Start with default initial values GLfloat xMin = 0.0f; GLfloat xMax = 1.0f; GLfloat yMin = 0.0f; GLfloat yMax = 1.0f; int vCount = 4; CC3VertexLocations* locArray = CC3VertexLocations::vertexArray(); locArray->setDrawingMode( GL_TRIANGLE_STRIP ); // Location array will do the drawing as a strip locArray->setVertexStride( 0 ); // Tightly packed locations only locArray->setElementOffset( 0 ); // Only locations locArray->setAllocatedVertexCapacity( vCount ); vertices = (CC3Vector*)locArray->getVertices(); // Populate vertex locations in the X-Y plane vertices[0] = cc3v(xMax, yMax, 0.0f); vertices[1] = cc3v(xMin, yMax, 0.0f); vertices[2] = cc3v(xMax, yMin, 0.0f); vertices[3] = cc3v(xMin, yMin, 0.0f); // Create mesh with vertex location array CC3Mesh* aMesh = CC3Mesh::mesh(); aMesh->setVertexLocations( locArray ); setMesh( aMesh ); updateBoundingMesh(); }
/** If the bounding mesh exists, update its vertices to match the bounding box of the 2D node. */ void CC3Billboard::updateBoundingMesh() { if (m_pMesh) { CCRect bRect = getBillboardBoundingRect(); GLfloat xMin = bRect.getMinX(); GLfloat xMax = bRect.getMaxX(); GLfloat yMin = bRect.getMinX(); GLfloat yMax = bRect.getMaxY(); m_pMesh->setVertexLocation( cc3v(xMax, yMax, 0.0), 0 ); m_pMesh->setVertexLocation( cc3v(xMin, yMax, 0.0), 1 ); m_pMesh->setVertexLocation( cc3v(xMax, yMin, 0.0), 2 ); m_pMesh->setVertexLocation( cc3v(xMin, yMin, 0.0), 3 ); } }
/** * Calculate the end of the directonal marker line. * * This is done by calculating the scale we need to multiply the directional marker by to * reach each of the three sides of the bounding box, then take the smallest of these, * because that is the side it will intersect. Finally, multiply by an overall scale factor. */ CC3Vector CC3DirectionMarkerNode::calculateLineEnd() { CC3Box pbb = getParentBoundingBox(); CC3Vector md = getMarkerDirection(); CC3Vector pbbDirScale = cc3v(calcScale( md.x, pbb.minimum.x, pbb.maximum.x ), calcScale( md.y, pbb.minimum.y, pbb.maximum.y ), calcScale( md.z, pbb.minimum.z, pbb.maximum.z )); //CC3_PUSH_NOSHADOW GLfloat dirScale = MIN(pbbDirScale.x, MIN(pbbDirScale.y, pbbDirScale.z)); dirScale = dirScale * getDirectionMarkerScale(); //CC3_POP_NOSHADOW // Ensure that the direction marker has the minimum length specified by directionMarkerMinimumLength if (directionMarkerMinimumLength) { GLfloat gblUniScale = getGlobalScale().length() / CC3Vector::kCC3VectorUnitCubeLength; GLfloat minScale = directionMarkerMinimumLength / gblUniScale; dirScale = MAX(dirScale, minScale); } CC3Vector lineEnd = md.scaleUniform( dirScale ); //LogTrace(@"%@ calculated line end %@ from pbb scale %@ and dir scale %.3f and min global length: %.3f", self, // NSStringFromCC3Vector(lineEnd), NSStringFromCC3Vector(pbbDirScale), dirScale, directionMarkerMinimumLength); return lineEnd; }
/** Measures the bounding box of the parent node and updates the vertex locations. */ void CC3WireframeBoundingBoxNode::updateFromParentBoundingBoxWithVisitor( CC3NodeUpdatingVisitor* visitor ) { CC3Box pbb = getParentBoundingBox(); setVertexLocation( cc3v(pbb.minimum.x, pbb.minimum.y, pbb.minimum.z), 0 ); setVertexLocation( cc3v(pbb.minimum.x, pbb.minimum.y, pbb.maximum.z), 1 ); setVertexLocation( cc3v(pbb.minimum.x, pbb.maximum.y, pbb.minimum.z), 2 ); setVertexLocation( cc3v(pbb.minimum.x, pbb.maximum.y, pbb.maximum.z), 3 ); setVertexLocation( cc3v(pbb.maximum.x, pbb.minimum.y, pbb.minimum.z), 4 ); setVertexLocation( cc3v(pbb.maximum.x, pbb.minimum.y, pbb.maximum.z), 5 ); setVertexLocation( cc3v(pbb.maximum.x, pbb.maximum.y, pbb.minimum.z), 6 ); setVertexLocation( cc3v(pbb.maximum.x, pbb.maximum.y, pbb.maximum.z), 7 ); updateVertexLocationsGLBuffer(); }
/** Transform the bounding rectangle of the 2D node on the X-Y plane into 3D. */ void CC3BillboardBoundingBoxArea::transformVolume() { super::transformVolume(); // Get the corners of the CCNode bounding box CCRect br = getBillboardBoundingRect(); CCPoint bbMin = ccp(br.getMinX(), br.getMinY()); CCPoint bbMax = ccp(br.getMaxX(), br.getMaxY()); // Construct all 4 corner vertices of the local bounding box and transform each to global coordinates m_vertices[0] = m_pNode->getGlobalTransformMatrix()->transformLocation( cc3v(bbMin.x, bbMin.y, 0.0) ); m_vertices[1] = m_pNode->getGlobalTransformMatrix()->transformLocation( cc3v(bbMin.x, bbMax.y, 0.0) ); m_vertices[2] = m_pNode->getGlobalTransformMatrix()->transformLocation( cc3v(bbMax.x, bbMin.y, 0.0) ); m_vertices[3] = m_pNode->getGlobalTransformMatrix()->transformLocation( cc3v(bbMax.x, bbMax.y, 0.0) ); /*LogTrace(@"%@ bounding volume transformed %@ MinMax(%@, %@) to (%@, %@, %@, %@)", _node, NSStringFromCGRect(br), NSStringFromCGPoint(bbMin), NSStringFromCGPoint(bbMax), NSStringFromCC3Vector(_vertices[0]), NSStringFromCC3Vector(_vertices[1]), NSStringFromCC3Vector(_vertices[2]), NSStringFromCC3Vector(_vertices[3]));*/ }
CC3Ray CC3Camera::unprojectPoint( const CCPoint& cc2Point ) { // Scale from UI points to GL points CCPoint glPoint = ccpMult(cc2Point, CCDirector::sharedDirector()->getContentScaleFactor()); // Express the glPoint X & Y as proportion of the viewport dimensions. CC3Viewport vp = getViewport(); GLfloat xp = ((2.0f * glPoint.x) / vp.w) - 1; GLfloat yp = ((2.0f * glPoint.y) / vp.h) - 1; // Ensure that the camera's frustum is up to date, and then map the proportional point // on the viewport to its position on the near clipping rectangle. The Z-coordinate is // negative because the camera points down the negative Z axis in its local coordinates. buildProjection(); CC3Vector pointLocNear = cc3v(_frustum->getRight() * xp, _frustum->getTop() * yp, -_frustum->getNear()); CC3Ray ray; if ( isUsingParallelProjection() ) { // The location on the near clipping plane is relative to the camera's // local coordinates. Convert it to global coordinates before returning. // The ray direction is straight out from that global location in the // camera's globalForwardDirection. ray.startLocation = getGlobalTransformMatrix()->transformLocation( pointLocNear ); ray.direction = getGlobalForwardDirection(); } else { // The location on the near clipping plane is relative to the camera's local // coordinates. Since the camera's origin is zero in its local coordinates, // this point on the near clipping plane forms a directional vector from the // camera's origin. Rotate this directional vector with the camera's rotation // matrix to convert it to a global direction vector in global coordinates. // Thanks to Cocos3D forum user Rogs for suggesting the use of the globalRotationMatrix. ray.startLocation = getGlobalLocation(); ray.direction = getGlobalRotationMatrix()->transformDirection( pointLocNear ); } // Ensure the direction component is normalized before returning. ray.direction = ray.direction.normalize(); //LogTrace(@"%@ unprojecting point %@ to near plane location %@ and to ray starting at %@ and pointing towards %@", // [self class], NSStringFromCGPoint(glPoint), NSStringFromCC3Vector(pointLocNear), // NSStringFromCC3Vector(ray.startLocation), NSStringFromCC3Vector(ray.direction)); return ray; }
void CC3TouchBox::populateBox( const CC3Box& aBox ) { CC3Mesh* mesh = prepareParametricMesh(); // Now update the vertex locations with the box data GLuint vIdx = 0; CC3Vector bbMin = aBox.minimum; CC3Vector bbMax = aBox.maximum; mesh->setVertexLocation( cc3v(bbMin.x, bbMin.y, bbMin.z), vIdx++ ); mesh->setVertexLocation( cc3v(bbMin.x, bbMin.y, bbMax.z), vIdx++ ); mesh->setVertexLocation( cc3v(bbMin.x, bbMax.y, bbMin.z), vIdx++ ); mesh->setVertexLocation( cc3v(bbMin.x, bbMax.y, bbMax.z), vIdx++ ); mesh->setVertexLocation( cc3v(bbMax.x, bbMin.y, bbMin.z), vIdx++ ); mesh->setVertexLocation( cc3v(bbMax.x, bbMin.y, bbMax.z), vIdx++ ); mesh->setVertexLocation( cc3v(bbMax.x, bbMax.y, bbMin.z), vIdx++ ); mesh->setVertexLocation( cc3v(bbMax.x, bbMax.y, bbMax.z), vIdx++ ); mesh->updateVertexLocationsGLBuffer(); markBoundingVolumeDirty(); }
CC3Box CC3LocalContentNode::getLocalContentBoundingBoxRelativeTo( CC3Node* ancestor ) { CC3Box lcbb = getLocalContentBoundingBox(); if (ancestor == this) return lcbb; CC3Matrix4x3 tMtx; getGlobalTransformMatrix()->populateCC3Matrix4x3( &tMtx ); if ( ancestor ) ancestor->getGlobalTransformMatrixInverted()->leftMultiplyIntoCC3Matrix4x3( &tMtx ); // The eight vertices of the transformed local bounding box CC3Vector bbVertices[8]; // Get the corners of the local bounding box CC3Vector bbMin = lcbb.minimum; CC3Vector bbMax = lcbb.maximum; // Construct all 8 corner vertices of the local bounding box and transform each // to the coordinate system of the ancestor. The result is an oriented-bounding-box. bbVertices[0] = CC3Matrix4x3TransformLocation(&tMtx, cc3v(bbMin.x, bbMin.y, bbMin.z)); bbVertices[1] = CC3Matrix4x3TransformLocation(&tMtx, cc3v(bbMin.x, bbMin.y, bbMax.z)); bbVertices[2] = CC3Matrix4x3TransformLocation(&tMtx, cc3v(bbMin.x, bbMax.y, bbMin.z)); bbVertices[3] = CC3Matrix4x3TransformLocation(&tMtx, cc3v(bbMin.x, bbMax.y, bbMax.z)); bbVertices[4] = CC3Matrix4x3TransformLocation(&tMtx, cc3v(bbMax.x, bbMin.y, bbMin.z)); bbVertices[5] = CC3Matrix4x3TransformLocation(&tMtx, cc3v(bbMax.x, bbMin.y, bbMax.z)); bbVertices[6] = CC3Matrix4x3TransformLocation(&tMtx, cc3v(bbMax.x, bbMax.y, bbMin.z)); bbVertices[7] = CC3Matrix4x3TransformLocation(&tMtx, cc3v(bbMax.x, bbMax.y, bbMax.z)); // Construct a transformed mesh bounding box that surrounds the eight global vertices CC3Box bb = CC3Box::kCC3BoxNull; for (int i = 0; i < 8; i++) bb = bb.boxEngulfLocation( bbVertices[i] ); return bb; }
void CC3ActionScaleTo::initWithDuration( float t, GLfloat aScale ) { return initWithDuration( t, cc3v(aScale, aScale, aScale) ); }
CC3ActionScaleBy* CC3ActionScaleBy::actionWithDuration( float t, GLfloat aScale ) { return actionWithDuration( t, cc3v(aScale, aScale, aScale) ); }
CC3Vector CC3Camera::calculateLocationToShowAllOf( CC3Node* aNode, const CC3Vector& targLoc, const CC3Vector& aDirection, GLfloat padding, bool checkScene ) { ensureSceneUpdated( checkScene ); // Complementary unit vectors pointing towards camera from node, and vice versa CC3Vector camDir = aDirection.normalize(); CC3Vector viewDir = camDir.negate(); // The camera's new forward direction will be viewDir. Use a matrix to detrmine // the camera's new up and right directions assuming the same scene up direction. CC3Matrix3x3 rotMtx; CC3Matrix3x3PopulateToPointTowards(&rotMtx, viewDir, getReferenceUpDirection()); CC3Vector upDir = CC3Matrix3x3ExtractUpDirection(&rotMtx); CC3Vector rtDir = CC3Matrix3x3ExtractRightDirection(&rotMtx); // Determine the eight vertices, of the node's bounding box, in the global coordinate system CC3Box gbb = aNode->getGlobalBoundingBox(); CC3Vector targetLoc = targLoc; // If a target location has not been specified, use the center of the node's global bounding box if ( targetLoc.isNull() ) targetLoc = gbb.getCenter(); CC3Vector bbMin = gbb.minimum; CC3Vector bbMax = gbb.maximum; CC3Vector bbVertices[8]; bbVertices[0] = cc3v(bbMin.x, bbMin.y, bbMin.z); bbVertices[1] = cc3v(bbMin.x, bbMin.y, bbMax.z); bbVertices[2] = cc3v(bbMin.x, bbMax.y, bbMin.z); bbVertices[3] = cc3v(bbMin.x, bbMax.y, bbMax.z); bbVertices[4] = cc3v(bbMax.x, bbMin.y, bbMin.z); bbVertices[5] = cc3v(bbMax.x, bbMin.y, bbMax.z); bbVertices[6] = cc3v(bbMax.x, bbMax.y, bbMin.z); bbVertices[7] = cc3v(bbMax.x, bbMax.y, bbMax.z); // Express the camera's FOV in terms of ratios of the near clip bounds to // the near clip distance, so we can determine distances using similar triangles. CCSize fovRatios = getFovRatios(); // Iterate through all eight vertices of the node's bounding box, and calculate // the largest distance required to place the camera away from the center of the // node in order to fit all eight vertices within the camera's frustum. // Simultaneously, calculate the extra distance from the center of the node to // the vertex that will be farthest from the camera, so we can ensure that all // vertices will fall within the frustum's far end. GLfloat maxCtrDist = 0; GLfloat maxVtxDeltaDist = 0; GLfloat minVtxDeltaDist = 0; for (int i = 0; i < 8; i++) { // Get a vector from the target location to the vertex CC3Vector relVtx = bbVertices[i] - targetLoc; // Project that vector onto each of the camera's new up and right directions, // and use similar triangles to determine the distance at which to place the // camera so that the vertex will fit in both the up and right directions. GLfloat vtxDistUp = fabs(relVtx.dot( upDir ) / fovRatios.height); GLfloat vtxDistRt = fabs(relVtx.dot( rtDir ) / fovRatios.width); GLfloat vtxDist = MAX(vtxDistUp, vtxDistRt); // Calculate how far along the view direction the vertex is from the center GLfloat vtxDeltaDist = relVtx.dot( viewDir ); GLfloat ctrDist = vtxDist - vtxDeltaDist; // Accumulate the maximum distance from the node's center to the camera // required to fit all eight points, and the distance from the node's // center to the vertex that will be farthest away from the camera. maxCtrDist = MAX(maxCtrDist, ctrDist); maxVtxDeltaDist = MAX(maxVtxDeltaDist, vtxDeltaDist); minVtxDeltaDist = MIN(minVtxDeltaDist, vtxDeltaDist); } // Add some padding so we will have a bit of space around the node when it fills the view. maxCtrDist *= (1 + padding); // Determine if we need to move the far end of the camera frustum farther away GLfloat farClip = viewDir.scaleUniform(maxCtrDist + maxVtxDeltaDist).length(); farClip *= (GLfloat)(1 + kCC3FrustumFitPadding); // Include a little bit of padding if (farClip > getFarClippingDistance()) setFarClippingDistance( farClip ); // Determine if we need to move the near end of the camera frustum closer GLfloat nearClip = viewDir.scaleUniform(maxCtrDist + minVtxDeltaDist).length(); nearClip *= (GLfloat)(1 - kCC3FrustumFitPadding); // Include a little bit of padding if (nearClip < getNearClippingDistance()) setNearClippingDistance( nearClip ); //LogTrace(@"%@ moving to %@ to show %@ at %@ within %@ with new farClip: %.3f", self, // NSStringFromCC3Vector(CC3VectorAdd(targLoc, CC3VectorScaleUniform(camDir, maxCtrDist))), // aNode, NSStringFromCC3Vector(targLoc), _frustum, self.farClippingDistance); // Return the new location of the camera, return targetLoc.add( camDir.scaleUniform( maxCtrDist ) ); }