You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mTGtkGLWidget.hpp 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /*********************************************************************
  2. * Software License Agreement (AGPL-3 License)
  3. *
  4. * OpenViBE Designer
  5. * Based on OpenViBE V1.1.0, Copyright (C) Inria, 2006-2015
  6. * Copyright (C) Inria, 2015-2017,V1.0
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License version 3,
  10. * as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Affero General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program.
  19. * If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #pragma once
  22. #include "m_defines.hpp"
  23. #include "m_VisualizationTools.hpp"
  24. #include "m_GtkGL.hpp"
  25. #include <openvibe/ov_all.h>
  26. #include <visualization-toolkit/ovviz_all.h>
  27. #if defined TARGET_OS_Windows
  28. #include <Windows.h>
  29. #endif
  30. #include <gtk/gtk.h>
  31. #include <GL/gl.h>
  32. #include <GL/glu.h>
  33. #include <string>
  34. // #define __DIRECT_RENDER__
  35. namespace OpenViBE {
  36. namespace AdvancedVisualization {
  37. template <class TBox>
  38. class TGtkGLWidget
  39. {
  40. public:
  41. TGtkGLWidget() : m_box(nullptr) { }
  42. virtual ~TGtkGLWidget()
  43. {
  44. if (m_widget)
  45. {
  46. if (m_textureId)
  47. {
  48. GtkGL::preRender(m_widget);
  49. glDeleteTextures(1, &m_textureId);
  50. GtkGL::postRender(m_widget);
  51. }
  52. if (m_timeoutSrc) { g_source_destroy(m_timeoutSrc); }
  53. GtkGL::uninitialize(m_widget);
  54. }
  55. }
  56. virtual void initialize(TBox& box, GtkWidget* widget, GtkWidget* left, GtkWidget* right, GtkWidget* bottom)
  57. {
  58. GtkGL::initialize(widget);
  59. {
  60. m_box = &box;
  61. m_widget = widget;
  62. m_left = left;
  63. m_right = right;
  64. m_bottom = bottom;
  65. ::g_signal_connect(widget, "configure-event", G_CALLBACK(TGtkGLWidget<TBox>::configureCB), m_box);
  66. ::g_signal_connect(widget, "expose-event", G_CALLBACK(TGtkGLWidget<TBox>::exposeCB), m_box);
  67. ::g_signal_connect(widget, "button-press-event", G_CALLBACK(TGtkGLWidget<TBox>::mouseButtonCB), m_box);
  68. ::g_signal_connect(widget, "button-release-event", G_CALLBACK(TGtkGLWidget<TBox>::mouseButtonCB), m_box);
  69. ::g_signal_connect(widget, "motion-notify-event", G_CALLBACK(TGtkGLWidget<TBox>::motionNotifyCB), m_box);
  70. ::g_signal_connect(widget, "enter-notify-event", G_CALLBACK(TGtkGLWidget<TBox>::enterNotifyCB), m_box);
  71. ::g_signal_connect(gtk_widget_get_parent(widget), "key-press-event", G_CALLBACK(TGtkGLWidget<TBox>::keyPressCB), m_box);
  72. ::g_signal_connect(gtk_widget_get_parent(widget), "key-release-event", G_CALLBACK(TGtkGLWidget<TBox>::keyReleaseCB), m_box);
  73. ::g_signal_connect_after(left, "expose-event", G_CALLBACK(TGtkGLWidget<TBox>::exposeLeftCB), m_box);
  74. ::g_signal_connect_after(right, "expose-event", G_CALLBACK(TGtkGLWidget<TBox>::exposeRightCB), m_box);
  75. ::g_signal_connect_after(bottom, "expose-event", G_CALLBACK(TGtkGLWidget<TBox>::exposeBottomCB), m_box);
  76. m_timeoutSrc = g_timeout_source_new(250); // timeouts every 50 ms
  77. g_source_set_priority(m_timeoutSrc, G_PRIORITY_LOW);
  78. g_source_set_callback(m_timeoutSrc, GSourceFunc(timeoutRedrawCB), m_box, nullptr);
  79. g_source_attach(m_timeoutSrc, nullptr);
  80. gtk_widget_queue_resize(widget);
  81. }
  82. }
  83. virtual void redrawTopLevelWindow(const bool immediate = false)
  84. {
  85. GtkWidget* top = gtk_widget_get_toplevel(m_widget);
  86. if (top != nullptr)
  87. {
  88. if (immediate)
  89. {
  90. gdk_window_process_updates(top->window, false);
  91. gtk_widget_queue_draw(top);
  92. }
  93. else { gdk_window_invalidate_rect(top->window, nullptr, true); }
  94. }
  95. }
  96. virtual void redraw(const bool immediate = false)
  97. {
  98. if (immediate)
  99. {
  100. gdk_window_process_updates(m_widget->window, false);
  101. gtk_widget_queue_draw(m_widget);
  102. }
  103. else { gdk_window_invalidate_rect(m_widget->window, nullptr, true); }
  104. }
  105. virtual void redrawLeft(const bool immediate = false)
  106. {
  107. if (immediate)
  108. {
  109. gdk_window_process_updates(m_left->window, false);
  110. gtk_widget_queue_draw(m_left);
  111. }
  112. else { gdk_window_invalidate_rect(m_left->window, nullptr, true); }
  113. }
  114. virtual void redrawRight(const bool immediate = false)
  115. {
  116. if (immediate)
  117. {
  118. gdk_window_process_updates(m_right->window, false);
  119. gtk_widget_queue_draw(m_right);
  120. }
  121. else { gdk_window_invalidate_rect(m_right->window, nullptr, true); }
  122. }
  123. virtual void redrawBottom(const bool immediate = false)
  124. {
  125. if (immediate)
  126. {
  127. gdk_window_process_updates(m_bottom->window, false);
  128. gtk_widget_queue_draw(m_bottom);
  129. }
  130. else { gdk_window_invalidate_rect(m_bottom->window, nullptr, true); }
  131. }
  132. virtual void setPointSmoothingActive(const bool active = false)
  133. {
  134. if (active) { glEnable(GL_POINT_SMOOTH); }
  135. else { glDisable(GL_POINT_SMOOTH); }
  136. }
  137. virtual uint32_t createTexture(const std::string& value)
  138. {
  139. #define M_GRADIENT_SIZE 128
  140. if (m_textureId == 0)
  141. {
  142. const std::string str = (value.empty() ? "0:0,0,100; 25:0,100,100; 50:0,49,0; 75:100,100,0; 100:100,0,0" : value);
  143. CMatrix gradientBase, gradient;
  144. VisualizationToolkit::ColorGradient::parse(gradientBase, str.c_str());
  145. VisualizationToolkit::ColorGradient::interpolate(gradient, gradientBase, M_GRADIENT_SIZE);
  146. float texture[M_GRADIENT_SIZE][3];
  147. for (size_t i = 0; i < M_GRADIENT_SIZE; ++i)
  148. {
  149. texture[i][0] = float(gradient[i * 4 + 1] * .01);
  150. texture[i][1] = float(gradient[i * 4 + 2] * .01);
  151. texture[i][2] = float(gradient[i * 4 + 3] * .01);
  152. }
  153. glGenTextures(1, &m_textureId);
  154. glBindTexture(GL_TEXTURE_1D, m_textureId);
  155. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // GL_LINEAR);
  156. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // LINEAR_MIPMAP_LINEAR);
  157. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  158. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  159. //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  160. //glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, __SIZE__, 0, GL_RGB, GL_UNSIGNED_BYTE, texture);
  161. gluBuild1DMipmaps(GL_TEXTURE_1D, GL_RGB, M_GRADIENT_SIZE, GL_RGB, GL_FLOAT, texture);
  162. }
  163. #undef M_GRADIENT_SIZE
  164. return m_textureId;
  165. }
  166. protected:
  167. GtkWidget* m_widget = nullptr;
  168. GtkWidget* m_left = nullptr;
  169. GtkWidget* m_right = nullptr;
  170. GtkWidget* m_bottom = nullptr;
  171. GSource* m_timeoutSrc = nullptr;
  172. TBox* m_box = nullptr;
  173. uint32_t m_textureId = 0;
  174. private:
  175. static gboolean timeoutRedrawCB(TBox* box)
  176. {
  177. box->redraw();
  178. return TRUE;
  179. }
  180. static gboolean configureCB(GtkWidget* widget, GdkEventConfigure* /*event*/, TBox* box)
  181. {
  182. GtkGL::preRender(widget);
  183. glViewport(0, 0, widget->allocation.width, widget->allocation.height);
  184. box->reshape(widget->allocation.width, widget->allocation.height);
  185. GtkGL::postRender(widget);
  186. return TRUE;
  187. }
  188. static gboolean exposeCB(GtkWidget* widget, GdkEventExpose* /*event*/, TBox* box)
  189. {
  190. const float d = 1.F;
  191. const float dx = d / (widget->allocation.width - d);
  192. const float dy = d / (widget->allocation.height - d);
  193. GtkGL::preRender(widget);
  194. glMatrixMode(GL_TEXTURE);
  195. glLoadIdentity();
  196. glTranslatef(0.5, 0, 0);
  197. glMatrixMode(GL_PROJECTION);
  198. glLoadIdentity();
  199. gluOrtho2D(0 - dx, 1 + dx, 0 - dy, 1 + dy);
  200. glMatrixMode(GL_MODELVIEW);
  201. glLoadIdentity();
  202. glEnable(GL_POLYGON_OFFSET_FILL);
  203. glPolygonOffset(1.0, 1.0);
  204. glEnable(GL_LINE_SMOOTH);
  205. glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  206. glLineWidth(1);
  207. glEnable(GL_BLEND);
  208. glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  209. glEnable(GL_TEXTURE_1D);
  210. glDisable(GL_DEPTH_TEST);
  211. glClearDepth(100);
  212. glClearColor(0, 0, 0, 0);
  213. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  214. glColor3f(1, 1, 1);
  215. // Lighting
  216. const float fAmbient = 0.0F;
  217. const float fDiffuse = 1.0F;
  218. const float fSpecular = 1.0F;
  219. GLfloat ambient[] = { fAmbient, fAmbient, fAmbient, 1 };
  220. GLfloat diffuse[] = { fDiffuse, fDiffuse, fDiffuse, 1 };
  221. GLfloat specular[] = { fSpecular, fSpecular, fSpecular, 1 };
  222. GLfloat position0[] = { 3, 1, 2, 1 };
  223. GLfloat position1[] = { -3, 0, -2, 1 };
  224. glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
  225. glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
  226. glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
  227. glLightfv(GL_LIGHT0, GL_POSITION, position0);
  228. glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
  229. glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
  230. glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
  231. glLightfv(GL_LIGHT1, GL_POSITION, position1);
  232. glShadeModel(GL_SMOOTH);
  233. glEnable(GL_LIGHT0);
  234. glEnable(GL_LIGHT1);
  235. glEnable(GL_COLOR_MATERIAL);
  236. glDisable(GL_LIGHTING);
  237. box->draw();
  238. GtkGL::postRender(widget);
  239. return TRUE;
  240. }
  241. static gboolean enterNotifyCB(GtkWidget* /*widget*/, GdkEventCrossing* /*event*/, TBox* box)
  242. {
  243. box->redraw();
  244. //box->request();
  245. //box->m_redrawNeeded = true;
  246. return TRUE;
  247. }
  248. static gboolean exposeLeftCB(GtkWidget* /*widget*/, GdkEventExpose* /*event*/, TBox* box)
  249. {
  250. box->drawLeft();
  251. return TRUE;
  252. }
  253. static gboolean exposeRightCB(GtkWidget* /*widget*/, GdkEventExpose* /*event*/, TBox* box)
  254. {
  255. box->drawRight();
  256. return TRUE;
  257. }
  258. static gboolean exposeBottomCB(GtkWidget* /*widget*/, GdkEventExpose* /*event*/, TBox* box)
  259. {
  260. box->drawBottom();
  261. return TRUE;
  262. }
  263. static gboolean mouseButtonCB(GtkWidget* /*widget*/, GdkEventButton* event, TBox* box)
  264. {
  265. int status = 0;
  266. switch (event->type)
  267. {
  268. case GDK_BUTTON_PRESS: status = 1;
  269. break;
  270. case GDK_2BUTTON_PRESS: status = 2;
  271. break;
  272. case GDK_3BUTTON_PRESS: status = 3;
  273. break;
  274. default: break;
  275. }
  276. box->mouseButton(int(event->x), int(event->y), event->button, status);
  277. box->draw();
  278. return TRUE;
  279. }
  280. static gboolean motionNotifyCB(GtkWidget* /*widget*/, GdkEventMotion* event, TBox* box)
  281. {
  282. box->mouseMotion(int(event->x), int(event->y));
  283. return TRUE;
  284. }
  285. static gboolean keyPressCB(GtkWidget* /*widget*/, GdkEventKey* event, TBox* box)
  286. {
  287. box->keyboard(0, 0, /*event->x, event->y,*/ event->keyval, true);
  288. return TRUE;
  289. }
  290. static gboolean keyReleaseCB(GtkWidget* /*widget*/, GdkEventKey* event, TBox* box)
  291. {
  292. box->keyboard(0, 0, /*event->x, event->y,*/ event->keyval, false);
  293. return TRUE;
  294. }
  295. };
  296. } // namespace AdvancedVisualization
  297. } // namespace OpenViBE