void cCritterViewer::setViewpoint(cVector toviewer, cVector lookatpoint, BOOL trytoseewholeworld) { //First do some default setup stuff _fieldofviewangle = cCritterViewer::STARTFIELDOFVIEWANGLE; setSpeed(0.0); #ifndef THREEDVECTORS //not THREEDVECTORS means the 2D case. _attitude = cMatrix(cVector2(1.0, 0.0), cVector2(0.0, 1.0), _position); #else //THREEDVECTORS _attitude = cMatrix(-cVector::ZAXIS, -cVector::XAXIS, cVector::YAXIS, cVector::ZEROVECTOR); /* To get a reasonable default orientation, we arrange the viewer axes so that: viewer x axis = world -z axis, viewer y axis = world -x axis, viewer z axis = world y axis. We pick this orientation so that if the viewer moves "forward" (along its tangent vector) it moves towards the world. (We correct the mismatch between the coordinate systems in the cCritterViewer::loadViewMatrix method, which has a long comment about this.) Note that we will adjust _position (fourth column) later in this call with a moveTo, also we may rotate the _attitude a bit. */ if (!_perspective) //Ortho view, simply move up. { _proportionofworldtoshow = 1.0; //Show all of a flat world. moveTo(lookatpoint + cCritterViewer::ORTHOZOFFSET * cVector::ZAXIS); // Get above the world _maxspeed = _maxspeedstandard = 0.5 * cCritterViewer::ORTHOZOFFSET; //Mimic perspective case. } else //_perspective { if (toviewer.isPracticallyZero()) //Not usable, so pick a real direction. toviewer = cVector::ZAXIS; //Default is straight up. if (trytoseewholeworld) /* Treat toviewer as a direction, and back off in that direction enough to see the whole world */ { toviewer.normalize(); //Make it a unit vector. _proportionofworldtoshow = cCritterViewer::PROPORTIONOFWORLDTOSHOW; //Trying to show all of a world when flying around it, often leaves too big a space around it. Real furthestcornerdistance = pgame()->border().maxDistanceToCorner(lookatpoint); Real tanangle = tan(_fieldofviewangle/2.0); /* We work with half the fov in this calculation, the tanangle will be the ratio of visible distance to distance above the world, that is, tanangle = dr/dz, where Our dr is _proportionofworldtoshow * furthestcornerdistance, and our dz is the unknown seeallz height we need to back off to. Swap tangangle and dz to get the next formula. */ ASSERT(tanangle); Real seeallz = _proportionofworldtoshow * furthestcornerdistance / tanangle; moveTo(lookatpoint + seeallz * toviewer); } else /*Not trytoseewholeworld. In this case we don't normalize toviewer, instead we treat it as a displacment from the lookatpoint. */ moveTo(lookatpoint + toviewer); lookAt(lookatpoint); _maxspeed = _maxspeedstandard = 0.5 * (position()-lookatpoint).magnitude(); /* Define the speed like this so it typically takes two seconds (1/0.5) to fly in to lookatpoint. */ _lastgoodplayeroffset = position() - pgame()->pplayer()->position(); } #endif //THREEDVECTORS case }
BOOL cCritterViewer::isVisible(const cVector &testpos) const { /* _foveaproportion lies between 0.0 and 1.0. We say something is visible if it appears on the inner foveaproportion central box of the viewer's image screen, which is what you see in the view window. */ if (!_perspective) { cRealBox2 fovea; fovea = orthoViewRect(); fovea = fovea.innerBox((1.0-_foveaproportion)*fovea.minsize()); return (fovea.inside(cVector2(testpos)-cVector2(_position))); } else { cVector totestpos = (testpos - position()).normalize(); return fabs(angleBetween(totestpos, attitudeTangent())) < _foveaproportion * 0.5 * _fieldofviewangle; } }
cVector2 cVector2::ProjectedOn( const cVector2& vec ) { float mult = ( ( x * vec.x ) + ( y * vec.y ) ) / ( ( vec.x * vec.x ) + ( vec.y * vec.y ) ); return cVector2( ( vec.x * mult ), ( vec.y * mult ) ); }