bool GLView::getViewport(Camera::Viewport& v) const { v.x=(int)x; v.y=(int)y; v.w=(int)w; v.h=(int)h; v.setCameraMatrix(modelview); const Matrix4& p=projection; //now the projmat... bool error=false; if(p(3,3)==One) { //ortho v.perspective=false; //m00=2/(r-l)=2/(w/scale)=scale*2/w; //m11=2/(t-b)=2/(h/scale)=scale*2/h; //m22=-2/(f-n) //m23=-(f+n)/(f-n) //[f*m22-n*m22=-2 ] => [m22 -m22 ] * [f] = [-2] //[f*m23-n*m23=-f-n] [m23+1 -m23+1] * [n] [0 ] v.scale=p(0,0)*(w/2); Matrix2 A; A(0,0)=p(2,2); A(0,1)=-p(2,2); A(1,0)=p(2,3)+1; A(1,1)=-p(2,3)+1; if(!A.inplaceInverse()) error=true; Vector2 nf; A.mul(Vector2(-2,Zero),nf); v.n=nf.x; v.f=nf.y; #ifdef _DEBUG if(v.scale != p(1,1)*h*0.5) error=true; //no projection translation if(p(0,3)!=Zero) error=true; if(p(1,3)!=Zero) error=true; //these ought to be zero if(p(3,2)!=Zero) error=true; if(p(3,1)!=Zero) error=true; if(p(3,0)!=Zero) error=true; if(p(2,1)!=Zero) error=true; if(p(2,0)!=Zero) error=true; if(p(1,0)!=Zero) error=true; if(p(1,2)!=Zero) error=true; if(p(0,2)!=Zero) error=true; if(p(0,1)!=Zero) error=true; #endif } else if(p(3,3)==Zero) { //perspective v.perspective=true; //m00=2n/(r-l)=2n/n/scale=2*scale //m11=2n/(t-b)=2n/n/(aspect*scale)=2*aspect*scale //m22=-(f+n)/(f-n) //m23=-2fn/(f-n) //f*(m22+1)+n*(-m22+1)=0 //f*m23 +n*(-m23)=2fn //f=n*(m22-1)/(m22+1)=n*c //so n*(c*m23-m23)=2*c*n*n //c*m23-m23=2*c*n v.scale=p(0,0)*Half; if(p(2,2)-One != Zero) { //solve for n Real c=(p(2,2)-1)/(p(2,2)+1); v.n=p(2,3)*Half-p(2,3)*Half/c; v.f=v.n*c; } else error=true; #ifdef _DEBUG if(v.scale!=p(1,1)*Half*h/w) error=true; //no translation if(p(0,2)!=Zero) error=true; if(p(1,2)!=Zero) error=true; if(p(0,1)!=Zero) error=true; if(p(0,3)!=Zero) error=true; if(p(1,0)!=Zero) error=true; if(p(1,3)!=Zero) error=true; if(p(2,0)!=Zero) error=true; if(p(2,1)!=Zero) error=true; if(p(3,0)!=Zero) error=true; if(p(3,1)!=Zero) error=true; if(p(3,2)!=-One) error=true; #endif } else error=true; if(error) { fprintf(stderr,"GLView: There was an error in the projection matrix\n"); return false; } return true; }