ccIncludeGL.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. //##########################################################################
  2. //# #
  3. //# CLOUDCOMPARE #
  4. //# #
  5. //# This program is free software; you can redistribute it and/or modify #
  6. //# it under the terms of the GNU General Public License as published by #
  7. //# the Free Software Foundation; version 2 or later of the License. #
  8. //# #
  9. //# This program is distributed in the hope that it will be useful, #
  10. //# but WITHOUT ANY WARRANTY; without even the implied warranty of #
  11. //# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  12. //# GNU General Public License for more details. #
  13. //# #
  14. //# COPYRIGHT: EDF R&D / TELECOM ParisTech (ENST-TSI) #
  15. //# #
  16. //##########################################################################
  17. #ifndef CC_INCLUDE_GL_HEADER
  18. #define CC_INCLUDE_GL_HEADER
  19. #include <cmath>
  20. //CCCoreLib
  21. #include <CCMath.h>
  22. //Local
  23. #include "ccGLMatrix.h"
  24. #include "ccColorTypes.h"
  25. //Qt
  26. #include <QOpenGLFunctions_2_1>
  27. //! Shortcuts to OpenGL commands independent on the input type
  28. class ccGL
  29. {
  30. public:
  31. //type-less glVertex3Xv call (X=f,d)
  32. static inline void Vertex3v(QOpenGLFunctions_2_1* glFunc, const float* v) { glFunc->glVertex3fv(v); }
  33. static inline void Vertex3v(QOpenGLFunctions_2_1* glFunc, const double* v) { glFunc->glVertex3dv(v); }
  34. //type-less glVertex3X call (X=f,d)
  35. static inline void Vertex3(QOpenGLFunctions_2_1* glFunc, float x, float y, float z) { glFunc->glVertex3f(x, y, z); }
  36. static inline void Vertex3(QOpenGLFunctions_2_1* glFunc, double x, double y, double z) { glFunc->glVertex3d(x, y, z); }
  37. //type-less glScaleX call (X=f,d)
  38. static inline void Scale(QOpenGLFunctions_2_1* glFunc, float x, float y, float z) { glFunc->glScalef(x, y, z); }
  39. static inline void Scale(QOpenGLFunctions_2_1* glFunc, double x, double y, double z) { glFunc->glScaled(x, y, z); }
  40. //type-less glNormal3Xv call (X=f,d)
  41. static inline void Normal3v(QOpenGLFunctions_2_1* glFunc, const float* v) { glFunc->glNormal3fv(v); }
  42. static inline void Normal3v(QOpenGLFunctions_2_1* glFunc, const double* v) { glFunc->glNormal3dv(v); }
  43. //type-less glRotateX call (X=f,d)
  44. static inline void Rotate(QOpenGLFunctions_2_1* glFunc, float a, float x, float y, float z) { glFunc->glRotatef(a, x, y, z); }
  45. static inline void Rotate(QOpenGLFunctions_2_1* glFunc, double a, double x, double y, double z) { glFunc->glRotated(a, x, y, z); }
  46. //type-less glTranslateX call (X=f,d)
  47. static inline void Translate(QOpenGLFunctions_2_1* glFunc, float x, float y, float z) { glFunc->glTranslatef(x, y, z); }
  48. static inline void Translate(QOpenGLFunctions_2_1* glFunc, double x, double y, double z) { glFunc->glTranslated(x, y, z); }
  49. //type-less glColor3Xv call (X=f,ub)
  50. static inline void Color3v(QOpenGLFunctions_2_1* glFunc, const unsigned char* v) { glFunc->glColor3ubv(v); }
  51. static inline void Color3v(QOpenGLFunctions_2_1* glFunc, const float* v) { glFunc->glColor3fv(v); }
  52. //type-less glColor4Xv call (X=f,ub)
  53. static inline void Color4v(QOpenGLFunctions_2_1* glFunc, const unsigned char* v) { glFunc->glColor4ubv(v); }
  54. static inline void Color4v(QOpenGLFunctions_2_1* glFunc, const float* v) { glFunc->glColor4fv(v); }
  55. //ccColor dedicated calls
  56. static inline void Color(QOpenGLFunctions_2_1* glFunc, const ccColor::RgbaTpl<unsigned char>& col) { glFunc->glColor4ubv(col.rgba); }
  57. static inline void Color(QOpenGLFunctions_2_1* glFunc, const ccColor::RgbaTpl<float>& col) { glFunc->glColor4fv(col.rgba); }
  58. static inline void Color(QOpenGLFunctions_2_1* glFunc, const ccColor::RgbTpl<unsigned char>& col) { glFunc->glColor3ubv(col.rgb); }
  59. static inline void Color(QOpenGLFunctions_2_1* glFunc, const ccColor::RgbTpl<float>& col) { glFunc->glColor3fv(col.rgb); }
  60. public: //GLU equivalent methods
  61. static ccGLMatrixd Frustum(double left, double right, double bottom, double top, double znear, double zfar)
  62. {
  63. // invalid for: n<=0, f<=0, l=r, b=t, or n=f
  64. assert(znear > 0);
  65. assert(zfar > 0);
  66. assert(left != right);
  67. assert(bottom != top);
  68. assert(znear != zfar);
  69. ccGLMatrixd outMatrix;
  70. {
  71. double* matrix = outMatrix.data();
  72. double dX = right - left;
  73. double dY = top - bottom;
  74. double dZ = zfar - znear;
  75. matrix[0] = (2 * znear) / dX;
  76. matrix[1] = 0.0;
  77. matrix[2] = 0.0;
  78. matrix[3] = 0.0;
  79. matrix[4] = 0.0;
  80. matrix[5] = (2 * znear) / dY;
  81. matrix[6] = 0.0;
  82. matrix[7] = 0.0;
  83. matrix[8] = (right + left) / dX;
  84. matrix[9] = (top + bottom) / dY;
  85. matrix[10] = -(zfar + znear) / dZ;
  86. matrix[11] = -1.0;
  87. matrix[12] = 0.0;
  88. matrix[13] = 0.0;
  89. matrix[14] = (-2 * zfar*znear) / dZ;
  90. matrix[15] = 0.0;
  91. }
  92. return outMatrix;
  93. }
  94. static ccGLMatrixd Ortho( double left, double right,
  95. double bottom, double top,
  96. double nearVal, double farVal )
  97. {
  98. ccGLMatrixd matrix;
  99. double dx = (right - left);
  100. double dy = (top - bottom);
  101. double dz = (farVal - nearVal);
  102. if (dx != 0 && dy != 0 && dz != 0)
  103. {
  104. double* mat = matrix.data();
  105. // set OpenGL perspective projection matrix
  106. mat[0] = 2.0 / dx;
  107. mat[1] = 0;
  108. mat[2] = 0;
  109. mat[3] = 0;
  110. mat[4] = 0;
  111. mat[5] = 2.0 / dy;
  112. mat[6] = 0;
  113. mat[7] = 0;
  114. mat[8] = 0;
  115. mat[9] = 0;
  116. mat[10] = -2.0 / dz;
  117. mat[11] = 0;
  118. mat[12] = -(right + left) / dx;
  119. mat[13] = -(top + bottom) / dy;
  120. mat[14] = -(farVal + nearVal) / dz;
  121. mat[15] = 1.0;
  122. }
  123. else
  124. {
  125. matrix.toIdentity();
  126. }
  127. return matrix;
  128. }
  129. //inspired from http://www.songho.ca/opengl/gl_projectionmatrix.html
  130. static ccGLMatrixd Ortho(double w, double h, double d)
  131. {
  132. ccGLMatrixd matrix;
  133. if (w != 0 && h != 0 && d != 0)
  134. {
  135. double* mat = matrix.data();
  136. mat[0] = 1.0 / w;
  137. mat[1] = 0.0;
  138. mat[2] = 0.0;
  139. mat[3] = 0.0;
  140. mat[4] = 0.0;
  141. mat[5] = 1.0 / h;
  142. mat[6] = 0.0;
  143. mat[7] = 0.0;
  144. mat[8] = 0.0;
  145. mat[9] = 0.0;
  146. mat[10] = - 1.0 / d;
  147. mat[11] = 0.0;
  148. mat[12] = 0.0;
  149. mat[13] = 0.0;
  150. mat[14] = 0.0;
  151. mat[15] = 1.0;
  152. }
  153. else
  154. {
  155. matrix.toIdentity();
  156. }
  157. return matrix;
  158. }
  159. template <typename iType, typename oType>
  160. static bool Project(const Vector3Tpl<iType>& input3D,
  161. const oType* modelview,
  162. const oType* projection,
  163. const int* viewport,
  164. Vector3Tpl<oType>& output2D,
  165. bool* inFrustum = nullptr,
  166. const double* nearClippingDepth = nullptr,
  167. const double* farClippingDepth = nullptr)
  168. {
  169. //Modelview transform
  170. Tuple4Tpl<oType> Pm;
  171. {
  172. Pm.x = static_cast<oType>(modelview[0]*input3D.x + modelview[4]*input3D.y + modelview[ 8]*input3D.z + modelview[12]);
  173. Pm.y = static_cast<oType>(modelview[1]*input3D.x + modelview[5]*input3D.y + modelview[ 9]*input3D.z + modelview[13]);
  174. Pm.z = static_cast<oType>(modelview[2]*input3D.x + modelview[6]*input3D.y + modelview[10]*input3D.z + modelview[14]);
  175. Pm.w = static_cast<oType>(modelview[3]*input3D.x + modelview[7]*input3D.y + modelview[11]*input3D.z + modelview[15]);
  176. };
  177. //Projection transform
  178. Tuple4Tpl<oType> Pp;
  179. {
  180. Pp.x = static_cast<oType>(projection[0]*Pm.x + projection[4]*Pm.y + projection[ 8]*Pm.z + projection[12]*Pm.w);
  181. Pp.y = static_cast<oType>(projection[1]*Pm.x + projection[5]*Pm.y + projection[ 9]*Pm.z + projection[13]*Pm.w);
  182. Pp.z = static_cast<oType>(projection[2]*Pm.x + projection[6]*Pm.y + projection[10]*Pm.z + projection[14]*Pm.w);
  183. Pp.w = static_cast<oType>(projection[3]*Pm.x + projection[7]*Pm.y + projection[11]*Pm.z + projection[15]*Pm.w);
  184. };
  185. //The result normalizes between -1 and 1
  186. if (Pp.w == 0.0)
  187. {
  188. return false;
  189. }
  190. //Perspective division
  191. Pp.x /= Pp.w;
  192. Pp.y /= Pp.w;
  193. Pp.z /= Pp.w;
  194. if (inFrustum)
  195. {
  196. //Check if the point is inside the frustum
  197. if (nearClippingDepth && -Pm.z < *nearClippingDepth)
  198. *inFrustum = false;
  199. else if (farClippingDepth && -Pm.z > *farClippingDepth)
  200. *inFrustum = false;
  201. else
  202. *inFrustum = (std::abs(Pp.x) <= 1.0 && std::abs(Pp.y) <= 1.0 && std::abs(Pp.z) <= 1.0);
  203. }
  204. //Window coordinates
  205. //Map x, y to range 0-1
  206. output2D.x = (1.0 + Pp.x) / 2 * viewport[2] + viewport[0];
  207. output2D.y = (1.0 + Pp.y) / 2 * viewport[3] + viewport[1];
  208. //This is only correct when glDepthRange(0.0, 1.0)
  209. output2D.z = (1.0 + Pp.z) / 2; //Between 0 and 1
  210. return true;
  211. }
  212. inline static double MAT(const double* m, int r, int c) { return m[c * 4 + r]; }
  213. inline static float MAT(const float* m, int r, int c) { return m[c * 4 + r]; }
  214. inline static double& MAT(double* m, int r, int c) { return m[c * 4 + r]; }
  215. inline static float& MAT(float* m, int r, int c) { return m[c * 4 + r]; }
  216. template <typename Type>
  217. static bool InvertMatrix(const Type* m, Type* out)
  218. {
  219. Type wtmp[4][8];
  220. Type m0, m1, m2, m3, s;
  221. Type *r0, *r1, *r2, *r3;
  222. r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
  223. r0[0] = MAT(m, 0, 0); r0[1] = MAT(m, 0, 1);
  224. r0[2] = MAT(m, 0, 2); r0[3] = MAT(m, 0, 3);
  225. r0[4] = 1.0; r0[5] = r0[6] = r0[7] = 0.0;
  226. r1[0] = MAT(m, 1, 0); r1[1] = MAT(m, 1, 1);
  227. r1[2] = MAT(m, 1, 2); r1[3] = MAT(m, 1, 3);
  228. r1[5] = 1.0; r1[4] = r1[6] = r1[7] = 0.0;
  229. r2[0] = MAT(m, 2, 0); r2[1] = MAT(m, 2, 1);
  230. r2[2] = MAT(m, 2, 2); r2[3] = MAT(m, 2, 3);
  231. r2[6] = 1.0; r2[4] = r2[5] = r2[7] = 0.0;
  232. r3[0] = MAT(m, 3, 0); r3[1] = MAT(m, 3, 1);
  233. r3[2] = MAT(m, 3, 2); r3[3] = MAT(m, 3, 3);
  234. r3[7] = 1.0; r3[4] = r3[5] = r3[6] = 0.0;
  235. //choose pivot - or die
  236. if (std::abs(r3[0]) > std::abs(r2[0]))
  237. std::swap(r3, r2);
  238. if (std::abs(r2[0]) > std::abs(r1[0]))
  239. std::swap(r2, r1);
  240. if (std::abs(r1[0]) > std::abs(r0[0]))
  241. std::swap(r1, r0);
  242. if (0.0 == r0[0])
  243. return false;
  244. //eliminate first variable
  245. m1 = r1[0] / r0[0];
  246. m2 = r2[0] / r0[0];
  247. m3 = r3[0] / r0[0];
  248. s = r0[1];
  249. r1[1] -= m1 * s;
  250. r2[1] -= m2 * s;
  251. r3[1] -= m3 * s;
  252. s = r0[2];
  253. r1[2] -= m1 * s;
  254. r2[2] -= m2 * s;
  255. r3[2] -= m3 * s;
  256. s = r0[3];
  257. r1[3] -= m1 * s;
  258. r2[3] -= m2 * s;
  259. r3[3] -= m3 * s;
  260. s = r0[4];
  261. if (s != 0.0)
  262. {
  263. r1[4] -= m1 * s;
  264. r2[4] -= m2 * s;
  265. r3[4] -= m3 * s;
  266. }
  267. s = r0[5];
  268. if (s != 0.0)
  269. {
  270. r1[5] -= m1 * s;
  271. r2[5] -= m2 * s;
  272. r3[5] -= m3 * s;
  273. }
  274. s = r0[6];
  275. if (s != 0.0)
  276. {
  277. r1[6] -= m1 * s;
  278. r2[6] -= m2 * s;
  279. r3[6] -= m3 * s;
  280. }
  281. s = r0[7];
  282. if (s != 0.0)
  283. {
  284. r1[7] -= m1 * s;
  285. r2[7] -= m2 * s;
  286. r3[7] -= m3 * s;
  287. }
  288. //choose pivot - or die
  289. if (std::abs(r3[1]) > std::abs(r2[1]))
  290. std::swap(r3, r2);
  291. if (std::abs(r2[1]) > std::abs(r1[1]))
  292. std::swap(r2, r1);
  293. if (0.0 == r1[1])
  294. return false;
  295. //eliminate second variable
  296. m2 = r2[1] / r1[1];
  297. m3 = r3[1] / r1[1];
  298. r2[2] -= m2 * r1[2];
  299. r3[2] -= m3 * r1[2];
  300. r2[3] -= m2 * r1[3];
  301. r3[3] -= m3 * r1[3];
  302. s = r1[4];
  303. if (0.0 != s)
  304. {
  305. r2[4] -= m2 * s;
  306. r3[4] -= m3 * s;
  307. }
  308. s = r1[5];
  309. if (0.0 != s)
  310. {
  311. r2[5] -= m2 * s;
  312. r3[5] -= m3 * s;
  313. }
  314. s = r1[6];
  315. if (0.0 != s)
  316. {
  317. r2[6] -= m2 * s;
  318. r3[6] -= m3 * s;
  319. }
  320. s = r1[7];
  321. if (0.0 != s)
  322. {
  323. r2[7] -= m2 * s;
  324. r3[7] -= m3 * s;
  325. }
  326. //choose pivot - or die
  327. if (std::abs(r3[2]) > std::abs(r2[2]))
  328. std::swap(r3, r2);
  329. if (0.0 == r2[2])
  330. return false;
  331. //eliminate third variable
  332. m3 = r3[2] / r2[2];
  333. r3[3] -= m3 * r2[3]; r3[4] -= m3 * r2[4];
  334. r3[5] -= m3 * r2[5]; r3[6] -= m3 * r2[6]; r3[7] -= m3 * r2[7];
  335. //last check
  336. if (0.0 == r3[3])
  337. return false;
  338. s = 1.0 / r3[3]; //now back substitute row 3
  339. r3[4] *= s;
  340. r3[5] *= s;
  341. r3[6] *= s;
  342. r3[7] *= s;
  343. m2 = r2[3]; //now back substitute row 2
  344. s = 1.0 / r2[2];
  345. r2[4] = s * (r2[4] - r3[4] * m2); r2[5] = s * (r2[5] - r3[5] * m2);
  346. r2[6] = s * (r2[6] - r3[6] * m2); r2[7] = s * (r2[7] - r3[7] * m2);
  347. m1 = r1[3];
  348. r1[4] -= r3[4] * m1; r1[5] -= r3[5] * m1;
  349. r1[6] -= r3[6] * m1; r1[7] -= r3[7] * m1;
  350. m0 = r0[3];
  351. r0[4] -= r3[4] * m0; r0[5] -= r3[5] * m0;
  352. r0[6] -= r3[6] * m0; r0[7] -= r3[7] * m0;
  353. m1 = r1[2]; //now back substitute row 1
  354. s = 1.0 / r1[1];
  355. r1[4] = s * (r1[4] - r2[4] * m1); r1[5] = s * (r1[5] - r2[5] * m1);
  356. r1[6] = s * (r1[6] - r2[6] * m1); r1[7] = s * (r1[7] - r2[7] * m1);
  357. m0 = r0[2];
  358. r0[4] -= r2[4] * m0; r0[5] -= r2[5] * m0;
  359. r0[6] -= r2[6] * m0; r0[7] -= r2[7] * m0;
  360. m0 = r0[1]; //now back substitute row 0
  361. s = 1.0 / r0[0];
  362. r0[4] = s * (r0[4] - r1[4] * m0); r0[5] = s * (r0[5] - r1[5] * m0);
  363. r0[6] = s * (r0[6] - r1[6] * m0); r0[7] = s * (r0[7] - r1[7] * m0);
  364. MAT(out, 0, 0) = r0[4];
  365. MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
  366. MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
  367. MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
  368. MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
  369. MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
  370. MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
  371. MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
  372. MAT(out, 3, 3) = r3[7];
  373. return true;
  374. }
  375. template <typename iType, typename oType>
  376. static bool Unproject(const Vector3Tpl<iType>& input2D, const oType* modelview, const oType* projection, const int* viewport, Vector3Tpl<oType>& output3D)
  377. {
  378. //compute projection x modelview
  379. ccGLMatrixTpl<oType> A = ccGLMatrixTpl<oType>(projection) * ccGLMatrixTpl<oType>(modelview);
  380. ccGLMatrixTpl<oType> m;
  381. if (!InvertMatrix(A.data(), m.data()))
  382. {
  383. return false;
  384. }
  385. ccGLMatrixTpl<oType> mA = m * A;
  386. //Transformation of normalized coordinates between -1 and 1
  387. Tuple4Tpl<oType> in;
  388. in.x = static_cast<oType>((input2D.x - static_cast<iType>(viewport[0])) / viewport[2] * 2 - 1);
  389. in.y = static_cast<oType>((input2D.y - static_cast<iType>(viewport[1])) / viewport[3] * 2 - 1);
  390. in.z = static_cast<oType>(2 * input2D.z - 1);
  391. in.w = 1;
  392. //Objects coordinates
  393. Tuple4Tpl<oType> out = m * in;
  394. if (out.w == 0)
  395. {
  396. return false;
  397. }
  398. output3D = Vector3Tpl<oType>(out.u) / out.w;
  399. return true;
  400. }
  401. static void PickMatrix(double x, double y, double width, double height, int viewport[4], double m[16])
  402. {
  403. double sx = viewport[2] / width;
  404. double sy = viewport[3] / height;
  405. double tx = (viewport[2] + 2.0 * (viewport[0] - x)) / width;
  406. double ty = (viewport[3] + 2.0 * (viewport[1] - y)) / height;
  407. MAT(m, 0, 0) = sx;
  408. MAT(m, 0, 1) = 0.0;
  409. MAT(m, 0, 2) = 0.0;
  410. MAT(m, 0, 3) = tx;
  411. MAT(m, 1, 0) = 0.0;
  412. MAT(m, 1, 1) = sy;
  413. MAT(m, 1, 2) = 0.0;
  414. MAT(m, 1, 3) = ty;
  415. MAT(m, 2, 0) = 0.0;
  416. MAT(m, 2, 1) = 0.0;
  417. MAT(m, 2, 2) = 1.0;
  418. MAT(m, 2, 3) = 0.0;
  419. MAT(m, 3, 0) = 0.0;
  420. MAT(m, 3, 1) = 0.0;
  421. MAT(m, 3, 2) = 0.0;
  422. MAT(m, 3, 3) = 1.0;
  423. }
  424. };
  425. #endif //CC_INCLUDE_GL_HEADER