Engine.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. #include "Engine.hpp"
  2. #include <libslic3r/Utils.hpp>
  3. #include <libslic3r/SLAPrint.hpp>
  4. #include <GL/glew.h>
  5. #include <boost/log/trivial.hpp>
  6. #ifndef NDEBUG
  7. #define HAS_GLSAFE
  8. #endif
  9. #ifdef HAS_GLSAFE
  10. extern void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char *function_name);
  11. inline void glAssertRecentCall() { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); }
  12. #define glsafe(cmd) do { cmd; glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false)
  13. #define glcheck() do { glAssertRecentCallImpl(__FILE__, __LINE__, __FUNCTION__); } while (false)
  14. void glAssertRecentCallImpl(const char *file_name, unsigned int line, const char *function_name)
  15. {
  16. GLenum err = glGetError();
  17. if (err == GL_NO_ERROR)
  18. return;
  19. const char *sErr = 0;
  20. switch (err) {
  21. case GL_INVALID_ENUM: sErr = "Invalid Enum"; break;
  22. case GL_INVALID_VALUE: sErr = "Invalid Value"; break;
  23. // be aware that GL_INVALID_OPERATION is generated if glGetError is executed between the execution of glBegin and the corresponding execution of glEnd
  24. case GL_INVALID_OPERATION: sErr = "Invalid Operation"; break;
  25. case GL_STACK_OVERFLOW: sErr = "Stack Overflow"; break;
  26. case GL_STACK_UNDERFLOW: sErr = "Stack Underflow"; break;
  27. case GL_OUT_OF_MEMORY: sErr = "Out Of Memory"; break;
  28. default: sErr = "Unknown"; break;
  29. }
  30. BOOST_LOG_TRIVIAL(error) << "OpenGL error in " << file_name << ":" << line << ", function " << function_name << "() : " << (int)err << " - " << sErr;
  31. assert(false);
  32. }
  33. #else
  34. inline void glAssertRecentCall() { }
  35. #define glsafe(cmd) cmd
  36. #define glcheck()
  37. #endif
  38. namespace Slic3r { namespace GL {
  39. Scene::Scene() = default;
  40. Scene::~Scene() = default;
  41. void CSGDisplay::render_scene()
  42. {
  43. GLfloat color[] = {1.f, 1.f, 0.f, 0.f};
  44. glsafe(::glColor4fv(color));
  45. if (m_csgsettings.is_enabled()) {
  46. OpenCSG::render(m_scene_cache.primitives_csg);
  47. glDepthFunc(GL_EQUAL);
  48. }
  49. for (auto& p : m_scene_cache.primitives_csg) p->render();
  50. if (m_csgsettings.is_enabled()) glDepthFunc(GL_LESS);
  51. for (auto& p : m_scene_cache.primitives_free) p->render();
  52. glFlush();
  53. }
  54. void Scene::set_print(std::unique_ptr<SLAPrint> &&print)
  55. {
  56. m_print = std::move(print);
  57. // Notify displays
  58. call(&Listener::on_scene_updated, m_listeners, *this);
  59. }
  60. BoundingBoxf3 Scene::get_bounding_box() const
  61. {
  62. return m_print->model().bounding_box();
  63. }
  64. void CSGDisplay::SceneCache::clear()
  65. {
  66. primitives_csg.clear();
  67. primitives_free.clear();
  68. primitives.clear();
  69. }
  70. std::shared_ptr<Primitive> CSGDisplay::SceneCache::add_mesh(const TriangleMesh &mesh)
  71. {
  72. auto p = std::make_shared<Primitive>();
  73. p->load_mesh(mesh);
  74. primitives.emplace_back(p);
  75. primitives_free.emplace_back(p.get());
  76. return p;
  77. }
  78. std::shared_ptr<Primitive> CSGDisplay::SceneCache::add_mesh(const TriangleMesh &mesh,
  79. OpenCSG::Operation o,
  80. unsigned c)
  81. {
  82. auto p = std::make_shared<Primitive>(o, c);
  83. p->load_mesh(mesh);
  84. primitives.emplace_back(p);
  85. primitives_csg.emplace_back(p.get());
  86. return p;
  87. }
  88. void IndexedVertexArray::push_geometry(float x, float y, float z, float nx, float ny, float nz)
  89. {
  90. assert(this->vertices_and_normals_interleaved_VBO_id == 0);
  91. if (this->vertices_and_normals_interleaved_VBO_id != 0)
  92. return;
  93. if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity())
  94. this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6));
  95. this->vertices_and_normals_interleaved.emplace_back(nx);
  96. this->vertices_and_normals_interleaved.emplace_back(ny);
  97. this->vertices_and_normals_interleaved.emplace_back(nz);
  98. this->vertices_and_normals_interleaved.emplace_back(x);
  99. this->vertices_and_normals_interleaved.emplace_back(y);
  100. this->vertices_and_normals_interleaved.emplace_back(z);
  101. this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size();
  102. }
  103. void IndexedVertexArray::push_triangle(int idx1, int idx2, int idx3) {
  104. assert(this->vertices_and_normals_interleaved_VBO_id == 0);
  105. if (this->vertices_and_normals_interleaved_VBO_id != 0)
  106. return;
  107. if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity())
  108. this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3));
  109. this->triangle_indices.emplace_back(idx1);
  110. this->triangle_indices.emplace_back(idx2);
  111. this->triangle_indices.emplace_back(idx3);
  112. this->triangle_indices_size = this->triangle_indices.size();
  113. }
  114. void IndexedVertexArray::load_mesh(const TriangleMesh &mesh)
  115. {
  116. assert(triangle_indices.empty() && vertices_and_normals_interleaved_size == 0);
  117. assert(quad_indices.empty() && triangle_indices_size == 0);
  118. assert(vertices_and_normals_interleaved.size() % 6 == 0 && quad_indices_size == vertices_and_normals_interleaved.size());
  119. this->vertices_and_normals_interleaved.reserve(this->vertices_and_normals_interleaved.size() + 3 * 3 * 2 * mesh.facets_count());
  120. int vertices_count = 0;
  121. for (size_t i = 0; i < mesh.facets_count(); ++i) {
  122. const stl_facet &facet = mesh.stl.facet_start[i];
  123. for (int j = 0; j < 3; ++j)
  124. this->push_geometry(facet.vertex[j](0), facet.vertex[j](1), facet.vertex[j](2), facet.normal(0), facet.normal(1), facet.normal(2));
  125. this->push_triangle(vertices_count, vertices_count + 1, vertices_count + 2);
  126. vertices_count += 3;
  127. }
  128. }
  129. void IndexedVertexArray::finalize_geometry()
  130. {
  131. assert(this->vertices_and_normals_interleaved_VBO_id == 0);
  132. assert(this->triangle_indices_VBO_id == 0);
  133. assert(this->quad_indices_VBO_id == 0);
  134. if (!this->vertices_and_normals_interleaved.empty()) {
  135. glsafe(
  136. ::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id));
  137. glsafe(::glBindBuffer(GL_ARRAY_BUFFER,
  138. this->vertices_and_normals_interleaved_VBO_id));
  139. glsafe(
  140. ::glBufferData(GL_ARRAY_BUFFER,
  141. GLsizeiptr(
  142. this->vertices_and_normals_interleaved.size() *
  143. 4),
  144. this->vertices_and_normals_interleaved.data(),
  145. GL_STATIC_DRAW));
  146. glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
  147. this->vertices_and_normals_interleaved.clear();
  148. }
  149. if (!this->triangle_indices.empty()) {
  150. glsafe(::glGenBuffers(1, &this->triangle_indices_VBO_id));
  151. glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
  152. this->triangle_indices_VBO_id));
  153. glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER,
  154. GLsizeiptr(this->triangle_indices.size() * 4),
  155. this->triangle_indices.data(), GL_STATIC_DRAW));
  156. glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
  157. this->triangle_indices.clear();
  158. }
  159. if (!this->quad_indices.empty()) {
  160. glsafe(::glGenBuffers(1, &this->quad_indices_VBO_id));
  161. glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
  162. this->quad_indices_VBO_id));
  163. glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER,
  164. GLsizeiptr(this->quad_indices.size() * 4),
  165. this->quad_indices.data(), GL_STATIC_DRAW));
  166. glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
  167. this->quad_indices.clear();
  168. }
  169. }
  170. void IndexedVertexArray::release_geometry()
  171. {
  172. if (this->vertices_and_normals_interleaved_VBO_id) {
  173. glsafe(
  174. ::glDeleteBuffers(1,
  175. &this->vertices_and_normals_interleaved_VBO_id));
  176. this->vertices_and_normals_interleaved_VBO_id = 0;
  177. }
  178. if (this->triangle_indices_VBO_id) {
  179. glsafe(::glDeleteBuffers(1, &this->triangle_indices_VBO_id));
  180. this->triangle_indices_VBO_id = 0;
  181. }
  182. if (this->quad_indices_VBO_id) {
  183. glsafe(::glDeleteBuffers(1, &this->quad_indices_VBO_id));
  184. this->quad_indices_VBO_id = 0;
  185. }
  186. this->clear();
  187. }
  188. void IndexedVertexArray::render() const
  189. {
  190. assert(this->vertices_and_normals_interleaved_VBO_id != 0);
  191. assert(this->triangle_indices_VBO_id != 0 ||
  192. this->quad_indices_VBO_id != 0);
  193. glsafe(::glBindBuffer(GL_ARRAY_BUFFER,
  194. this->vertices_and_normals_interleaved_VBO_id));
  195. glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float),
  196. reinterpret_cast<const void *>(3 * sizeof(float))));
  197. glsafe(::glNormalPointer(GL_FLOAT, 6 * sizeof(float), nullptr));
  198. glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
  199. glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
  200. // Render using the Vertex Buffer Objects.
  201. if (this->triangle_indices_size > 0) {
  202. glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
  203. this->triangle_indices_VBO_id));
  204. glsafe(::glDrawElements(GL_TRIANGLES,
  205. GLsizei(this->triangle_indices_size),
  206. GL_UNSIGNED_INT, nullptr));
  207. glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
  208. }
  209. if (this->quad_indices_size > 0) {
  210. glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
  211. this->quad_indices_VBO_id));
  212. glsafe(::glDrawElements(GL_QUADS, GLsizei(this->quad_indices_size),
  213. GL_UNSIGNED_INT, nullptr));
  214. glsafe(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
  215. }
  216. glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
  217. glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
  218. glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
  219. }
  220. void IndexedVertexArray::clear() {
  221. this->vertices_and_normals_interleaved.clear();
  222. this->triangle_indices.clear();
  223. this->quad_indices.clear();
  224. vertices_and_normals_interleaved_size = 0;
  225. triangle_indices_size = 0;
  226. quad_indices_size = 0;
  227. }
  228. void IndexedVertexArray::shrink_to_fit() {
  229. this->vertices_and_normals_interleaved.shrink_to_fit();
  230. this->triangle_indices.shrink_to_fit();
  231. this->quad_indices.shrink_to_fit();
  232. }
  233. void Volume::render()
  234. {
  235. glsafe(::glPushMatrix());
  236. glsafe(::glMultMatrixd(m_trafo.get_matrix().data()));
  237. m_geom.render();
  238. glsafe(::glPopMatrix());
  239. }
  240. void Display::clear_screen()
  241. {
  242. glViewport(0, 0, GLsizei(m_size.x()), GLsizei(m_size.y()));
  243. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  244. }
  245. Display::~Display()
  246. {
  247. OpenCSG::freeResources();
  248. }
  249. void Display::set_active(long width, long height)
  250. {
  251. if (!m_initialized) {
  252. glewInit();
  253. m_initialized = true;
  254. }
  255. // gray background
  256. glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
  257. // Enable two OpenGL lights
  258. GLfloat light_diffuse[] = { 1.0f, 1.0f, 0.0f, 1.0f}; // White diffuse light
  259. GLfloat light_position0[] = {-1.0f, -1.0f, -1.0f, 0.0f}; // Infinite light location
  260. GLfloat light_position1[] = { 1.0f, 1.0f, 1.0f, 0.0f}; // Infinite light location
  261. glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
  262. glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
  263. glEnable(GL_LIGHT0);
  264. glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
  265. glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
  266. glEnable(GL_LIGHT1);
  267. glEnable(GL_LIGHTING);
  268. glEnable(GL_NORMALIZE);
  269. // Use depth buffering for hidden surface elimination
  270. glEnable(GL_DEPTH_TEST);
  271. glEnable(GL_STENCIL_TEST);
  272. set_screen_size(width, height);
  273. }
  274. void Display::set_screen_size(long width, long height)
  275. {
  276. if (m_size.x() != width || m_size.y() != height)
  277. m_camera->set_screen(width, height);
  278. m_size = {width, height};
  279. }
  280. void Display::repaint()
  281. {
  282. clear_screen();
  283. m_camera->view();
  284. render_scene();
  285. m_fps_counter.update();
  286. swap_buffers();
  287. }
  288. void Controller::on_scene_updated(const Scene &scene)
  289. {
  290. const SLAPrint *print = scene.get_print();
  291. if (!print) return;
  292. auto bb = scene.get_bounding_box();
  293. double d = std::max(std::max(bb.size().x(), bb.size().y()), bb.size().z());
  294. m_wheel_pos = long(2 * d);
  295. call_cameras(&Camera::set_zoom, m_wheel_pos);
  296. call(&Display::on_scene_updated, m_displays, scene);
  297. }
  298. void Controller::on_scroll(long v, long d, MouseInput::WheelAxis /*wa*/)
  299. {
  300. m_wheel_pos += v / d;
  301. call_cameras(&Camera::set_zoom, m_wheel_pos);
  302. call(&Display::repaint, m_displays);
  303. }
  304. void Controller::on_moved_to(long x, long y)
  305. {
  306. if (m_left_btn) {
  307. call_cameras(&Camera::rotate, (Vec2i{x, y} - m_mouse_pos).cast<float>());
  308. call(&Display::repaint, m_displays);
  309. }
  310. m_mouse_pos = {x, y};
  311. }
  312. void CSGDisplay::apply_csgsettings(const CSGSettings &settings)
  313. {
  314. using namespace OpenCSG;
  315. bool needupdate = m_csgsettings.get_convexity() != settings.get_convexity();
  316. m_csgsettings = settings;
  317. setOption(AlgorithmSetting, m_csgsettings.get_algo());
  318. setOption(DepthComplexitySetting, m_csgsettings.get_depth_algo());
  319. setOption(DepthBoundsOptimization, m_csgsettings.get_optimization());
  320. if (needupdate) {
  321. for (OpenCSG::Primitive * p : m_scene_cache.primitives_csg)
  322. if (p->getConvexity() > 1)
  323. p->setConvexity(m_csgsettings.get_convexity());
  324. }
  325. }
  326. void CSGDisplay::on_scene_updated(const Scene &scene)
  327. {
  328. const SLAPrint *print = scene.get_print();
  329. if (!print) return;
  330. m_scene_cache.clear();
  331. for (const SLAPrintObject *po : print->objects()) {
  332. const ModelObject *mo = po->model_object();
  333. TriangleMesh msh = mo->raw_mesh();
  334. sla::DrainHoles holedata = mo->sla_drain_holes;
  335. for (const ModelInstance *mi : mo->instances) {
  336. TriangleMesh mshinst = msh;
  337. auto interior = po->hollowed_interior_mesh();
  338. interior.transform(po->trafo().inverse());
  339. mshinst.merge(interior);
  340. mi->transform_mesh(&mshinst);
  341. auto bb = mshinst.bounding_box();
  342. auto center = bb.center().cast<float>();
  343. mshinst.translate(-center);
  344. m_scene_cache.add_mesh(mshinst, OpenCSG::Intersection,
  345. m_csgsettings.get_convexity());
  346. }
  347. for (const sla::DrainHole &holept : holedata) {
  348. TriangleMesh holemesh = sla::to_triangle_mesh(holept.to_mesh());
  349. m_scene_cache.add_mesh(holemesh, OpenCSG::Subtraction, 1);
  350. }
  351. }
  352. repaint();
  353. }
  354. void Camera::view()
  355. {
  356. glMatrixMode(GL_MODELVIEW);
  357. glLoadIdentity();
  358. gluLookAt(0.0, m_zoom, 0.0, /* eye is at (0,zoom,0) */
  359. m_referene.x(), m_referene.y(), m_referene.z(),
  360. 0.0, 0.0, 1.0); /* up is in positive Y direction */
  361. // TODO Could have been set in prevoius gluLookAt in first argument
  362. glRotatef(m_rot.y(), 1.0, 0.0, 0.0);
  363. glRotatef(m_rot.x(), 0.0, 0.0, 1.0);
  364. if (m_clip_z > 0.) {
  365. GLdouble plane[] = {0., 0., 1., m_clip_z};
  366. glClipPlane(GL_CLIP_PLANE0, plane);
  367. glEnable(GL_CLIP_PLANE0);
  368. } else {
  369. glDisable(GL_CLIP_PLANE0);
  370. }
  371. }
  372. void PerspectiveCamera::set_screen(long width, long height)
  373. {
  374. // Setup the view of the CSG shape
  375. glMatrixMode(GL_PROJECTION);
  376. glLoadIdentity();
  377. gluPerspective(45.0, width / double(height), .1, 200.0);
  378. glMatrixMode(GL_MODELVIEW);
  379. }
  380. bool enable_multisampling(bool e)
  381. {
  382. if (!e) { glDisable(GL_MULTISAMPLE); return false; }
  383. GLint is_ms_context;
  384. glGetIntegerv(GL_SAMPLE_BUFFERS, &is_ms_context);
  385. if (is_ms_context) { glEnable(GL_MULTISAMPLE); return true; }
  386. else return false;
  387. }
  388. MouseInput::Listener::~Listener() = default;
  389. void FpsCounter::update()
  390. {
  391. ++m_frames;
  392. TimePoint msec = Clock::now();
  393. double seconds_window = to_sec(msec - m_window);
  394. m_fps = 0.5 * m_fps + 0.5 * (m_frames / seconds_window);
  395. if (to_sec(msec - m_last) >= m_resolution) {
  396. m_last = msec;
  397. for (auto &l : m_listeners) l(m_fps);
  398. }
  399. if (seconds_window >= m_window_size) {
  400. m_frames = 0;
  401. m_window = msec;
  402. }
  403. }
  404. }} // namespace Slic3r::GL