Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
QtWidgetNode.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 #include <ACG/GL/acg_glew.hh>
51 #include "QtWidgetNode.hh"
52 #include <ACG/Geometry/Types/PlaneT.hh>
53 
54 #include <QApplication>
55 
56 #include <QGLWidget>
57 
58 
59 //== NAMESPACES ===============================================================
60 
61 
62 namespace ACG {
63 namespace SceneGraph {
64 
65 
66 
67 //== IMPLEMENTATION ==========================================================
68 bool QtWidgetNode::NodeEventFilter::eventFilter(QObject *_obj, QEvent *_event)
69 {
70  bool repaint = false;
71  //repaint, if layout was changed or paint requested
72  if (_event->type() == QEvent::LayoutRequest || _event->type() == QEvent::Paint)
73  repaint = true;
74 
75  //repaint only, if initial geometry was created
76  repaint = repaint && node_->planeCreated_;
77 
78  bool result = QObject::eventFilter(_obj, _event);
79 
80 
81  if (repaint)
82  {
83  //check if geometry needs an update
84  if( (node_->oldWidgetWidth_ != node_->widget_->width()) || (node_->oldWidgetHeight_ != node_->widget_->height()))
85  node_->updateGeometry();
86 
87  //create new widget texture
88  node_->createTexture();
89  node_->setDirty(true);
90  }
91  return result;
92 }
93 //----------------------------------------------------------------------------
94 
95 QtWidgetNode::QtWidgetNode(QWidget* _widget, BaseNode *_parent, std::string _name)
96 :BaseNode(_parent, _name),
97  ef_(new NodeEventFilter(this)),
98  vbo_(0),
99  texID_(0),
100  widget_(_widget),
101  oldWidgetWidth_(0),
102  oldWidgetHeight_(0),
103  planeCreated_(false),
104  state_(0),
105  anisotropicSupport_(false)
106 {
107  vertexDecl_.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_POSITION);
108  vertexDecl_.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_NORMAL);
109  vertexDecl_.addElement(GL_FLOAT, 2, ACG::VERTEX_USAGE_TEXCOORD);
110  setWidget(_widget);
111  plane_.position = ACG::Vec3d(0.0,0.0,0.0);
112  plane_.xDirection = ACG::Vec3d(1.0,0.0,0.0);
113  plane_.yDirection = ACG::Vec3d(0.0,1.0,0.0);
114 }
115 
116 //----------------------------------------------------------------------------
117 
119 {
120  if ( vbo_)
122 
123  if (texID_)
124  glDeleteTextures(1,&texID_);
125 
126 
127 }
128 
129 //----------------------------------------------------------------------------
130 
131 void QtWidgetNode::setWidget(QWidget* _w)
132 {
133  if (widget_)
134  widget_->removeEventFilter(ef_);
135 
136  widget_ = _w;
137  if(!widget_)
138  {
139  oldWidgetWidth_ = oldWidgetHeight_ = 0;
140  planeCreated_ = false;
141  setDirty(true);
142  return;
143  }
144 
145  widget_->adjustSize();
146  widget_->installEventFilter(ef_);
147  if (planeCreated_)
148  {
149  updateGeometry();
150  createTexture();
151  }
152  setDirty(true);
153 
154 }
155 
156 //----------------------------------------------------------------------------
157 
159 {
160  ACG::Vec3d pos = plane_.position - plane_.xDirection * 0.5 - plane_.yDirection * 0.5;
161 
162  //add a little offset in normal direction
163  ACG::Vec3d pos0 = ACG::Vec3d( pos + plane_.normal * 0.1 );
164  ACG::Vec3d pos1 = ACG::Vec3d( pos - plane_.normal * 0.1 );
165 
166  ACG::Vec3d xDird = ACG::Vec3d( plane_.xDirection );
167  ACG::Vec3d yDird = ACG::Vec3d( plane_.yDirection );
168 
169  _bbMin.minimize( pos0 );
170  _bbMin.minimize( pos0 + xDird);
171  _bbMin.minimize( pos0 + yDird);
172  _bbMin.minimize( pos0 + xDird + yDird);
173  _bbMax.maximize( pos1 );
174  _bbMax.maximize( pos1 + xDird);
175  _bbMax.maximize( pos1 + yDird);
176  _bbMax.maximize( pos1 + xDird + yDird);
177 }
178 
179 //----------------------------------------------------------------------------
180 
183 {
186 }
187 
188 
189 //----------------------------------------------------------------------------
190 
192 {
193 
194  const ACG::Vec3d outerCorner = plane_.xDirection + plane_.yDirection;
195 
196  // Array of coordinates for the plane
197  // Interleaved with normals
198 
199  // 4 vertices with 3 pos, 3 normal, 2 texcoords
200  const size_t buffersize = 4*8;
201  float vboData_[buffersize] = { 0.0,0.0,0.0,
202  (float)plane_.normal[0],(float)plane_.normal[1],(float)plane_.normal[2],
203  0.0,0.0,
204  (float)plane_.xDirection[0],(float)plane_.xDirection[1],(float)plane_.xDirection[2],
205  (float)plane_.normal[0],(float)plane_.normal[1],(float)plane_.normal[2],
206  1.0,0.0,
207  (float)outerCorner[0],(float)outerCorner[1],(float)outerCorner[2],
208  (float)plane_.normal[0],(float)plane_.normal[1],(float)plane_.normal[2],
209  1.0,1.0,
210  (float)plane_.yDirection[0],(float)plane_.yDirection[1],(float)plane_.yDirection[2],
211  (float)plane_.normal[0],(float)plane_.normal[1],(float)plane_.normal[2],
212  0.0,1.0};
213 
214  // Create buffer for vertex coordinates if necessary
215  if ( ! vbo_ ) {
216  glGenBuffersARB(1, &vbo_);
217  }
218  // Bind buffer
219  glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo_);
220 
221  // Upload to buffer
222  glBufferDataARB(GL_ARRAY_BUFFER_ARB, buffersize * sizeof(float), &vboData_[0], GL_STATIC_DRAW_ARB);
223 
224  glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
225 }
226 //----------------------------------------------------------------
227 
229 {
230  //grab texture from qt
231  widget_->removeEventFilter(ef_);
232  QPixmap pix = QPixmap::grabWidget(widget_);
233  widget_->installEventFilter(ef_);
234 
235  QImage image = pix.toImage();
236  image = QGLWidget::convertToGLFormat( image );
237 
238  // generate texture
239  if (!texID_)
240  {
241  glGenTextures( 1, &texID_ );
242  anisotropicSupport_ = ACG::checkExtensionSupported("GL_EXT_texture_filter_anisotropic");
243  }
244  glBindTexture( GL_TEXTURE_2D, texID_ );
245 
246  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
247  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
248  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
249  glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
250 
251  if (anisotropicSupport_)
252  {
253  GLfloat anisotropyValue;
254  glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropyValue);
255  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropyValue);
256  }
257 
258  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA,
259  GL_UNSIGNED_BYTE, image.bits());
260  glGenerateMipmap(GL_TEXTURE_2D);
261 }
262 //----------------------------------------------------------------
263 
265 {
266  // compute the widgetsize in world space
267  oldWidgetWidth_ = widget_->width();
268  oldWidgetHeight_= widget_->height();;
269  ACG::Vec3d projPos = ACG::Vec3d(widget_->width(),widget_->height(),0.0);
270  ACG::Vec3d projNullPos = ACG::Vec3d(0.0,0.0,0.0);
271 
272  //unproject the 2D coordinates
273  projPos = _state.unproject(projPos);
274  projNullPos = _state.unproject(projNullPos);
275 
276 
277  // create plane
278  const ACG::Vec3d xDirection = Vec3d(projPos[0]-projNullPos[0],0.0,0.0);
279  const ACG::Vec3d yDirection = Vec3d(0.0,projPos[1]-projNullPos[1],0.0);
280 
281  plane_.setPlane(ACG::Vec3d(0.0,0.0,0.0),xDirection,yDirection);
282 
283  //update plane
284  uploadPlane();
285 }
286 //----------------------------------------------------------------
287 
289 {
290  double widthRatio = widget_->width() / (double)oldWidgetWidth_;
291  double heightRatio = widget_->height() / (double)oldWidgetHeight_;
292 
293  oldWidgetWidth_ = widget_->width();
294  oldWidgetHeight_ = widget_->height();
295 
296  plane_.setPlane(plane_.position,plane_.xDirection*widthRatio,plane_.yDirection*heightRatio);
297 
298  uploadPlane();
299 }
300 
301 //----------------------------------------------------------------
302 
303 void QtWidgetNode::mouseEvent(GLState& _state , QMouseEvent* _event )
304 {
306  return;
307 
308  ACG::Vec3d eventPos = ACG::Vec3d(_event->pos().x(),_state.viewport_height()-_event->pos().y(),0.0);
309 
310  //compute 2d event position in world space
311  ACG::Vec3d unprojEventPos = _state.unproject(eventPos);
312 
313  // get intersection position
314  ACG::Vec3d intersecPos;
315  double distance;
316 
317  ACG::Vec3d pos = plane_.position;
318  ACG::Geometry::Planed intersectPlane(pos,plane_.normal);
319 
320  ACG::Vec3d rayDir = (unprojEventPos - _state.eye()).normalize();
321  if (!intersectPlane.intersect_ray(_state.eye(),_state.eye()+rayDir,intersecPos,distance))
322  return;//no intersection was found
323 
324 
325  ACG::Vec3d topLeftCorner = pos - 0.5*plane_.xDirection - 0.5*plane_.yDirection;
326  ACG::Vec3d toInter = intersecPos - topLeftCorner;
327  ACG::Vec3d xDir = plane_.xDirection;
328  ACG::Vec3d yDir = plane_.yDirection;
329  double sX = (xDir | toInter)/xDir.sqrnorm();
330  double sY = (yDir | toInter)/yDir.sqrnorm();
331 
332  if (sX < 0.0 || sX > 1.0 || sY < 0.0 || sY > 1.0)
333  return;
334 
335 
336  QPoint widgetEventPos(sX * widget_->width(), sY * widget_->height());
337 
338  //Search for the widget where the event should be sent
339  QWidget *childWidget = widget_->childAt(widgetEventPos);
340  if (!childWidget)
341  return;
342 
343  //compute event pos in child space
344  widgetEventPos -= childWidget->pos();
345 
346  //send event
347  QMouseEvent event(_event->type(),widgetEventPos,_event->button(),_event->buttons(),_event->modifiers());
348  QApplication::sendEvent(childWidget,&event);
349 
350  //update widget
351  QEvent paintEvent(QEvent::Paint);
352  QApplication::sendEvent(widget_,&paintEvent);
353 }
354 //----------------------------------------------------------------------------
355 
356 void QtWidgetNode::mouseEvent(QMouseEvent* _event )
357 {
358  if (!state_)
359  return;
360  mouseEvent(*state_,_event);
361 }
362 //----------------------------------------------------------------------------
363 
365 
366  // init base render object
367  state_ = &_state;
368  if (!widget_)
369  return;
370 
372 
373  ro.initFromState(&_state);
374  ro.debugName = (std::string("QtWidgetNode: ")+name()).c_str();
375 
376  if (!planeCreated_)
377  {
378  //one initial creation of the plane
379  createGeometry(_state);
380  //texture updates will be done via QWidget events (see eventfilter)
381  createTexture();
382  planeCreated_ = true;
383  }
384 
385 
386  ACG::Vec3d pos = plane_.position - plane_.xDirection*0.5 - plane_.yDirection*0.5;
387  _state.push_modelview_matrix();
388  _state.translate(pos[0], pos[1], pos[2]);
389  ro.modelview = _state.modelview();
390  _state.pop_modelview_matrix();
391 
392  // Render with depth test enabled
393  ro.depthTest = true;
394 
395  // Set the buffers for rendering
396  ro.vertexBuffer = vbo_;
397  ro.vertexDecl = &vertexDecl_;
398 
399  // Set Texture
400  RenderObject::Texture texture;
401  texture.id = texID_;
402  texture.type = GL_TEXTURE_2D;
403  texture.shadow = false;
404  ro.addTexture(texture);
405 
406  // Set shading
407  ro.shaderDesc.vertexColors = false;
408  ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
409 
410  ACG::SceneGraph::Material localMaterial;
411 
412  localMaterial.baseColor(ACG::Vec4f(1.0, 1.0, 1.0, 1.0 ));
413  localMaterial.ambientColor(ACG::Vec4f(0.0, 0.0, 0.0, 1.0 ));
414  localMaterial.diffuseColor(ACG::Vec4f(0.0, 0.0, 0.0, 1.0 ));
415  localMaterial.specularColor(ACG::Vec4f(0.0, 0.0, 0.0, 1.0 ));
416  ro.setMaterial(&localMaterial);
417 
418 
419  ro.glDrawArrays(GL_QUADS, 0, 4);
420  _renderer->addRenderObject(&ro);
421 }
422 
423 //=============================================================================
424 } // namespace SceneGraph
425 } // namespace ACG
426 //=============================================================================
QWidget * widget_
current widget
ShaderGenDesc shaderDesc
Drawmode and other shader params.
Definition: MeshNode2T.cc:232
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
ACG::SceneGraph::DrawModes::DrawMode availableDrawModes() const
return available draw modes
std::string name() const
Returns: name of node (needs not be unique)
Definition: MeshNode2T.cc:391
QtWidgetNode(QWidget *_widget, BaseNode *_parent=0, std::string _name="<QtWidgetNode>")
Construct a QtWidget Node.
Definition: QtWidgetNode.cc:95
void translate(double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
translate by (_x, _y, _z)
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:649
const GLMatrixd & modelview() const
get modelview matrix
Definition: MeshNode2T.cc:794
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
Definition: MeshNode2T.cc:169
void setWidget(QWidget *_w)
set a new widget at the current widgets position (if last widget wasn't zero)
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
void addElement(const VertexElement *_pElement)
void baseColor(const Vec4f &_c)
set the base color
Definition: MeshNode2T.cc:167
bool checkExtensionSupported(const std::string &_extension)
Definition: gl.cc:73
void push_modelview_matrix()
push modelview matrix
ACGDLLEXPORT DrawMode SOLID_FLAT_SHADED
draw flat shaded faces (requires face normals)
Definition: DrawModes.cc:87
void initFromState(GLState *_glState)
Initializes a RenderObject instance.
void createGeometry(GLState &_state)
widgetgeometry will be screen aligned. the width/height and position is in respect to the _state proj...
bool hidden()
Is node not visible (status != Active)?
Definition: BaseNode.hh:387
void updateGeometry()
update geometry on current position with old projection/view matrix
Interface class between scenegraph and renderer.
Definition: MeshNode2T.cc:105
GLMatrixd modelview
Modelview transform.
Definition: MeshNode2T.cc:145
void diffuseColor(const Vec4f &_d)
set the diffuse color.
Definition: MeshNode2T.cc:177
Texture to be used.
unsigned int vbo_
VBO used to render the plane.
static void deleteBuffers(GLsizei n, const GLuint *buffers)
Definition: GLState.cc:2105
void getRenderObjects(ACG::IRenderer *_renderer, ACG::GLState &_state, const ACG::SceneGraph::DrawModes::DrawMode &_drawMode, const ACG::SceneGraph::Material *_mat)
Add the objects to the given renderer.
ACGDLLEXPORT DrawMode POINTS
draw unlighted points using the default base color
Definition: DrawModes.cc:79
void addTexture(const Texture &_t)
adds a texture to stage RenderObjects::numTextures()
Definition: MeshNode2T.cc:319
void setPlane(const ACG::Vec3d &_position, const ACG::Vec3d &_xDirection, const ACG::Vec3d &)
Set plane.
Definition: PlaneType.cc:56
void pop_modelview_matrix()
pop modelview matrix
GLState * state_
last state
void specularColor(const Vec4f &_s)
set the specular color
Definition: MeshNode2T.cc:182
void uploadPlane()
upload widget plane data to graphics card
void createTexture()
create and update the widget texture
Vec3d eye() const
get eye point
Definition: GLState.cc:882
Plane plane_
plane position and dimensions
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
Definition: MeshNode2T.cc:215
int viewport_height() const
get viewport height
Definition: GLState.hh:827
int oldWidgetWidth_
initial widgetHeight/Width. Is 0, if widget is 0 or if plane wasn't initialized with current view/pro...
void boundingBox(ACG::Vec3d &_bbMin, ACG::Vec3d &_bbMax)
update bounding box
void setDirty(bool _dirty=true)
mark node for redrawn
Definition: MeshNode2T.cc:251
void ambientColor(const Vec4f &_a)
set the ambient color.
Definition: MeshNode2T.cc:172