bool FlyingCamera::onSimCameraQuery(SimCameraQuery *query) { SimObjectTransformQuery tquery; query->cameraInfo.fov = g_rDefaultFOV; query->cameraInfo.nearPlane = DEFAULT_NEAR_PLANE; query->cameraInfo.farPlane = getFarPlane(); if (objFollow && objFollow->processQuery(&tquery)) { Point3F objPos = tquery.tmat.p; Vector3F x, y, z; RMat3F rmat(EulerF(rotation.x - M_PI / 2, rotation.y, -rotation.z)); tquery.tmat.p += m_mul(Vector3F(0.0f, rDistance, 0.0f), rmat, &y); tquery.tmat.p.z += 2.0f; y.neg(); y.normalize(); m_cross(y, Vector3F(0.0f, 0.0f, 1.0f), &x); x.normalize(); m_cross(x, y, &z); tquery.tmat.setRow(0, x); tquery.tmat.setRow(1, y); tquery.tmat.setRow(2, z); // Set our position findLOSPosition(tquery.tmat, objPos); } query->cameraInfo.tmat = getTransform(); return (true); }
bool ITR3DMImport::isLine(const Point3F& k,const Point3F& j,const Point3F& l) { Point3F kj = k,lj = l,pv; kj -= j; lj -= j; m_cross( kj, lj, &pv ); return isEqual(pv.len(),.0f,TPlaneF::NormalPrecision); }
// assumes dirY is normalized void fxRenderImage::faceDirection(Point3F & dirY) { // if we rotate about an axis, use a different routine... if (useRotationAxis) { faceDirection(dirY,rotationAxis); return; } Point3F dirX,dirZ; if (fabs(dirY.z) < 0.95) { // dirY is not near vector (0,0,1), so we can // use it as the pivot vector m_cross(dirY, Point3F(0,0,1), &dirX); dirX.normalize(); m_cross(dirX, dirY, &dirZ); } else { // dirY is near vector (0,0,1), so use // pivot Point3F(1,0,0) instead m_cross(Point3F(1,0,0), dirY, &dirZ); dirZ.normalize(); m_cross(dirY, dirZ, &dirX); } transform.setRow(0,dirX); transform.setRow(1,dirY); transform.setRow(2,dirZ); transform.flags |= TMat3F::Matrix_HasRotation; transform.flags &= ~TMat3F::Matrix_HasScale; if (useAxisSpin == true) { RMat3F tempRot(EulerF(0, axisSpin, 0)); TMat3F tempOutput; m_mul(tempRot, transform, &tempOutput); transform = tempOutput; } }
void ITR3DMImport::splitX(Poly* poly,PolyList* polyList) { Vector<Point3F> points; Point3F iPoint; int v1 = poly->vertexList.size() - 1; for (int v2 = 0; v2 < poly->vertexList.size(); v2++) { Poly::Vertex* p1 = &poly->vertexList[v1]; Poly::Vertex* p2 = &poly->vertexList[v2]; if (p1->texture.x <= float(splitDist - 1) && p2->texture.x > float(splitDist - 1) || p2->texture.x <= float(splitDist - 1) && p1->texture.x > float(splitDist - 1)) { Point3F vec; vec = p2->point; vec -= p1->point; vec *= (float(splitDist - 1) - p1->texture.x) / (p2->texture.x - p1->texture.x); vec += p1->point; points.push_back(vec); } if (p1->texture.x < float(splitDist - 1)) iPoint = p1->point; v1 = v2; } // Build plane and split the poly if (points.size() > 1) { Point3F vec = points[0]; vec -= points[1]; Point3F normal; m_cross(vec,poly->plane,&normal); TPlaneF plane(points[0],normal); if (plane.whichSide(iPoint) != TPlaneF::Inside) plane.neg(); Poly tmp; Poly* npoly = new Poly; poly->split(plane,&tmp,npoly); poly->vertexList = tmp.vertexList; npoly->plane = poly->plane; npoly->textureOffset = poly->textureOffset; npoly->material = poly->material; npoly->volumeMask = poly->volumeMask; npoly->textureScaleShift = poly->textureScaleShift; npoly->applyAmbient = poly->applyAmbient; polyList->push_back(npoly); // Normalize after the previous information copy, // normalize alters some of the poly's fields. normalizeTexture(poly); normalizeTexture(npoly); } }
// assumes dirY and dirZ are normalized void fxRenderImage::faceDirection(Point3F & _dirY, Point3F & dirZ) { // dirZ is the fixed axis we rotate about, dirY can change some Point3F dirX, dirY = _dirY; m_cross(dirY, dirZ, &dirX); float xlenSq = m_dot(dirX,dirX); if (IsEqual(xlenSq,0.0f)) { // hard-luck case -- dirY and dirZ are parallel // find any old normalized dirX perp. to dirZ if (fabs(dirY.z) < 0.95) { // dirY is not near vector (0,0,1), so we can // use it as the pivot vector m_cross(dirY, Point3F(0,0,1), &dirX); dirX.normalize(); } else { // dirY is near vector (0,0,1), so use // pivot Point3F(1,0,0) instead m_cross(dirY, Point3F(1,0,0), &dirX); dirX.normalize(); } } else dirX *= m_invsqrtf(xlenSq); m_cross(dirZ, dirX, &dirY); transform.setRow(0,dirX); transform.setRow(1,dirY); transform.setRow(2,dirZ); transform.flags |= TMat3F::Matrix_HasRotation; transform.flags &= ~TMat3F::Matrix_HasScale; }
void m_rotate(float ax,float ay,float az,float phi,matrix &m) { matrix m1; vector a; if (ax==0 && ay==0 && az==0) {m_identity(m); return;} v3_make(ax, ay, az, a); v3_normalize(a, a); m_identity(m); m_mults(m, (float)cos(phi), m); m_diadic3(a, a, m1); m_mults(m1, (float)(1-cos(phi)), m1); m_add(m, m1, m); m_cross(a, m1); m_mults(m1, (float)sin(phi), m1); m_add(m, m1, m); m[3][3] = 1.0; }
void PlanetRenderImage::render(TSRenderContext &rc) { // A simple planet culling scheme would be to dot the line of sight // with the vector from the camera to the planet. This would eliminate // the length test of v below (after m_cross((Point3F)plane, vpNormal, &v)) GFXSurface *gfxSurface = rc.getSurface(); gfxSurface->setHazeSource(GFX_HAZE_NONE); gfxSurface->setShadeSource(GFX_SHADE_CONSTANT); gfxSurface->setAlphaSource(GFX_ALPHA_NONE); gfxSurface->setFillMode(GFX_FILL_TEXTURE); gfxSurface->setTransparency(FALSE); gfxSurface->setTexturePerspective(FALSE); gfxSurface->setConstantShade(1.0f); int textureHeight; gfxSurface->setTextureMap(texture); textureHeight = texture->height; TSCamera *camera = rc.getCamera(); TS::PointArray *pointArray = rc.getPointArray(); pointArray->reset(); pointArray->useIntensities(false); pointArray->useTextures(textCoord); pointArray->useTextures(true); pointArray->setVisibility( TS::ClipMask ); // find out how high the bitmap is at 100% as projected onto the viewport, // texel:pixel will be 1:1 at 640x480 //const RectF &worldVP = camera->getWorldViewport(); //const float h = textureHeight*((worldVP.upperL.y - worldVP.lowerR.y)/480.0f); //const float sz = 0.5*distance*(h/camera->getNearDist()); // find the position of the planet Point3F displacement = camera->getTCW().p; //displacement.z *= -(distance - visibleDistance)/visibleDistance; displacement.z = -displacement.z*(distance/(visibleDistance*1.5f)); Point3F pos = position; pos += displacement; // find the normal to the view plane in world coords Point3F v0(0.0f, 1.0f, 0.0f), vpNormal; m_mul(v0, (RMat3F)camera->getTCW(), &vpNormal); vpNormal.normalize(); // construct the plane that the camera, planet pos & celestial NP all // lie on PlaneF plane(pos, camera->getTCW().p, Point3F(displacement.x, displacement.y, displacement.z + distance)); // the cross product of the VP normal and the normal to the plane just // constructed is the up vector for the planet Point3F v; m_cross((Point3F)plane, vpNormal, &v); if (IsEqual(v.len(), 0.0f)) // planet is directly to the right or left of camera return; v.normalize(); // cross the up with the normal and we get the right vector Point3F u; m_cross(vpNormal, v, &u); u *= size; v *= size; TS::VertexIndexPair V[6]; Point3F ul = pos; ul -= u; ul += v; V[0].fVertexIndex = pointArray->addPoint(ul); V[0].fTextureIndex = 0; Point3F ur = pos; ur += u; ur += v; V[1].fVertexIndex = pointArray->addPoint(ur); V[1].fTextureIndex = 1; Point3F lr = pos; lr += u; lr -= v; V[2].fVertexIndex = pointArray->addPoint(lr); V[2].fTextureIndex = 2; Point3F ll = pos; ll -= u; ll -=v; V[3].fVertexIndex = pointArray->addPoint(ll); V[3].fTextureIndex = 3; if (gfxSurface->getCaps() & GFX_DEVCAP_SUPPORTS_CONST_ALPHA) gfxSurface->setZTest(GFX_NO_ZTEST); pointArray->drawPoly(4, V, 0); if (gfxSurface->getCaps() & GFX_DEVCAP_SUPPORTS_CONST_ALPHA) gfxSurface->setZTest(GFX_ZTEST_AND_WRITE); if(lensFlare) { TS::TransformedVertex vx; camera->transformProject(pos, &vx); bool vis = vx.fStatus & TS::TransformedVertex::Projected; lensFlare->setSunPos(vis, vx.fPoint, pos); } }
bool CelAnimMesh::collideTube( int frameIndex, const Point3F & a, const Point3F &b, float radius, CollisionSurface & cs, float minTime) const { minTime; // hitTime holds the current smallest... float hitTime = cs.time; int hitFace = -1; Point3F hitPoint; AssertFatal( fFrames.size() > 0, "Shape must have at least one frame." ); AssertFatal( frameIndex >= 0 && frameIndex < fFrames.size(), "TS::CelAnimMesh: frame index out of range" ); // get the frame struct: const Frame *frm = &fFrames[frameIndex]; int fv = frm->fFirstVert; const Point3F *pScale = &frm->fScale; const Point3F *pOrigin = &frm->fOrigin; Point3F tubeVect; tubeVect.x = b.x - a.x; tubeVect.y = b.y - a.y; tubeVect.z = b.z - a.z; float tubeLen = tubeVect.len(); float invTubeLen = 1.0f/tubeLen; // tubeVect will hold unit length vector pointing down tube tubeVect *= invTubeLen; float vectDotA = m_dot(tubeVect,a); // inverse radius squared for edgeInTube routine float invRadius2 = 1.0f / (radius*radius); int i; workVerts.setSize(fnVertsPerFrame); workRs.setSize(fnVertsPerFrame); workTs.setSize(fnVertsPerFrame); bool gotNormal; for (i=0;i<fFaces.size();i++) { const Face & theFace = fFaces[i]; int idx1 = theFace.fVIP[0].fVertexIndex; int idx2 = theFace.fVIP[1].fVertexIndex; int idx3 = theFace.fVIP[2].fVertexIndex; Point3F &v1=workVerts[idx1]; Point3F &v2=workVerts[idx2]; Point3F &v3=workVerts[idx3]; Point3F &R1=workRs[idx1]; Point3F &R2=workRs[idx2]; Point3F &R3=workRs[idx3]; float &t1=workTs[idx1]; float &t2=workTs[idx2]; float &t3=workTs[idx3]; if (!(v1Recycled&faceReuseFlags[i])) { fVerts[idx1+fv].getPoint(v1,*pScale,*pOrigin); // distance of vertex down the tube t1 = m_dot(v1,tubeVect) - vectDotA; // projection of vertex onto tube cross-section (centered on origin) R1.x = v1.x - a.x - t1 * tubeVect.x; R1.y = v1.y - a.y - t1 * tubeVect.y; R1.z = v1.z - a.z - t1 * tubeVect.z; } if (!(v2Recycled&faceReuseFlags[i])) { fVerts[idx2+fv].getPoint(v2,*pScale,*pOrigin); // distance of vertex down the tube t2 = m_dot(v2,tubeVect) - vectDotA; // projection of vertex onto tube cross-section (centered on origin) R2.x = v2.x - a.x - t2 * tubeVect.x; R2.y = v2.y - a.y - t2 * tubeVect.y; R2.z = v2.z - a.z - t2 * tubeVect.z; } if (!(v3Recycled&faceReuseFlags[i])) { fVerts[idx3+fv].getPoint(v3,*pScale,*pOrigin); // distance of vertex down the tube t3 = m_dot(v3,tubeVect) - vectDotA; // projection of vertex onto tube cross-section (centered on origin) R3.x = v3.x - a.x - t3 * tubeVect.x; R3.y = v3.y - a.y - t3 * tubeVect.y; R3.z = v3.z - a.z - t3 * tubeVect.z; } bool gotHit=false; if (!(e1Recycled&faceReuseFlags[i])) { if (t1<=t2) gotHit = edgeInTube(R1,R2,t1,t2,radius,invRadius2,invTubeLen,hitTime,hitPoint); else gotHit = edgeInTube(R2,R1,t2,t1,radius,invRadius2,invTubeLen,hitTime,hitPoint); } if (!(e2Recycled&faceReuseFlags[i])) { if (t2<=t3) gotHit |= edgeInTube(R2,R3,t2,t3,radius,invRadius2,invTubeLen,hitTime,hitPoint); else gotHit |= edgeInTube(R3,R2,t3,t2,radius,invRadius2,invTubeLen,hitTime,hitPoint); } if (!(e3Recycled&faceReuseFlags[i])) { if (t3<=t1) gotHit |= edgeInTube(R3,R1,t3,t1,radius,invRadius2,invTubeLen,hitTime,hitPoint); else gotHit |= edgeInTube(R1,R3,t1,t3,radius,invRadius2,invTubeLen,hitTime,hitPoint); } if (gotHit) { hitPoint.x += tubeLen * hitTime * tubeVect.x + a.x; hitPoint.y += tubeLen * hitTime * tubeVect.y + a.y; hitPoint.z += tubeLen * hitTime * tubeVect.z + a.z; hitFace=i; gotNormal=false; } // now check if tube goes through center of face w/o hitting any edges if (m_pointInTriangle(Point3F(0.0f,0.0f,0.0f),tubeVect,R1,R2,R3)) { // build the normal Point3F normal; m_normal(v1,v2,v3,normal); // now we need to find hitTime float d = m_dot(normal,v3); // distance of plane from origin float denom = m_dot(normal,tubeVect) * tubeLen; if (denom>=0.0f) // back face, we can ignore continue; float absT = d - m_dot(normal,a); if (absT<=hitTime*denom) // denom is neg. continue; // ok, a real collision, set ci variables... hitTime=absT/denom; hitFace=i; cs.normal=normal; gotNormal=true; hitPoint.x = a.x + hitTime * tubeLen * tubeVect.x; hitPoint.y = a.y + hitTime * tubeLen * tubeVect.y; hitPoint.z = a.z + hitTime * tubeLen * tubeVect.z; } } if (hitFace>=0) { const Face & theFace = fFaces[hitFace]; if (!gotNormal) { Point3F &v1=workVerts[theFace.fVIP[0].fVertexIndex]; Point3F &v2=workVerts[theFace.fVIP[1].fVertexIndex]; Point3F &v3=workVerts[theFace.fVIP[2].fVertexIndex]; // build the normal Point3F v13,v23; v13.x = v1.x-v3.x; v13.y = v1.y-v3.y; v13.z = v1.z-v3.z; v23.x = v2.x-v3.x; v23.y = v2.y-v3.y; v23.z = v2.z-v3.z; m_cross(v23,v13,&cs.normal); } cs.material=theFace.fMaterial; cs.surface=hitFace; cs.time=hitTime; cs.position=hitPoint; // cs.distance ?? return true; } return false; }
// decide where to place and then add to the manager void SimExplosionCloud::lightFuse(SimExplosion * explosion, Point3F & cameraPos, bool igniteNow) { // decide when to detonate if (!igniteNow) explosion->setDetonationTime(g_expRand.getFloat(0,detonationMax)); Point3F pos; Point3F vec(0, 0, 0); Point3F worldPos,worldVec; switch (form) { case Sphere : { // try to make sure explosions no closer together than 1m in z int maxZ = (int) radius; if (maxZ) { if (topOnly) vec.z = g_expRand.getInt(0,maxZ); else vec.z = g_expRand.getInt(-maxZ,maxZ); } // don't break, fall through to circle } case Circle : { float angle = g_expRand.getFloat(0,float(M_2PI)); float circleRad = m_sqrtf(radius*radius - vec.z *vec.z); vec.x = circleRad * m_cos(angle); vec.y = circleRad * m_sin(angle); pos = center; pos += vec; break; } case Screen: { if (radius>0.1f) // if radius==0, skip some work { vec=cameraPos; vec -= center; vec.normalize(); Point3F dirX,dirZ; if (fabs(vec.z) < 0.95) { // vec is not near vector (0,0,1), so we can // use it as the pivot vector m_cross(vec, Point3F(0,0,1), &dirX); dirX.normalize(); m_cross(dirX, vec, &dirZ); } else { // dirY is near vector (0,0,1), so use // pivot Point3F(1,0,0) instead m_cross(Point3F(1,0,0), vec, &dirZ); dirZ.normalize(); m_cross(vec, dirZ, &dirX); } dirX *= g_expRand.getFloat(-radius,radius); dirZ *= g_expRand.getFloat(-radius,radius); vec *= radius; vec += dirX; vec += dirZ; } pos = center; pos += vec; break; } case Box : { int side; if (topOnly) side = g_expRand.getInt(1,5); else side = g_expRand.getInt(0,5); pos = box.fMax; switch (side) { case 0: pos.z = box.fMin.z; case 1: pos.x = g_expRand.getFloat(box.fMin.x,box.fMax.x); pos.y = g_expRand.getFloat(box.fMin.y,box.fMax.y); break; case 2: pos.y = box.fMin.y; case 3: pos.x = g_expRand.getFloat(box.fMin.x,box.fMax.x); pos.z = g_expRand.getFloat(box.fMin.z,box.fMax.z); break; case 4: pos.x = box.fMin.x; case 5: pos.y = g_expRand.getFloat(box.fMin.y,box.fMax.y); pos.z = g_expRand.getFloat(box.fMin.z,box.fMax.z); break; } switch (side) { case 0: vec.set(0,0,box.fMin.z-box.fMax.z); break; case 1: vec.set(0,0,box.fMax.z-box.fMin.z); break; case 2: vec.set(0,box.fMin.y-box.fMax.y,0); break; case 3: vec.set(0,box.fMax.y-box.fMin.y,0); break; case 4: vec.set(box.fMin.x-box.fMax.x,0,0); break; case 5: vec.set(box.fMax.x-box.fMin.x,0,0); break; } break; } } // now put into world coords if (hasTransform) { m_mul(pos,transform,&worldPos); m_mul(vec,(RMat3F&)transform,&worldVec); } else { worldPos=pos; worldVec=vec; } Point3F camAxis = worldPos; camAxis -= cameraPos; if (m_dot(camAxis,worldVec)>0.0f) { worldPos -= worldVec; worldPos -= worldVec; } explosion->setPosition(worldPos); explosion->setAxis(worldVec); // move away from the building... ;-> explosion->setSound(false); manager->addObject(explosion); }