void ForestConvex::getPolyList(AbstractPolyList* list) { list->setTransform( &mTransform, Point3F(mScale,mScale,mScale)); list->setObject(mObject); TSShapeInstance *si = mData->getShapeInstance(); S32 detail = mData->getCollisionDetails()[hullId]; si->animate(detail); si->buildPolyList(list, detail); }
void ForestConvex::getFeatures( const MatrixF &mat, const VectorF &n, ConvexFeature *cf ) { cf->material = 0; cf->object = mObject; TSShapeInstance *si = mData->getShapeInstance(); TSShape::ConvexHullAccelerator* pAccel = si->getShape()->getAccelerator(mData->getCollisionDetails()[hullId]); AssertFatal(pAccel != NULL, "Error, no accel!"); F32 currMaxDP = mDot(pAccel->vertexList[0], n); U32 index = 0; U32 i; for (i = 1; i < pAccel->numVerts; i++) { F32 dp = mDot(pAccel->vertexList[i], n); if (dp > currMaxDP) { currMaxDP = dp; index = i; } } const U8* emitString = pAccel->emitStrings[index]; U32 currPos = 0; U32 numVerts = emitString[currPos++]; for (i = 0; i < numVerts; i++) { cf->mVertexList.increment(); U32 index = emitString[currPos++]; mat.mulP(pAccel->vertexList[index], &cf->mVertexList.last()); } U32 numEdges = emitString[currPos++]; for (i = 0; i < numEdges; i++) { U32 ev0 = emitString[currPos++]; U32 ev1 = emitString[currPos++]; cf->mEdgeList.increment(); cf->mEdgeList.last().vertex[0] = ev0; cf->mEdgeList.last().vertex[1] = ev1; } U32 numFaces = emitString[currPos++]; for (i = 0; i < numFaces; i++) { cf->mFaceList.increment(); U32 plane = emitString[currPos++]; mat.mulV(pAccel->normalList[plane], &cf->mFaceList.last().normal); for (U32 j = 0; j < 3; j++) cf->mFaceList.last().vertex[j] = emitString[currPos++]; } }
bool FlyingVehicleData::preload(bool server, String &errorStr) { if (!Parent::preload(server, errorStr)) return false; TSShapeInstance* si = new TSShapeInstance(mShape, false); // Resolve objects transmitted from server if (!server) { for (S32 i = 0; i < MaxSounds; i++) if (sound[i]) Sim::findObject(SimObjectId(sound[i]),sound[i]); for (S32 j = 0; j < MaxJetEmitters; j++) if (jetEmitter[j]) Sim::findObject(SimObjectId(jetEmitter[j]),jetEmitter[j]); } // Extract collision planes from shape collision detail level if (collisionDetails[0] != -1) { MatrixF imat(1); PlaneExtractorPolyList polyList; polyList.mPlaneList = &rigidBody.mPlaneList; polyList.setTransform(&imat, Point3F(1,1,1)); si->animate(collisionDetails[0]); si->buildPolyList(&polyList,collisionDetails[0]); } // Resolve jet nodes for (S32 j = 0; j < MaxJetNodes; j++) jetNode[j] = mShape->findNode(sJetNode[j]); // maxSpeed = maneuveringForce / minDrag; delete si; return true; }
Point3F ForestConvex::support(const VectorF& v) const { TSShapeInstance *si = mData->getShapeInstance(); TSShape::ConvexHullAccelerator* pAccel = si->getShape()->getAccelerator(mData->getCollisionDetails()[hullId]); AssertFatal(pAccel != NULL, "Error, no accel!"); F32 currMaxDP = mDot(pAccel->vertexList[0], v); U32 index = 0; for (U32 i = 1; i < pAccel->numVerts; i++) { F32 dp = mDot(pAccel->vertexList[i], v); if (dp > currMaxDP) { currMaxDP = dp; index = i; } } return pAccel->vertexList[index]; }
bool ForestItem::buildPolyList( AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere ) const { TSForestItemData *data = (TSForestItemData*)mDataBlock; bool ret = false; MatrixF xfm = getTransform(); polyList->setTransform( &xfm, Point3F(mScale,mScale,mScale) ); TSShapeInstance *si = data->getShapeInstance(); const Vector<S32> &details = data->getCollisionDetails(); S32 detail; for (U32 i = 0; i < details.size(); i++ ) { detail = details[i]; if (detail != -1) ret |= si->buildPolyList( polyList, detail ); } return ret; }
void Turret::getNodeOffset (TMat3F *trans, char *nodeName, int Node) { TSShapeInstance *si = image.shape; if(si) { int node; if (Node == -1) node = si->getShape().findNode(nodeName); else node = Node; if (node != -1) { TMat3F nodeTrans; nodeTrans.identity(); nodeTrans.p = si->getTransform (node).p; m_mul (nodeTrans, getTransform(), trans); } } }
void TSLastDetail::_update() { // We're gonna render... make sure we can. bool sceneBegun = GFX->canCurrentlyRender(); if ( !sceneBegun ) GFX->beginScene(); _validateDim(); Vector<GBitmap*> bitmaps; Vector<GBitmap*> normalmaps; // We need to create our own instance to render with. TSShapeInstance *shape = new TSShapeInstance( mShape, true ); // Animate the shape once. shape->animate( mDl ); // So we don't have to change it everywhere. const GFXFormat format = GFXFormatR8G8B8A8; S32 imposterCount = ( ((2*mNumPolarSteps) + 1 ) * mNumEquatorSteps ) + ( mIncludePoles ? 2 : 0 ); // Figure out the optimal texture size. Point2I texSize( smMaxTexSize, smMaxTexSize ); while ( true ) { Point2I halfSize( texSize.x / 2, texSize.y / 2 ); U32 count = ( halfSize.x / mDim ) * ( halfSize.y / mDim ); if ( count < imposterCount ) { // Try half of the height. count = ( texSize.x / mDim ) * ( halfSize.y / mDim ); if ( count >= imposterCount ) texSize.y = halfSize.y; break; } texSize = halfSize; } GBitmap *imposter = NULL; GBitmap *normalmap = NULL; GBitmap destBmp( texSize.x, texSize.y, true, format ); GBitmap destNormal( texSize.x, texSize.y, true, format ); U32 mipLevels = destBmp.getNumMipLevels(); ImposterCapture *imposterCap = new ImposterCapture(); F32 equatorStepSize = M_2PI_F / (F32)mNumEquatorSteps; static const MatrixF topXfm( EulerF( -M_PI_F / 2.0f, 0, 0 ) ); static const MatrixF bottomXfm( EulerF( M_PI_F / 2.0f, 0, 0 ) ); MatrixF angMat; F32 polarStepSize = 0.0f; if ( mNumPolarSteps > 0 ) polarStepSize = -( 0.5f * M_PI_F - mDegToRad( mPolarAngle ) ) / (F32)mNumPolarSteps; PROFILE_START(TSLastDetail_snapshots); S32 currDim = mDim; for ( S32 mip = 0; mip < mipLevels; mip++ ) { if ( currDim < 1 ) currDim = 1; dMemset( destBmp.getWritableBits(mip), 0, destBmp.getWidth(mip) * destBmp.getHeight(mip) * GFXFormat_getByteSize( format ) ); dMemset( destNormal.getWritableBits(mip), 0, destNormal.getWidth(mip) * destNormal.getHeight(mip) * GFXFormat_getByteSize( format ) ); bitmaps.clear(); normalmaps.clear(); F32 rotX = 0.0f; if ( mNumPolarSteps > 0 ) rotX = -( mDegToRad( mPolarAngle ) - 0.5f * M_PI_F ); // We capture the images in a particular order which must // match the order expected by the imposter renderer. imposterCap->begin( shape, mDl, currDim, mRadius, mCenter ); for ( U32 j=0; j < (2 * mNumPolarSteps + 1); j++ ) { F32 rotZ = -M_PI_F / 2.0f; for ( U32 k=0; k < mNumEquatorSteps; k++ ) { angMat.mul( MatrixF( EulerF( rotX, 0, 0 ) ), MatrixF( EulerF( 0, 0, rotZ ) ) ); imposterCap->capture( angMat, &imposter, &normalmap ); bitmaps.push_back( imposter ); normalmaps.push_back( normalmap ); rotZ += equatorStepSize; } rotX += polarStepSize; if ( mIncludePoles ) { imposterCap->capture( topXfm, &imposter, &normalmap ); bitmaps.push_back(imposter); normalmaps.push_back( normalmap ); imposterCap->capture( bottomXfm, &imposter, &normalmap ); bitmaps.push_back( imposter ); normalmaps.push_back( normalmap ); } } imposterCap->end(); Point2I texSize( destBmp.getWidth(mip), destBmp.getHeight(mip) ); // Ok... pack in bitmaps till we run out. for ( S32 y=0; y+currDim <= texSize.y; ) { for ( S32 x=0; x+currDim <= texSize.x; ) { // Copy the next bitmap to the dest texture. GBitmap* bmp = bitmaps.first(); bitmaps.pop_front(); destBmp.copyRect( bmp, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip ); delete bmp; // Copy the next normal to the dest texture. GBitmap* normalmap = normalmaps.first(); normalmaps.pop_front(); destNormal.copyRect( normalmap, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip ); delete normalmap; // Did we finish? if ( bitmaps.empty() ) break; x += currDim; } // Did we finish? if ( bitmaps.empty() ) break; y += currDim; } // Next mip... currDim /= 2; } PROFILE_END(); // TSLastDetail_snapshots delete imposterCap; delete shape; // Should we dump the images? if ( Con::getBoolVariable( "$TSLastDetail::dumpImposters", false ) ) { String imposterPath = mCachePath + ".imposter.png"; String normalsPath = mCachePath + ".imposter_normals.png"; FileStream stream; if ( stream.open( imposterPath, Torque::FS::File::Write ) ) destBmp.writeBitmap( "png", stream ); stream.close(); if ( stream.open( normalsPath, Torque::FS::File::Write ) ) destNormal.writeBitmap( "png", stream ); stream.close(); } // DEBUG: Some code to force usage of a test image. //GBitmap* tempMap = GBitmap::load( "./forest/data/test1234.png" ); //tempMap->extrudeMipLevels(); //mTexture.set( tempMap, &GFXDefaultStaticDiffuseProfile, false ); //delete tempMap; DDSFile *ddsDest = DDSFile::createDDSFileFromGBitmap( &destBmp ); DDSUtil::squishDDS( ddsDest, GFXFormatDXT3 ); DDSFile *ddsNormals = DDSFile::createDDSFileFromGBitmap( &destNormal ); DDSUtil::squishDDS( ddsNormals, GFXFormatDXT5 ); // Finally save the imposters to disk. FileStream fs; if ( fs.open( _getDiffuseMapPath(), Torque::FS::File::Write ) ) { ddsDest->write( fs ); fs.close(); } if ( fs.open( _getNormalMapPath(), Torque::FS::File::Write ) ) { ddsNormals->write( fs ); fs.close(); } delete ddsDest; delete ddsNormals; // If we did a begin then end it now. if ( !sceneBegun ) GFX->endScene(); }
bool ForestItem::castRay( const Point3F &start, const Point3F &end, RayInfo *outInfo, bool rendered ) const { if ( !mWorldBox.collideLine( start, end ) ) return false; Point3F s, e; MatrixF mat = getTransform(); mat.scale( Point3F(mScale) ); mat.inverse(); mat.mulP( start, &s ); mat.mulP( end, &e ); TSForestItemData *data = (TSForestItemData*)mDataBlock; TSShapeInstance *si = data->getShapeInstance(); if ( !si ) return false; if ( rendered ) { // Always raycast against detail level zero // because it makes lots of things easier. if ( !si->castRayRendered( s, e, outInfo, 0 ) ) return false; if ( outInfo->userData != NULL ) *(ForestItem*)(outInfo->userData) = *this; return true; } RayInfo shortest; shortest.t = 1e8; bool gotMatch = false; S32 detail; const Vector<S32> &details = data->getLOSDetails(); for (U32 i = 0; i < details.size(); i++) { detail = details[i]; if (detail != -1) { //si->animate(data->mLOSDetails[i]); if ( si->castRayOpcode( detail, s, e, outInfo ) ) { if (outInfo->t < shortest.t) { gotMatch = true; shortest = *outInfo; } } } } if ( !gotMatch ) return false; // Copy out the shortest time... *outInfo = shortest; if ( outInfo->userData != NULL ) *(ForestItem*)(outInfo->userData) = *this; return true; }