00001 #include <gra/camera/Camera.h>
00002 #include <gra/camera/OrthoProj.h>
00003 #include <assert.h>
00004
00005 using namespace gra;
00006
00007 Camera::Camera(AutoPtr<Projection> * pAP)
00008 : _pTrMat(NULL), _pAProjection(pAP)
00009 {
00010 assert(_pAProjection);
00011 _pAProjection->registerReferer(this);
00012 _pProjection = _pAProjection->origObject();
00013 assert(_pProjection);
00014 }
00015
00016 Camera::Camera()
00017 : _pTrMat(NULL), _pAProjection(NULL)
00018 {
00019 _pAProjection = new AutoPtr<Projection>(new OrthoProj(-1.0, 1.0,
00020 -1.0, 1.0,
00021 -1.0, 1.0));
00022 _pAProjection->registerReferer(this);
00023 _pProjection = _pAProjection->origObject();
00024 assert(_pProjection);
00025 }
00026
00027 Camera::Camera(const Camera& src)
00028 : _pTrMat(NULL)
00029 {
00030 assert(src._pProjection);
00031 _pProjection = src._pProjection->clone();
00032 _pAProjection = new AutoPtr<Projection>(_pProjection);
00033 _pAProjection->registerReferer(this);
00034
00035 if (src._pTrMat) _pTrMat = new Matrix4(*(src._pTrMat));
00036 }
00037
00038 Camera::~Camera()
00039 {
00040 if (_pTrMat) delete _pTrMat;
00041 (void) AutoPtr<Projection>::destroy(_pAProjection, this);
00042 }
00043
00044 void Camera::setTransform(const Matrix4& trMat)
00045 {
00046 if (_pTrMat) _pTrMat->set(trMat);
00047 else _pTrMat = new Matrix4(trMat);
00048 }
00049
00050 void Camera::unsetTransform()
00051 {
00052 if (_pTrMat) { delete _pTrMat; _pTrMat = NULL; }
00053 }
00054
00055 void Camera::rotateX(float a)
00056 {
00057 Matrix4 trMat;
00058 trMat.rotX(a);
00059 if (_pTrMat) _pTrMat->mul(trMat, *_pTrMat);
00060 else _pTrMat = new Matrix4(trMat);
00061 }
00062
00063 void Camera::rotateY(float a)
00064 {
00065 Matrix4 trMat;
00066 trMat.rotY(a);
00067 if (_pTrMat) _pTrMat->mul(trMat, *_pTrMat);
00068 else _pTrMat = new Matrix4(trMat);
00069 }
00070
00071 void Camera::rotateZ(float a)
00072 {
00073 Matrix4 trMat;
00074 trMat.rotZ(a);
00075 if (_pTrMat) _pTrMat->mul(trMat, *_pTrMat);
00076 else _pTrMat = new Matrix4(trMat);
00077 }
00078
00079 void Camera::rotate(float a, const Vector3& axis)
00080 {
00081 Matrix4 trMat;
00082 trMat.rotationGL(a, axis);
00083 if (_pTrMat) _pTrMat->mul(trMat, *_pTrMat);
00084 else _pTrMat = new Matrix4(trMat);
00085 }
00086
00087 void Camera::translate(float x, float y, float z)
00088 {
00089 Matrix4 trMat;
00090 trMat.setScaleTranslate(1, x, y, z);
00091 if (_pTrMat) _pTrMat->mul(trMat, *_pTrMat);
00092 else _pTrMat = new Matrix4(trMat);
00093 }
00094
00095 bool Camera::isTransformed(Matrix4* pTrMat) const
00096 {
00097 if (_pTrMat) {
00098 if (pTrMat) pTrMat->set(*_pTrMat);
00099 return true;
00100 } else
00101 return false;
00102 }
00103
00104 void Camera::setProjection(AutoPtr<Projection> * pProj)
00105 {
00106 assert(pProj);
00107 AutoPtr<Projection>::destroy(_pAProjection, this);
00108 _pAProjection = pProj;
00109 _pAProjection->registerReferer(this);
00110 _pProjection = _pAProjection->origObject();
00111 assert(_pProjection);
00112 }
00113
00114 Vector2 Camera::getPixelSize(unsigned resX, unsigned resY) const
00115 {
00116 return Vector2((_pProjection->getRightPlane() - _pProjection->getLeftPlane()) / resX,
00117 (_pProjection->getTopPlane() - _pProjection->getBottomPlane()) / resY);
00118 }
00119
00120 void Camera::getProjectionPlane(Vector3& ll,
00121 Vector3& ul,
00122 Vector3& ur,
00123 Vector3& lr) const
00124 {
00125 _pProjection->getProjectionArea(ll, ul, ur, lr);
00126 if (_pTrMat) {
00127 _pTrMat->transform(ll);
00128 _pTrMat->transform(ul);
00129 _pTrMat->transform(ur);
00130 _pTrMat->transform(lr);
00131 }
00132 }
00133
00134 Vector2 Camera::mapPixelToProjPlane(unsigned posX,
00135 unsigned posY,
00136 unsigned resX,
00137 unsigned resY,
00138 PixelSample sample) const
00139 {
00140 double xSize =
00141 (_pProjection->getRightPlane() - _pProjection->getLeftPlane()) / resX;
00142 double ySize =
00143 (_pProjection->getTopPlane() - _pProjection->getBottomPlane()) / resY;
00144
00145 Vector2 ret(xSize * posX, ySize * posY);
00146
00147 switch (sample) {
00148 case PS_CENTROID:
00149 ret.x += .5 * xSize;
00150 ret.y += .5 * ySize;
00151 break;
00152 case PS_UPPER_LEFT_CORNER:
00153 ret.y += ySize;
00154 break;
00155 case PS_UPPER_RIGHT_CORNER:
00156 ret.x += xSize;
00157 ret.y += ySize;
00158 break;
00159 case PS_LOWER_RIGHT_CORNER:
00160 ret.x += xSize;
00161 break;
00162 case PS_LOWER_LEFT_CORNER:
00163 break;
00164 case PS_RANDOM:
00165 ret.x += ESG_DBL_RAND * xSize;
00166 ret.x += ESG_DBL_RAND * ySize;
00167 break;
00168 default:
00169 break;
00170 }
00171
00172 return ret;
00173 }
00174
00175 Vector3 Camera::getProjectionDirection(const Vector2& point)
00176 {
00177 Vector3 dir = _pProjection->getProjectionDirection(point);
00178 if (_pTrMat) {
00179 Matrix3 rMat;
00180 _pTrMat->get(rMat);
00181 rMat.transform(dir);
00182 }
00183 return dir;
00184 }
00185
00186 Vector3 Camera::getDirection()
00187 {
00188 Vector3 dir(0.0, 0.0, -1.0);
00189 if (_pTrMat) {
00190 Matrix3 rMat;
00191 _pTrMat->get(rMat);
00192 rMat.transform(dir);
00193 }
00194 return dir;
00195 }
00196
00197 Vector3 Camera::getZenith()
00198 {
00199 Vector3 zenith(0.0, 1.0, 0.0);
00200 if (_pTrMat) {
00201 Matrix3 rMat;
00202 _pTrMat->get(rMat);
00203 rMat.transform(zenith);
00204 }
00205 return zenith;
00206 }
00207
00208 Vector2 Camera::project(const Vector3& point) const
00209 {
00210 if (_pTrMat) {
00211 Matrix3 rMat;
00212 Vector3 tVec, sVec, p;
00213 _pTrMat->get(rMat, tVec, sVec);
00214 ESG_INVERSE_TR_POINT(rMat, tVec, sVec, point, p);
00215 Vector3 v(_pProjection->project(p));
00216 return Vector2(v.x - _pProjection->getLeftPlane(),
00217 v.y - _pProjection->getBottomPlane());
00218 } else {
00219 Vector3 v(_pProjection->project(point));
00220 return Vector2(v.x - _pProjection->getLeftPlane(),
00221 v.y - _pProjection->getBottomPlane());
00222 }
00223 }
00224
00225 bool Camera::projectAndClip(const Vector3& point, Vector2* res) const
00226 {
00227 Vector3 v;
00228
00229 if (_pTrMat) {
00230 Matrix3 rMat;
00231 Vector3 tVec, sVec, p;
00232 _pTrMat->get(rMat, tVec, sVec);
00233 ESG_INVERSE_TR_POINT(rMat, tVec, sVec, point, p);
00234 bool in = _pProjection->projectAndClip(p, &v);
00235 if (in && res)
00236 res->set(v.x - _pProjection->getLeftPlane(),
00237 v.y - _pProjection->getBottomPlane());
00238 return in;
00239 } else {
00240 bool in = _pProjection->projectAndClip(point, &v);
00241 if (in && res)
00242 res->set(v.x - _pProjection->getLeftPlane(),
00243 v.y - _pProjection->getBottomPlane());
00244 return in;
00245 }
00246 }