void FlyingVehicle::updateEmitter(bool active,F32 dt,ParticleEmitterData *emitter,S32 idx,S32 count) { if (!emitter) return; for (S32 j = idx; j < idx + count; j++) if (active) { if (mDataBlock->jetNode[j] != -1) { if (!bool(mJetEmitter[j])) { mJetEmitter[j] = new ParticleEmitter; mJetEmitter[j]->onNewDataBlock(emitter,false); mJetEmitter[j]->registerObject(); } MatrixF mat; Point3F pos,axis; mat.mul(getRenderTransform(), mShapeInstance->mNodeTransforms[mDataBlock->jetNode[j]]); mat.getColumn(1,&axis); mat.getColumn(3,&pos); mJetEmitter[j]->emitParticles(pos,true,axis,getVelocity(),(U32)(dt * 1000)); } } else { for (S32 j = idx; j < idx + count; j++) if (bool(mJetEmitter[j])) { mJetEmitter[j]->deleteWhenEmpty(); mJetEmitter[j] = 0; } } }
GLint gluProject( GLdouble objx, GLdouble objy, GLdouble objz, const F64 *model, const F64 * proj, const GLint * vp, F64 * winx, F64 * winy, F64 * winz ) { Vector4F v = Vector4F( objx, objy, objz, 1.0f ); MatrixF pmat = MatrixF( false ); for (int i=0; i<16; i++) { ((F32*)pmat)[i] = (float)proj[i]; } MatrixF mmat = MatrixF( false ); for (int i=0; i<16; i++) { ((F32*)mmat)[i] = (float)model[i]; } //Luma: Projection fix mmat.transpose(); pmat.transpose(); (pmat.mul(mmat)).mul(v); //Luma: Projection fix if(v.w == 0.0f) { return GL_FALSE; } F32 invW = 1.0f / v.w; v.x *= invW; v.y *= invW; v.z *= invW; *winx = (GLfloat)vp[0] + (GLfloat)vp[2] * (v.x + 1.0f) * 0.5f; *winy = (GLfloat)vp[1] + (GLfloat)vp[3] * (v.y + 1.0f) * 0.5f; *winz = (v.z + 1.0f) * 0.5f; int glError; glError = TEST_FOR_OPENGL_ERRORS return GL_TRUE; }
void T3DSceneComponent::_ComputeObjectBox() { _objectBox->set(Box3F(10E30f, 10E30f, 10E30f, -10E30f, -10E30f, -10E30f)); bool gotone = false; for (T3DSceneClient * walk = _sceneClientList; walk != NULL; walk = walk->getNextSceneClient()) { ISolid3D * solid = dynamic_cast<ISolid3D*>(walk); if (solid == NULL) continue; Box3F box = solid->getObjectBox(); if (solid->getTransform3D() != NULL) { MatrixF mat; solid->getTransform3D()->getObjectMatrix(mat, true); mat.mul(box); } box.extend(_objectBox->get().min); box.extend(_objectBox->get().max); _objectBox->set(box); gotone = true; } if (!gotone) _objectBox->set(Box3F()); setDirtyObjectBox(false); setDirtyWorldBox(true); }
void TurretShape::getRenderWeaponMountTransform( F32 delta, S32 mountPoint, const MatrixF &xfm, MatrixF *outMat ) { // Returns mount point to world space transform if ( mountPoint >= 0 && mountPoint < SceneObject::NumMountPoints) { S32 ni = mDataBlock->weaponMountNode[mountPoint]; if (ni != -1) { MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni]; mountTransform.mul( xfm ); const Point3F& scale = getScale(); // The position of the mount point needs to be scaled. Point3F position = mountTransform.getPosition(); position.convolve( scale ); mountTransform.setPosition( position ); // Also we would like the object to be scaled to the model. mountTransform.scale( scale ); outMat->mul(getRenderTransform(), mountTransform); return; } } // Then let SceneObject handle it. GrandParent::getRenderMountTransform( delta, mountPoint, xfm, outMat ); }
Box3F PSSMLightShadowMap::_calcClipSpaceAABB(const Frustum& f, const MatrixF& transform, F32 farDist) { // Calculate frustum center Point3F center(0,0,0); for (U32 i = 0; i < 8; i++) { const Point3F& pt = f.getPoints()[i]; center += pt; } center /= 8; // Calculate frustum bounding sphere radius F32 radius = 0.0f; for (U32 i = 0; i < 8; i++) radius = getMax(radius, (f.getPoints()[i] - center).lenSquared()); radius = mFloor( mSqrt(radius) ); // Now build box for sphere Box3F result; Point3F radiusBox(radius, radius, radius); result.minExtents = center - radiusBox; result.maxExtents = center + radiusBox; // Transform to light projection space transform.mul(result); return result; }
void AITurretShape::_setScanBox() { mTransformedScanBox = mScanBox; MatrixF mat; getScanTransform(mat); mat.mul(mTransformedScanBox); }
// This "rounds" the projection matrix to remove subtexel movement during shadow map // rasterization. This is here to reduce shadow shimmering. void PSSMLightShadowMap::_roundProjection(const MatrixF& lightMat, const MatrixF& cropMatrix, Point3F &offset, U32 splitNum) { // Round to the nearest shadowmap texel, this helps reduce shimmering MatrixF currentProj = GFX->getProjectionMatrix(); currentProj = cropMatrix * currentProj * lightMat; // Project origin to screen. Point4F originShadow4F(0,0,0,1); currentProj.mul(originShadow4F); Point2F originShadow(originShadow4F.x / originShadow4F.w, originShadow4F.y / originShadow4F.w); // Convert to texture space (0..shadowMapSize) F32 t = mNumSplits < 4 ? mShadowMapTex->getWidth() / mNumSplits : mShadowMapTex->getWidth() / 2; Point2F texelsToTexture(t / 2.0f, mShadowMapTex->getHeight() / 2.0f); if (mNumSplits >= 4) texelsToTexture.y *= 0.5f; originShadow.convolve(texelsToTexture); // Clamp to texel boundary Point2F originRounded; originRounded.x = mFloor(originShadow.x + 0.5f); originRounded.y = mFloor(originShadow.y + 0.5f); // Subtract origin to get an offset to recenter everything on texel boundaries originRounded -= originShadow; // Convert back to texels (0..1) and offset originRounded.convolveInverse(texelsToTexture); offset.x += originRounded.x; offset.y += originRounded.y; }
void T3DSceneComponent::AddSceneClient(T3DSceneClient * sceneClient) { AssertFatal(sceneClient,"Cannot add a NULL scene client"); // add to the front of the list sceneClient->setNextSceneClient(_sceneClientList); _sceneClientList = sceneClient; // extend object box ISolid3D * solid = dynamic_cast<ISolid3D*>(sceneClient); if (solid != NULL) { if (isObjectBoxLocked()) setDirtyObjectBox(true); else { Box3F box = solid->getObjectBox(); if (solid->getTransform3D() != NULL) { MatrixF mat; solid->getTransform3D()->getObjectMatrix(mat, true); mat.mul(box); } box.extend(_objectBox->get().min); box.extend(_objectBox->get().max); _objectBox->set(box); } // policy is that we become parent transform if (solid->getTransform3D() != NULL && solid->getTransform3D()->isChildOf(_transform, true)) solid->getTransform3D()->setParentTransform(_transform); } }
void TurretShape::getRenderImageTransform(U32 imageSlot,S32 node,MatrixF* mat) { // Same as ShapeBase::getRenderImageTransform() other than getRenderWeaponMountTransform() below // Image transform in world space MountedImage& image = mMountedImageList[imageSlot]; if (image.dataBlock) { if (node != -1) { ShapeBaseImageData& data = *image.dataBlock; U32 shapeIndex = getImageShapeIndex(image); MatrixF nmat = image.shapeInstance[shapeIndex]->mNodeTransforms[node]; MatrixF mmat; if ( data.useEyeNode && isFirstPerson() && data.eyeMountNode[shapeIndex] != -1 ) { MatrixF emat; getRenderEyeBaseTransform(&emat, mDataBlock->mountedImagesBank); MatrixF mountTransform = image.shapeInstance[shapeIndex]->mNodeTransforms[data.eyeMountNode[shapeIndex]]; mountTransform.affineInverse(); mmat.mul(emat, mountTransform); } else if ( data.useEyeOffset && isFirstPerson() ) { MatrixF emat; getRenderEyeTransform(&emat); mmat.mul(emat,data.eyeOffset); } else { MatrixF emat; getRenderWeaponMountTransform( 0.0f, imageSlot, MatrixF::Identity, &emat ); mmat.mul(emat,data.mountTransform[shapeIndex]); } mat->mul(mmat, nmat); } else getRenderImageTransform(imageSlot,mat); } else *mat = getRenderTransform(); }
Box3F ForestConvex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const { Box3F newBox = box; newBox.minExtents.convolve(scale); newBox.maxExtents.convolve(scale); mat.mul(newBox); return newBox; }
Box3F Convex::getBoundingBox(const MatrixF& mat, const Point3F& scale) const { Box3F wBox;//TOFIX = mObject->getObjBox(); wBox.minExtents.convolve(scale); wBox.maxExtents.convolve(scale); mat.mul(wBox); return wBox; }
GLint gluUnProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z ) { Vector4F v = Vector4F( 2.0f*(winx-vp[0])/vp[2] - 1.0f, 2.0f*(winy-vp[1])/vp[2] - 1.0f, 2.0f*vp[2] - 1.0f, 1.0f ); MatrixF pmat = MatrixF( false ); for (int i=0; i<16; i++) { ((F32*)pmat)[i] = (float)proj[i]; } MatrixF mmat = MatrixF( false ); for (int i=0; i<16; i++) { ((F32*)mmat)[i] = (float)model[i]; } mmat = pmat.mul(mmat); mmat = mmat.inverse(); mmat.mul( v ); *x = v.x; *y = v.y; *z = v.z; int glError; glError = TEST_FOR_OPENGL_ERRORS return GL_TRUE; }
void Etherform::setRenderPosition(const Point3F& pos, const Point3F& rot, F32 dt) { MatrixF xRot, zRot; xRot.set(EulerF(rot.x, 0, 0)); zRot.set(EulerF(0, 0, rot.z)); MatrixF temp; temp.mul(zRot, xRot); temp.setColumn(3, pos); Parent::setRenderTransform(temp); }
Box3F T3DSceneComponent::getWorldBox() { if (DirtyWorldBox && !LockWorldBox) _UpdateWorldBox(); MatrixF mat = getTransform3D()->getWorldMatrix(); Box3F box = getObjectBox(); mat.mul(box); return box; }
void TSShapeInstance::addPath(TSThread *gt, F32 start, F32 end, MatrixF *mat) { // never get here while in transition... AssertFatal(!gt->transitionData.inTransition,"TSShapeInstance::addPath"); if (!mat) mat = &mGroundTransform; MatrixF startInvM; gt->getGround(start,&startInvM); startInvM.inverse(); MatrixF endM; gt->getGround(end,&endM); MatrixF addM; addM.mul(startInvM,endM); endM.mul(*mat,addM); *mat = endM; }
void BtBody::applyCorrection( const MatrixF &transform ) { AssertFatal( mActor, "BtBody::applyCorrection - The actor is null!" ); AssertFatal( isDynamic(), "BtBody::applyCorrection - This call is only for dynamics!" ); if ( mCenterOfMass ) { MatrixF xfm; xfm.mul( transform, *mCenterOfMass ); mActor->setCenterOfMassTransform( btCast<btTransform>( xfm ) ); } else mActor->setCenterOfMassTransform( btCast<btTransform>( transform ) ); }
MatrixF ConvexShape::getSurfaceWorldMat( S32 surfId, bool scaled ) const { if ( surfId < 0 || surfId >= mSurfaces.size() ) return MatrixF::Identity; MatrixF objToWorld( mObjToWorld ); if ( scaled ) objToWorld.scale( mObjScale ); MatrixF surfMat; surfMat.mul( objToWorld, mSurfaces[surfId] ); return surfMat; }
void WorldEditorSelection::rotate(const EulerF &rot) { for( iterator iter = begin(); iter != end(); ++ iter ) { SceneObject* object = dynamic_cast< SceneObject* >( *iter ); if( !object ) continue; MatrixF mat = object->getTransform(); MatrixF transform(rot); mat.mul(transform); object->setTransform(mat); } }
bool TurretShape::getNodeTransform(S32 node, MatrixF& mat) { if (node == -1) return false; MatrixF nodeTransform = mShapeInstance->mNodeTransforms[node]; const Point3F& scale = getScale(); // The position of the node needs to be scaled. Point3F position = nodeTransform.getPosition(); position.convolve( scale ); nodeTransform.setPosition( position ); mat.mul(mObjToWorld, nodeTransform); return true; }
void Etherform::interpolateTick(F32 dt) { Parent::interpolateTick(dt); if(dt != 0.0f) { Point3F pos = delta.pos + delta.posVec * dt; Point3F rot = delta.rot + delta.rotVec * dt; this->setRenderPosition(pos, rot, dt); // update laser trails... for( S32 i=0; i < NUM_ETHERFORM_LASERTRAILS; i++ ) { if(mLaserTrailList[i]) mLaserTrailList[i]->setLastNodePos(pos); } // apply camera effects - is this the best place? - bramage GameConnection* connection = GameConnection::getConnectionToServer(); if(connection->isFirstPerson()) { GameBase* obj = connection->getControlObject(); if( obj == this ) { MatrixF curTrans = this->getRenderTransform(); curTrans.mul( gCamFXMgr.getTrans() ); Parent::setRenderTransform( curTrans ); } } } else { this->setRenderPosition(delta.pos, delta.rot, 0); } // Save last interpolation delta value. delta.dt = dt; }
void BtBody::setTransform( const MatrixF &transform ) { AssertFatal( mActor, "BtBody::setTransform - The actor is null!" ); if ( mCenterOfMass ) { MatrixF xfm; xfm.mul( transform, *mCenterOfMass ); mActor->setCenterOfMassTransform( btCast<btTransform>( xfm ) ); } else mActor->setCenterOfMassTransform( btCast<btTransform>( transform ) ); // If its dynamic we have more to do. if ( isDynamic() ) { // Clear any velocity and forces... this is a warp. mActor->clearForces(); mActor->setLinearVelocity( btVector3( 0, 0, 0 ) ); mActor->setAngularVelocity( btVector3( 0, 0, 0 ) ); mActor->activate(); } }
void BtBody::getState( PhysicsState *outState ) { AssertFatal( isDynamic(), "BtBody::getState - This call is only for dynamics!" ); // TODO: Fix this to do what we intended... to return // false so that the caller can early out of the state // hasn't changed since the last tick. MatrixF trans; if ( mInvCenterOfMass ) trans.mul( btCast<MatrixF>( mActor->getCenterOfMassTransform() ), *mInvCenterOfMass ); else trans = btCast<MatrixF>( mActor->getCenterOfMassTransform() ); outState->position = trans.getPosition(); outState->orientation.set( trans ); outState->linVelocity = btCast<Point3F>( mActor->getLinearVelocity() ); outState->angVelocity = btCast<Point3F>( mActor->getAngularVelocity() ); outState->sleeping = !mActor->isActive(); // Bullet doesn't keep the momentum... recalc it. outState->momentum = ( 1.0f / mActor->getInvMass() ) * outState->linVelocity; }
void TurretShape::getWeaponMountTransform( S32 index, const MatrixF &xfm, MatrixF *outMat ) { // Returns mount point to world space transform if ( index >= 0 && index < SceneObject::NumMountPoints) { S32 ni = mDataBlock->weaponMountNode[index]; if (ni != -1) { MatrixF mountTransform = mShapeInstance->mNodeTransforms[ni]; mountTransform.mul( xfm ); const Point3F& scale = getScale(); // The position of the mount point needs to be scaled. Point3F position = mountTransform.getPosition(); position.convolve( scale ); mountTransform.setPosition( position ); // Also we would like the object to be scaled to the model. outMat->mul(mObjToWorld, mountTransform); return; } } // Then let SceneObject handle it. GrandParent::getMountTransform( index, xfm, outMat ); }
void WorldEditorSelection::rotate(const EulerF & rot, const Point3F & center) { // single selections will rotate around own axis, multiple about world if(size() == 1) { SceneObject* object = dynamic_cast< SceneObject* >( at( 0 ) ); if( object ) { MatrixF mat = object->getTransform(); Point3F pos; mat.getColumn(3, &pos); // get offset in obj space Point3F offset = pos - center; MatrixF wMat = object->getWorldTransform(); wMat.mulV(offset); // MatrixF transform(EulerF(0,0,0), -offset); transform.mul(MatrixF(rot)); transform.mul(MatrixF(EulerF(0,0,0), offset)); mat.mul(transform); object->setTransform(mat); } } else { for( iterator iter = begin(); iter != end(); ++ iter ) { SceneObject* object = dynamic_cast< SceneObject* >( *iter ); if( !object ) continue; MatrixF mat = object->getTransform(); Point3F pos; mat.getColumn(3, &pos); // get offset in obj space Point3F offset = pos - center; MatrixF transform(rot); Point3F wOffset; transform.mulV(offset, &wOffset); MatrixF wMat = object->getWorldTransform(); wMat.mulV(offset); // transform.set(EulerF(0,0,0), -offset); mat.setColumn(3, Point3F(0,0,0)); wMat.setColumn(3, Point3F(0,0,0)); transform.mul(wMat); transform.mul(MatrixF(rot)); transform.mul(mat); mat.mul(transform); mat.normalize(); mat.setColumn(3, wOffset + center); object->setTransform(mat); } } mCentroidValid = false; }
//----------------------------------------------------------------------------- // Object Rendering //----------------------------------------------------------------------------- void MetaShapeRenderer::createGeometry() { Point3F scale = this->getScale(); Box3F box = this->getObjBox(); box.minExtents.convolve(scale); box.maxExtents.convolve(scale); MatrixF mat = this->getTransform(); mat.mul(box); mPolyList.clear(); this->getContainer()->buildPolyList( PLC_Collision, box, ShapeBaseObjectType, &mPolyList ); mUpdatePolyList = false; static const Point3F cubePoints[8] = { Point3F( 1.0f, -1.0f, -1.0f), Point3F( 1.0f, -1.0f, 1.0f), Point3F( 1.0f, 1.0f, -1.0f), Point3F( 1.0f, 1.0f, 1.0f), Point3F(-1.0f, -1.0f, -1.0f), Point3F(-1.0f, 1.0f, -1.0f), Point3F(-1.0f, -1.0f, 1.0f), Point3F(-1.0f, 1.0f, 1.0f) }; static const Point3F cubeNormals[6] = { Point3F( 1.0f, 0.0f, 0.0f), Point3F(-1.0f, 0.0f, 0.0f), Point3F( 0.0f, 1.0f, 0.0f), Point3F( 0.0f, -1.0f, 0.0f), Point3F( 0.0f, 0.0f, 1.0f), Point3F( 0.0f, 0.0f, -1.0f) }; static const ColorI cubeColors[3] = { ColorI( 0, 0, 100, 100), ColorI( 0, 0, 100, 100), ColorI( 0, 0, 100, 100) }; static const U32 cubeFaces[36][3] = { { 3, 0, 0 }, { 0, 0, 0 }, { 1, 0, 0 }, { 2, 0, 0 }, { 0, 0, 0 }, { 3, 0, 0 }, { 7, 1, 0 }, { 4, 1, 0 }, { 5, 1, 0 }, { 6, 1, 0 }, { 4, 1, 0 }, { 7, 1, 0 }, { 3, 2, 1 }, { 5, 2, 1 }, { 2, 2, 1 }, { 7, 2, 1 }, { 5, 2, 1 }, { 3, 2, 1 }, { 1, 3, 1 }, { 4, 3, 1 }, { 6, 3, 1 }, { 0, 3, 1 }, { 4, 3, 1 }, { 1, 3, 1 }, { 3, 4, 2 }, { 6, 4, 2 }, { 7, 4, 2 }, { 1, 4, 2 }, { 6, 4, 2 }, { 3, 4, 2 }, { 2, 5, 2 }, { 4, 5, 2 }, { 0, 5, 2 }, { 5, 5, 2 }, { 4, 5, 2 }, { 2, 5, 2 } }; // Fill the vertex buffer VertexType *pVert = NULL; mVertexBuffer.set( GFX, 36, GFXBufferTypeStatic ); pVert = mVertexBuffer.lock(); Point3F halfSize = getObjBox().getExtents() * 0.5f; for (U32 i = 0; i < 36; i++) { const U32& vdx = cubeFaces[i][0]; const U32& ndx = cubeFaces[i][1]; const U32& cdx = cubeFaces[i][2]; pVert[i].point = cubePoints[vdx] * halfSize; pVert[i].normal = cubeNormals[ndx]; pVert[i].color = cubeColors[cdx]; } mVertexBuffer.unlock(); // Set up our normal and reflection StateBlocks GFXStateBlockDesc desc; // The normal StateBlock only needs a default StateBlock mNormalSB = GFX->createStateBlock( desc ); // The reflection needs its culling reversed desc.cullDefined = true; desc.cullMode = GFXCullCW; mReflectSB = GFX->createStateBlock( desc ); }
void AITurretShape::_trackTarget(F32 dt) { // Only on server if (isClientObject()) return; // We can only track a target if we have one if (!mTarget.isValid()) return; Point3F targetPos = mTarget.target->getBoxCenter(); // Can we see the target? MatrixF aimMat; getAimTransform(aimMat); Point3F start; aimMat.getColumn(3, &start); RayInfo ri; Point3F sightPoint; disableCollision(); bool los = _testTargetLineOfSight(start, mTarget.target, sightPoint); enableCollision(); if (!los) { // Target is blocked. Should we try to track from its last // known position and velocity? SimTime curTime = Sim::getCurrentTime(); if ( (curTime - mTarget.lastSightTime) > (mDataBlock->trackLostTargetTime * 1000.0f) ) { // Time's up. Stop tracking. _cleanupTargetAndTurret(); return; } // Use last known information to attempt to // continue to track target for a while. targetPos = mTarget.lastPos + mTarget.lastVel * F32(curTime - mTarget.lastSightTime) / 1000.0f; } else { // Target is visible // We only track targets that are alive if (mTarget.target->getDamageState() != Enabled) { // We can't track any more _cleanupTargetAndTurret(); return; } targetPos = sightPoint; // Store latest target info mTarget.lastPos = targetPos; mTarget.lastVel = mTarget.target->getVelocity(); mTarget.lastSightTime = Sim::getCurrentTime(); } // Calculate angles to face the target, specifically the part that we can see VectorF toTarget; MatrixF mat; S32 node = mDataBlock->aimNode; if (node != -1) { // Get the current position of our node MatrixF* nodeTrans = &mShapeInstance->mNodeTransforms[node]; Point3F currentPos; nodeTrans->getColumn(3, ¤tPos); // Turn this into a matrix we can use to put the target // position into our space. MatrixF nodeMat(true); nodeMat.setColumn(3, currentPos); mat.mul(mObjToWorld, nodeMat); mat.affineInverse(); } else { mat = mWorldToObj; } mat.mulP(targetPos, &toTarget); // lead the target F32 timeToTargetSquared = (mWeaponLeadVelocitySquared > 0) ? toTarget.lenSquared() / mWeaponLeadVelocitySquared : 0; if (timeToTargetSquared > 1.0) { targetPos = targetPos + (mTarget.lastVel * mSqrt(timeToTargetSquared)); mat.mulP(targetPos, &toTarget); } F32 yaw, pitch; MathUtils::getAnglesFromVector(toTarget, yaw, pitch); if (yaw > M_PI_F) yaw = yaw - M_2PI_F; //if (pitch > M_PI_F) // pitch = -(pitch - M_2PI_F); Point3F rot(-pitch, 0.0f, yaw); // If we have a rotation rate make sure we follow it if (mHeadingRate > 0) { F32 rate = mHeadingRate * dt; F32 rateCheck = mFabs(rot.z - mRot.z); if (rateCheck > rate) { // This will clamp the new value to the rate regardless if it // is increasing or decreasing. rot.z = mClampF(rot.z, mRot.z-rate, mRot.z+rate); } } if (mPitchRate > 0) { F32 rate = mPitchRate * dt; F32 rateCheck = mFabs(rot.x - mRot.x); if (rateCheck > rate) { // This will clamp the new value to the rate regardless if it // is increasing or decreasing. rot.x = mClampF(rot.x, mRot.x-rate, mRot.x+rate); } } // Test if the rotation to the target is outside of our limits if (_outsideLimits(rot)) { // We can't track any more _cleanupTargetAndTurret(); return; } // Test if the target is out of weapons range if (toTarget.lenSquared() > mWeaponRangeSquared) { // We can't track any more _cleanupTargetAndTurret(); return; } mRot = rot; _setRotation( mRot ); setMaskBits(TurretUpdateMask); }
void TerrainBlock::_renderBlock( SceneRenderState *state ) { PROFILE_SCOPE( TerrainBlock_RenderBlock ); // Prevent rendering shadows if feature is disabled if ( !mCastShadows && state->isShadowPass() ) return; MatrixF worldViewXfm = state->getWorldViewMatrix(); worldViewXfm.mul( getRenderTransform() ); MatrixF worldViewProjXfm = state->getProjectionMatrix(); worldViewProjXfm.mul( worldViewXfm ); const MatrixF &objectXfm = getRenderWorldTransform(); Point3F objCamPos = state->getDiffuseCameraPosition(); objectXfm.mulP( objCamPos ); // Get the shadow material. if ( !mDefaultMatInst ) mDefaultMatInst = TerrainCellMaterial::getShadowMat(); // Make sure we have a base material. if ( !mBaseMaterial ) { mBaseMaterial = new TerrainCellMaterial(); mBaseMaterial->init( this, 0, false, false, true ); } // Did the detail layers change? if ( mDetailsDirty ) { _updateMaterials(); mDetailsDirty = false; } // If the layer texture has been cleared or is // dirty then update it. if ( mLayerTex.isNull() || mLayerTexDirty ) _updateLayerTexture(); // If the layer texture is dirty or we lost the base // texture then regenerate it. if ( mLayerTexDirty || mBaseTex.isNull() ) { _updateBaseTexture( false ); mLayerTexDirty = false; } static Vector<TerrCell*> renderCells; renderCells.clear(); mCell->cullCells( state, objCamPos, &renderCells ); RenderPassManager *renderPass = state->getRenderPass(); MatrixF *riObjectToWorldXfm = renderPass->allocUniqueXform( getRenderTransform() ); const bool isColorDrawPass = state->isDiffusePass() || state->isReflectPass(); // This is here for shadows mostly... it allows the // proper shadow material to be generated. BaseMatInstance *defaultMatInst = state->getOverrideMaterial( mDefaultMatInst ); // Only pass and use the light manager if this is not a shadow pass. LightManager *lm = NULL; if ( isColorDrawPass ) lm = LIGHTMGR; for ( U32 i=0; i < renderCells.size(); i++ ) { TerrCell *cell = renderCells[i]; // Ok this cell is fit to render. TerrainRenderInst *inst = renderPass->allocInst<TerrainRenderInst>(); // Setup lights for this cell. if ( lm ) { SphereF bounds = cell->getSphereBounds(); getRenderTransform().mulP( bounds.center ); LightQuery query; query.init( bounds ); query.getLights( inst->lights, 8 ); } GFXVertexBufferHandleBase vertBuff; GFXPrimitiveBufferHandle primBuff; cell->getRenderPrimitive( &inst->prim, &vertBuff, &primBuff ); inst->mat = defaultMatInst; inst->vertBuff = vertBuff.getPointer(); if ( primBuff.isValid() ) { // Use the cell's custom primitive buffer inst->primBuff = primBuff.getPointer(); } else { // Use the standard primitive buffer for this cell inst->primBuff = mPrimBuffer.getPointer(); } inst->objectToWorldXfm = riObjectToWorldXfm; // If we're not drawing to the shadow map then we need // to include the normal rendering materials. if ( isColorDrawPass ) { const SphereF &bounds = cell->getSphereBounds(); F32 sqDist = ( bounds.center - objCamPos ).lenSquared(); F32 radiusSq = mSquared( ( mMaxDetailDistance + bounds.radius ) * smDetailScale ); // If this cell is near enough to get detail textures then // use the full detail mapping material. Else we use the // simple base only material. if ( !state->isReflectPass() && sqDist < radiusSq ) inst->cellMat = cell->getMaterial(); else if ( state->isReflectPass() ) inst->cellMat = mBaseMaterial->getReflectMat(); else inst->cellMat = mBaseMaterial; } inst->defaultKey = (U32)cell->getMaterials(); // Submit it for rendering. renderPass->addInst( inst ); } // Trigger the debug rendering. if ( state->isDiffusePass() && !renderCells.empty() && smDebugRender ) { // Store the render cells for later. mDebugCells = renderCells; ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>(); ri->renderDelegate.bind( this, &TerrainBlock::_renderDebug ); ri->type = RenderPassManager::RIT_Editor; state->getRenderPass()->addInst( ri ); } }
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(); }
void ConvexShape::_renderDebug( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *mat ) { GFXDrawUtil *drawer = GFX->getDrawUtil(); GFX->setTexture( 0, NULL ); // Render world box. if ( false ) { Box3F wbox( mWorldBox ); //if ( getServerObject() ) // Box3F wbox = static_cast<ConvexShape*>( getServerObject() )->mWorldBox; GFXStateBlockDesc desc; desc.setCullMode( GFXCullNone ); desc.setFillModeWireframe(); drawer->drawCube( desc, wbox, ColorI::RED ); } const Vector< Point3F > &pointList = mGeometry.points; const Vector< ConvexShape::Face > &faceList = mGeometry.faces; // Render Edges. if ( false ) { GFXTransformSaver saver; //GFXFrustumSaver fsaver; MatrixF xfm( getRenderTransform() ); xfm.scale( getScale() ); GFX->multWorld( xfm ); GFXStateBlockDesc desc; desc.setZReadWrite( true, false ); desc.setBlend( true ); GFX->setStateBlockByDesc( desc ); //MathUtils::getZBiasProjectionMatrix( 0.01f, state->getFrustum(), ) const Point3F &camFvec = state->getCameraTransform().getForwardVector(); for ( S32 i = 0; i < faceList.size(); i++ ) { const ConvexShape::Face &face = faceList[i]; const Vector< ConvexShape::Edge > &edgeList = face.edges; const Vector< U32 > &facePntList = face.points; PrimBuild::begin( GFXLineList, edgeList.size() * 2 ); PrimBuild::color( ColorI::WHITE * 0.8f ); for ( S32 j = 0; j < edgeList.size(); j++ ) { PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p0 ] ] - camFvec * 0.001f ); PrimBuild::vertex3fv( pointList[ facePntList[ edgeList[j].p1 ] ] - camFvec * 0.001f ); } PrimBuild::end(); } } ColorI faceColorsx[4] = { ColorI( 255, 0, 0 ), ColorI( 0, 255, 0 ), ColorI( 0, 0, 255 ), ColorI( 255, 0, 255 ) }; MatrixF objToWorld( mObjToWorld ); objToWorld.scale( mObjScale ); // Render faces centers/colors. if ( false ) { GFXStateBlockDesc desc; desc.setCullMode( GFXCullNone ); Point3F size( 0.1f ); for ( S32 i = 0; i < faceList.size(); i++ ) { ColorI color = faceColorsx[ i % 4 ]; S32 div = ( i / 4 ) * 4; if ( div > 0 ) color /= div; color.alpha = 255; Point3F pnt; objToWorld.mulP( faceList[i].centroid, &pnt ); drawer->drawCube( desc, size, pnt, color, NULL ); } } // Render winding order. if ( false ) { GFXStateBlockDesc desc; desc.setCullMode( GFXCullNone ); desc.setZReadWrite( true, false ); GFX->setStateBlockByDesc( desc ); U32 pointCount = 0; for ( S32 i = 0; i < faceList.size(); i++ ) pointCount += faceList[i].winding.size(); PrimBuild::begin( GFXLineList, pointCount * 2 ); for ( S32 i = 0; i < faceList.size(); i++ ) { for ( S32 j = 0; j < faceList[i].winding.size(); j++ ) { Point3F p0 = pointList[ faceList[i].points[ faceList[i].winding[j] ] ]; Point3F p1 = p0 + mSurfaces[ faceList[i].id ].getUpVector() * 0.75f * ( Point3F::One / mObjScale ); objToWorld.mulP( p0 ); objToWorld.mulP( p1 ); ColorI color = faceColorsx[ j % 4 ]; S32 div = ( j / 4 ) * 4; if ( div > 0 ) color /= div; color.alpha = 255; PrimBuild::color( color ); PrimBuild::vertex3fv( p0 ); PrimBuild::color( color ); PrimBuild::vertex3fv( p1 ); } } PrimBuild::end(); } // Render Points. if ( false ) { /* GFXTransformSaver saver; MatrixF xfm( getRenderTransform() ); xfm.scale( getScale() ); GFX->multWorld( xfm ); GFXStateBlockDesc desc; Point3F size( 0.05f ); */ } // Render surface transforms. if ( false ) { GFXStateBlockDesc desc; desc.setBlend( false ); desc.setZReadWrite( true, true ); Point3F scale(mNormalLength); for ( S32 i = 0; i < mSurfaces.size(); i++ ) { MatrixF objToWorld( mObjToWorld ); objToWorld.scale( mObjScale ); MatrixF renderMat; renderMat.mul( objToWorld, mSurfaces[i] ); renderMat.setPosition( renderMat.getPosition() + renderMat.getUpVector() * 0.001f ); drawer->drawTransform( desc, renderMat, &scale, NULL ); } } }
void EditTSCtrl::renderCameraAxis() { GFXDEBUGEVENT_SCOPE( Editor_renderCameraAxis, ColorI::WHITE ); static MatrixF sRotMat(EulerF( (M_PI_F / -2.0f), 0.0f, 0.0f)); MatrixF camMat = mLastCameraQuery.cameraMatrix; camMat.mul(sRotMat); camMat.inverse(); MatrixF axis; axis.setColumn(0, Point3F(1, 0, 0)); axis.setColumn(1, Point3F(0, 0, 1)); axis.setColumn(2, Point3F(0, -1, 0)); axis.mul(camMat); Point3F forwardVec, upVec, rightVec; axis.getColumn( 2, &forwardVec ); axis.getColumn( 1, &upVec ); axis.getColumn( 0, &rightVec ); Point2I pos = getPosition(); F32 offsetx = pos.x + 20.0; F32 offsety = pos.y + getExtent().y - 42.0; // Take the status bar into account F32 scale = 15.0; // Generate correct drawing order ColorI c1(255,0,0); ColorI c2(0,255,0); ColorI c3(0,0,255); ColorI tc; Point3F *p1, *p2, *p3, *tp; p1 = &rightVec; p2 = &upVec; p3 = &forwardVec; if(p3->y > p2->y) { tp = p2; tc = c2; p2 = p3; c2 = c3; p3 = tp; c3 = tc; } if(p2->y > p1->y) { tp = p1; tc = c1; p1 = p2; c1 = c2; p2 = tp; c2 = tc; } PrimBuild::begin( GFXLineList, 6 ); //*** Axis 1 PrimBuild::color(c1); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p1->x*scale, offsety-p1->z*scale, 0); //*** Axis 2 PrimBuild::color(c2); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p2->x*scale, offsety-p2->z*scale, 0); //*** Axis 3 PrimBuild::color(c3); PrimBuild::vertex3f(offsetx, offsety, 0); PrimBuild::vertex3f(offsetx+p3->x*scale, offsety-p3->z*scale, 0); PrimBuild::end(); }