SoGLHighlightRenderAction.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package MemoryX::gui-plugins::SceneEditor
19 * @date 2015
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
24/*
25 * SoGLHighlightRenderAction.cpp
26 *
27 * Created on: Jan 13, 2015
28 * Author: philipp
29 */
30
32
34 const SbViewportRegion& viewportregion,
35 Scene* scene) :
36 SoGLRenderAction(viewportregion),
37 scene(scene),
38 selectedcolor_storage(sizeof(void*), alloc_colorpacker, free_colorpacker)
39{
40
41 this->isVisible = true;
42 this->selectedColor = SbColor(1.0f, 0.8f, 0.4f);
43 this->activeColor = SbColor(1.0f, 0.4f, 0.2f);
44 this->linepattern = 0xffff;
45 this->linewidth = 5;
46
47 // SoBase-derived objects should be dynamically allocated.
48 this->postprocpath = new SoTempPath(32);
49 this->postprocpath->ref();
50}
51
56
57void
59{
60 std::unique_lock lock(scene->execute_mutex);
61
62 //Render complete scene with standard action
63 SoGLRenderAction::apply(node);
64
65 if (this->isVisible)
66 {
67 SoSearchAction* searchAction = new SoSearchAction;
68 searchAction->setType(SoSelection::getClassTypeId());
69 searchAction->setInterest(SoSearchAction::ALL);
70 searchAction->apply(node);
71
72 const SoPathList& pathlist = searchAction->getPaths();
73
74 if (pathlist.getLength() > 0)
75 {
76 for (int i = 0; i < pathlist.getLength(); i++)
77 {
78 SoPath* path = pathlist[i];
79 SoSelection* selection = (SoSelection*)path->getTail();
80
81 if (selection->getNumSelected() > 0)
82 //Add highlight border around selected objects
83 {
84 this->drawHighlight(path, selection->getList());
85 }
86 }
87 }
88 }
89}
90
91void
92scene3D::SoGLHighlightRenderAction::drawHighlight(SoPath* pathtothis, const SoPathList* pathlist)
93{
94 // Copied from Coin implementation, no idea what it does
95 int oldnumpasses = this->getNumPasses();
96 this->setNumPasses(1);
97
98 //Insert path to SoSelection node in our postprocesspath
99 int thispos = ((SoFullPath*)pathtothis)->getLength() - 1;
100 this->postprocpath->truncate(0);
101
102 for (int i = 0; i < thispos; i++)
103 {
104 this->postprocpath->append(pathtothis->getNode(i));
105 }
106
107 //For 0 to n - 1 selected object of selection list render colored wireframe
108 for (int i = 0; i < pathlist->getLength(); i++)
109 {
110 //Retrieve full path
111 SoFullPath* path = (SoFullPath*)(*pathlist)[i];
112
113 //Append to postprocesspath
114 for (int j = 0; j < path->getLength(); j++)
115 {
116 this->postprocpath->append(path->getNode(j));
117 }
118
119 /*
120 We use a little algorithm mostly explained here:
121 http://www.flipcode.com/archives/Object_Outlining.shtml
122 and here:
123 http://www.informit.com/articles/article.aspx?p=328646&seqNum=10
124
125 We basically fill the opengl stencil buffer with the value 1,
126 tell opengl to never touch the color buffer but modify the stencil buffer only.
127 (Actually writing zero into it at the respective pixel positions).
128 In the next step we render the object again, this time drawing
129 the wireframe version of the object with the selection color
130 and only drawing where we still have the value 1 in stencil buffer.
131 Because line width is 5, we actually get some sort of 'edge glow'
132 effect out of this. :)
133 */
134
135 // Use 1 for clearing stencil buffer, clear buffer and enable stencil test
136 glEnable(GL_STENCIL_TEST);
137 glClearStencil(1.0f);
138 glClear(GL_STENCIL_BUFFER_BIT);
139
140 // All drawing commands fail the stencil test and are not
141 // drawn, but set the value in the stencil buffer to zero.
142 glStencilFunc(GL_NEVER, 0x0, 0x0);
143 glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO);
144 SoGLRenderAction::apply(this->postprocpath);
145
146 //Render only where stencil is not set to 0, to achieve sort of 'edge glow' effect
147 glStencilFunc(GL_NOTEQUAL, 0, 1);
148 //Do not modify stencil buffer in any way (just to keep it clean, doesn't really matter)
149 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
150
151 //Draw wireframe in selection color, masked by stencil
152 drawWireframe(this->postprocpath, i == pathlist->getLength() - 1);
153
154 //Reset postprocesspath to SoSelection node
155 this->postprocpath->truncate(thispos);
156
157 glDisable(GL_STENCIL_TEST);
158 }
159
160 //Restore this mysterious numpass thing
161 this->setNumPasses(oldnumpasses);
162}
163
164void
165scene3D::SoGLHighlightRenderAction::drawWireframe(SoPath* pathtothis, bool active)
166{
167 //Save current openGL state
168 SoState* state = this->getState();
169 state->push();
170
171 //Cause Coin sucks we have to use OpenGL calls directly here
172 //because calling SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR)
173 //ends in SEGFAULT for some selected objects
174 glDisable(GL_LIGHTING);
175
176 //Do some pretty complex and fun OpenGL adaptions
177 SoColorPacker** selected_cptr = (SoColorPacker**)this->selectedcolor_storage.get();
178
179 if (!active)
180 {
181 SoGLLazyElement::setDiffuse(
182 state, pathtothis->getHead(), 1, &this->selectedColor, *selected_cptr);
183 }
184 else
185 {
186 //Set new color for last object
187 SoGLLazyElement::setDiffuse(
188 state, pathtothis->getTail(), 1, &this->activeColor, *selected_cptr);
189 }
190
191 SoLineWidthElement::set(state, this->linewidth);
192 SoLinePatternElement::set(state, this->linepattern);
193 SoTextureQualityElement::set(state, 0.0f);
194 SoDrawStyleElement::set(state, SoDrawStyleElement::LINES);
195 SoPolygonOffsetElement::set(state, NULL, -1.0f, 1.0f, SoPolygonOffsetElement::LINES, TRUE);
196 SoMaterialBindingElement::set(state, NULL, SoMaterialBindingElement::OVERALL);
197 SoNormalElement::set(state, NULL, 0, NULL, FALSE);
198 SoOverrideElement::setNormalVectorOverride(state, NULL, TRUE);
199 SoOverrideElement::setMaterialBindingOverride(state, NULL, TRUE);
200 SoOverrideElement::setLightModelOverride(state, NULL, TRUE);
201 SoOverrideElement::setDiffuseColorOverride(state, NULL, TRUE);
202 SoOverrideElement::setLineWidthOverride(state, NULL, TRUE);
203 SoOverrideElement::setLinePatternOverride(state, NULL, TRUE);
204 SoOverrideElement::setDrawStyleOverride(state, NULL, TRUE);
205 SoOverrideElement::setPolygonOffsetOverride(state, NULL, TRUE);
206 SoTextureOverrideElement::setQualityOverride(state, TRUE);
207
208 //Render with new OpenGL context
209 SoGLRenderAction::apply(this->postprocpath);
210
211 //Cause switching light on again might be a good idea
212 glEnable(GL_LIGHTING);
213
214 //Restore OpenGL context
215 state->pop();
216}
void apply(SoNode *node) override
Applies the Highlighting to a given node.
SoGLHighlightRenderAction(const SbViewportRegion &viewportregion, Scene *scene)
Constructor Creates an Instance of the Class.