Developer Documentation
Loading...
Searching...
No Matches
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#include <ACG/Utils/ImageConversion.hh>
54
55#include <QApplication>
56
57
58//== NAMESPACES ===============================================================
59
60
61namespace ACG {
62namespace SceneGraph {
63
64
65
66//== IMPLEMENTATION ==========================================================
67bool QtWidgetNode::NodeEventFilter::eventFilter(QObject *_obj, QEvent *_event)
68{
69 bool repaint = false;
70 //repaint, if layout was changed or paint requested
71 if (_event->type() == QEvent::LayoutRequest || _event->type() == QEvent::Paint)
72 repaint = true;
73
74 //repaint only, if initial geometry was created
75 repaint = repaint && node_->planeCreated_;
76
77 bool result = QObject::eventFilter(_obj, _event);
78
79
80 if (repaint)
81 {
82 //check if geometry needs an update
83 if( (node_->oldWidgetWidth_ != node_->widget_->width()) || (node_->oldWidgetHeight_ != node_->widget_->height()))
84 node_->updateGeometry();
85
86 //create new widget texture
87 node_->createTexture();
88 node_->setDirty(true);
89 }
90 return result;
91}
92//----------------------------------------------------------------------------
93
94QtWidgetNode::QtWidgetNode(QWidget* _widget, BaseNode *_parent, std::string _name)
95:BaseNode(_parent, _name),
96 ef_(new NodeEventFilter(this)),
97 vbo_(0),
98 texID_(0),
99 widget_(_widget),
101 oldWidgetHeight_(0),
102 planeCreated_(false),
103 state_(0),
104 anisotropicSupport_(false)
105{
106 vertexDecl_.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_POSITION);
107 vertexDecl_.addElement(GL_FLOAT, 3, ACG::VERTEX_USAGE_NORMAL);
108 vertexDecl_.addElement(GL_FLOAT, 2, ACG::VERTEX_USAGE_TEXCOORD);
109 setWidget(_widget);
110 plane_.position = ACG::Vec3d(0.0,0.0,0.0);
111 plane_.xDirection = ACG::Vec3d(1.0,0.0,0.0);
112 plane_.yDirection = ACG::Vec3d(0.0,1.0,0.0);
113}
114
115//----------------------------------------------------------------------------
116
118{
119 if ( vbo_)
121
122 if (texID_)
123 glDeleteTextures(1,&texID_);
124
125
126}
127
128//----------------------------------------------------------------------------
129
130void QtWidgetNode::setWidget(QWidget* _w)
131{
132 if (widget_)
133 widget_->removeEventFilter(ef_);
134
135 widget_ = _w;
136 if(!widget_)
137 {
138 oldWidgetWidth_ = oldWidgetHeight_ = 0;
139 planeCreated_ = false;
140 setDirty(true);
141 return;
142 }
143
144 widget_->adjustSize();
145 widget_->installEventFilter(ef_);
146 if (planeCreated_)
147 {
150 }
151 setDirty(true);
152
153}
154
155//----------------------------------------------------------------------------
156
158{
159 ACG::Vec3d pos = plane_.position - plane_.xDirection * 0.5 - plane_.yDirection * 0.5;
160
161 //add a little offset in normal direction
162 ACG::Vec3d pos0 = ACG::Vec3d( pos + plane_.normal * 0.1 );
163 ACG::Vec3d pos1 = ACG::Vec3d( pos - plane_.normal * 0.1 );
164
165 ACG::Vec3d xDird = ACG::Vec3d( plane_.xDirection );
166 ACG::Vec3d yDird = ACG::Vec3d( plane_.yDirection );
167
168 _bbMin.minimize( pos0 );
169 _bbMin.minimize( pos0 + xDird);
170 _bbMin.minimize( pos0 + yDird);
171 _bbMin.minimize( pos0 + xDird + yDird);
172 _bbMax.maximize( pos1 );
173 _bbMax.maximize( pos1 + xDird);
174 _bbMax.maximize( pos1 + yDird);
175 _bbMax.maximize( pos1 + xDird + yDird);
176}
177
178//----------------------------------------------------------------------------
179
186
187
188//----------------------------------------------------------------------------
189
191{
192
193 const ACG::Vec3d outerCorner = plane_.xDirection + plane_.yDirection;
194
195 // Array of coordinates for the plane
196 // Interleaved with normals
197
198 // 4 vertices with 3 pos, 3 normal, 2 texcoords
199 const size_t buffersize = 4*8;
200 float vboData_[buffersize] = { 0.0,0.0,0.0,
201 (float)plane_.normal[0],(float)plane_.normal[1],(float)plane_.normal[2],
202 0.0,0.0,
203 (float)plane_.xDirection[0],(float)plane_.xDirection[1],(float)plane_.xDirection[2],
204 (float)plane_.normal[0],(float)plane_.normal[1],(float)plane_.normal[2],
205 1.0,0.0,
206 (float)outerCorner[0],(float)outerCorner[1],(float)outerCorner[2],
207 (float)plane_.normal[0],(float)plane_.normal[1],(float)plane_.normal[2],
208 1.0,1.0,
209 (float)plane_.yDirection[0],(float)plane_.yDirection[1],(float)plane_.yDirection[2],
210 (float)plane_.normal[0],(float)plane_.normal[1],(float)plane_.normal[2],
211 0.0,1.0};
212
213 // Create buffer for vertex coordinates if necessary
214 if ( ! vbo_ ) {
215 glGenBuffers(1, &vbo_);
216 }
217 // Bind buffer
218 glBindBuffer(GL_ARRAY_BUFFER_ARB, vbo_);
219
220 // Upload to buffer
221 glBufferData(GL_ARRAY_BUFFER_ARB, buffersize * sizeof(float), &vboData_[0], GL_STATIC_DRAW_ARB);
222
223 glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
224}
225//----------------------------------------------------------------
226
228{
229 //grab texture from qt
230 widget_->removeEventFilter(ef_);
231 QPixmap pix = widget_->grab();
232 widget_->installEventFilter(ef_);
233
234 QImage image = pix.toImage();
235 image = ACG::Util::convertToGLFormat(image);// QGLWidget::convertToGLFormat( image );
236
237 // generate texture
238 if (!texID_)
239 {
240 glGenTextures( 1, &texID_ );
241 anisotropicSupport_ = ACG::checkExtensionSupported("GL_EXT_texture_filter_anisotropic");
242 }
243 glBindTexture( GL_TEXTURE_2D, texID_ );
244
245 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
246 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
247 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
248 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
249
250 if (anisotropicSupport_)
251 {
252 GLfloat anisotropyValue;
253 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropyValue);
254 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropyValue);
255 }
256
257 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA,
258 GL_UNSIGNED_BYTE, image.bits());
259 glGenerateMipmap(GL_TEXTURE_2D);
260}
261//----------------------------------------------------------------
262
264{
265 // compute the widgetsize in world space
266 oldWidgetWidth_ = widget_->width();
267 oldWidgetHeight_= widget_->height();;
268 ACG::Vec3d projPos = ACG::Vec3d(widget_->width(),widget_->height(),0.0);
269 ACG::Vec3d projNullPos = ACG::Vec3d(0.0,0.0,0.0);
270
271 //unproject the 2D coordinates
272 projPos = _state.unproject(projPos);
273 projNullPos = _state.unproject(projNullPos);
274
275
276 // create plane
277 const ACG::Vec3d xDirection = Vec3d(projPos[0]-projNullPos[0],0.0,0.0);
278 const ACG::Vec3d yDirection = Vec3d(0.0,projPos[1]-projNullPos[1],0.0);
279
280 plane_.setPlane(ACG::Vec3d(0.0,0.0,0.0),xDirection,yDirection);
281
282 //update plane
283 uploadPlane();
284}
285//----------------------------------------------------------------
286
288{
289 double widthRatio = widget_->width() / (double)oldWidgetWidth_;
290 double heightRatio = widget_->height() / (double)oldWidgetHeight_;
291
292 oldWidgetWidth_ = widget_->width();
293 oldWidgetHeight_ = widget_->height();
294
295 plane_.setPlane(plane_.position,plane_.xDirection*widthRatio,plane_.yDirection*heightRatio);
296
297 uploadPlane();
298}
299
300//----------------------------------------------------------------
301
302void QtWidgetNode::mouseEvent(GLState& _state , QMouseEvent* _event )
303{
305 return;
306
307 ACG::Vec3d eventPos = ACG::Vec3d(_event->pos().x(),_state.viewport_height()-_event->pos().y(),0.0);
308
309 //compute 2d event position in world space
310 ACG::Vec3d unprojEventPos = _state.unproject(eventPos);
311
312 // get intersection position
313 ACG::Vec3d intersecPos;
314 double distance;
315
316 ACG::Vec3d pos = plane_.position;
317 ACG::Geometry::Planed intersectPlane(pos,plane_.normal);
318
319 ACG::Vec3d rayDir = (unprojEventPos - _state.eye()).normalize();
320 if (!intersectPlane.intersect_ray(_state.eye(),_state.eye()+rayDir,intersecPos,distance))
321 return;//no intersection was found
322
323
324 ACG::Vec3d topLeftCorner = pos - 0.5*plane_.xDirection - 0.5*plane_.yDirection;
325 ACG::Vec3d toInter = intersecPos - topLeftCorner;
326 ACG::Vec3d xDir = plane_.xDirection;
327 ACG::Vec3d yDir = plane_.yDirection;
328 double sX = (xDir | toInter)/xDir.sqrnorm();
329 double sY = (yDir | toInter)/yDir.sqrnorm();
330
331 if (sX < 0.0 || sX > 1.0 || sY < 0.0 || sY > 1.0)
332 return;
333
334
335 QPoint widgetEventPos(sX * widget_->width(), sY * widget_->height());
336
337 //Search for the widget where the event should be sent
338 QWidget *childWidget = widget_->childAt(widgetEventPos);
339 if (!childWidget)
340 return;
341
342 //compute event pos in child space
343 widgetEventPos -= childWidget->pos();
344
345 //send event
346 QMouseEvent event(_event->type(),widgetEventPos,_event->button(),_event->buttons(),_event->modifiers());
347 QApplication::sendEvent(childWidget,&event);
348
349 //update widget
350 QEvent paintEvent(QEvent::Paint);
351 QApplication::sendEvent(widget_,&paintEvent);
352}
353//----------------------------------------------------------------------------
354
355void QtWidgetNode::mouseEvent(QMouseEvent* _event )
356{
357 if (!state_)
358 return;
359 mouseEvent(*state_,_event);
360}
361//----------------------------------------------------------------------------
362
364
365 // init base render object
366 state_ = &_state;
367 if (!widget_)
368 return;
369
371
372 ro.initFromState(&_state);
373 ro.debugName = (std::string("QtWidgetNode: ")+name()).c_str();
374
375 if (!planeCreated_)
376 {
377 //one initial creation of the plane
378 createGeometry(_state);
379 //texture updates will be done via QWidget events (see eventfilter)
381 planeCreated_ = true;
382 }
383
384
385 ACG::Vec3d pos = plane_.position - plane_.xDirection*0.5 - plane_.yDirection*0.5;
386 _state.push_modelview_matrix();
387 _state.translate(pos[0], pos[1], pos[2]);
388 ro.modelview = _state.modelview();
389 _state.pop_modelview_matrix();
390
391 // Render with depth test enabled
392 ro.depthTest = true;
393
394 // Set the buffers for rendering
395 ro.vertexBuffer = vbo_;
396 ro.vertexDecl = &vertexDecl_;
397
398 // Set Texture
399 RenderObject::Texture texture;
400 texture.id = texID_;
401 texture.type = GL_TEXTURE_2D;
402 texture.shadow = false;
403 ro.addTexture(texture);
404
405 // Set shading
406 ro.shaderDesc.vertexColors = false;
407 ro.shaderDesc.shadeMode = SG_SHADE_UNLIT;
408
409 ACG::SceneGraph::Material localMaterial;
410
411 localMaterial.baseColor(ACG::Vec4f(1.0, 1.0, 1.0, 1.0 ));
412 localMaterial.ambientColor(ACG::Vec4f(0.0, 0.0, 0.0, 1.0 ));
413 localMaterial.diffuseColor(ACG::Vec4f(0.0, 0.0, 0.0, 1.0 ));
414 localMaterial.specularColor(ACG::Vec4f(0.0, 0.0, 0.0, 1.0 ));
415 ro.setMaterial(&localMaterial);
416
417
418 ro.glDrawArrays(GL_QUADS, 0, 4);
419 _renderer->addRenderObject(&ro);
420}
421
422//=============================================================================
423} // namespace SceneGraph
424} // namespace ACG
425//=============================================================================
void pop_modelview_matrix()
pop modelview matrix
Definition GLState.cc:1026
Vec3d eye() const
get eye point
Definition GLState.cc:886
const GLMatrixd & modelview() const
get modelview matrix
Definition GLState.hh:816
void translate(double _x, double _y, double _z, MultiplyFrom _mult_from=MULT_FROM_RIGHT)
translate by (_x, _y, _z)
Definition GLState.cc:533
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition GLState.cc:651
int viewport_height() const
get viewport height
Definition GLState.hh:849
static void deleteBuffers(GLsizei n, const GLuint *buffers)
Definition GLState.cc:2232
void push_modelview_matrix()
push modelview matrix
Definition GLState.cc:1010
void setPlane(const ACG::Vec3d &_position, const ACG::Vec3d &_xDirection, const ACG::Vec3d &)
Set plane.
Definition PlaneType.cc:48
virtual void addRenderObject(RenderObject *_renderObject)
Callback for the scenegraph nodes, which send new render objects via this function.
Definition IRenderer.cc:104
bool hidden()
Is node not visible (status != Active)?
Definition BaseNode.hh:411
void setDirty(bool _dirty=true)
mark node for redrawn
Definition BaseNode.hh:275
std::string name() const
Returns: name of node (needs not be unique)
Definition BaseNode.hh:415
void baseColor(const Vec4f &_c)
set the base color (Sets the baseColor which is the same as the emission(const Vec4f& _c) )
void specularColor(const Vec4f &_s)
set the specular color
void ambientColor(const Vec4f &_a)
set the ambient color.
void diffuseColor(const Vec4f &_d)
set the diffuse color.
ACG::SceneGraph::DrawModes::DrawMode availableDrawModes() const override
return available draw modes
void createGeometry(GLState &_state)
widgetgeometry will be screen aligned. the width/height and position is in respect to the _state proj...
void updateGeometry()
update geometry on current position with old projection/view matrix
void mouseEvent(GLState &_state, QMouseEvent *_event) override
Handle mouse event (some interaction, e.g. modeling)
void getRenderObjects(ACG::IRenderer *_renderer, ACG::GLState &_state, const ACG::SceneGraph::DrawModes::DrawMode &_drawMode, const ACG::SceneGraph::Material *_mat) override
Add the objects to the given renderer.
int oldWidgetWidth_
initial widgetHeight/Width. Is 0, if widget is 0 or if plane wasn't initialized with current view/pro...
void uploadPlane()
upload widget plane data to graphics card
QtWidgetNode(QWidget *_widget, BaseNode *_parent=0, std::string _name="<QtWidgetNode>")
Construct a QtWidget Node.
Plane plane_
plane position and dimensions
void createTexture()
create and update the widget texture
QWidget * widget_
current widget
void setWidget(QWidget *_w)
set a new widget at the current widgets position (if last widget wasn't zero)
unsigned int vbo_
VBO used to render the plane.
void boundingBox(ACG::Vec3d &_bbMin, ACG::Vec3d &_bbMax) override
update bounding box
void addElement(const VertexElement *_pElement)
decltype(std::declval< S >() *std::declval< S >()) sqrnorm() const
compute squared euclidean norm
Definition Vector11T.hh:422
vector_type & maximize(const vector_type &_rhs)
maximize values: same as *this = max(*this, _rhs), but faster
Definition Vector11T.hh:588
vector_type & minimize(const vector_type &_rhs)
minimize values: same as *this = min(*this, _rhs), but faster
Definition Vector11T.hh:560
DrawMode POINTS
draw unlighted points using the default base color
Definition DrawModes.cc:73
DrawMode SOLID_FLAT_SHADED
draw flat shaded faces (requires face normals)
Definition DrawModes.cc:81
Namespace providing different geometric functions concerning angles.
bool checkExtensionSupported(const std::string &_extension)
Definition gl.cc:107
@ VERTEX_USAGE_NORMAL
"inNormal"
@ VERTEX_USAGE_POSITION
"inPosition"
@ VERTEX_USAGE_TEXCOORD
"inTexCoord"
VectorT< double, 3 > Vec3d
Definition VectorT.hh:121
Texture to be used.
Interface class between scenegraph and renderer.
ShaderGenDesc shaderDesc
Drawmode and other shader params.
const VertexDeclaration * vertexDecl
Defines the vertex buffer layout, ignored if VAO is provided.
void addTexture(const Texture &_t)
adds a texture to stage RenderObjects::numTextures()
GLMatrixd modelview
Modelview transform.
GLuint vertexBuffer
VBO, IBO ids, ignored if VAO is provided.
void initFromState(GLState *_glState)
Initializes a RenderObject instance.