Viewport4.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. namespace Edit{
  5. /******************************************************************************
  6. 'Arrows' uses one GuiObj instead of multiple Buttons so that Mouse/Touch can switch buttons while being continuously pressed.
  7. Normally MT.guiObj sticks to just one Object when pressed.
  8. /******************************************************************************/
  9. static Bool AdjustToGround(Viewport4 &v4) {return v4.horizontal() && !v4.fpp();} // World Editor mode
  10. static Bool AdjustToCamera(Viewport4 &v4) {return !v4.horizontal() && !v4.fpp();} // Object Editor mode
  11. /******************************************************************************/
  12. void Viewport4::View::setViewportCamera()
  13. {
  14. viewport.setDisplayView();
  15. camera .set();
  16. }
  17. /******************************************************************************/
  18. void Viewport4::ViewportEx::draw(C GuiPC &gpc)
  19. {
  20. if(visible() && gpc.visible)
  21. {
  22. Color rect_color=T.rect_color; T.rect_color.a=0;
  23. super::draw(gpc);
  24. T.rect_color=rect_color;
  25. if(Viewport4 *v4=(Viewport4*)user)
  26. if(v4->sel()<0 && rect_color.a)
  27. {
  28. Rect r=rect()+gpc.offset;
  29. D.clip(gpc.clip);
  30. // down
  31. if(this==&v4->view[VIEW_FRONT].viewport
  32. || this==&v4->view[VIEW_LEFT ].viewport)D.lineX(rect_color, r.max.y-D._pixel_size_2.y, r.min.x, r.max.x); // align down = -pixel_size
  33. // right
  34. if(this==&v4->view[VIEW_DIAGONAL].viewport
  35. || this==&v4->view[VIEW_LEFT ].viewport)D.lineY(rect_color, r.min.x+D._pixel_size_2.x, r.min.y, r.max.y); // align right = +pixel_size
  36. }
  37. }
  38. }
  39. /******************************************************************************/
  40. // CUBE
  41. /******************************************************************************/
  42. Viewport4::Cube& Viewport4::Cube::create(Viewport4 &v4, View &view) {super::create(); T.v4=&v4; T.view=&view; mesh="Gui/Viewcube/0.mesh"; return T;}
  43. void Viewport4::Cube::setView(C GuiPC &gpc, Display::ViewportSettings &view, Camera &camera, MatrixM &matrix)
  44. {
  45. if(T.view)
  46. {
  47. // backup
  48. camera=ActiveCam;
  49. view.get();
  50. D.view(rect()+gpc.offset, 0.1f, 100, DegToRad(30), FOV_Y);
  51. T.view->camera.set();
  52. matrix.identity(); matrix.pos.z+=3.3f; matrix.pos*=T.view->camera.matrix;
  53. }
  54. }
  55. void Viewport4::Cube::resetView(C Display::ViewportSettings &view, C Camera &camera)
  56. {
  57. view .set();
  58. camera.set();
  59. }
  60. GuiObj* Viewport4::Cube::test(C GuiPC &gpc, C Vec2 &pos, GuiObj* &mouse_wheel)
  61. {
  62. GuiObj *ret=null;
  63. if(mesh && super::test(gpc, pos, mouse_wheel))
  64. {
  65. Display::ViewportSettings view; Camera camera; MatrixM matrix;
  66. setView(gpc, view, camera, matrix);
  67. VecD pos3D; Vec dir; ScreenToPosDir(pos, pos3D, dir);
  68. if(Sweep(pos3D, dir*D.viewRange(), *mesh, &matrix, null, null, null, &part, false))ret=this;
  69. resetView(view, camera);
  70. }
  71. return ret;
  72. }
  73. void Viewport4::Cube::update(C GuiPC &gpc)
  74. {
  75. super::update(gpc);
  76. if(view && v4)
  77. {
  78. Touch *touch=null; REPA(Touches)if(Touches[i].guiObj()==this){touch=&Touches[i]; break;}
  79. if(touch || Gui.ms()==this)
  80. {
  81. Bool possible_drag=(touch ? touch->life()>=DragTime+Time.ad() || touch->selecting() : Ms.life()>=DragTime+Time.ad()),
  82. rot =(touch ? touch->on() : (Ms.b(0) || Ms.b(2) || Ms.b(4))),
  83. move =(touch ? false : (Ms.b(1) || Ms.b(3) ));
  84. if(rot && !move)
  85. {
  86. if(!touch)Ms.freeze();
  87. View &view=(v4->lock() ? v4->view[VIEW_FRONT] : *T.view);
  88. VecD pos =view.camera.matrix.pos;
  89. if(!(!Kb.ctrlCmd() && Kb.alt()))view.camera.yaw -=(touch ? touch->ad().x*3.0f : Ms.d().x); // disable X rotation when only Alt pressed
  90. if(!( Kb.ctrlCmd() && !Kb.alt()))view.camera.pitch+=(touch ? touch->ad().y*3.0f : Ms.d().y); // disable Y rotation when only Ctrl pressed
  91. view.camera.setSpherical();
  92. if(v4->fpp())view.camera+=pos-view.camera.matrix.pos;
  93. if(possible_drag)part=-1;
  94. }
  95. if(move)
  96. {
  97. Ms.freeze();
  98. Camera &cam=view->camera;
  99. VecD at=cam.at ; cam.transformByMouse(0, 0, ((v4->horizontal()^rot) ? CAMH_MOVE_XZ : CAMH_MOVE) | CAMH_NO_VEL_UPDATE | CAMH_NO_SET);
  100. VecD d =cam.at-at;
  101. if(v4->lock())REPA(v4->view)if(&v4->view[i]!=view)v4->view[i].camera+=d;
  102. }
  103. if((touch ? touch->rs() : Ms.br(0)) && !possible_drag && mesh && InRange(part, *mesh))
  104. {
  105. Flt y=0, p=0;
  106. CChar8 *name=mesh->parts[part].name;
  107. if(Equal(name, "l" ))y=-PI_2;else
  108. if(Equal(name, "r" ))y= PI_2;else
  109. if(Equal(name, "f" ))y= PI ;else
  110. if(Equal(name, "b" ))y= 0 ;else
  111. if(Equal(name, "u" )){y=AlignRound(view->camera.yaw, PI_2); p=-PI_2;}else // v4->_default_yaw
  112. if(Equal(name, "d" )){y=AlignRound(view->camera.yaw, PI_2); p= PI_2;}else
  113. if(Equal(name, "lb"))y=-PI_4;else
  114. if(Equal(name, "lf"))y=-PI_4-PI_2;else
  115. if(Equal(name, "rf"))y= PI_4+PI_2;else
  116. if(Equal(name, "rb"))y= PI_4;else
  117. if(Equal(name, "lu")){y=-PI_2; p=-PI_4;}else
  118. if(Equal(name, "ru")){y= PI_2; p=-PI_4;}else
  119. if(Equal(name, "uf")){y= PI ; p=-PI_4;}else
  120. if(Equal(name, "ub")){y= 0 ; p=-PI_4;}else
  121. if(Equal(name, "ld")){y=-PI_2; p= PI_4;}else
  122. if(Equal(name, "rd")){y= PI_2; p= PI_4;}else
  123. if(Equal(name, "df")){y= PI ; p= PI_4;}else
  124. if(Equal(name, "db")){y= 0 ; p= PI_4;}else
  125. if(Equal(name, "lub")){y=-PI_4 ; p=-PI_4;}else
  126. if(Equal(name, "luf")){y=-PI_4-PI_2; p=-PI_4;}else
  127. if(Equal(name, "ruf")){y= PI_4+PI_2; p=-PI_4;}else
  128. if(Equal(name, "rub")){y= PI_4 ; p=-PI_4;}else
  129. if(Equal(name, "ldb")){y=-PI_4 ; p= PI_4;}else
  130. if(Equal(name, "ldf")){y=-PI_4-PI_2; p= PI_4;}else
  131. if(Equal(name, "rdf")){y= PI_4+PI_2; p= PI_4;}else
  132. if(Equal(name, "rdb")){y= PI_4 ; p= PI_4;}
  133. if(Kb.ctrlCmd() && Kb.shift())p=SignBool(p>0)*(PI_4*2.0f/3);else // 0.66
  134. if( Kb.shift())p=SignBool(p>0)*(PI_4*0.75f );else // 0.75
  135. if(Kb.ctrlCmd() )p=SignBool(p>0)*(PI_4*0.5f ); // 0.50
  136. if(!v4->lock())v4->_rotate_view=view;else
  137. {
  138. v4->_rotate_view=&v4->view[VIEW_FRONT];
  139. y+=v4->_rotate_view->camera.yaw -view->camera.yaw ;
  140. p+=v4->_rotate_view->camera.pitch-view->camera.pitch;
  141. }
  142. v4->_rotate_time=0;
  143. v4->_rotate_yaw .set(v4->_rotate_view->camera.yaw , y);
  144. v4->_rotate_pitch.set(v4->_rotate_view->camera.pitch, p);
  145. }
  146. }
  147. }
  148. }
  149. void Viewport4::Cube::draw(C GuiPC &gpc)
  150. {
  151. if(mesh && visible() && gpc.visible)
  152. {
  153. D.clip(gpc.clip);
  154. ALPHA_MODE alpha=D.alpha();
  155. Display::ViewportSettings view; Camera camera; MatrixM matrix;
  156. setView(gpc, view, camera, matrix);
  157. D.sampler3D(); D.depthLock (false); mesh->drawBlend(matrix); if(Gui.ms()==this && InRange(part, *mesh))mesh->parts[part].drawBlend(&NoTemp(Vec4(2)));
  158. D.sampler2D(); D.depthUnlock( ); D.depthWrite(true); D.alpha(alpha); // reset 'depthWrite' and 'alpha' because they can be modified by 'drawBlend'
  159. resetView(view, camera);
  160. }
  161. }
  162. /******************************************************************************/
  163. // ZOOM
  164. /******************************************************************************/
  165. Viewport4::Zoom& Viewport4::Zoom::create(Viewport4 *v4, View *view) {super::create(); T.v4=v4; T.view=view; return T;}
  166. void Viewport4::Zoom::update(C GuiPC &gpc)
  167. {
  168. zoom=0;
  169. if(gpc.enabled)
  170. {
  171. if(Gui.ms()==this && Ms.b(0)){zoom-=Ms.d().y; Ms.freeze();} REPA(Touches)if(Touches[i].guiObj()==this && Touches[i].on())zoom-=Touches[i].ad().y*2.0f;
  172. if(zoom && v4 && view)
  173. {
  174. Flt scale=ScaleFactor(zoom);
  175. if(v4->lock())REPA(v4->view)
  176. {
  177. if(v4->perspective()){Clamp(v4->view[i].camera.dist*=scale, v4->minDist(), v4->maxDist()); v4->view[i].camera.setSpherical();}else v4->view[i].viewport.fov*=scale;
  178. }else
  179. {
  180. if(v4->perspective()){Clamp( view ->camera.dist*=scale, v4->minDist(), v4->maxDist()); view ->camera.setSpherical();}else view ->viewport.fov*=scale;
  181. }
  182. }
  183. }
  184. }
  185. void Viewport4::Zoom::draw(C GuiPC &gpc)
  186. {
  187. if(visible() && gpc.visible)
  188. {
  189. D.clip(gpc.clip);
  190. Rect rect=T.rect()+gpc.offset;
  191. rect.draw(Color(192, 200, 232, 64));
  192. rect.draw(Color(0, 0, 0, 128), false);
  193. {
  194. VI.color(Color(0, 0, 0, 64));
  195. Flt offset=-0.2f*Log2((v4 && view) ? v4->perspective() ? view->camera.dist : view->viewport.fov : ActiveCam.dist),
  196. x0=rect.lerpX(0.2f),
  197. x1=rect.lerpX(0.8f);
  198. REP(3){Flt y=rect.min.y+Frac(offset+(i*rect.h())/3, rect.h()); VI.line(Vec2(x0, y), Vec2(x1, y));}
  199. VI.end();
  200. }
  201. }
  202. }
  203. /******************************************************************************/
  204. // DIGITAL PAD
  205. /******************************************************************************/
  206. #define DPAD_INNER 0.33f
  207. Viewport4::DPad & Viewport4::DPad ::create(Viewport4 *v4, View *view) {super::create(); T.v4=v4; T.view=view; return T;}
  208. Viewport4::DPadY& Viewport4::DPadY::create(Viewport4 *v4, View *view) {super::create(); T.v4=v4; T.view=view; return T;}
  209. GuiObj* Viewport4::DPad::test(C GuiPC &gpc, C Vec2 &pos, GuiObj* &mouse_wheel)
  210. {
  211. return (visible() && gpc.visible && Cuts(pos, Circle(rect().h()*0.5f, rect().center()+gpc.offset))) ? this : null;
  212. }
  213. void Viewport4::DPad::update(C GuiPC &gpc)
  214. {
  215. touched=false;
  216. axis =0;
  217. if(gpc.enabled)
  218. {
  219. C Vec2 *pos=null; if(Gui.ms()==this && Ms.b(0))pos=&Ms.pos(); REPA(Touches)if(Touches[i].guiObj()==this && Touches[i].on()){pos=&Touches[i].pos(); break;}
  220. if(pos)
  221. {
  222. Circle inner(rect().h()*0.5f*DPAD_INNER, rect().center()+gpc.offset);
  223. if(!Cuts(*pos, inner))
  224. {
  225. touched=true;
  226. Vec2 delta=*pos-inner.pos; angle=AlignRound(AngleFast(delta), PI_4);
  227. CosSin(delta.x, delta.y, angle); axis.set(SignEps(delta.x), SignEps(delta.y));
  228. if(v4 && view)
  229. {
  230. delta*=v4->moveScale(*view);
  231. Vec move;
  232. if(AdjustToGround(*v4)){if(view->camera.matrix.y.y<0)CHS(delta.y); move.y=0; CosSin(move.x, move.z, view->camera.yaw+Angle(delta)); move*=delta.length();}else
  233. if(AdjustToCamera(*v4))move=view->camera.matrix.x*delta.x + view->camera.matrix.y*delta.y;else
  234. move=view->camera.matrix.x*delta.x + view->camera.matrix.z*delta.y;
  235. if(v4->lock())REPAO(v4->view).camera+=move;else view->camera+=move;
  236. }
  237. }
  238. }
  239. }
  240. }
  241. void Viewport4::DPadY::update(C GuiPC &gpc)
  242. {
  243. dir=0;
  244. if(gpc.enabled)
  245. {
  246. C Vec2 *pos=null; if(Gui.ms()==this && Ms.b(0))pos=&Ms.pos(); REPA(Touches)if(Touches[i].guiObj()==this && Touches[i].on()){pos=&Touches[i].pos(); break;}
  247. if(pos)
  248. {
  249. dir=Sign(pos->y-(rect().centerY()+gpc.offset.y));
  250. if(v4 && view)
  251. {
  252. Vec move=(AdjustToGround(*v4) ? Vec(0,1,0) : AdjustToCamera(*v4) ? view->camera.matrix.z : view->camera.matrix.y)*(v4->moveScale(*view)*dir);
  253. if(v4->lock())REPAO(v4->view).camera+=move;else view->camera+=move;
  254. }
  255. }
  256. }
  257. }
  258. void Viewport4::DPad::draw(C GuiPC &gpc)
  259. {
  260. if(visible() && gpc.visible)
  261. {
  262. D.clip(gpc.clip);
  263. Circle circle(rect().h()*0.5f, rect().center()+gpc.offset);
  264. Flt r2=circle.r*DPAD_INNER;
  265. circle.drawPie(Color(0, 192, 255, 64), r2);
  266. if(touched)circle.drawPie(Color(0, 192, 255, 192), r2, angle-PI_4/2, PI_4);
  267. // draw lines
  268. {
  269. VI.color(Color(0, 0, 0, 64));
  270. REP(8){Flt c, s; CosSin(c, s, i*PI_4 + PI_4/2); VI.line(Vec2(circle.pos.x+c*circle.r, circle.pos.y+s*circle.r), Vec2(circle.pos.x+c*r2, circle.pos.y+s*r2));}
  271. VI.end();
  272. }
  273. circle.r=r2; circle.draw(Color(0, 0, 0, 64));
  274. }
  275. }
  276. void Viewport4::DPadY::draw(C GuiPC &gpc)
  277. {
  278. if(visible() && gpc.visible)
  279. {
  280. D.clip(gpc.clip);
  281. Rect rect=T.rect()+gpc.offset; Vec2 right=rect.lerp(0.66f, 0.5f);
  282. VI.color(Color(0, 192, 255, 64));
  283. VI.tri(rect.lu(), right, rect.ld()); // left
  284. VI.tri(rect.lu(), rect.ru(), right); // top right
  285. VI.tri(rect.rd(), rect.ld(), right); // bottom right
  286. VI.end();
  287. if(dir>0)Quad2(rect.left(), rect.lu(), rect.ru (), right).draw(Color(0, 192, 255, 192), true);else
  288. if(dir<0)Quad2(rect.rd (), rect.ld(), rect.left(), right).draw(Color(0, 192, 255, 192), true);
  289. D.line(Color(0, 0, 0, 64), rect.left(), right);
  290. }
  291. }
  292. /******************************************************************************/
  293. // ANALOG PAD
  294. /******************************************************************************/
  295. Viewport4::APad & Viewport4::APad ::create(Viewport4 &v4, View &view) {super::create(); T.v4=&v4; T.view=&view; return T;}
  296. Viewport4::APadY& Viewport4::APadY::create(Viewport4 &v4, View &view) {super::create(); T.v4=&v4; T.view=&view; return T;}
  297. GuiObj* Viewport4::APad::test(C GuiPC &gpc, C Vec2 &pos, GuiObj* &mouse_wheel)
  298. {
  299. return (visible() && gpc.visible && Cuts(pos, Circle(rect().h()*0.5f, rect().center()+gpc.offset))) ? this : null;
  300. }
  301. void Viewport4::APad::update(C GuiPC &gpc)
  302. {
  303. touched=false;
  304. if(gpc.enabled)
  305. {
  306. C Vec2 *pos=null; Bool pushed=false; if(Gui.ms()==this && Ms.b(0)){pos=&Ms.pos(); pushed=Ms.bp(0);} REPA(Touches)if(Touches[i].guiObj()==this && Touches[i].on()){pos=&Touches[i].pos(); pushed=Touches[i].pd(); break;}
  307. if(pos)
  308. {
  309. touched=true; cur=*pos-(rect().center()+gpc.offset); if(pushed)start=cur;
  310. Vec2 delta=(cur-start)/(rect().h()*0.5f)*v4->moveScale(*view);
  311. Vec move;
  312. if(AdjustToGround(*v4)){if(view->camera.matrix.y.y<0)CHS(delta.y); move.y=0; CosSin(move.x, move.z, view->camera.yaw+Angle(delta)); move*=delta.length();}else
  313. if(AdjustToCamera(*v4))move=view->camera.matrix.x*delta.x + view->camera.matrix.y*delta.y;else
  314. move=view->camera.matrix.x*delta.x + view->camera.matrix.z*delta.y;
  315. if(v4->lock())REPAO(v4->view).camera+=move;else view->camera+=move;
  316. }
  317. }
  318. }
  319. void Viewport4::APadY::update(C GuiPC &gpc)
  320. {
  321. touched=false;
  322. if(gpc.enabled)
  323. {
  324. C Vec2 *pos=null; Bool pushed=false; if(Gui.ms()==this && Ms.b(0)){pos=&Ms.pos(); pushed=Ms.bp(0);} REPA(Touches)if(Touches[i].guiObj()==this && Touches[i].on()){pos=&Touches[i].pos(); pushed=Touches[i].pd(); break;}
  325. if(pos)
  326. {
  327. touched=true; cur=pos->y-(rect().centerY()+gpc.offset.y); if(pushed)start=cur;
  328. Vec move=(AdjustToGround(*v4) ? Vec(0,1,0) : AdjustToCamera(*v4) ? view->camera.matrix.z : view->camera.matrix.y)*(v4->moveScale(*view)*(cur-start)/rect().h());
  329. if(v4->lock())REPAO(v4->view).camera+=move;else view->camera+=move;
  330. }
  331. }
  332. }
  333. void Viewport4::APad::draw(C GuiPC &gpc)
  334. {
  335. if(visible() && gpc.visible)
  336. {
  337. D.clip(gpc.clip);
  338. Circle c(rect().h()*0.5f, rect().center()+gpc.offset);
  339. c.draw(Color(192, 192, 192, 64));
  340. c.draw(Color(255, 255, 255, 192), false);
  341. if(touched)
  342. {
  343. Vec2 begin=start+rect().center()+gpc.offset,
  344. end =cur +rect().center()+gpc.offset;
  345. c.r*=0.5f;
  346. c.pos=end;
  347. c.draw(Color(192, 192, 192, 64));
  348. c.draw(Color(255, 255, 255, 192), false);
  349. D.line(Color(255, 255, 255, 192), begin, end);
  350. }
  351. }
  352. }
  353. void Viewport4::APadY::draw(C GuiPC &gpc)
  354. {
  355. if(visible() && gpc.visible)
  356. {
  357. D.clip(gpc.clip);
  358. Rect rect=T.rect()+gpc.offset;
  359. rect.draw(Color(192, 192, 192, 64));
  360. rect.draw(Color(255, 255, 255, 192), false);
  361. if(touched)
  362. {
  363. Flt begin=rect.centerY()+start,
  364. end =rect.centerY()+cur ;
  365. rect.setC(rect.centerX(), end, 0.06f, 0.03f);
  366. rect.draw (Color(192, 192, 192, 64));
  367. rect.draw (Color(255, 255, 255, 192), false);
  368. D.lineY(Color(255, 255, 255, 192), rect.centerX(), begin, end);
  369. }
  370. }
  371. }
  372. /******************************************************************************/
  373. // ZOOM
  374. /******************************************************************************/
  375. Viewport4::Drag & Viewport4::Drag ::create(Viewport4 &v4, View &view) {super::create(); T.v4=&v4; T.view=&view; return T;}
  376. Viewport4::DragY& Viewport4::DragY::create(Viewport4 &v4, View &view) {super::create(); T.v4=&v4; T.view=&view; return T;}
  377. GuiObj* Viewport4::Drag::test(C GuiPC &gpc, C Vec2 &pos, GuiObj* &mouse_wheel)
  378. {
  379. return (visible() && gpc.visible && Cuts(pos, Circle(rect().h()*0.5f, rect().center()+gpc.offset))) ? this : null;
  380. }
  381. void Viewport4::Drag::update(C GuiPC &gpc)
  382. {
  383. if(gpc.enabled)
  384. {
  385. Vec2 delta(0,0); if(Gui.ms()==this && Ms.b(0)){delta-=Ms.d(); Ms.freeze();} REPA(Touches)if(Touches[i].guiObj()==this && Touches[i].on())delta-=Touches[i].ad()*2.0f;
  386. if( delta.any())
  387. {
  388. delta*=v4->moveScale(*view, false);
  389. Vec move;
  390. if(AdjustToGround(*v4)){if(view->camera.matrix.y.y<0)CHS(delta.y); move.y=0; CosSin(move.x, move.z, view->camera.yaw+Angle(delta)); move*=delta.length();}else
  391. if(AdjustToCamera(*v4))move=view->camera.matrix.x*delta.x + view->camera.matrix.y*delta.y;else
  392. move=view->camera.matrix.x*delta.x + view->camera.matrix.z*delta.y;
  393. if(v4->lock())REPAO(v4->view).camera+=move;else view->camera+=move;
  394. }
  395. }
  396. }
  397. void Viewport4::DragY::update(C GuiPC &gpc)
  398. {
  399. if(gpc.enabled)
  400. {
  401. Flt delta=0; if(Gui.ms()==this && Ms.b(0)){delta-=Ms.d().y; Ms.freeze();} REPA(Touches)if(Touches[i].guiObj()==this && Touches[i].on())delta-=Touches[i].ad().y*2.0f;
  402. if( delta)
  403. {
  404. Vec move=(AdjustToGround(*v4) ? Vec(0,1,0) : AdjustToCamera(*v4) ? view->camera.matrix.z : view->camera.matrix.y)*(v4->moveScale(*view, false)*delta);
  405. if(v4->lock())REPAO(v4->view).camera+=move;else view->camera+=move;
  406. }
  407. }
  408. }
  409. void Viewport4::Drag::draw(C GuiPC &gpc)
  410. {
  411. if(visible() && gpc.visible)
  412. {
  413. D.clip(gpc.clip);
  414. Circle c(rect().h()*0.5f, rect().center()+gpc.offset);
  415. c.draw(Color(192, 200, 232, 64));
  416. c.draw(Color(0, 0, 0, 128), false);
  417. }
  418. }
  419. void Viewport4::DragY::draw(C GuiPC &gpc)
  420. {
  421. if(visible() && gpc.visible)
  422. {
  423. D.clip(gpc.clip);
  424. Rect rect=T.rect()+gpc.offset;
  425. rect.draw(Color(192, 200, 232, 64));
  426. rect.draw(Color(0, 0, 0, 128), false);
  427. }
  428. }
  429. /******************************************************************************/
  430. // ARROWS
  431. /******************************************************************************/
  432. Viewport4::Arrows& Viewport4::Arrows::create(Viewport4 &v4, View &view) {super::create(); T.v4=&v4; T.view=&view; return T;}
  433. GuiObj& Viewport4::Arrows::rect (C Rect &rect)
  434. {
  435. Flt x0=rect.lerpX(0.00f), y0=rect.lerpY(0.0f),
  436. x1=rect.lerpX(0.33f), y1=rect.lerpY(0.5f),
  437. x2=rect.lerpX(0.66f), y2=rect.lerpY(1.0f),
  438. x3=rect.lerpX(1.00f);
  439. arrow_rect[DIR_LEFT ].set(x0, y0, x1, y1);
  440. arrow_rect[DIR_BACK ].set(x1, y0, x2, y1);
  441. arrow_rect[DIR_RIGHT ].set(x2, y0, x3, y1);
  442. arrow_rect[DIR_DOWN ].set(x0, y1, x1, y2);
  443. arrow_rect[DIR_FORWARD].set(x1, y1, x2, y2);
  444. arrow_rect[DIR_UP ].set(x2, y1, x3, y2);
  445. return super::rect(rect);
  446. }
  447. void Viewport4::Arrows::update(C GuiPC &gpc)
  448. {
  449. Zero(arrow_pushed);
  450. if(gpc.visible && visible() && v4 && view)
  451. {
  452. if( Gui.ms()==this && Ms.b (0)){Vec2 pos= Ms.pos()-gpc.offset; REPA(arrow_rect)if(Cuts(pos, arrow_rect[i])){arrow_pushed[i]=true; break;}}
  453. REPA(Touches)if(Touches[i].guiObj()==this && Touches[i].on( )){Vec2 pos=Touches[i].pos()-gpc.offset; REPA(arrow_rect)if(Cuts(pos, arrow_rect[i])){arrow_pushed[i]=true; break;}}
  454. Vec move=0;
  455. if(AdjustToGround(*v4))
  456. {
  457. VecI2 di(arrow_pushed[DIR_RIGHT]-arrow_pushed[DIR_LEFT], arrow_pushed[DIR_FORWARD]-arrow_pushed[DIR_BACK]);
  458. if(di.any()){if(view->camera.matrix.y.y<0)CHS(di.y); CosSin(move.x, move.z, view->camera.yaw+Angle(Vec2(di)));}
  459. }else
  460. if(AdjustToCamera(*v4))
  461. {
  462. if(arrow_pushed[DIR_RIGHT ])move+=view->camera.matrix.x;
  463. if(arrow_pushed[DIR_LEFT ])move-=view->camera.matrix.x;
  464. if(arrow_pushed[DIR_FORWARD])move+=view->camera.matrix.y;
  465. if(arrow_pushed[DIR_BACK ])move-=view->camera.matrix.y;
  466. }else
  467. {
  468. if(arrow_pushed[DIR_RIGHT ])move+=view->camera.matrix.x;
  469. if(arrow_pushed[DIR_LEFT ])move-=view->camera.matrix.x;
  470. if(arrow_pushed[DIR_FORWARD])move+=view->camera.matrix.z;
  471. if(arrow_pushed[DIR_BACK ])move-=view->camera.matrix.z;
  472. }
  473. if(arrow_pushed[DIR_UP ])move+=(AdjustToGround(*v4) ? Vec(0, 1, 0) : AdjustToCamera(*v4) ? view->camera.matrix.z : view->camera.matrix.y);
  474. if(arrow_pushed[DIR_DOWN])move-=(AdjustToGround(*v4) ? Vec(0, 1, 0) : AdjustToCamera(*v4) ? view->camera.matrix.z : view->camera.matrix.y);
  475. move*=v4->moveScale(*view); if(v4->lock())REPAO(v4->view).camera+=move;else view->camera+=move;
  476. }
  477. }
  478. void Viewport4::Arrows::draw(C GuiPC &gpc)
  479. {
  480. if(gpc.visible && visible())
  481. {
  482. D.clip(gpc.clip);
  483. Button b; b.create().disabled(true); b.text_size=0.75f; // set disabled to be half transparent
  484. REPA(arrow_rect)
  485. {
  486. if(i==DIR_UP )b.text=(AdjustToCamera(*v4) ? "Fw" : "Up");else
  487. if(i==DIR_DOWN)b.text=(AdjustToCamera(*v4) ? "Bk" : "Dn");else
  488. b.text.clear();
  489. b._on=arrow_pushed[i];
  490. b.rect(arrow_rect[i]);
  491. b.draw(gpc);
  492. }
  493. if(GuiSkin *skin=b.getSkin())
  494. {
  495. Color color=skin->button.disabled_color;
  496. if(skin->slidebar.left.image)
  497. {
  498. skin->slidebar.left.image->drawFit (color, TRANSPARENT, arrow_rect[DIR_LEFT]+gpc.offset);
  499. skin->slidebar.left.image->drawFitVertical(color, TRANSPARENT, arrow_rect[DIR_BACK]+gpc.offset);
  500. }
  501. if(skin->slidebar.right.image)
  502. {
  503. skin->slidebar.right.image->drawFit (color, TRANSPARENT, arrow_rect[DIR_RIGHT ]+gpc.offset);
  504. skin->slidebar.right.image->drawFitVertical(color, TRANSPARENT, arrow_rect[DIR_FORWARD]+gpc.offset);
  505. }
  506. }
  507. }
  508. }
  509. /******************************************************************************/
  510. // MANAGE
  511. /******************************************************************************/
  512. Viewport4& Viewport4::create(void (*draw)(Viewport&), Flt default_pitch, Flt default_yaw, Flt default_dist, Flt from, Flt range)
  513. {
  514. _sel =0;
  515. _perspective=true;
  516. _horizontal =true;
  517. _keyboard =true;
  518. _fpp =false;
  519. _lock =true;
  520. #if DESKTOP
  521. _orn_mode =ORIENT_TOP_LEFT;
  522. _move_mode =MOVE_NONE;
  523. #else
  524. _orn_mode =ORIENT_RIGHT;
  525. _move_mode =MOVE_DPAD;
  526. _draw_zoom =true;
  527. #endif
  528. _rect =D.rect();
  529. _focus =null;
  530. _last =&view[0];
  531. _rotate_view=null;
  532. _fpp_speed =5;
  533. _persp_fov =DegToRad(70);
  534. _default_pitch=default_pitch;
  535. _default_yaw =default_yaw ;
  536. _default_dist =default_dist ;
  537. REPA(view)
  538. {
  539. view[i].viewport.create(draw, this);
  540. view[i].viewport.rect_color.set(64);
  541. view[i].viewport.from =from ;
  542. view[i].viewport.range=range;
  543. view[i].viewport.fov =_persp_fov;
  544. }
  545. REPA(_cube )_cube [i].create( T, view[i]);
  546. REPA(_zoom )_zoom [i].create(&T, &view[i]);
  547. REPA(_dpad )_dpad [i].create(&T, &view[i]);
  548. REPA(_dpady )_dpady [i].create(&T, &view[i]);
  549. REPA(_apad )_apad [i].create( T, view[i]);
  550. REPA(_apady )_apady [i].create( T, view[i]);
  551. REPA(_drag )_drag [i].create( T, view[i]);
  552. REPA(_dragy )_dragy [i].create( T, view[i]);
  553. REPA(_arrows)_arrows[i].create( T, view[i]);
  554. resetPosOrn();
  555. sel(-1);
  556. return T;
  557. }
  558. /******************************************************************************/
  559. // GET / SET
  560. /******************************************************************************/
  561. Viewport4::View* Viewport4::getView(GuiObj *go)
  562. {
  563. if(go)REPA(view)if(go==&view[i].viewport)return &view[i];
  564. return null;
  565. }
  566. Viewport4::View* Viewport4::getViewCtrl(GuiObj *go)
  567. {
  568. if(go)REPA(view)
  569. if(go==& view [i].viewport
  570. || go==&_cube [i]
  571. || go==&_zoom [i]
  572. || go==&_dpad [i]
  573. || go==&_dpady [i]
  574. || go==&_apad [i]
  575. || go==&_apady [i]
  576. || go==&_drag [i]
  577. || go==&_dragy [i]
  578. || go==&_arrows[i]
  579. )return &view [i];
  580. return null;
  581. }
  582. Flt Viewport4::minDist ( )C {return 0.01f;}
  583. Flt Viewport4::maxDist ( )C {return _last->viewport.range*0.5f;}
  584. Flt Viewport4::moveScale(View &view, Bool time)C {return (fpp() ? fppSpeed() : 1.3f*(perspective() ? Max(horizontal() ? 2.5f : 0.0f, view.camera.dist)*Tan(view.viewport.fov/2) : view.viewport.fov))*(time ? Time.d() : 1)*(Kb.shift() ? 4 : 1);}
  585. Bool Viewport4::visible ( )C {REPA(view)if(view[i].viewport.visible())return true; return false;}
  586. /******************************************************************************/
  587. Viewport4& Viewport4::perspective(Bool on)
  588. {
  589. if(perspective()!=on)
  590. {
  591. T._perspective=on;
  592. REPA(view)
  593. {
  594. if(on)
  595. {
  596. view[i].camera .dist =view[i].viewport.fov/Tan(perspFov()/2);
  597. view[i].viewport.fov_mode=FOV_Y;
  598. view[i].viewport.fov =perspFov();
  599. }else
  600. {
  601. view[i].viewport.fov_mode=FOV_ORTHO_Y;
  602. view[i].viewport.fov =Tan(perspFov()/2)*view[i].camera.dist;
  603. view[i].camera .dist =view[i].viewport.range*0.5f;
  604. }
  605. }
  606. }
  607. return T;
  608. }
  609. Viewport4& Viewport4::lock(Bool on)
  610. {
  611. if(on!=lock())toggleLock();
  612. return T;
  613. }
  614. Viewport4& Viewport4::fpp(Bool on)
  615. {
  616. T._fpp=on;
  617. return T;
  618. }
  619. Viewport4& Viewport4::horizontal(Bool on)
  620. {
  621. T._horizontal=on;
  622. return T;
  623. }
  624. Viewport4& Viewport4::keyboard(Bool on)
  625. {
  626. T._keyboard=on;
  627. return T;
  628. }
  629. Viewport4& Viewport4::sel(Int view)
  630. {
  631. Clamp(view, -1, 3);
  632. if(T._sel!=view)
  633. {
  634. T._sel=view;
  635. if(InRange(T._sel, T.view))_last=&T.view[T._sel]; // if we're selecting one view then set it as last to help with setting default view/cam for it without needing the mouse to hover over it
  636. if(visible())visible(true);
  637. setRect();
  638. }
  639. return T;
  640. }
  641. Viewport4& Viewport4::fppSpeed(Flt speed) {T._fpp_speed=Max(0, speed); return T;}
  642. Viewport4& Viewport4::perspFov(Flt fov )
  643. {
  644. _persp_fov=fov;
  645. if(perspective())REPAO(view).viewport.fov=fov;
  646. return T;
  647. }
  648. Viewport4& Viewport4::drawZoom(Bool on)
  649. {
  650. T._draw_zoom=on; if(visible())visible(true); return T;
  651. }
  652. Viewport4& Viewport4::orientMode(ORIENT_MODE mode)
  653. {
  654. T._orn_mode=mode; if(visible())visible(true); return T;
  655. }
  656. Viewport4& Viewport4::moveMode(MOVE_MODE mode)
  657. {
  658. T._move_mode=mode; if(visible())visible(true); return T;
  659. }
  660. /******************************************************************************/
  661. // OPERATIONS
  662. /******************************************************************************/
  663. Viewport4& Viewport4::visible(Bool visible)
  664. {
  665. REPAO(view).viewport.visible(visible && (T._sel<0 || T._sel==i));
  666. REPAO(_cube ).visible(visible && _orn_mode && (T._sel<0 || T._sel==i)); if(visible && _orn_mode)setCubeRect();
  667. REPAO(_zoom ).visible(visible && drawZoom() && (T._sel<0 || T._sel==i));
  668. REPAO(_dpad ).visible(visible && _move_mode==MOVE_DPAD && (T._sel<0 || T._sel==i));
  669. REPAO(_dpady ).visible(visible && _move_mode==MOVE_DPAD && (T._sel<0 || T._sel==i));
  670. REPAO(_apad ).visible(visible && _move_mode==MOVE_APAD && (T._sel<0 || T._sel==i));
  671. REPAO(_apady ).visible(visible && _move_mode==MOVE_APAD && (T._sel<0 || T._sel==i));
  672. REPAO(_drag ).visible(visible && _move_mode==MOVE_DRAG && (T._sel<0 || T._sel==i));
  673. REPAO(_dragy ).visible(visible && _move_mode==MOVE_DRAG && (T._sel<0 || T._sel==i));
  674. REPAO(_arrows).visible(visible && _move_mode==MOVE_ARROWS && (T._sel<0 || T._sel==i));
  675. return T;
  676. }
  677. void Viewport4::setCubeRect()
  678. {
  679. Flt s=0.20f, // size
  680. y=0.45f, // y viewport fraction to place touch controls
  681. p=0.09f; // padding
  682. if(orientMode()==ORIENT_RIGHT)
  683. {
  684. REPAO(_cube).rect(Rect_R(view[i].viewport.rect().lerp(1, y)+Vec2(-p, 0), s, s));
  685. }else
  686. {
  687. REPAO(_cube).rect(Rect_C(view[i].viewport.rect().lu()+Vec2(0.13f, -0.13f), s, s));
  688. }
  689. }
  690. void Viewport4::setRect()
  691. {
  692. if(_sel<0)
  693. {
  694. view[VIEW_TOP ].viewport.rect(Rect(rect().min.x , rect().centerY(), rect().centerX(), rect().max.y ));
  695. view[VIEW_DIAGONAL].viewport.rect(Rect(rect().centerX(), rect().centerY(), rect().max.x , rect().max.y ));
  696. view[VIEW_FRONT ].viewport.rect(Rect(rect().min.x , rect().min.y , rect().centerX(), rect().centerY()));
  697. view[VIEW_LEFT ].viewport.rect(Rect(rect().centerX(), rect().min.y , rect().max.x , rect().centerY()));
  698. }else
  699. {
  700. view[_sel].viewport.rect(rect());
  701. }
  702. Flt s =0.15f , // size
  703. sc=s *SQRT2, // size of cube (must be Sqrt2, because cube can be rotated)
  704. sd=sc*1.1f , // size of dpad
  705. sa=s *1.8f , // size of arrows ('s' is too small for arrows so use bigger)
  706. sl=0.08f , // size of sliders
  707. y =0.45f , // y viewport fraction to place touch controls
  708. p =0.09f ; // padding
  709. REPAO(_dpad ).rect(Rect_L(view[i].viewport.rect().lerp(0, y)+Vec2(p, 0), sd , sd));
  710. REPAO(_dpady ).rect(Rect_L(view[i].viewport.rect().lerp(0, y) , sl , sd));
  711. REPAO(_apad ).rect(Rect_L(view[i].viewport.rect().lerp(0, y)+Vec2(p, 0), sc , sc));
  712. REPAO(_apady ).rect(Rect_L(view[i].viewport.rect().lerp(0, y) , sl , sc));
  713. REPAO(_drag ).rect(Rect_L(view[i].viewport.rect().lerp(0, y)+Vec2(p, 0), sc , sc));
  714. REPAO(_dragy ).rect(Rect_L(view[i].viewport.rect().lerp(0, y) , sl , sc));
  715. REPAO(_arrows).rect(Rect_L(view[i].viewport.rect().lerp(0, y)+Vec2(0, 0), sa*1.5f, sa));
  716. REPAO(_zoom ).rect(Rect_R(view[i].viewport.rect().lerp(1, y) , sl , sc));
  717. setCubeRect();
  718. }
  719. Viewport4& Viewport4::rect(C Rect &rect)
  720. {
  721. if(T.rect()!=rect)
  722. {
  723. T._rect=rect;
  724. setRect();
  725. }
  726. return T;
  727. }
  728. Viewport4& Viewport4::resetPosOrn()
  729. {
  730. if(lock())
  731. {
  732. View &v=view[VIEW_FRONT];
  733. v.camera.setSpherical(VecZero, _default_yaw, _default_pitch, 0, perspective() ? _default_dist : v.viewport.range*0.5f);
  734. }else
  735. {
  736. if(_last==&view[VIEW_FRONT ])_last->camera.setSpherical(VecZero, _default_yaw , _default_pitch , 0, perspective() ? _default_dist : _last->viewport.range*0.5f);else
  737. if(_last==&view[VIEW_TOP ])_last->camera.setSpherical(VecZero, _default_yaw , _default_pitch-PI_2, 0, perspective() ? _default_dist : _last->viewport.range*0.5f);else
  738. if(_last==&view[VIEW_DIAGONAL])_last->camera.setSpherical(VecZero, _default_yaw+PI_4, _default_pitch-PI_4, 0, perspective() ? _default_dist : _last->viewport.range*0.5f);else
  739. if(_last==&view[VIEW_LEFT ])_last->camera.setSpherical(VecZero, _default_yaw+PI_2, _default_pitch , 0, perspective() ? _default_dist : _last->viewport.range*0.5f);
  740. }
  741. return T;
  742. }
  743. Viewport4& Viewport4::axisAlign()
  744. {
  745. if(lock())
  746. {
  747. Camera &camera=view[VIEW_FRONT].camera;
  748. camera.setSpherical(camera.at, _default_yaw, 0, 0, camera.dist);
  749. }else
  750. {
  751. if(_last==&view[VIEW_FRONT ])_last->camera.setSpherical(_last->camera.at, _default_yaw , 0, 0, _last->camera.dist);else
  752. if(_last==&view[VIEW_TOP ])_last->camera.setSpherical(_last->camera.at, _default_yaw , -PI_2, 0, _last->camera.dist);else
  753. if(_last==&view[VIEW_DIAGONAL])_last->camera.setSpherical(_last->camera.at, _default_yaw+PI_4, -PI_4, 0, _last->camera.dist);else
  754. if(_last==&view[VIEW_LEFT ])_last->camera.setSpherical(_last->camera.at, _default_yaw+PI_2, 0, 0, _last->camera.dist);
  755. }
  756. return T;
  757. }
  758. Viewport4& Viewport4::moveTo(C VecD &pos)
  759. {
  760. if(lock())
  761. {
  762. VecD d=pos-view[VIEW_FRONT].camera.at;
  763. REPAO(view).camera+=d;
  764. }else
  765. {
  766. _last->camera.at=pos;
  767. _last->camera.setSpherical();
  768. }
  769. return T;
  770. }
  771. Viewport4& Viewport4::dist(Flt dist)
  772. {
  773. Clamp(dist, minDist(), maxDist());
  774. if(lock())
  775. {
  776. REPAO(view).camera.dist=dist;
  777. REPAO(view).camera.setSpherical();
  778. }else
  779. {
  780. _last->camera.dist=dist;
  781. _last->camera.setSpherical();
  782. }
  783. return T;
  784. }
  785. Viewport4& Viewport4::toggleView(Int view)
  786. {
  787. return sel((view==T._sel) ? -1 : view);
  788. }
  789. Viewport4& Viewport4::toggleOrientMode(ORIENT_MODE mode)
  790. {
  791. return orientMode((orientMode()==mode) ? ORIENT_NONE : mode);
  792. }
  793. Viewport4& Viewport4::toggleMoveMode(MOVE_MODE mode)
  794. {
  795. return moveMode((moveMode()==mode) ? MOVE_NONE : mode);
  796. }
  797. Viewport4& Viewport4::toggleZoom()
  798. {
  799. return drawZoom(!drawZoom());
  800. }
  801. Viewport4& Viewport4::togglePerspective()
  802. {
  803. return perspective(!perspective());
  804. }
  805. Viewport4& Viewport4::toggleHorizontal()
  806. {
  807. return horizontal(!horizontal());
  808. }
  809. Viewport4& Viewport4::toggleKeyboard()
  810. {
  811. return keyboard(!keyboard());
  812. }
  813. Viewport4& Viewport4::toggleFpp()
  814. {
  815. _fpp^=1;
  816. return T;
  817. }
  818. Viewport4& Viewport4::toggleLock()
  819. {
  820. if(_lock^=1)
  821. {
  822. if(!fpp())view[VIEW_FRONT].camera.at=_last->camera.at;
  823. else view[VIEW_FRONT].camera +=_last->camera.matrix.pos-view[VIEW_FRONT].camera.matrix.pos;
  824. }
  825. return T;
  826. }
  827. Viewport4& Viewport4::setViewportCamera()
  828. {
  829. if(_last)_last->setViewportCamera();
  830. return T;
  831. }
  832. /******************************************************************************/
  833. // UPDATE
  834. /******************************************************************************/
  835. void Viewport4::update()
  836. {
  837. // detect highlight
  838. if(_focus=getView(Gui.ms()))_last=_focus;
  839. // auto-rotate
  840. if(_rotate_view)
  841. {
  842. _rotate_time+=Time.ad();
  843. Camera &cam=_rotate_view->camera;
  844. Flt s =Sat(_rotate_time/0.2f);
  845. VecD pos=cam.matrix.pos;
  846. cam.yaw =LerpAngle(_rotate_yaw .x, _rotate_yaw .y, s);
  847. cam.pitch=LerpAngle(_rotate_pitch.x, _rotate_pitch.y, s);
  848. cam.setSpherical();
  849. if(fpp())cam+=pos-cam.matrix.pos;
  850. if(s==1 )_rotate_view=null;
  851. }
  852. // update camera change
  853. Bool zoom =(Ms.wheel() && !Kb.ctrlCmd() && !Kb.shift() && !Kb.alt() && !fpp()),
  854. zoom_manual=( (Ms.b(2) && Kb.alt() && Kb.ctrlCmd() )),
  855. rotate_ex =(Ms.b(4) || Kb.winCtrl() || Kb.b(KB_FIND)),
  856. rotate =(rotate_ex || (Ms.b(2) && (!Kb.alt() || Kb.ctrlCmd()) && !zoom_manual)),
  857. move =(Ms.b(3) || Kb.b(KB_SPACE) || (Ms.b(2) && ( Kb.alt() || Kb.ctrlCmd()) && !zoom_manual)),
  858. rotate_move=(rotate && move); if(rotate_move)rotate=move=false;
  859. // set main camera
  860. View &v =(lock() ? view[VIEW_FRONT] : *_last); v.viewport.setDisplayView();
  861. Camera &cam=v.camera;
  862. // zoom / rotate
  863. if(_focus)
  864. {
  865. if(rotate || move || rotate_move || zoom_manual)Ms.freeze();
  866. VecD pos=cam.matrix.pos;
  867. if(zoom_manual)
  868. {
  869. Flt f=ScaleFactor(-Ms.d().sum());
  870. if(perspective())Clamp(cam.dist*=f, minDist(), maxDist());else REPAO(view).viewport.fov*=f;
  871. }
  872. UInt flag=CAMH_NO_VEL_UPDATE|CAMH_NO_SET;
  873. if(rotate)
  874. {
  875. if(rotate_ex)
  876. {
  877. if(!(!Kb.ctrlCmd() && Kb.alt()))flag|=CAMH_ROT_X; // disable X rotation when only Alt pressed
  878. if(!( Kb.ctrlCmd() && !Kb.alt()))flag|=CAMH_ROT_Y; // disable Y rotation when only Ctrl pressed
  879. }else flag|=CAMH_ROT;
  880. }
  881. cam.transformByMouse(minDist(), maxDist(), flag);
  882. if(fpp())cam+=pos-cam.matrix.pos;
  883. }
  884. if(zoom)if(View *view=getViewCtrl(Gui.ms()))
  885. {
  886. if(perspective())Clamp(cam.dist*=ScaleFactor(Ms.wheel()*-0.3f), minDist(), maxDist());
  887. else REPAO(T.view).viewport.fov*=ScaleFactor(Ms.wheel()*-0.3f);
  888. }
  889. // set cameras
  890. if(lock())
  891. {
  892. // set secondary basing on the primary
  893. REPA(view)
  894. {
  895. Camera &camera=view[i].camera;
  896. camera.at =cam.at;
  897. camera.dist =cam.dist;
  898. camera.yaw =cam.yaw;
  899. camera.pitch=cam.pitch;
  900. camera.roll =cam.roll;
  901. }
  902. view[VIEW_TOP ].camera.pitch-=PI_2;
  903. view[VIEW_DIAGONAL].camera.pitch-=PI_4; view[VIEW_DIAGONAL].camera.yaw+=PI_4;
  904. view[VIEW_LEFT ].camera.yaw +=PI_2;
  905. // set all in one place
  906. if(fpp())REPA(view)
  907. {
  908. Camera &camera=view[i].camera;
  909. camera.setSpherical();
  910. camera+=cam.matrix.pos-camera.matrix.pos;
  911. }
  912. }
  913. // move
  914. if(_focus && !Gui.window())
  915. {
  916. _focus->viewport.setDisplayView();
  917. Camera &cam=_focus->camera .setSpherical ();
  918. VecD at=cam.at;
  919. // fpp movement
  920. if(_keyboard && !Kb.ctrlCmd() && !Kb.alt())
  921. if(!Gui.kb() || Gui.kb()->type()!=GO_TEXTLINE && Gui.kb()->type()!=GO_TEXTBOX && Gui.kb()->type()!=GO_LIST)
  922. {
  923. Flt scale=moveScale(*_focus);
  924. if(Kb.b(Kb.qwerty(KB_A)) || Kb.b(KB_LEFT ))cam.at -=cam.matrix.x*scale;
  925. if(Kb.b(Kb.qwerty(KB_D)) || Kb.b(KB_RIGHT))cam.at +=cam.matrix.x*scale;
  926. if(Kb.b(Kb.qwerty(KB_S)) || Kb.b(KB_DOWN ))cam.at -=cam.matrix.z*scale;
  927. if(Kb.b(Kb.qwerty(KB_W)) || Kb.b(KB_UP ))cam.at +=cam.matrix.z*scale;
  928. if(Kb.b(Kb.qwerty(KB_Q)) )cam.at.y-=scale;
  929. if(Kb.b(Kb.qwerty(KB_E)) )cam.at.y+=scale;
  930. }
  931. // mouse movement
  932. if(move || rotate_move)
  933. {
  934. if(!horizontal())Swap(move, rotate_move);
  935. Flt temp; if(fpp()){temp=cam.dist; cam.dist=fppSpeed()*0.5f;} cam.transformByMouse(minDist(), maxDist(), (move?CAMH_MOVE_XZ:0) | (rotate_move?CAMH_MOVE:0) | CAMH_NO_VEL_UPDATE | CAMH_NO_SET);
  936. if(fpp()) cam.dist=temp;
  937. }
  938. VecD d=cam.at-at;
  939. if(lock())REPA(view)if(&view[i]!=_focus)view[i].camera+=d;
  940. }
  941. // finalize cameras
  942. REPAO(view).camera.setSpherical().updateVelocities(CAM_ATTACH_FREE);
  943. // set main view
  944. setViewportCamera();
  945. }
  946. /******************************************************************************/
  947. } // Edit
  948. /******************************************************************************/
  949. void operator+=(GuiObj &gui_obj, Edit::Viewport4 &child)
  950. {
  951. REPA(child. view )gui_obj+=child. view [i].viewport;
  952. REPA(child._cube )gui_obj+=child._cube [i];
  953. REPA(child._zoom )gui_obj+=child._zoom [i];
  954. REPA(child._dpad )gui_obj+=child._dpad [i];
  955. REPA(child._dpady )gui_obj+=child._dpady [i];
  956. REPA(child._apad )gui_obj+=child._apad [i];
  957. REPA(child._apady )gui_obj+=child._apady [i];
  958. REPA(child._drag )gui_obj+=child._drag [i];
  959. REPA(child._dragy )gui_obj+=child._dragy [i];
  960. REPA(child._arrows)gui_obj+=child._arrows[i];
  961. }
  962. void operator-=(GuiObj &gui_obj, Edit::Viewport4 &child)
  963. {
  964. REPA(child. view )gui_obj-=child. view [i].viewport;
  965. REPA(child._cube )gui_obj-=child._cube [i];
  966. REPA(child._zoom )gui_obj-=child._zoom [i];
  967. REPA(child._dpad )gui_obj-=child._dpad [i];
  968. REPA(child._dpady )gui_obj-=child._dpady [i];
  969. REPA(child._apad )gui_obj-=child._apad [i];
  970. REPA(child._apady )gui_obj-=child._apady [i];
  971. REPA(child._drag )gui_obj-=child._drag [i];
  972. REPA(child._dragy )gui_obj-=child._dragy [i];
  973. REPA(child._arrows)gui_obj-=child._arrows[i];
  974. }
  975. /******************************************************************************/
  976. } // EE
  977. /******************************************************************************/