void CBeamLaser::Update(void) { if(targetType!=Target_None){ weaponPos=owner->pos+owner->frontdir*relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*relWeaponPos.x; if(!onlyForward){ wantedDir=targetPos-weaponPos; wantedDir.Normalize(); } predict=salvoSize/2; } CWeapon::Update(); if(lastFireFrame > gs->frameNum - 18 && lastFireFrame != gs->frameNum && weaponDef->sweepFire) { if (gs->Team(owner->team)->metal>=metalFireCost && gs->Team(owner->team)->energy>=energyFireCost) { owner->UseEnergy(energyFireCost / salvoSize); owner->UseMetal(metalFireCost / salvoSize); std::vector<int> args; args.push_back(0); owner->cob->Call(COBFN_QueryPrimary+weaponNum,args); CMatrix44f weaponMat = owner->localmodel->GetPieceMatrix(args[0]); float3 relWeaponPos = weaponMat.GetPos(); weaponPos=owner->pos+owner->frontdir*-relWeaponPos.z+owner->updir*relWeaponPos.y+owner->rightdir*-relWeaponPos.x; float3 dir = owner->frontdir * weaponMat[10] + owner->updir * weaponMat[6] + -owner->rightdir * weaponMat[2]; FireInternal(dir, true); } } }
float3 LocalS3DOModel::GetRawPiecePos(int piecenum) const { CMatrix44f mat; pieces[piecenum].GetPiecePosIter(&mat); // stupid fix for valkyres const S3DO* p3do = pieces[piecenum].original3do; if (p3do && (p3do->vertices.size() == 2)) { const std::vector<S3DOVertex>& pv = p3do->vertices; if (pv[0].pos.y > pv[1].pos.y) { mat.Translate(pv[0].pos.x, pv[0].pos.y, -pv[0].pos.z); } else { mat.Translate(pv[1].pos.x, pv[1].pos.y, -pv[1].pos.z); } } /* logOutput.Print("%f %f %f %f",mat[0],mat[4],mat[8],mat[12]); logOutput.Print("%f %f %f %f",mat[1],mat[5],mat[9],mat[13]); logOutput.Print("%f %f %f %f",mat[2],mat[6],mat[10],mat[14]); logOutput.Print("%f %f %f %f",mat[3],mat[7],mat[11],mat[15]);/**/ float3 pos = mat.GetPos(); pos.z *= -1.0f; pos.x *= -1.0f; return pos; }
void CBeamLaser::UpdatePosAndMuzzlePos() { if (sweepFireState.IsSweepFiring()) { const int weaponPiece = owner->script->QueryWeapon(weaponNum); const CMatrix44f weaponMat = owner->script->GetPieceMatrix(weaponPiece); const float3 relWeaponPos = weaponMat.GetPos(); const float3 newWeaponDir = owner->GetObjectSpaceVec(float3(weaponMat[2], weaponMat[6], weaponMat[10])); relWeaponMuzzlePos = owner->script->GetPiecePos(weaponPiece); weaponPos = owner->GetObjectSpacePos(relWeaponPos * float3(-1.0f, 1.0f, -1.0f)); // ?? weaponMuzzlePos = owner->GetObjectSpacePos(relWeaponMuzzlePos); sweepFireState.SetSweepTempDir(newWeaponDir); } else { weaponPos = owner->GetObjectSpacePos(relWeaponPos); weaponMuzzlePos = owner->GetObjectSpacePos(relWeaponMuzzlePos); if (weaponDef->sweepFire) { // needed for first call to GetFireDir() when new sweep starts after inactivity sweepFireState.SetSweepTempDir((weaponMuzzlePos - weaponPos).SafeNormalize()); } } }
static void DrawUnitDebugPieceTree(const LocalModelPiece* p, const LocalModelPiece* lap, int lapf, CMatrix44f mat) { mat.Translate(p->pos.x, p->pos.y, p->pos.z); mat.RotateY(-p->rot[1]); mat.RotateX(-p->rot[0]); mat.RotateZ(-p->rot[2]); glPushMatrix(); glMultMatrixf(mat.m); if (p->visible && !p->GetCollisionVolume()->IsDisabled()) { if ((p == lap) && (lapf > 0 && ((gs->frameNum - lapf) < 150))) { glColor3f((1.0f - ((gs->frameNum - lapf) / 150.0f)), 0.0f, 0.0f); } DrawCollisionVolume(p->GetCollisionVolume()); if ((p == lap) && (lapf > 0 && ((gs->frameNum - lapf) < 150))) { glColorf3(defaultColVolColor); } } glPopMatrix(); for (unsigned int i = 0; i < p->childs.size(); i++) { DrawUnitDebugPieceTree(p->childs[i], lap, lapf, mat); } }
bool CCollisionHandler::Collision(const CUnit* u, const float3& p) { const CollisionVolume* v = u->collisionVolume; if (((u->midPos + v->GetOffsets()) - p).SqLength() > v->GetBoundingRadiusSq()) { return false; } switch (u->collisionVolume->GetVolumeType()) { case CollisionVolume::COLVOL_TYPE_SPHERE: { return true; } case CollisionVolume::COLVOL_TYPE_FOOTPRINT: { return CCollisionHandler::CollisionFootprint(u, p); } default: { // NOTE: we have to translate by relMidPos to get to midPos // (which is where the collision volume gets drawn) because // GetTransformMatrix() only uses pos CMatrix44f m = u->GetTransformMatrix(true); m.Translate(u->relMidPos * float3(-1.0f, 1.0f, 1.0f)); m.Translate(v->GetOffsets()); return CCollisionHandler::Collision(v, m, p); } } }
// test if ray from <p0> to <p1> (in world-coors) intersects // the volume whose transformation matrix is given by <m> bool CCollisionHandler::Intersect(const CollisionVolume* v, const CMatrix44f& m, const float3& p0, const float3& p1, CollisionQuery* q) { CMatrix44f mInv = m.Invert(); const float3 pi0 = mInv.Mul(p0); const float3 pi1 = mInv.Mul(p1); bool intersect = false; // minimum and maximum (x, y, z) coordinates of transformed ray const float rminx = MIN(pi0.x, pi1.x), rminy = MIN(pi0.y, pi1.y), rminz = MIN(pi0.z, pi1.z); const float rmaxx = MAX(pi0.x, pi1.x), rmaxy = MAX(pi0.y, pi1.y), rmaxz = MAX(pi0.z, pi1.z); // minimum and maximum (x, y, z) coordinates of (bounding box around) volume const float vminx = -v->axisHScales.x, vminy = -v->axisHScales.y, vminz = -v->axisHScales.z; const float vmaxx = v->axisHScales.x, vmaxy = v->axisHScales.y, vmaxz = v->axisHScales.z; // check if ray segment misses (bounding box around) volume // (if so, then no further intersection tests are necessary) if (rmaxx < vminx || rminx > vmaxx) { return false; } if (rmaxy < vminy || rminy > vmaxy) { return false; } if (rmaxz < vminz || rminz > vmaxz) { return false; } switch (v->volumeType) { case COLVOL_TYPE_ELLIPSOID: { intersect = CCollisionHandler::IntersectEllipsoid(v, pi0, pi1, q); } break; case COLVOL_TYPE_CYLINDER: { intersect = CCollisionHandler::IntersectCylinder(v, pi0, pi1, q); } break; case COLVOL_TYPE_BOX: { intersect = CCollisionHandler::IntersectBox(v, pi0, pi1, q); } break; } return intersect; }
bool CCollisionHandler::IntersectPieceTree(const CUnit* u, const float3& p0, const float3& p1, CollisionQuery* q) { std::list<CollisionQuery> hits; std::list<CollisionQuery>::const_iterator hitsIt; // this probably needs an early-out test CMatrix44f mat = u->GetTransformMatrix(true); mat.Translate(u->relMidPos * float3(-1.0f, 0.0f, 1.0f)); IntersectPieceTreeHelper(u->localmodel->GetRoot(), mat, p0, p1, &hits); float dstNearSq = 1e30f; // save the closest intersection for (hitsIt = hits.begin(); hitsIt != hits.end(); ++hitsIt) { const CollisionQuery& qTmp = *hitsIt; const float dstSq = (qTmp.p0 - p0).SqLength(); if (q != NULL && dstSq < dstNearSq) { dstNearSq = dstSq; q->b0 = qTmp.b0; q->t0 = qTmp.t0; q->p0 = qTmp.p0; q->b1 = qTmp.b1; q->t1 = qTmp.t1; q->p1 = qTmp.p1; q->lmp = qTmp.lmp; } } return (!hits.empty()); }
float3 LocalS3DOModel::GetPiecePos(int piecenum) { if(piecenum>=numpieces || piecenum<0) return ZeroVector; int p=scritoa[piecenum]; if(p==-1) return ZeroVector; CMatrix44f mat; pieces[p].GetPiecePosIter(&mat); if(pieces[p].original3do && pieces[p].original3do->vertices.size()==2){ //stupid fix for valkyres if(pieces[p].original3do->vertices[0].pos.y > pieces[p].original3do->vertices[1].pos.y) mat.Translate(pieces[p].original3do->vertices[0].pos.x, pieces[p].original3do->vertices[0].pos.y, -pieces[p].original3do->vertices[0].pos.z); else mat.Translate(pieces[p].original3do->vertices[1].pos.x, pieces[p].original3do->vertices[1].pos.y, -pieces[p].original3do->vertices[1].pos.z); } /* logOutput.Print("%f %f %f %f",mat[0],mat[4],mat[8],mat[12]); logOutput.Print("%f %f %f %f",mat[1],mat[5],mat[9],mat[13]); logOutput.Print("%f %f %f %f",mat[2],mat[6],mat[10],mat[14]); logOutput.Print("%f %f %f %f",mat[3],mat[7],mat[11],mat[15]);/**/ float3 pos=mat.GetPos(); pos.z*=-1; pos.x*=-1; return pos; //return UpVector; }
static void DrawUnitDebugPieceTree(const LocalModelPiece* p, const LocalModelPiece* lap, int lapf, CMatrix44f mat) { const float3& rot = p->GetRotation(); mat.Translate(p->GetPosition()); mat.RotateY(-rot[1]); mat.RotateX(-rot[0]); mat.RotateZ(-rot[2]); glPushMatrix(); glMultMatrixf(mat.m); if (p->scriptSetVisible && !p->GetCollisionVolume()->IgnoreHits()) { if ((p == lap) && (lapf > 0 && ((gs->frameNum - lapf) < 150))) { glColor3f((1.0f - ((gs->frameNum - lapf) / 150.0f)), 0.0f, 0.0f); } DrawCollisionVolume(p->GetCollisionVolume()); if ((p == lap) && (lapf > 0 && ((gs->frameNum - lapf) < 150))) { glColorf3(DEFAULT_VOLUME_COLOR); } } glPopMatrix(); for (unsigned int i = 0; i < p->children.size(); i++) { DrawUnitDebugPieceTree(p->children[i], lap, lapf, mat); } }
//! generalized inverse for non-orthonormal 4x4 matrices //! A^-1 = (1 / det(A)) (C^T)_{ij} = (1 / det(A)) C_{ji} CMatrix44f CMatrix44f::Invert(bool* status) const { CMatrix44f mat; CMatrix44f& cofac = mat; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { cofac.md[i][j] = CalculateCofactor(md, i, j); } } const float det = (md[0][0] * cofac.md[0][0]) + (md[0][1] * cofac.md[0][1]) + (md[0][2] * cofac.md[0][2]) + (md[0][3] * cofac.md[0][3]); if (det == 0.0f) { //! singular matrix, set to identity? mat.LoadIdentity(); if (status) *status = false; return mat; } mat *= 1.f / det; mat.Transpose(); if (status) *status = true; return mat; }
bool CCollisionHandler::MouseHit(const CUnit* u, const float3& p0, const float3& p1, const CollisionVolume* v, CollisionQuery* q) { // note: use the piece tree? CMatrix44f m = u->GetTransformMatrix(false, true); m.Translate(u->relMidPos + v->GetOffsets()); return CCollisionHandler::Intersect(v, m, p0, p1, q); }
inline bool CCollisionHandler::Intersect(const CollisionVolume* v, const CSolidObject* o, const float3 p0, const float3 p1, CollisionQuery* cq) { CMatrix44f m = o->GetTransformMatrix(true); m.Translate(o->relMidPos * WORLD_TO_OBJECT_SPACE); m.Translate(v->GetOffsets()); return (CCollisionHandler::Intersect(v, m, p0, p1, cq)); }
bool CCollisionHandler::Collision(const CollisionVolume* v, const CMatrix44f& m, const float3& p) { numDiscTests += 1; // get the inverse volume transformation matrix and // apply it to the projectile's position, then test // if the transformed position lies within the axis- // aligned collision volume CMatrix44f mInv = m.Invert(); float3 pi = mInv.Mul(p); bool hit = false; switch (v->GetVolumeType()) { case CollisionVolume::COLVOL_TYPE_SPHERE: { // normally, this code is never executed, because the higher level // Collision(CFeature*) and Collision(CUnit*) already optimize via // early-out tests hit = (pi.dot(pi) <= v->GetHSqScales().x); // test for arbitrary ellipsoids (no longer supported) // const float f1 = (pi.x * pi.x) / v->GetHSqScales().x; // const float f2 = (pi.y * pi.y) / v->GetHSqScales().y; // const float f3 = (pi.z * pi.z) / v->GetHSqScales().z; // hit = ((f1 + f2 + f3) <= 1.0f); } break; case CollisionVolume::COLVOL_TYPE_CYLINDER: { switch (v->GetPrimaryAxis()) { case CollisionVolume::COLVOL_AXIS_X: { const bool xPass = (math::fabs(pi.x) < v->GetHScales().x); const float yRat = (pi.y * pi.y) / v->GetHSqScales().y; const float zRat = (pi.z * pi.z) / v->GetHSqScales().z; hit = (xPass && (yRat + zRat <= 1.0f)); } break; case CollisionVolume::COLVOL_AXIS_Y: { const bool yPass = (math::fabs(pi.y) < v->GetHScales().y); const float xRat = (pi.x * pi.x) / v->GetHSqScales().x; const float zRat = (pi.z * pi.z) / v->GetHSqScales().z; hit = (yPass && (xRat + zRat <= 1.0f)); } break; case CollisionVolume::COLVOL_AXIS_Z: { const bool zPass = (math::fabs(pi.z) < v->GetHScales().z); const float xRat = (pi.x * pi.x) / v->GetHSqScales().x; const float yRat = (pi.y * pi.y) / v->GetHSqScales().y; hit = (zPass && (xRat + yRat <= 1.0f)); } break; } } break; case CollisionVolume::COLVOL_TYPE_BOX: { const bool b1 = (math::fabs(pi.x) < v->GetHScales().x); const bool b2 = (math::fabs(pi.y) < v->GetHScales().y); const bool b3 = (math::fabs(pi.z) < v->GetHScales().z); hit = (b1 && b2 && b3); } break; } return hit; }
float CollisionVolume::GetPointSurfaceDistance(const CFeature* f, const LocalModelPiece* /*lmp*/, const float3& p) const { CMatrix44f mat = f->GetTransformMatrixRef(); mat.Translate(f->relMidPos * WORLD_TO_OBJECT_SPACE); mat.Translate(GetOffsets()); mat.InvertAffineInPlace(); return (GetPointSurfaceDistance(mat, p)); }
void CBeamLaser::Update(void) { if (targetType != Target_None) { weaponPos = owner->pos + owner->frontdir * relWeaponPos.z + owner->updir * relWeaponPos.y + owner->rightdir * relWeaponPos.x; weaponMuzzlePos = owner->pos + owner->frontdir * relWeaponMuzzlePos.z + owner->updir * relWeaponMuzzlePos.y + owner->rightdir * relWeaponMuzzlePos.x; if (!onlyForward) { wantedDir = targetPos - weaponPos; wantedDir.ANormalize(); } if (!weaponDef->beamburst) { predict = salvoSize / 2; } else { // beamburst tracks the target during the burst so there's no need to lead predict = 0; } } CWeapon::Update(); if (lastFireFrame > gs->frameNum - 18 && lastFireFrame != gs->frameNum && weaponDef->sweepFire) { if (teamHandler->Team(owner->team)->metal >= metalFireCost && teamHandler->Team(owner->team)->energy >= energyFireCost) { owner->UseEnergy(energyFireCost / salvoSize); owner->UseMetal(metalFireCost / salvoSize); std::vector<int> args; args.push_back(0); owner->cob->Call(COBFN_QueryPrimary + weaponNum, args); CMatrix44f weaponMat = owner->cob->GetPieceMatrix(args[0]); const float3 relWeaponPos = weaponMat.GetPos(); const float3 dir = owner->frontdir * weaponMat[10] + owner->updir * weaponMat[ 6] + owner->rightdir * -weaponMat[ 2]; weaponPos = owner->pos + owner->frontdir * -relWeaponPos.z + owner->updir * relWeaponPos.y + owner->rightdir * -relWeaponPos.x; FireInternal(dir, true); } } }
void CCamera::Pitch(float rad) { CMatrix44f rotate; rotate.Rotate(rad, right); forward = rotate.Mul(forward); forward.Normalize(); rot.y = atan2(forward.x,forward.z); rot.x = asin(forward.y); UpdateForward(); }
bool CCollisionHandler::Intersect(const CUnit* u, const float3& p0, const float3& p1, CollisionQuery* q) { const CollisionVolume* v = u->collisionVolume; CMatrix44f m = u->GetTransformMatrix(true); m.Translate(u->relMidPos * float3(-1.0f, 1.0f, 1.0f)); m.Translate(v->GetOffsets()); return CCollisionHandler::Intersect(v, m, p0, p1, q); }
bool CCollisionHandler::Collision(const CollisionVolume* v, const CMatrix44f& m, const float3& p) { // get the inverse volume transformation matrix and // apply it to the projectile's position, then test // if the transformed position lies within the axis- // aligned collision volume CMatrix44f mInv = m.Invert(); float3 pi = mInv.Mul(p); bool hit = false; switch (v->GetVolumeType()) { case CollisionVolume::COLVOL_TYPE_SPHERE: { // normally, this code is never executed, because the higher level // Collision(CFeature*) and Collision(CUnit*) already optimize // for volumeType == CollisionVolume::COLVOL_TYPE_SPHERE. hit = (pi.dot(pi) <= v->GetHScalesSq().x); } break; case CollisionVolume::COLVOL_TYPE_ELLIPSOID: { const float f1 = (pi.x * pi.x) / v->GetHScalesSq().x; const float f2 = (pi.y * pi.y) / v->GetHScalesSq().y; const float f3 = (pi.z * pi.z) / v->GetHScalesSq().z; hit = ((f1 + f2 + f3) <= 1.0f); } break; case CollisionVolume::COLVOL_TYPE_CYLINDER: { switch (v->GetPrimaryAxis()) { case CollisionVolume::COLVOL_AXIS_X: { const bool xPass = (pi.x > -v->GetHScales().x && pi.x < v->GetHScales().x); const float yRat = (pi.y * pi.y) / v->GetHScalesSq().y; const float zRat = (pi.z * pi.z) / v->GetHScalesSq().z; hit = (xPass && (yRat + zRat <= 1.0f)); } break; case CollisionVolume::COLVOL_AXIS_Y: { const bool yPass = (pi.y > -v->GetHScales().y && pi.y < v->GetHScales().y); const float xRat = (pi.x * pi.x) / v->GetHScalesSq().x; const float zRat = (pi.z * pi.z) / v->GetHScalesSq().z; hit = (yPass && (xRat + zRat <= 1.0f)); } break; case CollisionVolume::COLVOL_AXIS_Z: { const bool zPass = (pi.z > -v->GetHScales().z && pi.z < v->GetHScales().z); const float xRat = (pi.x * pi.x) / v->GetHScalesSq().x; const float yRat = (pi.y * pi.y) / v->GetHScalesSq().y; hit = (zPass && (xRat + yRat <= 1.0f)); } break; } } break; case CollisionVolume::COLVOL_TYPE_BOX: { const bool b1 = (pi.x > -v->GetHScales().x && pi.x < v->GetHScales().x); const bool b2 = (pi.y > -v->GetHScales().y && pi.y < v->GetHScales().y); const bool b3 = (pi.z > -v->GetHScales().z && pi.z < v->GetHScales().z); hit = (b1 && b2 && b3); } break; } return hit; }
bool CCollisionHandler::Intersect(const CUnit* u, const float3& p0, const float3& p1, CollisionQuery* q) { const CollisionVolume* v = u->collisionVolume; CMatrix44f m; u->GetTransformMatrix(m, true); m.Translate(u->relMidPos.x, u->relMidPos.y, u->relMidPos.z); m.Translate(v->axisOffsets.x, v->axisOffsets.y, v->axisOffsets.z); return CCollisionHandler::Intersect(v, m, p0, p1, q); }
// test if point <p> (in world-coors) lies inside the // volume whose transformation matrix is given by <m> bool CCollisionHandler::Collision(const CollisionVolume* v, const CMatrix44f& m, const float3& p) { // get the inverse volume transformation matrix and // apply it to the projectile's position, then test // if the transformed position lies within the axis- // aligned collision volume CMatrix44f mInv = m.Invert(); float3 pi = mInv.Mul(p); bool hit = false; switch (v->volumeType) { case COLVOL_TYPE_ELLIPSOID: { if (v->spherical) { hit = (pi.dot(pi) <= v->axisHScalesSq.x); } else { const float f1 = (pi.x * pi.x) / v->axisHScalesSq.x; const float f2 = (pi.y * pi.y) / v->axisHScalesSq.y; const float f3 = (pi.z * pi.z) / v->axisHScalesSq.z; hit = ((f1 + f2 + f3) <= 1.0f); } } break; case COLVOL_TYPE_CYLINDER: { switch (v->primaryAxis) { case COLVOL_AXIS_X: { const bool xPass = (pi.x > -v->axisHScales.x && pi.x < v->axisHScales.x); const float yRat = (pi.y * pi.y) / v->axisHScalesSq.y; const float zRat = (pi.z * pi.z) / v->axisHScalesSq.z; hit = (xPass && (yRat + zRat <= 1.0f)); } break; case COLVOL_AXIS_Y: { const bool yPass = (pi.y > -v->axisHScales.y && pi.y < v->axisHScales.y); const float xRat = (pi.x * pi.x) / v->axisHScalesSq.x; const float zRat = (pi.z * pi.z) / v->axisHScalesSq.z; hit = (yPass && (xRat + zRat <= 1.0f)); } break; case COLVOL_AXIS_Z: { const bool zPass = (pi.z > -v->axisHScales.z && pi.z < v->axisHScales.z); const float xRat = (pi.x * pi.x) / v->axisHScalesSq.x; const float yRat = (pi.y * pi.y) / v->axisHScalesSq.y; hit = (zPass && (xRat + yRat <= 1.0f)); } break; } } break; case COLVOL_TYPE_BOX: { const bool b1 = (pi.x > -v->axisHScales.x && pi.x < v->axisHScales.x); const bool b2 = (pi.y > -v->axisHScales.y && pi.y < v->axisHScales.y); const bool b3 = (pi.z > -v->axisHScales.z && pi.z < v->axisHScales.z); hit = (b1 && b2 && b3); } break; } return hit; }
float3 LocalModelPiece::GetAbsolutePos() const { CMatrix44f mat; GetPiecePosIter(&mat); mat.Translate(original->GetPosOffset()); //! we use a 'right' vector, and the positive x axis points to the left float3 pos = mat.GetPos(); pos.x = -pos.x; return pos; }
void CShadowHandler::SetShadowMatrix(CCamera* playerCam, CCamera* shadowCam) { const CMatrix44f lightMatrix = std::move(ComposeLightMatrix(sky->GetLight())); const CMatrix44f scaleMatrix = std::move(ComposeScaleMatrix(GetShadowProjectionScales(playerCam, -lightMatrix.GetZ()))); // convert xy-diameter to radius shadowCam->SetFrustumScales(shadowProjScales * float4(0.5f, 0.5f, 1.0f, 1.0f)); #if 0 // reshape frustum (to maximize SM resolution); for culling we want // the scales-matrix applied to projMatrix instead of to viewMatrix // ((V*S) * P = V * (S*P); note that S * P is a pre-multiplication // so we express it as P * S in code) projMatrix[SHADOWMAT_TYPE_CULLING] = projMatrix[SHADOWMAT_TYPE_DRAWING]; projMatrix[SHADOWMAT_TYPE_CULLING] *= scaleMatrix; // frustum-culling needs this form viewMatrix[SHADOWMAT_TYPE_CULLING].LoadIdentity(); viewMatrix[SHADOWMAT_TYPE_CULLING].SetX(std::move(lightMatrix.GetX())); viewMatrix[SHADOWMAT_TYPE_CULLING].SetY(std::move(lightMatrix.GetY())); viewMatrix[SHADOWMAT_TYPE_CULLING].SetZ(std::move(lightMatrix.GetZ())); viewMatrix[SHADOWMAT_TYPE_CULLING].Transpose(); // invert rotation (R^T == R^{-1}) viewMatrix[SHADOWMAT_TYPE_CULLING].Translate(-projMidPos[2]); // same as SetPos(mat * -pos) #else // KISS; define only the world-to-light transform (P[CULLING] is unused anyway) // // we have two options: either place the camera such that it *looks at* projMidPos // (along lightMatrix.GetZ()) or such that it is *at or behind* projMidPos looking // in the inverse direction (the latter is chosen here) viewMatrix[SHADOWMAT_TYPE_CULLING].LoadIdentity(); viewMatrix[SHADOWMAT_TYPE_CULLING].SetX(-std::move(lightMatrix.GetX())); viewMatrix[SHADOWMAT_TYPE_CULLING].SetY( std::move(lightMatrix.GetY())); viewMatrix[SHADOWMAT_TYPE_CULLING].SetZ(-std::move(lightMatrix.GetZ())); viewMatrix[SHADOWMAT_TYPE_CULLING].SetPos(projMidPos[2]); #endif // shaders need this form, projection into SM-space is done by shadow2DProj() // note: ShadowGenVertProg is a special case because it does not use uniforms viewMatrix[SHADOWMAT_TYPE_DRAWING].LoadIdentity(); viewMatrix[SHADOWMAT_TYPE_DRAWING].SetX(std::move(lightMatrix.GetX())); viewMatrix[SHADOWMAT_TYPE_DRAWING].SetY(std::move(lightMatrix.GetY())); viewMatrix[SHADOWMAT_TYPE_DRAWING].SetZ(std::move(lightMatrix.GetZ())); viewMatrix[SHADOWMAT_TYPE_DRAWING].Scale(float3(scaleMatrix[0], scaleMatrix[5], scaleMatrix[10])); // extract (X.x, Y.y, Z.z) viewMatrix[SHADOWMAT_TYPE_DRAWING].Transpose(); viewMatrix[SHADOWMAT_TYPE_DRAWING].SetPos(viewMatrix[SHADOWMAT_TYPE_DRAWING] * -projMidPos[2]); viewMatrix[SHADOWMAT_TYPE_DRAWING].SetPos(viewMatrix[SHADOWMAT_TYPE_DRAWING].GetPos() + (FwdVector * 0.5f)); // add z-bias #if 0 // holds true in the non-KISS case, but needs an epsilon-tolerance equality test assert((viewMatrix[0] * projMatrix[0]) == (viewMatrix[1] * projMatrix[1])); #endif }
bool CCollisionHandler::Intersect(const CollisionVolume* v, const CMatrix44f& m, const float3& p0, const float3& p1, CollisionQuery* q) { if (q) { // reset the query q->b0 = false; q->t0 = 0.0f; q->p0 = ZVEC; q->b1 = false; q->t1 = 0.0f; q->p1 = ZVEC; } CMatrix44f mInv = m.Invert(); const float3 pi0 = mInv.Mul(p0); const float3 pi1 = mInv.Mul(p1); bool intersect = false; // minimum and maximum (x, y, z) coordinates of transformed ray const float rminx = std::min(pi0.x, pi1.x), rminy = std::min(pi0.y, pi1.y), rminz = std::min(pi0.z, pi1.z); const float rmaxx = std::max(pi0.x, pi1.x), rmaxy = std::max(pi0.y, pi1.y), rmaxz = std::max(pi0.z, pi1.z); // minimum and maximum (x, y, z) coordinates of (bounding box around) volume const float vminx = -v->GetHScales().x, vminy = -v->GetHScales().y, vminz = -v->GetHScales().z; const float vmaxx = v->GetHScales().x, vmaxy = v->GetHScales().y, vmaxz = v->GetHScales().z; // check if ray segment misses (bounding box around) volume // (if so, then no further intersection tests are necessary) if (rmaxx < vminx || rminx > vmaxx) { return false; } if (rmaxy < vminy || rminy > vmaxy) { return false; } if (rmaxz < vminz || rminz > vmaxz) { return false; } switch (v->GetVolumeType()) { case CollisionVolume::COLVOL_TYPE_FOOTPRINT: // fall through, intersection with footprint collision volume // is not supported yet, so only test against sphere/ellipsoid case CollisionVolume::COLVOL_TYPE_SPHERE: // fall through, sphere is special case of ellipsoid case CollisionVolume::COLVOL_TYPE_ELLIPSOID: { intersect = CCollisionHandler::IntersectEllipsoid(v, pi0, pi1, q); } break; case CollisionVolume::COLVOL_TYPE_CYLINDER: { intersect = CCollisionHandler::IntersectCylinder(v, pi0, pi1, q); } break; case CollisionVolume::COLVOL_TYPE_BOX: { intersect = CCollisionHandler::IntersectBox(v, pi0, pi1, q); } break; } if (q) { // transform the intersection points if (q->b0) { q->p0 = m.Mul(q->p0); } if (q->b1) { q->p1 = m.Mul(q->p1); } } return intersect; }
static inline std::array<float2, 4> GetEdgePoinsOfDecal(const CDecalsDrawerGL4::Decal& d) { CMatrix44f m; m.RotateY(d.rot); auto f3tof2 = [](float3 f3) { return float2(f3.x, f3.z); }; return { f3tof2(d.pos + m * float3(-d.size.x, 0.f, -d.size.y)), f3tof2(d.pos + m * float3(-d.size.x, 0.f, d.size.y)), f3tof2(d.pos + m * float3( d.size.x, 0.f, d.size.y)), f3tof2(d.pos + m * float3( d.size.x, 0.f, -d.size.y)) }; }
void CPieceProjectile::Update() { if (flags & PP_Fall) speed.y += gs->gravity; /* speed.x *= 0.994f; speed.z *= 0.994f; if(speed.y > 0) speed.y *= 0.998f;*/ speed*=0.997f; pos += speed; spinPos+=spinSpeed; *numCallback=0; if ((flags & PP_Fire && HasVertices() )/* && (gs->frameNum & 1)*/) { ENTER_MIXED; OldInfo* tempOldInfo=oldInfos[7]; for(int a=6;a>=0;--a){ oldInfos[a+1]=oldInfos[a]; } CMatrix44f m; m.Translate(pos.x,pos.y,pos.z); m.Rotate(spinPos*PI/180,spinVec); float3 pos=RandomVertexPos(); m.Translate(pos.x,pos.y,pos.z); oldInfos[0]=tempOldInfo; oldInfos[0]->pos=m.GetPos(); oldInfos[0]->size=gu->usRandFloat()*1+1; ENTER_SYNCED; } age++; if(!(age & 7) && (flags & PP_Smoke)){ float3 dir=speed; dir.Normalize(); if(curCallback) curCallback->drawCallbacker=0; curCallback=SAFE_NEW CSmokeTrailProjectile(pos,oldSmoke,dir,oldSmokeDir,owner,age==8,false,14,Smoke_Time,0.5f,drawTrail,this); useAirLos=curCallback->useAirLos; oldSmoke=pos; oldSmokeDir=dir; if(!drawTrail){ float3 camDir=(pos-camera->pos).Normalize(); if(camera->pos.distance(pos)+(1-fabs(camDir.dot(dir)))*3000 > 300) drawTrail=true; } } if(age>10) checkCol=true; }
bool CCollisionHandler::Intersect(const CollisionVolume* v, const CMatrix44f& m, const float3& p0, const float3& p1, CollisionQuery* q) { numContTests += 1; CMatrix44f mInv = m.Invert(); const float3 pi0 = mInv.Mul(p0); const float3 pi1 = mInv.Mul(p1); bool intersect = false; // minimum and maximum (x, y, z) coordinates of transformed ray const float rminx = std::min(pi0.x, pi1.x), rminy = std::min(pi0.y, pi1.y), rminz = std::min(pi0.z, pi1.z); const float rmaxx = std::max(pi0.x, pi1.x), rmaxy = std::max(pi0.y, pi1.y), rmaxz = std::max(pi0.z, pi1.z); // minimum and maximum (x, y, z) coordinates of (bounding box around) volume const float vminx = -v->GetHScales().x, vminy = -v->GetHScales().y, vminz = -v->GetHScales().z; const float vmaxx = v->GetHScales().x, vmaxy = v->GetHScales().y, vmaxz = v->GetHScales().z; // check if ray segment misses (bounding box around) volume // (if so, then no further intersection tests are necessary) if (rmaxx < vminx || rminx > vmaxx) { return false; } if (rmaxy < vminy || rminy > vmaxy) { return false; } if (rmaxz < vminz || rminz > vmaxz) { return false; } switch (v->GetVolumeType()) { case CollisionVolume::COLVOL_TYPE_SPHERE: { // sphere is special case of ellipsoid, reuse code intersect = CCollisionHandler::IntersectEllipsoid(v, pi0, pi1, q); } break; case CollisionVolume::COLVOL_TYPE_CYLINDER: { intersect = CCollisionHandler::IntersectCylinder(v, pi0, pi1, q); } break; case CollisionVolume::COLVOL_TYPE_BOX: { // also covers footprints, but without taking the blocking-map into account // TODO: this would require stepping ray across non-blocking yardmap squares? // // intersect = CCollisionHandler::IntersectFootPrint(v, pi0, pi1, q); intersect = CCollisionHandler::IntersectBox(v, pi0, pi1, q); } break; } if (q != NULL) { // transform intersection points (iff not a special // case, otherwise calling code should not use them) if (q->b0 == CQ_POINT_ON_RAY) { q->p0 = m.Mul(q->p0); } if (q->b1 == CQ_POINT_ON_RAY) { q->p1 = m.Mul(q->p1); } } return intersect; }
bool CCollisionHandler::IntersectPiecesHelper( const CUnit* u, const float3& p0, const float3& p1, CollisionQuery* cq ) { CMatrix44f unitMat = u->GetTransformMatrix(true); CMatrix44f volMat; CollisionQuery cqt; if (cq == NULL) cq = &cqt; float minDistSq = std::numeric_limits<float>::max(); float curDistSq = std::numeric_limits<float>::max(); for (unsigned int n = 0; n < u->localModel->pieces.size(); n++) { const LocalModelPiece* lmp = u->localModel->GetPiece(n); const CollisionVolume* lmpVol = lmp->GetCollisionVolume(); if (!lmp->scriptSetVisible || lmpVol->IgnoreHits()) continue; volMat = unitMat * lmp->GetModelSpaceMatrix(); volMat.Translate(lmpVol->GetOffsets()); if (!CCollisionHandler::Intersect(lmpVol, volMat, p0, p1, cq)) continue; // skip if neither an ingress nor an egress hit if (cq->GetHitPos() == ZeroVector) continue; cq->SetHitPiece(const_cast<LocalModelPiece*>(lmp)); // save the closest intersection (others are not needed) if ((curDistSq = (cq->GetHitPos() - p0).SqLength()) >= minDistSq) continue; minDistSq = curDistSq; } // true iff at least one piece was intersected // (query must have been reset by calling code) return (cq->GetHitPiece() != NULL); }
// Iterate over the model and calculate its overall dimensions void CAssParser::CalculateModelDimensions(S3DModel* model, S3DModelPiece* piece) { CMatrix44f scaleRotMat; piece->ComposeTransform(scaleRotMat, ZeroVector, ZeroVector, piece->scales); // cannot set this until parent relations are known, so either here or in BuildPieceHierarchy() piece->goffset = scaleRotMat.Mul(piece->offset) + ((piece->parent != NULL)? piece->parent->goffset: ZeroVector); // update model min/max extents model->mins = float3::min(piece->goffset + piece->mins, model->mins); model->maxs = float3::max(piece->goffset + piece->maxs, model->maxs); piece->SetCollisionVolume(new CollisionVolume("box", piece->maxs - piece->mins, (piece->maxs + piece->mins) * 0.5f)); // Repeat with children for (unsigned int i = 0; i < piece->children.size(); i++) { CalculateModelDimensions(model, piece->children[i]); } }
bool CCollisionHandler::MouseHit(const CUnit* u, const float3& p0, const float3& p1, const CollisionVolume* v, CollisionQuery* cq) { if (!u->IsInVoid()) { if (v->DefaultToPieceTree()) { return (CCollisionHandler::IntersectPieceTree(u, p0, p1, cq)); } if (!v->IgnoreHits()) { // note: should mouse-rays care about // IgnoreHits if unit is not in void? CMatrix44f m = u->GetTransformMatrix(false, true); m.Translate(u->relMidPos * WORLD_TO_OBJECT_SPACE); m.Translate(v->GetOffsets()); return (CCollisionHandler::Intersect(v, m, p0, p1, cq)); } } return false; }
static void DRAW_DECAL(CVertexArray* va, const CDecalsDrawerGL4::Decal* d) { CMatrix44f m; m.Translate(d->pos.x, d->pos.z, 0.0f); m.RotateZ(d->rot * fastmath::DEG_TO_RAD); float2 dsize = d->size; // make sure it is at least 1x1 pixels! dsize.x = std::max(dsize.x, std::ceil( float(mapDims.mapx * SQUARE_SIZE) / CDecalsDrawerGL4::OVERLAP_TEST_TEXTURE_SIZE )); dsize.y = std::max(dsize.y, std::ceil( float(mapDims.mapy * SQUARE_SIZE) / CDecalsDrawerGL4::OVERLAP_TEST_TEXTURE_SIZE )); const float3 ds1 = float3(dsize.x, dsize.y, 0.0f); const float3 ds2 = float3(dsize.x, -dsize.y, 0.0f); auto f3tof2 = [](float3 f3) { return *(float2*)&f3; }; const float4 tc = d->texOffsets; va->EnlargeArrays(4, 0, VA_SIZE_2DT); va->AddVertexQ2dT(f3tof2(m * (-ds1)), float2(tc[0], tc[1])); va->AddVertexQ2dT(f3tof2(m * ( ds2)), float2(tc[2], tc[1])); va->AddVertexQ2dT(f3tof2(m * ( ds1)), float2(tc[2], tc[3])); va->AddVertexQ2dT(f3tof2(m * (-ds2)), float2(tc[0], tc[3])); }