Warning, /include/Geant4/tools/sg/base_camera is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_sg_base_camera
0005 #define tools_sg_base_camera
0006
0007 #include "node"
0008
0009 #include "sf_vec3f"
0010 #include "sf_vec4f"
0011 #include "sf_rotf"
0012
0013 #include "render_action"
0014 #include "pick_action"
0015 #include "event_action"
0016 #include "visible_action"
0017 #include "enums"
0018
0019 #include "../mathf" //astro
0020
0021 namespace tools {
0022 namespace sg {
0023
0024 class base_camera : public node {
0025 TOOLS_HEADER(base_camera,tools::sg::base_camera,node)
0026 public:
0027 sf<float> znear;
0028 sf<float> zfar;
0029 sf_vec3f position;
0030 //Camera orientation specified as a rotation value from the default
0031 //orientation where the camera is pointing along the negative z-axis,
0032 //with "up" along the positive y-axis.
0033 sf_rotf orientation;
0034
0035 //for viewers :
0036 sf<float> dx;
0037 sf<float> da;
0038 sf<float> ds;
0039 sf<float> focal;
0040 public:
0041 virtual const desc_fields& node_desc_fields() const {
0042 TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::base_camera)
0043 static const desc_fields s_v(parent::node_desc_fields(),8, //WARNING : take care of count.
0044 TOOLS_ARG_FIELD_DESC(znear),
0045 TOOLS_ARG_FIELD_DESC(zfar),
0046 TOOLS_ARG_FIELD_DESC(position),
0047 TOOLS_ARG_FIELD_DESC(orientation),
0048 TOOLS_ARG_FIELD_DESC(dx),
0049 TOOLS_ARG_FIELD_DESC(da),
0050 TOOLS_ARG_FIELD_DESC(ds),
0051 TOOLS_ARG_FIELD_DESC(focal)
0052 );
0053 return s_v;
0054 }
0055 private:
0056 void add_fields(){
0057 add_field(&znear);
0058 add_field(&zfar);
0059 add_field(&position);
0060 add_field(&orientation);
0061
0062 add_field(&dx);
0063 add_field(&da);
0064 add_field(&ds);
0065 add_field(&focal);
0066 }
0067 public:
0068 virtual float near_height() const = 0;
0069 virtual void zoom(float) = 0;
0070 virtual camera_type type() const = 0;
0071 virtual void get_lrbt(unsigned int,unsigned int,
0072 float&,float&,float&,float&) = 0;
0073 public:
0074 virtual void render(render_action& a_action) {
0075 _mult_matrix(a_action);
0076 set_state(a_action);
0077 //{mat4f& _mtx = a_action.projection_matrix();
0078 // a_action.out() << "debug : tools::sg::base_camera::render : proj :" << std::endl;
0079 // a_action.out() << _mtx << std::endl;}
0080 a_action.load_proj_matrix(a_action.projection_matrix());
0081 a_action.load_model_matrix(a_action.model_matrix());
0082 }
0083 virtual void pick(pick_action& a_action) {
0084 _mult_matrix(a_action);
0085 set_state(a_action);
0086 }
0087 virtual void event(event_action& a_action){
0088 _mult_matrix(a_action);
0089 set_state(a_action);
0090 }
0091 virtual void get_matrix(get_matrix_action& a_action){
0092 _mult_matrix(a_action);
0093 set_state(a_action);
0094 }
0095 virtual void is_visible(visible_action& a_action){
0096 _mult_matrix(a_action);
0097 set_state(a_action);
0098 }
0099 protected:
0100 base_camera()
0101 :parent()
0102 ,znear(1)
0103 ,zfar(10)
0104 ,position(vec3f(0,0,1))
0105 ,orientation(rotf(vec3f(0,0,1),0)) //quat = vec4f(0,0,0,1)
0106 ,dx(0.01f)
0107 ,da(0.017f) //one degree.
0108 ,ds(0.99f)
0109 ,focal(1)
0110 {
0111 #ifdef TOOLS_MEM
0112 mem::increment(s_class().c_str());
0113 #endif
0114 add_fields();
0115 }
0116 public:
0117 virtual ~base_camera(){
0118 #ifdef TOOLS_MEM
0119 mem::decrement(s_class().c_str());
0120 #endif
0121 }
0122 protected:
0123 base_camera(const base_camera& a_from)
0124 :parent(a_from)
0125 ,znear(a_from.znear)
0126 ,zfar(a_from.zfar)
0127 ,position(a_from.position)
0128 ,orientation(a_from.orientation)
0129 ,dx(a_from.dx)
0130 ,da(a_from.da)
0131 ,ds(a_from.ds)
0132 ,focal(a_from.focal)
0133 {
0134 #ifdef TOOLS_MEM
0135 mem::increment(s_class().c_str());
0136 #endif
0137 add_fields();
0138 }
0139 base_camera& operator=(const base_camera& a_from){
0140 parent::operator=(a_from);
0141 znear = a_from.znear;
0142 zfar = a_from.zfar;
0143 position = a_from.position;
0144 orientation = a_from.orientation;
0145 dx = a_from.dx;
0146 da = a_from.da;
0147 ds = a_from.ds;
0148 focal = a_from.focal;
0149 m_lrbt.set_value(0,0,0,0);
0150 return *this;
0151 }
0152 protected: //operators:
0153 bool operator==(const base_camera& a_from) const{
0154 if(znear!=a_from.znear) return false;
0155 if(zfar!=a_from.zfar) return false;
0156 if(position!=a_from.position) return false;
0157 if(orientation!=a_from.orientation) return false;
0158 //we do not test dx,da,ds.
0159 return true;
0160 }
0161 //bool operator!=(const base_camera& a_from) const {
0162 // return !operator==(a_from);
0163 //}
0164 public:
0165 void direction(vec3f& a_dir) const {
0166 orientation.value().mul_vec(vec3f(0,0,-1),a_dir);
0167 }
0168
0169 void rotate_around_direction(float a_delta) {
0170 //vec3f dir;
0171 //orientation.value().mul_vec(vec3f(0,0,-1),dir);
0172 //orientation.value(rotf(dir,a_delta) * orientation.value());
0173 orientation.value(rotf(vec3f(0,0,-1),a_delta) * orientation.value());
0174 }
0175
0176 void rotate_around_z(float a_delta) {
0177 //vec3f z;
0178 //orientation.value().mul_vec(vec3f(0,0,1),z);
0179 //orientation.value(rotf(z,a_delta) * orientation.value());
0180 orientation.value(rotf(vec3f(0,0,1),a_delta) * orientation.value());
0181 }
0182
0183 void rotate_around_up(float a_delta){
0184 vec3f up;
0185 orientation.value().mul_vec(vec3f(0,1,0),up);
0186 //orientation.value(rotf(up,a_delta) * orientation.value());
0187 // must be the below so that rot-cam works for exlib/cbk/[astro,cfitsio] astro setup.
0188 // (astro setup change camera orientation).
0189 orientation.value(orientation.value() * rotf(up,a_delta));
0190 }
0191
0192 void rotate_around_x(float a_delta){
0193 orientation.value(rotf(vec3f(1,0,0),a_delta) * orientation.value());
0194 }
0195
0196 void rotate_around_x_at_focal(float a_delta){
0197 //from coin SoGuiExaminerViewerP::rotXWheelMotion.
0198 vec3f dir;
0199 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0200 vec3f focalpoint = position.value() + focal * dir;
0201 orientation.value(rotf(vec3f(1,0,0),a_delta) * orientation.value());
0202 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0203 position = focalpoint - focal * dir;
0204 }
0205
0206 void rotate_around_y_at_focal(float a_delta){
0207 //from coin SoGuiExaminerViewerP::rotYWheelMotion.
0208 vec3f dir;
0209 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0210 vec3f focalpoint = position.value() + focal * dir;
0211 orientation.value(rotf(vec3f(0,1,0),a_delta) * orientation.value());
0212 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0213 position = focalpoint - focal * dir;
0214 }
0215
0216 void rotate_around_z_at_focal(float a_delta){
0217 //from coin SoGuiExaminerViewerP::rotYWheelMotion.
0218 vec3f dir;
0219 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0220 vec3f focalpoint = position.value() + focal * dir;
0221 orientation.value(rotf(vec3f(0,0,1),a_delta) * orientation.value());
0222 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0223 position = focalpoint - focal * dir;
0224 }
0225
0226 void rotate_to_dir(const vec3f& a_dir) {
0227 //rotate around up so that a_dir is in (dir,up) plane
0228
0229 //NOTE : it is the invert of orientation which is used
0230 // in projection matrix.
0231
0232 {vec3f dir;
0233 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0234 vec3f up;
0235 orientation.value().mul_vec(vec3f(0,1,0),up);
0236 vec3f side;dir.cross(up,side);
0237 vec3f v = side * (side.dot(a_dir)) + dir * (dir.dot(a_dir));
0238 if(v.normalize()) orientation.value(orientation.value()*rotf(dir,v));}
0239
0240 //rotate around dir^up so that a_dir matches dir.
0241 {vec3f dir;
0242 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0243 orientation.value(orientation.value()*rotf(dir,a_dir));}
0244
0245 /*
0246 //check that dir is on a_dir :
0247 {vec3f dir;
0248 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0249 float cos_angle; //it should be 1
0250 if(!dir.cos_angle(a_dir,cos_angle)) {
0251 ::printf("debug : can't get angle\n");
0252 return;
0253 }
0254 ::printf("debug : cos_angle %g\n",cos_angle);}
0255 */
0256 }
0257
0258 void pane_to(float a_x,float a_y,float a_z){
0259 //translate in view plane so that (a_x,a_y,a_z) is on direction.
0260
0261 vec3f dir;
0262 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0263 vec3f up;
0264 orientation.value().mul_vec(vec3f(0,1,0),up);
0265 vec3f side;dir.cross(up,side);
0266
0267 vec3f d(a_x,a_y,a_z);
0268 d.subtract(position.value());
0269
0270 vec3f pos = position.value() + side * (side.dot(d)) + up * (up.dot(d));
0271 position.value(pos);
0272 }
0273
0274 void translate_along_side(float a_delta){
0275 vec3f dir;
0276 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0277 vec3f up;
0278 orientation.value().mul_vec(vec3f(0,1,0),up);
0279 vec3f side;dir.cross(up,side);
0280 vec3f pos = position.value() + side * a_delta;
0281 position.value(pos);
0282 }
0283 void translate_along_up(float a_delta){
0284 vec3f dir;
0285 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0286 vec3f up;
0287 orientation.value().mul_vec(vec3f(0,1,0),up);
0288 vec3f pos = position.value() + up * a_delta;
0289 position.value(pos);
0290 }
0291 void translate_along_dir(float a_delta){
0292 vec3f dir;
0293 orientation.value().mul_vec(vec3f(0,0,-1),dir);
0294 vec3f pos = position.value() + dir * a_delta;
0295 position.value(pos);
0296 }
0297
0298 bool look_at(const vec3f& a_dir,const vec3f& a_up) {
0299 vec3f z = -a_dir;
0300 vec3f y = a_up;
0301 vec3f x;y.cross(z,x);
0302
0303 // recompute y to create a valid coordinate system
0304 z.cross(x,y);
0305
0306 // normalize x and y to create an orthonormal coord system
0307 if(!x.normalize()) return false;
0308 if(!y.normalize()) return false;
0309 if(!z.normalize()) return false;
0310
0311 // create a rotation matrix
0312 mat4f rot;
0313 rot.set_identity();
0314 rot.set_value(0,0,x[0]);
0315 rot.set_value(1,0,x[1]);
0316 rot.set_value(2,0,x[2]);
0317
0318 rot.set_value(0,1,y[0]);
0319 rot.set_value(1,1,y[1]);
0320 rot.set_value(2,1,y[2]);
0321
0322 rot.set_value(0,2,z[0]);
0323 rot.set_value(1,2,z[1]);
0324 rot.set_value(2,2,z[2]);
0325
0326 orientation.value().set_value(rot);
0327 return true;
0328 }
0329
0330 //NOTE : print is a Python keyword.
0331 void dump(std::ostream& a_out) {
0332 a_out << " znear " << znear.value() << std::endl;
0333 a_out << " zfar " << zfar.value() << std::endl;
0334 vec3f& pos = position.value();
0335 a_out << " pos " << pos[0] << " " << pos[1] << " " << pos[2] << std::endl;
0336 //FIXME : dump orientation.
0337 }
0338
0339 bool is_type_ortho() const {return type()==camera_ortho?true:false;}
0340
0341 bool height_at_focal(float& a_h) const {
0342 if(is_type_ortho()) {
0343 a_h = near_height();
0344 } else {
0345 if(!znear.value()) {a_h = near_height();return false;}
0346 a_h = focal.value()*near_height()/znear.value();
0347 }
0348 return true;
0349 }
0350
0351 void astro_orientation(float a_ra,float a_dec/*,const vec3f& a_center*/) {
0352 // a_ra, a_dec are in decimal degrees.
0353
0354 // Camera default point toward -z with up along +y and +x at right.
0355
0356 // Arrange so that camera points toward x with up along +z :
0357 rotf r(vec3f::s_y(),-fhalf_pi());
0358 r *= rotf(vec3f::s_x(),fhalf_pi());
0359 // Now -y is at right.
0360
0361 // Then rotate it so that it points toward given (ra,dec) by keeping up upward +z direction.
0362 r *= rotf(vec3f::s_y(),-a_dec*fdeg2rad());
0363 r *= rotf(vec3f::s_z(),a_ra*fdeg2rad());
0364 orientation = r;
0365
0366 /*
0367 position = a_center*0.99f;
0368 znear = 0.1f;
0369 zfar = 200.0f;
0370 focal = (a_center-position).length();
0371 */
0372 /*
0373 position = vec3f(0,0,0);
0374 znear = 1.0f;
0375 zfar = 2000.0f; //2*sky_radius.
0376 focal = a_center.length();
0377 da = 0.017f/100; //1/100 of a degree
0378 */
0379 }
0380
0381 bool update_motion(int a_move) {
0382 float _dx = dx;
0383 float _da = da;
0384 float _ds = ds;
0385
0386 if(a_move==move_rotate_right) { //should match camera_yaw().
0387 rotate_around_up(_da);
0388 return true;
0389 }
0390 if(a_move==move_rotate_left) {
0391 rotate_around_up(-_da);
0392 return true;
0393 }
0394
0395 if(a_move==move_rotate_up) { //should match camera_pitch().
0396 rotate_around_x(_da);
0397 return true;
0398 }
0399 if(a_move==move_rotate_down) {
0400 rotate_around_x(-_da);
0401 return true;
0402 }
0403
0404 if(a_move==move_roll_plus) { //should match camera_roll().
0405 rotate_around_direction(-_da); //direction = -z, then the minus.
0406 return true;
0407 }
0408 if(a_move==move_roll_minus) {
0409 rotate_around_direction(_da);
0410 return true;
0411 }
0412
0413 if(a_move==move_translate_right) {
0414 translate_along_side(_dx);
0415 return true;
0416 }
0417 if(a_move==move_translate_left) {
0418 translate_along_side(-_dx);
0419 return true;
0420 }
0421
0422 if(a_move==move_up) {
0423 translate_along_up(_dx);
0424 return true;
0425 }
0426 if(a_move==move_down) {
0427 translate_along_up(-_dx);
0428 return true;
0429 }
0430 if(a_move==move_forward) {
0431 translate_along_dir(_dx);
0432 return true;
0433 }
0434 if(a_move==move_backward) {
0435 translate_along_dir(-_dx);
0436 return true;
0437 }
0438 if(a_move==move_zoom_in) {
0439 zoom(_ds);
0440 return true;
0441 }
0442 if(a_move==move_zoom_out) {
0443 zoom(1.0f/_ds);
0444 return true;
0445 }
0446
0447 if(a_move==move_rotate_around_focal_right) { //yaw around focal.
0448 rotate_around_y_at_focal(_da);
0449 return true;
0450 }
0451 if(a_move==move_rotate_around_focal_left) {
0452 rotate_around_y_at_focal(-_da);
0453 return true;
0454 }
0455 if(a_move==move_rotate_around_focal_up) { //pitch around focal.
0456 rotate_around_x_at_focal(_da);
0457 return true;
0458 }
0459 if(a_move==move_rotate_around_focal_down) {
0460 rotate_around_x_at_focal(-_da);
0461 return true;
0462 }
0463 if(a_move==move_roll_around_focal_plus) {
0464 rotate_around_z_at_focal(_da);
0465 return true;
0466 }
0467 if(a_move==move_roll_around_focal_minus) {
0468 rotate_around_z_at_focal(-_da);
0469 return true;
0470 }
0471
0472 return false;
0473 }
0474 protected:
0475 void update_sg(std::ostream& a_out) {
0476
0477 {const vec4f& v = m_lrbt.value();
0478 float l = v[0];
0479 float r = v[1];
0480 float b = v[2];
0481 float t = v[3];
0482 float n = znear.value();
0483 float f = zfar.value();
0484 if(is_type_ortho()) {
0485 m_proj.set_ortho(l,r,b,t,n,f);
0486 } else {
0487 m_proj.set_frustum(l,r,b,t,n,f);
0488 }}
0489
0490 if(orientation.value().quat()!=id_orientation()) //OPTIMIZATION
0491 {rotf rinv;
0492 if(orientation.value().inverse(rinv)) {
0493 mat4f mtx;
0494 rinv.value(mtx);
0495 m_proj.mul_mtx(mtx,m_tmp);
0496 } else {
0497 a_out << "update_sg :"
0498 << " get orientation inverse failed."
0499 << std::endl;
0500 }}
0501
0502 m_proj.mul_translate(-position.value()[0],
0503 -position.value()[1],
0504 -position.value()[2]);
0505 }
0506
0507 void _mult_matrix(matrix_action& a_action) {
0508 float l,r,b,t;
0509 get_lrbt(a_action.ww(),a_action.wh(),l,r,b,t);
0510 m_lrbt.set_value(l,r,b,t);
0511
0512 if(touched()||m_lrbt.touched()) {
0513 update_sg(a_action.out());
0514 reset_touched();
0515 m_lrbt.reset_touched();
0516 }
0517
0518 a_action.projection_matrix().mul_mtx(m_proj,m_tmp);
0519 }
0520
0521 void set_state(matrix_action& a_action) {
0522 state& _state = a_action.state();
0523 _state.m_camera_ortho = is_type_ortho();
0524 _state.m_camera_znear = znear;
0525 _state.m_camera_zfar = zfar;
0526 _state.m_camera_position = position.value();
0527 _state.m_camera_orientation = orientation.value();
0528 //_state.m_camera_near_height = near_height();
0529 _state.m_camera_lrbt = m_lrbt.value();
0530 _state.m_proj = a_action.projection_matrix();
0531 }
0532
0533 #if defined(TOOLS_MEM) && !defined(TOOLS_MEM_ATEXIT)
0534 static const vec4<float>& id_orientation() {static const vec4<float> s_v(0,0,0,1,false);return s_v;}
0535 #else
0536 static const vec4<float>& id_orientation() {static const vec4<float> s_v(0,0,0,1);return s_v;}
0537 #endif
0538
0539 protected:
0540 //OPTIMIZATION :
0541 sf_vec4f m_lrbt;
0542 mat4f m_proj;
0543 float m_tmp[16];
0544 };
0545
0546 }}
0547
0548 #endif