Tue Dec 13 15:35:52 2011 +0100
SIMRESERVOIR-3849: Use textMaterial to color the text when using an SmTextureText2Collector, as is done otherwise.
1 /**************************************************************************\
2 *
3 * This file is part of the SmallChange extension library for Coin.
4 * Copyright (C) 1998-2003 by Systems in Motion. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * ("GPL") version 2 as published by the Free Software Foundation.
9 * See the file LICENSE.GPL at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using SmallChange with software that can not be combined with the
13 * GNU GPL, and for taking advantage of the additional benefits of our
14 * support services, please contact Systems in Motion about acquiring
15 * a Coin Professional Edition License.
16 *
17 * See <URL:http://www.coin3d.org> for more information.
18 *
19 * Systems in Motion, Teknobyen, Abels Gate 5, 7030 Trondheim, NORWAY.
20 * <URL:http://www.sim.no>.
21 *
22 \**************************************************************************/
24 #include "SmAnnotationAxis.h"
25 #include <Inventor/nodes/SoSeparator.h>
26 #include <Inventor/elements/SoModelMatrixElement.h>
27 #include <Inventor/elements/SoProjectionMatrixElement.h>
28 #include <Inventor/elements/SoViewingMatrixElement.h>
29 #include <Inventor/elements/SoCacheElement.h>
30 #include <Inventor/elements/SoViewportRegionElement.h>
31 #include <Inventor/elements/SoViewVolumeElement.h>
32 #include <Inventor/elements/SoCullElement.h>
33 #include <Inventor/actions/SoGLRenderAction.h>
34 #include <Inventor/actions/SoGetBoundingBoxAction.h>
35 #include <Inventor/nodes/SoSwitch.h>
36 #include <Inventor/nodes/SoInfo.h>
37 #include <Inventor/nodes/SoMaterial.h>
38 #include <Inventor/nodes/SoLineSet.h>
39 #include <Inventor/nodes/SoSeparator.h>
40 #include <Inventor/nodes/SoVertexProperty.h>
41 #include <Inventor/SbTime.h>
42 #include <Inventor/sensors/SoAlarmSensor.h>
43 #include <Inventor/sensors/SoOneShotSensor.h>
44 #include <SmallChange/nodes/SmTextureText2.h>
45 #include <SmallChange/nodes/SmTextureText2Collector.h>
46 #include <cstring>
48 // *************************************************************************
50 SO_KIT_SOURCE(SmAnnotationAxis);
52 // *************************************************************************
54 class SmAnnotationAxisP {
56 public:
57 SmAnnotationAxisP(SmAnnotationAxis * master) {
58 this->master = master;
59 }
61 SmAnnotationAxis * master;
62 SbList <int> axisidx;
63 SoOneShotSensor * regen_sensor;
65 void add_anno_text(const int level,
66 SbList <int> & list,
67 const SbMatrix & projm,
68 const SbVec2s & vpsize,
69 const float gap,
70 const SbVec3f * pos, int i0, int i1);
72 SbTime lastchanged;
73 SoAlarmSensor * alarm;
75 static void alarmCB(void * closure, SoSensor * s) {
76 SmAnnotationAxisP * thisp = (SmAnnotationAxisP*) closure;
77 thisp->master->touch();
78 }
79 };
81 #define PRIVATE(p) ((p)->pimpl)
82 #define PUBLIC(p) ((p)->master)
84 // *************************************************************************
86 SmAnnotationAxis::SmAnnotationAxis()
87 {
88 PRIVATE(this) = new SmAnnotationAxisP(this);
89 PRIVATE(this)->regen_sensor = NULL;
90 PRIVATE(this)->alarm = new SoAlarmSensor(SmAnnotationAxisP::alarmCB, PRIVATE(this));
91 PRIVATE(this)->lastchanged = SbTime::zero();
93 SO_KIT_CONSTRUCTOR(SmAnnotationAxis);
94 SO_KIT_ADD_CATALOG_ENTRY(topSeparator, SoSeparator, FALSE, this, "", FALSE);
95 SO_KIT_ADD_CATALOG_ENTRY(textMaterial, SoMaterial, FALSE, topSeparator, text, TRUE);
96 SO_KIT_ADD_CATALOG_ENTRY(text, SmTextureText2, FALSE, topSeparator, axisSwitch, TRUE);
97 SO_KIT_ADD_CATALOG_ENTRY(axisSwitch, SoSwitch, FALSE, topSeparator, "", FALSE);
98 SO_KIT_ADD_CATALOG_ENTRY(noAxis, SoInfo, FALSE, axisSwitch, axisSep, FALSE);
99 SO_KIT_ADD_CATALOG_ENTRY(axisSep, SoSeparator, FALSE, axisSwitch, "", FALSE);
100 SO_KIT_ADD_CATALOG_ENTRY(axisMaterial, SoMaterial, FALSE, axisSep, axisLineSet, TRUE);
101 SO_KIT_ADD_CATALOG_ENTRY(axisLineSet, SoLineSet, FALSE, axisSep, "", FALSE);
103 SO_KIT_ADD_FIELD(annotation, (""));
104 SO_KIT_ADD_FIELD(annotationPos, (0.0f, 0.0f, 0.0f));
105 SO_KIT_ADD_FIELD(annotationGap, (30.0f));
106 SO_KIT_ADD_FIELD(renderAxis, (FALSE));
107 SO_KIT_ADD_FIELD(axisTickSize, (0.0f, 0.0f, 0.0f));
108 SO_KIT_ADD_FIELD(annotationOffset, (0.0f, 0.0f, 0.0f));
109 SO_KIT_ADD_FIELD(annotationRot, (0.0f));
111 this->annotation.setNum(0);
112 this->annotationPos.setNum(0);
113 this->annotation.setDefault(TRUE);
114 this->annotationPos.setDefault(TRUE);
116 SO_KIT_INIT_INSTANCE();
118 SoSwitch * sw = static_cast<SoSwitch*>(this->getAnyPart("axisSwitch", TRUE));
119 sw->whichChild.connectFrom(&this->renderAxis);
121 SmTextureText2 * t = static_cast<SmTextureText2*>(this->getAnyPart("text", TRUE));
122 t->justification = SmTextureText2::CENTER;
123 t->rotation.connectFrom(&this->annotationRot);
125 PRIVATE(this)->regen_sensor = new SoOneShotSensor(regen_geometry, this);
126 }
128 SmAnnotationAxis::~SmAnnotationAxis()
129 {
130 delete PRIVATE(this)->alarm;
131 delete PRIVATE(this)->regen_sensor;
132 delete PRIVATE(this);
133 }
135 void
136 SmAnnotationAxis::initClass(void)
137 {
138 SO_KIT_INIT_CLASS(SmAnnotationAxis, SoBaseKit, "BaseKit");
139 }
141 void
142 SmAnnotationAxis::getBoundingBox(SoGetBoundingBoxAction * action)
143 {
144 SoState * state = action->getState();
146 // supply an approximate bbox and always invalidate the bbox cache
147 SoCacheElement::invalidate(state);
149 SbBox3f bbox;
150 bbox.makeEmpty();
151 for (int i = 0; i < this->annotationPos.getNum(); i++) {
152 bbox.extendBy(this->annotationPos[i]);
153 }
155 if (!bbox.isEmpty()) {
156 action->extendBy(bbox);
157 action->setCenter(bbox.getCenter(), TRUE);
158 }
159 inherited::getBoundingBox(action);
160 }
162 void
163 SmAnnotationAxis::GLRender(SoGLRenderAction * action)
164 {
165 SoState * state = action->getState();
167 SbBool render = TRUE;
169 // don't create render caches for this node
170 SoCacheElement::invalidate(state);
172 SbMatrix projmatrix;
173 projmatrix = (SoModelMatrixElement::get(state) *
174 SoViewingMatrixElement::get(state) *
175 SoProjectionMatrixElement::get(state));
177 SbVec2s vpsize = SoViewportRegionElement::get(state).getViewportSizePixels();
178 const SbViewVolume & vv = SoViewVolumeElement::get(state);
179 float maxsize = SbMax(vpsize[0], vpsize[1]);
181 SbList <int> l1;
182 if (this->annotationPos.getNum() >= 2) {
183 l1.truncate(0);
184 PRIVATE(this)->add_anno_text(0, l1, projmatrix,
185 vpsize,
186 this->annotationGap.getValue(),
187 this->annotationPos.getValues(0),
188 0, this->annotationPos.getNum() - 1);
190 }
191 if (SmTextureText2CollectorElement::isCollecting(state)) {
192 if (this->annotation.getNum()) {
193 SoMaterial * material = static_cast<SoMaterial*>(this->getAnyPart("textMaterial", TRUE));
194 SmTextureText2 * text = static_cast<SmTextureText2*>(this->getAnyPart("text", TRUE));
195 SbMatrix modelmatrix = SoModelMatrixElement::get(state);
196 SbVec3f pos;
197 SbColor4f col(material->diffuseColor[0], 1.0f - material->transparency[0]);
199 for (int i = 0; i < l1.getLength(); i++) {
200 pos = this->annotationPos[l1[i]] + this->annotationOffset.getValue();
201 modelmatrix.multVecMatrix(pos, pos);
203 SmTextureText2CollectorElement::add(state,
204 this->annotation.getValues(0)[l1[i] % this->annotation.getNum()],
205 SmTextureFontElement::get(state),
206 pos,
207 -1.0,
208 col,
209 static_cast<SmTextureText2::Justification>(text->justification.getValue()),
210 static_cast<SmTextureText2::VerticalJustification>(text->verticalJustification.getValue()));
212 if (text->string.getNum()) text->string.setNum(0);
213 }
214 }
215 }
216 else {
217 if (l1 != PRIVATE(this)->axisidx) {
218 // avoid that we update the scene graph and trigger redraws too often
219 SbTime curtime = SbTime::getTimeOfDay();
220 if ((curtime.getValue() - PRIVATE(this)->lastchanged.getValue()) < 0.5) {
221 if (!PRIVATE(this)->alarm->isScheduled()) {
222 PRIVATE(this)->alarm->setTimeFromNow(1.0);
223 PRIVATE(this)->alarm->schedule();
224 }
225 }
226 else {
227 PRIVATE(this)->lastchanged = curtime;
228 SmTextureText2 * t = static_cast<SmTextureText2*>(this->getAnyPart("text", TRUE));
229 assert(t);
230 t->position.setNum(l1.getLength());
231 t->string.setNum(l1.getLength());
232 SbVec3f * pos = t->position.startEditing();
233 SbString * text = t->string.startEditing();
234 for (int i = 0; i < l1.getLength(); i++) {
235 pos[i] = this->annotationPos[l1[i]] + this->annotationOffset.getValue();
236 text[i] = this->annotation.getNum() > 0 ?
237 this->annotation.getValues(0)[l1[i]%this->annotation.getNum()] : "";
238 }
239 t->position.finishEditing();
240 t->string.finishEditing();
242 PRIVATE(this)->axisidx = l1;
243 }
244 }
245 }
246 if (render) inherited::GLRender(action);
247 }
249 void
250 SmAnnotationAxis::notify(SoNotList * list)
251 {
252 if (PRIVATE(this)->regen_sensor) {
253 SoField * f = list->getLastField();
254 if ((f == &this->annotationPos) ||
255 (f == &this->renderAxis) ||
256 (f == &this->axisTickSize)) {
257 PRIVATE(this)->regen_sensor->schedule();
258 }
259 }
260 inherited::notify(list);
261 }
263 void
264 SmAnnotationAxis::regen_geometry(void * userdata, SoSensor * s)
265 {
266 SmAnnotationAxis * thisp = (SmAnnotationAxis*) userdata;
267 if (thisp->renderAxis.getValue()) {
268 SoLineSet * ls = static_cast<SoLineSet*>(thisp->getAnyPart("axisLineSet", TRUE));
269 SoVertexProperty * vp = static_cast<SoVertexProperty*> (ls->vertexProperty.getValue());
270 if (vp == NULL) {
271 vp = new SoVertexProperty;
272 ls->vertexProperty = vp;
273 }
274 SbVec3f ticksize = thisp->axisTickSize.getValue();
276 const int numanno = thisp->annotationPos.getNum();
277 const int numlines = 1 + ((ticksize.length() > 0.0f) ? numanno : 0);
278 const int numcoords = numanno + ((ticksize.length() > 0.0f) ? numanno*2 : 0);
280 vp->vertex.setNum(numcoords);
281 ls->numVertices.setNum(numlines);
283 const SbVec3f * src = thisp->annotationPos.getValues(0);
284 SbVec3f * pts = vp->vertex.startEditing();
285 int32_t * v = ls->numVertices.startEditing();
287 v[0] = numanno;
289 int i;
291 for (i = 0; i < numanno; i++) {
292 pts[i] = thisp->annotationPos[i];
293 }
294 if (ticksize.length() > 0.0f) {
295 for (i = 0; i < numanno; i++) {
296 v[i+1] = 2;
297 pts[i*2+numanno] = src[i];
298 pts[i*2+1+numanno] = src[i] + ticksize;
299 }
300 }
302 vp->vertex.finishEditing();
303 ls->numVertices.finishEditing();
304 }
305 }
307 // *************************************************************************
309 void
310 SmAnnotationAxisP::add_anno_text(const int level,
311 SbList <int> & list,
312 const SbMatrix & projm,
313 const SbVec2s & vpsize,
314 const float gap,
315 const SbVec3f * pos, int i0, int i1)
316 {
317 if (i0 == i1) return;
319 int mid = (i0 + i1) / 2;
320 SbVec3f p[3];
321 p[0] = pos[i0];
322 p[1] = pos[mid];
323 p[2] = pos[i1];
325 int i;
326 for (i = 0; i < 3; i++) {
327 projm.multVecMatrix(p[i], p[i]);
328 }
330 if (level == 0) { // special case to handle the corner points
331 if ((p[0][2] < 1.0f) && (p[2][2] < 1.0f)) {
332 SbVec3f d = p[2]-p[0];
333 d[0] = SbAbs(d[0]) * float(vpsize[0]) * 0.5f;
334 d[1] = SbAbs(d[1]) * float(vpsize[1]) * 0.5f;
335 d[2] = 0.0f;
337 float len = d.length();
338 if (len > gap) {
339 list.append(i0);
340 list.append(i1);
341 }
342 }
343 else if (p[0][2] < 1.0f) {
344 list.append(i0);
345 }
346 else if (p[2][2] < 1.0f) {
347 list.append(i1);
348 }
349 }
351 if ((mid == i0) || (mid == i1)) return;
353 if (p[1][2] < 1.0f) {
354 SbBool add = FALSE;
355 float len = 0.0f;
356 if (p[0][2] < 1.0f) {
357 SbVec3f d = p[1]-p[0];
358 d[0] = SbAbs(d[0]) * float(vpsize[0]) * 0.5f;
359 d[1] = SbAbs(d[1]) * float(vpsize[1]) * 0.5f;
360 d[2] = 0.0f;
362 len = d.length();
363 }
364 else if (p[2][2] < 1.0f) {
365 SbVec3f d = p[1]-p[2];
366 d[0] = SbAbs(d[0]) * float(vpsize[0]) * 0.5f;
367 d[1] = SbAbs(d[1]) * float(vpsize[1]) * 0.5f;
368 d[2] = 0.0f;
369 len = d.length();
370 }
371 if (len > gap) {
372 list.append(mid);
373 }
374 }
375 add_anno_text(level+1, list, projm, vpsize, gap, pos, i0, mid);
376 add_anno_text(level+1, list, projm, vpsize, gap, pos, mid, i1);
377 }
379 // *************************************************************************