1// @configure_input@
2
3/**************************************************************************\
4 * Copyright (c) Kongsberg Oil & Gas Technologies AS
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived from
20 * this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33\**************************************************************************/
34
35#include <Inventor/SbPList.h>
36#include <Inventor/SoSceneManager.h>
37#include <Inventor/fields/SoSFColor.h>
38#include <Inventor/fields/SoMFColor.h>
39#include <Inventor/fields/SoMFUInt32.h>
40#include <Inventor/nodes/SoSwitch.h>
41#include <Inventor/nodes/SoSeparator.h>
42#include <Inventor/nodes/SoTexture2.h>
43#include <Inventor/sensors/SoFieldSensor.h>
44#include <Inventor/actions/SoGLRenderAction.h>
45
46#include <Inventor/@Gui@/SoAny.h>
47
48#include <Inventor/@Gui@/nodes/SoGuiViewportFix.h>
49#include <Inventor/@Gui@/nodes/SoGuiPane.h>
50#include <Inventor/@Gui@/nodes/SoGuiClickCounter.h>
51#include <Inventor/@Gui@/nodes/SoGuiSlider1.h>
52#include <Inventor/@Gui@/nodes/SoGuiSlider2.h>
53
54#include <Inventor/@Gui@/nodes/SoGuiColorEditor.h>
55#include <assert.h>
56
57/*!
58  \class SoGuiColorEditor Inventor/@Gui@/editors/SoGuiColorEditor.h
59  \brief The SoGuiColorEditor class is a GUI component for interactively
60  editing color fields.
61*/
62
63/*!
64  \enum SoGuiColorEditor::Sliders
65*/
66
67/*!
68  \val SoGuiColorEditor::NONE
69*/
70
71/*!
72  \val SoGuiColorEditor::INTENSITY
73*/
74
75/*!
76  \val SoGuiColorEditor::RGB
77*/
78
79/*!
80  \val SoGuiColorEditor::HSV
81*/
82
83/*!
84  \val SoGuiColorEditor::RGB_V
85*/
86
87/*!
88  \val SoGuiColorEditor::RGB_HSV
89*/
90
91/*!
92  \enum SoGuiColorEditor::Update
93*/
94
95/*!
96  \val SoGuiColorEditor::CONTINUOUS
97*/
98
99/*!
100  \val SoGuiColorEditor::AFTER_ACCEPT
101*/
102
103// *************************************************************************
104
105class ColorEditor {
106public:
107  SoGuiColorEditor * api;
108
109  void colorChange(void);
110
111  SoFieldSensor * color_sensor;
112  static void color_update_cb(void * closure, SoSensor * sensor);
113
114  SoGuiPane * editor;
115  SoGuiClickCounter * switcher;
116  SoGuiSlider1 * slider_r; // red
117  SoGuiSlider1 * slider_g; // green
118  SoGuiSlider1 * slider_b; // blue
119  SoGuiSlider1 * slider_h; // hue
120  SoGuiSlider1 * slider_s; // saturation
121  SoGuiSlider1 * slider_v; // value
122  SoGuiSlider2 * slider_wheel;
123
124  SoFieldSensor * sensor_r;
125  SoFieldSensor * sensor_g;
126  SoFieldSensor * sensor_b;
127  SoFieldSensor * sensor_h;
128  SoFieldSensor * sensor_s;
129  SoFieldSensor * sensor_v;
130  SoFieldSensor * sensor_wheel;
131
132  static void update_r_cb(void * closure, SoSensor * sensor);
133  static void update_g_cb(void * closure, SoSensor * sensor);
134  static void update_b_cb(void * closure, SoSensor * sensor);
135  static void update_h_cb(void * closure, SoSensor * sensor);
136  static void update_s_cb(void * closure, SoSensor * sensor);
137  static void update_v_cb(void * closure, SoSensor * sensor);
138  static void update_wheel_cb(void * closure, SoSensor * sensor);
139
140  static const char * editorscene[];
141
142  static float calculateHue(float x, float y);
143  static SbVec2f calculateFromHue(float h, float s, float v);
144
145  void generateSliderTextureR(const SbColor & current, SbBool wysiwyg);
146  void generateSliderTextureG(const SbColor & current, SbBool wysiwyg);
147  void generateSliderTextureB(const SbColor & current, SbBool wysiwyg);
148  void generateSliderTextureH(const SbColor & current, SbBool wysiwyg);
149  void generateSliderTextureS(const SbColor & current, SbBool wysiwyg);
150  void generateSliderTextureV(const SbColor & current, SbBool wysiwyg);
151  void generateSliderTextureHSV(const SbColor & current, SbBool wysiwyg);
152};
153
154// *************************************************************************
155
156#define PRIVATE(obj) ((ColorEditor *) ((SoGuiColorEditor *) obj)->internals)
157#define PUBLIC(obj) (((ColorEditor *) obj)->api)
158
159void
160SoGuiColorEditor::initClass(void)
161{
162  SO_KIT_INIT_CLASS(SoGuiColorEditor, SoBaseKit, "BaseKit");
163}
164
165SO_KIT_SOURCE(SoGuiColorEditor);
166
167SoGuiColorEditor::SoGuiColorEditor(void)
168{
169  this->internals = (void *) new ColorEditor;
170  PRIVATE(this)->api = this;
171
172  SO_KIT_CONSTRUCTOR(SoGuiColorEditor);
173
174  SO_KIT_ADD_FIELD(wysiwyg, (FALSE));
175  SO_KIT_ADD_FIELD(color, (SbColor(0.0f, 0.0f, 0.0f)));
176  SO_KIT_ADD_FIELD(sliders, (SoGuiColorEditor::RGB_V));
177  SO_KIT_ADD_FIELD(update, (SoGuiColorEditor::AFTER_ACCEPT));
178
179  SO_KIT_DEFINE_ENUM_VALUE(Sliders, NONE);
180  SO_KIT_DEFINE_ENUM_VALUE(Sliders, INTENSITY);
181  SO_KIT_DEFINE_ENUM_VALUE(Sliders, RGB);
182  SO_KIT_DEFINE_ENUM_VALUE(Sliders, HSV);
183  SO_KIT_DEFINE_ENUM_VALUE(Sliders, RGB_V);
184  SO_KIT_DEFINE_ENUM_VALUE(Sliders, RGB_HSV);
185
186  SO_KIT_DEFINE_ENUM_VALUE(Update, CONTINUOUS);
187  SO_KIT_DEFINE_ENUM_VALUE(Update, AFTER_ACCEPT);
188
189  SO_KIT_SET_SF_ENUM_TYPE(sliders, Sliders);
190  SO_KIT_SET_SF_ENUM_TYPE(update, Update);
191
192  SO_KIT_ADD_CATALOG_ENTRY(root, SoGuiPane, TRUE, this, "", FALSE);
193
194  SO_KIT_INIT_INSTANCE();
195
196  PRIVATE(this)->switcher = NULL;
197  PRIVATE(this)->sensor_r = NULL;
198  PRIVATE(this)->sensor_g = NULL;
199  PRIVATE(this)->sensor_b = NULL;
200  PRIVATE(this)->sensor_h = NULL;
201  PRIVATE(this)->sensor_s = NULL;
202  PRIVATE(this)->sensor_v = NULL;
203  PRIVATE(this)->sensor_wheel = NULL;
204
205  PRIVATE(this)->editor = NULL;
206
207  SoNode * scene = SoAny::loadSceneGraph(ColorEditor::editorscene);
208  assert(scene != NULL);
209  assert(scene->isOfType(SoGuiPane::getClassTypeId()));
210
211  PRIVATE(this)->editor = (SoGuiPane *) scene;
212  PRIVATE(this)->editor->ref();
213  PRIVATE(this)->switcher = (SoGuiClickCounter *) SoAny::scanSceneForName(PRIVATE(this)->editor, "switcher");
214  PRIVATE(this)->slider_r = (SoGuiSlider1 *) SoAny::scanSceneForName(PRIVATE(this)->editor, "slider_r", TRUE);
215  PRIVATE(this)->slider_g = (SoGuiSlider1 *) SoAny::scanSceneForName(PRIVATE(this)->editor, "slider_g", TRUE);
216  PRIVATE(this)->slider_b = (SoGuiSlider1 *) SoAny::scanSceneForName(PRIVATE(this)->editor, "slider_b", TRUE);
217  PRIVATE(this)->slider_h = (SoGuiSlider1 *) SoAny::scanSceneForName(PRIVATE(this)->editor, "slider_h", TRUE);
218  PRIVATE(this)->slider_s = (SoGuiSlider1 *) SoAny::scanSceneForName(PRIVATE(this)->editor, "slider_s", TRUE);
219  PRIVATE(this)->slider_v = (SoGuiSlider1 *) SoAny::scanSceneForName(PRIVATE(this)->editor, "slider_v", TRUE);
220  PRIVATE(this)->slider_wheel = (SoGuiSlider2 *) SoAny::scanSceneForName(PRIVATE(this)->editor, "colorwheel", TRUE);
221  if ( PRIVATE(this)->slider_r ) {
222    PRIVATE(this)->slider_r->ref();
223    PRIVATE(this)->sensor_r = new SoFieldSensor(ColorEditor::update_r_cb, PRIVATE(this));
224    PRIVATE(this)->sensor_r->attach(&(PRIVATE(this)->slider_r->value));
225    PRIVATE(this)->generateSliderTextureR(this->color.getValue(), FALSE);
226  }
227  if ( PRIVATE(this)->slider_g ) {
228    PRIVATE(this)->slider_g->ref();
229    PRIVATE(this)->sensor_g = new SoFieldSensor(ColorEditor::update_g_cb, PRIVATE(this));
230    PRIVATE(this)->sensor_g->attach(&(PRIVATE(this)->slider_g->value));
231    PRIVATE(this)->generateSliderTextureG(this->color.getValue(), FALSE);
232  }
233  if ( PRIVATE(this)->slider_b ) {
234    PRIVATE(this)->slider_b->ref();
235    PRIVATE(this)->sensor_b = new SoFieldSensor(ColorEditor::update_b_cb, PRIVATE(this));
236    PRIVATE(this)->sensor_b->attach(&(PRIVATE(this)->slider_b->value));
237    PRIVATE(this)->generateSliderTextureB(this->color.getValue(), FALSE);
238  }
239  if ( PRIVATE(this)->slider_h ) {
240    PRIVATE(this)->slider_h->ref();
241    PRIVATE(this)->sensor_h = new SoFieldSensor(ColorEditor::update_h_cb, PRIVATE(this));
242    PRIVATE(this)->sensor_h->attach(&(PRIVATE(this)->slider_h->value));
243    PRIVATE(this)->generateSliderTextureH(this->color.getValue(), FALSE);
244  }
245  if ( PRIVATE(this)->slider_s ) {
246    PRIVATE(this)->slider_s->ref();
247    PRIVATE(this)->sensor_s = new SoFieldSensor(ColorEditor::update_s_cb, PRIVATE(this));
248    PRIVATE(this)->sensor_s->attach(&(PRIVATE(this)->slider_s->value));
249    PRIVATE(this)->generateSliderTextureS(this->color.getValue(), FALSE);
250
251  }
252  if ( PRIVATE(this)->slider_v ) {
253    PRIVATE(this)->slider_v->ref();
254    PRIVATE(this)->sensor_v = new SoFieldSensor(ColorEditor::update_v_cb, PRIVATE(this));
255    PRIVATE(this)->sensor_v->attach(&(PRIVATE(this)->slider_v->value));
256    PRIVATE(this)->generateSliderTextureV(this->color.getValue(), FALSE);
257  }
258  if ( PRIVATE(this)->slider_wheel ) {
259    PRIVATE(this)->slider_wheel->ref();
260    PRIVATE(this)->sensor_wheel = new SoFieldSensor(ColorEditor::update_wheel_cb, PRIVATE(this));
261    PRIVATE(this)->sensor_wheel->attach(&(PRIVATE(this)->slider_wheel->value));
262    PRIVATE(this)->generateSliderTextureHSV(this->color.getValue(), FALSE);
263  }
264
265  PRIVATE(this)->editor->unrefNoDelete();
266  this->setAnyPart("root", scene);
267
268  PRIVATE(this)->color_sensor = new SoFieldSensor(ColorEditor::color_update_cb, PRIVATE(this));
269  PRIVATE(this)->color_sensor->attach(&(this->color));
270
271  // SoGuiViewportFix * viewportfix = (SoGuiViewportFix *) SoAny::scanSceneForName(inherited::getSceneGraph(), "viewportfix", FALSE);
272  // assert(viewportfix != NULL);
273  // PRIVATE(this)->editor->objectSize.connectFrom(&(viewportfix->viewportSize));
274}
275
276SoGuiColorEditor::~SoGuiColorEditor(void)
277{
278  ColorEditor * instance = PRIVATE(this);
279  delete instance;
280}
281
282// *************************************************************************
283
284// CAT_MOD BEGIN
285const char *
286ColorEditor::editorscene[] = {
287  "#Inventor V2.1 ascii",
288  "DEF pane SoGuiPane {",
289  "  worldSize 1 1 0",
290  "  objectSize 400 340 0",
291  //   Calculate positions
292  "  SoGuiPosition {",
293  "    position = DEF windowgeometry Calculator {",
294  "      A = USE pane.objectSize",
295  "      B 120 120 0",                               // colorwheel size
296  "      C 140 30 0",                                // clickcounter size
297  "      a 2",                                       // width of frame
298  "      expression [",
299  "        \"oA = vec3f(a, A[1] - C[1] - a, 0)\"",   // clickcounter pos
300  "        \"oB = vec3f(A[0] - B[0] - a, A[1] - B[1] - a, 0)\"",  // colorwheel pos
301  "      ]",
302  "    }.oA",
303  "  }",
304  //   Create a click counter
305  "  DEF switcher SoGuiClickCounter {",
306  "    size = USE windowgeometry.C",
307  "    first 2   # the INTENSITY sliders",
308  "    last 6    # the RGB_HSV sliders",
309  "    value 5   # start with the RGB_V group",
310  "  }",
311  //   Create a frame around the click counter area
312  "  SoGuiFrame {",
313  "    size = USE windowgeometry.C",
314  "    width 2",
315  "    design EMBOSS",
316  "  }",
317  //   Create labels for the click counter
318  "  Separator {",
319  "    Scale {",
320  "      scaleFactor 2 2 2",
321  "    }",
322  "    DEF sliderlabel SoGuiLabel {",
323  "      which = USE switcher.value",
324  "      text [",
325  "        \"?\"",
326  "        \"NONE\"",
327  "        \"VALUE\"",
328  "        \"RGB\"",
329  "        \"HSV\"",
330  "        \"RGBV\"",
331  "        \"RGBHSV\"",
332  "      ]",
333  "    }",
334  "  }",
335  //   Create a frame around the color wheel
336  "  SoGuiPosition { position = USE windowgeometry.oB }",
337  "  SoGuiFrame {",
338  "    size = USE windowgeometry.B",
339  "    design EMBOSS",
340  "    width 2",
341  "    complement TRUE",
342  "  }",
343  //   Create the color wheel
344  "  DEF colorwheel SoGuiSlider2 {",
345  "    size = USE windowgeometry.B",
346  "  }",
347  //   Position the sliders
348  "  SoGuiPosition {",
349  "    position = DEF slidergeometry Calculator {",
350  "      A = USE pane.objectSize",
351  "      B = USE windowgeometry.B",                    // color wheel size
352  "      a = USE windowgeometry.a",                    // width of frame
353  "      b 10",                                        // space
354  "      c 30",                                        // width of text
355  "      expression [",
356  "        \"ta = (A[1] - (2*a + B[1]) -  7*b) / 6\"", // slider height
357  "        \"tb = A[0] - 2*b - c\"",                   // slider width
358  "        \"oA = vec3f(tb, ta, 0)\"",                 // slider size
359  "        \"oB = vec3f(c+b , b, 0)\"",                // slider pos
360  "        \"oC = vec3f(0, ta + b, 0)\"",              // slider translation
361  "        \"oD = vec3f(-c, 0, 0)\"",                  // slider label translation
362  "      ]",
363  "    }.oB",
364  "  }",
365  //   Create the sliders depending on the click count value
366  "  Switch {",
367  "    whichChild = USE switcher.value",
368  "    Group {", // never to be rendered...
369  "      DEF slider_r SoGuiSlider1 { size = USE slidergeometry.oA }",
370  "      DEF slider_g SoGuiSlider1 { size = USE slidergeometry.oA }",
371  "      DEF slider_b SoGuiSlider1 { size = USE slidergeometry.oA }",
372  "      DEF slider_h SoGuiSlider1 { size = USE slidergeometry.oA }",
373  "      DEF slider_s SoGuiSlider1 { size = USE slidergeometry.oA }",
374  "      DEF slider_v SoGuiSlider1 { size = USE slidergeometry.oA }",
375  "      DEF slider_translation SoGuiTranslation { translation = USE slidergeometry.oC }",
376  "      DEF slider_frame SoGuiFrame {",
377  "        size = USE slidergeometry.oA ",
378  "        design EMBOSS",
379  "        width 2",
380  "        complement TRUE",
381  "      }",
382  "      DEF label_translation SoGuiTranslation { translation = USE slidergeometry.oD }",
383  "      DEF label_scale Scale { scaleFactor 2 2 2 }",
384  "      DEF label_r Separator {",
385  "        USE label_translation",
386  "        USE label_scale",
387  "        SoGuiLabel { text \"R\" }",
388  "      }",
389  "      DEF label_g Separator {",
390  "        USE label_translation",
391  "        USE label_scale",
392  "        SoGuiLabel { text \"G\" }",
393  "      }",
394  "      DEF label_b Separator {",
395  "        USE label_translation",
396  "        USE label_scale",
397  "        SoGuiLabel { text \"B\" }",
398  "      }",
399  "      DEF label_h Separator {",
400  "        USE label_translation",
401  "        USE label_scale",
402  "        SoGuiLabel { text \"H\" }",
403  "      }",
404  "      DEF label_s Separator {",
405  "        USE label_translation",
406  "        USE label_scale",
407  "        SoGuiLabel { text \"S\" }",
408  "      }",
409  "      DEF label_v Separator {",
410  "        USE label_translation",
411  "        USE label_scale",
412  "        SoGuiLabel { text \"V\" }",
413  "      }",
414  "    }",
415  "    DEF sliders_NONE Group {", // in case we search for names once, instead of indexing
416  "    }",                        // children directly inside setCurrentSliders()
417  "    DEF sliders_INTENSITY Group {",
418  "      USE slider_frame",       // frames before sliders - the knobs must paint over frames
419  "      USE slider_v",
420  "      USE label_v",
421  "    }",
422  "    DEF sliders_RGB Group {",
423  "      USE slider_frame",
424  "      USE slider_b",
425  "      USE label_b",
426  "      USE slider_translation",
427  "      USE slider_frame",
428  "      USE slider_g",
429  "      USE label_g",
430  "      USE slider_translation",
431  "      USE slider_frame",
432  "      USE slider_r",
433  "      USE label_r",
434  "    }",
435  "    DEF sliders_HSV Group {",
436  "      USE slider_frame",
437  "      USE slider_v",
438  "      USE label_v",
439  "      USE slider_translation",
440  "      USE slider_frame",
441  "      USE slider_s",
442  "      USE label_s",
443  "      USE slider_translation",
444  "      USE slider_frame",
445  "      USE slider_h",
446  "      USE label_h",
447  "    }",
448  "    DEF sliders_RGB_V Group {",
449  "      USE sliders_INTENSITY",
450  "      USE slider_translation",
451  "      USE sliders_RGB",
452  "    }",
453  "    DEF sliders_RGB_HSV Group {",
454  "      USE sliders_HSV",
455  "      USE slider_translation",
456  "      USE sliders_RGB",
457  "    }",
458  "  } # Switch",
459  "} # Pane pane",
460  NULL
461};
462// CAT_MOD END
463
464// *************************************************************************
465
466void
467ColorEditor::colorChange(void)
468{
469  float r = 0.0f, g = 0.0f, b = 0.0f, h = 0.0f, s = 0.0f, v = 0.0f;
470  SbColor color(PUBLIC(this)->color.getValue());
471  color.getValue(r, g, b);
472  color.getHSVValue(h, s, v);
473
474  SbVec2f wheel(this->calculateFromHue(h, s, v));
475
476  this->sensor_r->detach();
477  this->sensor_g->detach();
478  this->sensor_b->detach();
479  this->sensor_h->detach();
480  this->sensor_s->detach();
481  this->sensor_v->detach();
482  this->sensor_wheel->detach();
483
484  if ( r != this->slider_r->value.getValue() ) this->slider_r->value.setValue(r);
485  if ( g != this->slider_g->value.getValue() ) this->slider_g->value.setValue(g);
486  if ( b != this->slider_b->value.getValue() ) this->slider_b->value.setValue(b);
487  if ( h != this->slider_h->value.getValue() ) this->slider_h->value.setValue(h);
488  if ( s != this->slider_s->value.getValue() ) this->slider_s->value.setValue(s);
489  if ( v != this->slider_v->value.getValue() ) this->slider_v->value.setValue(v);
490  if ( wheel != this->slider_wheel->value.getValue() ) this->slider_wheel->value.setValue(wheel);
491
492  assert(PUBLIC(this) != NULL);
493  if ( PUBLIC(this)->wysiwyg.getValue() ) {
494    this->generateSliderTextureR(color, TRUE);
495    this->generateSliderTextureG(color, TRUE);
496    this->generateSliderTextureB(color, TRUE);
497    this->generateSliderTextureH(color, TRUE);
498    this->generateSliderTextureS(color, TRUE);
499    this->generateSliderTextureV(color, TRUE);
500    this->generateSliderTextureHSV(color, TRUE);
501  }
502
503  this->sensor_r->attach(&(this->slider_r->value));
504  this->sensor_g->attach(&(this->slider_g->value));
505  this->sensor_b->attach(&(this->slider_b->value));
506  this->sensor_h->attach(&(this->slider_h->value));
507  this->sensor_s->attach(&(this->slider_s->value));
508  this->sensor_v->attach(&(this->slider_v->value));
509  this->sensor_wheel->attach(&(this->slider_wheel->value));
510}
511
512void
513ColorEditor::color_update_cb(void * closure, SoSensor * sensor)
514{
515  assert(closure != NULL);
516  ColorEditor * me = (ColorEditor *) closure;
517  me->colorChange();
518}
519
520// *************************************************************************
521
522void
523ColorEditor::update_r_cb(void * closure, SoSensor * sensor)
524{
525  ColorEditor * me = (ColorEditor *) closure;
526  float r, g, b;
527  SbColor color = PUBLIC(me)->color.getValue();
528  color.getValue(r, g, b);
529  r = me->slider_r->value.getValue();
530  color.setValue(r, g, b);
531  PUBLIC(me)->color.setValue(color);
532}
533
534void
535ColorEditor::update_g_cb(void * closure, SoSensor * sensor)
536{
537  ColorEditor * me = (ColorEditor *) closure;
538  float r, g, b;
539  SbColor color = PUBLIC(me)->color.getValue();
540  color.getValue(r, g, b);
541  g = me->slider_g->value.getValue();
542  color.setValue(r, g, b);
543  PUBLIC(me)->color.setValue(color);
544}
545
546void
547ColorEditor::update_b_cb(void * closure, SoSensor * sensor)
548{
549  ColorEditor * me = (ColorEditor *) closure;
550  float r, g, b;
551  SbColor color = PUBLIC(me)->color.getValue();
552  color.getValue(r, g, b);
553  b = me->slider_b->value.getValue();
554  color.setValue(r, g, b);
555  PUBLIC(me)->color.setValue(color);
556}
557
558void
559ColorEditor::update_h_cb(void * closure, SoSensor * sensor)
560{
561  ColorEditor * me = (ColorEditor *) closure;
562  float h, s, v;
563  SbColor color = PUBLIC(me)->color.getValue();
564  color.getHSVValue(h, s, v);
565  h = me->slider_h->value.getValue();
566  color.setHSVValue(h, s, v);
567  PUBLIC(me)->color.setValue(color);
568}
569
570void
571ColorEditor::update_s_cb(void * closure, SoSensor * sensor)
572{
573  ColorEditor * me = (ColorEditor *) closure;
574  float h, s, v;
575  SbColor color = PUBLIC(me)->color.getValue();
576  color.getHSVValue(h, s, v);
577  s = me->slider_s->value.getValue();
578  color.setHSVValue(h, s, v);
579  PUBLIC(me)->color.setValue(color);
580}
581
582void
583ColorEditor::update_v_cb(void * closure, SoSensor * sensor)
584{
585  ColorEditor * me = (ColorEditor *) closure;
586  float h, s, v;
587  SbColor color = PUBLIC(me)->color.getValue();
588  color.getHSVValue(h, s, v);
589  v = me->slider_v->value.getValue();
590  color.setHSVValue(h, s, v);
591  PUBLIC(me)->color.setValue(color);
592}
593
594void
595ColorEditor::update_wheel_cb(void * closure, SoSensor * sensor)
596{
597  ColorEditor * me = (ColorEditor *) closure;
598  SbVec2f value = me->slider_wheel->value.getValue();
599  value = value * 2.0f - SbVec2f(1.0f, 1.0f);
600  if ( value.length() > 1.0f ) {
601    value.normalize();
602    SbVec2f reverse = (value + SbVec2f(1.0f, 1.0f)) / 2.0f;
603    me->slider_wheel->value.setValue(reverse);
604  }
605  float h;
606  if ( value[0] == 0.0f ) h = ((value[1] < 0.0f) ? 3.0f : 1.0f) * float(M_PI) / 2.0f;
607  else h = (float) atan(value[1] / value[0]);
608  if ( value[0] < 0.0f ) h += float(M_PI);
609  if ( h < 0.0f ) h += (2.0f * float(M_PI));
610  h /= 2.0f * float(M_PI);
611  float s = So@Gui@Min(value.length(), 1.0f); // float precision bugfix
612
613  float a = 0.0f, b = 0.0f, v = 1.0f;
614  SbColor existing = PUBLIC(me)->color.getValue();
615  existing.getHSVValue(a, b, v);
616
617  SbColor color;
618  color.setHSVValue(h, s, v);
619  PUBLIC(me)->color.setValue(color);
620}
621
622// *************************************************************************
623
624float
625ColorEditor::calculateHue(float x, float y)
626{
627  float hue;
628  if ( x == 0.0f ) hue = ((y < 0.0f) ? 3.0f : 1.0f) * float(M_PI) / 2.0f;
629  else hue = (float) atan(y / x);
630  if ( x < 0.0f ) hue += float(M_PI);
631  if ( hue < 0.0f ) hue += (2.0f * float(M_PI));
632  return hue / (2.0f * float(M_PI));
633}
634
635SbVec2f
636ColorEditor::calculateFromHue(float h, float s, float v)
637{
638  float hue = h * 2.0f * float(M_PI);
639  return SbVec2f(((float) cos(hue) * s + 1.0f) / 2.0f, ((float) sin(hue) * s + 1.0f) / 2.0f);
640}
641
642// *************************************************************************
643
644void
645ColorEditor::generateSliderTextureR(const SbColor & current, SbBool wysiwyg)
646{
647  assert(this->slider_r != NULL);
648  float red, green, blue;
649  current.getValue(red, green, blue);
650  if ( ! wysiwyg ) {
651    green = blue = 0.0f;
652  }
653  SoTexture2 * texture = SO_GET_PART(this->slider_r, "surfaceTexture", SoTexture2);
654  assert(texture);
655  texture->wrapS.setValue(SoTexture2::CLAMP);
656  texture->wrapT.setValue(SoTexture2::CLAMP);
657  SbVec2s size(256, 1);
658  int nc = 3;
659  texture->image.setValue(size, nc, NULL);
660  texture->model.setValue(SoTexture2::DECAL);
661  unsigned char * bytes = texture->image.startEditing(size, nc);
662  int x, y;
663  for ( x = 0; x < size[0]; x++ ) {
664    red = (float) x / (float) (size[0] - 1);
665    for ( y = 0; y < size[1]; y++ ) {
666      bytes[(size[0]*y+x)*nc+0] = (unsigned char) (red * 255.0f);
667      bytes[(size[0]*y+x)*nc+1] = (unsigned char) (green * 255.0f);
668      bytes[(size[0]*y+x)*nc+2] = (unsigned char) (blue * 255.0f);
669      // if ( nc > 3 ) bytes[(size[0]*y+x)*nc+4] = 255;
670    }
671  }
672  texture->image.finishEditing();
673}
674
675void
676ColorEditor::generateSliderTextureG(const SbColor & current, SbBool wysiwyg)
677{
678  assert(this->slider_g != NULL);
679  float red, green, blue;
680  current.getValue(red, green, blue);
681  if ( ! wysiwyg ) {
682    red = blue = 0.0f;
683  }
684  SoTexture2 * texture = SO_GET_PART(this->slider_g, "surfaceTexture", SoTexture2);
685  assert(texture);
686  texture->wrapS.setValue(SoTexture2::CLAMP);
687  texture->wrapT.setValue(SoTexture2::CLAMP);
688  SbVec2s size(256, 1);
689  int nc = 3;
690  texture->image.setValue(size, nc, NULL);
691  texture->model.setValue(SoTexture2::DECAL);
692  unsigned char * bytes = texture->image.startEditing(size, nc);
693  int x, y;
694  for ( x = 0; x < size[0]; x++ ) {
695    green = (float) x / (float) (size[0] - 1);
696    for ( y = 0; y < size[1]; y++ ) {
697      bytes[(size[0]*y+x)*nc+0] = (unsigned char) (red * 255.0f);
698      bytes[(size[0]*y+x)*nc+1] = (unsigned char) (green * 255.0f);
699      bytes[(size[0]*y+x)*nc+2] = (unsigned char) (blue * 255.0f);
700      // if ( nc > 3 ) bytes[(size[0]*y+x)*nc+4] = 255;
701    }
702  }
703  texture->image.finishEditing();
704}
705
706void
707ColorEditor::generateSliderTextureB(const SbColor & current, SbBool wysiwyg)
708{
709  assert(this->slider_b != NULL);
710  float red, green, blue;
711  current.getValue(red, green, blue);
712  if ( ! wysiwyg ) {
713    red = green = 0.0f;
714  }
715  SoTexture2 * texture = SO_GET_PART(this->slider_b, "surfaceTexture", SoTexture2);
716  assert(texture);
717  texture->wrapS.setValue(SoTexture2::CLAMP);
718  texture->wrapT.setValue(SoTexture2::CLAMP);
719  SbVec2s size(256, 1);
720  int nc = 3;
721  texture->image.setValue(size, nc, NULL);
722  texture->model.setValue(SoTexture2::DECAL);
723  unsigned char * bytes = texture->image.startEditing(size, nc);
724  int x, y;
725  for ( x = 0; x < size[0]; x++ ) {
726    blue = (float) x / (float) (size[0] - 1);
727    for ( y = 0; y < size[1]; y++ ) {
728      bytes[(size[0]*y+x)*nc+0] = (unsigned char) (red * 255.0f);
729      bytes[(size[0]*y+x)*nc+1] = (unsigned char) (green * 255.0f);
730      bytes[(size[0]*y+x)*nc+2] = (unsigned char) (blue * 255.0f);
731      // if ( nc > 3 ) bytes[(size[0]*y+x)*nc+4] = 255;
732    }
733  }
734  texture->image.finishEditing();
735}
736
737void
738ColorEditor::generateSliderTextureH(const SbColor & current, SbBool wysiwyg)
739{
740  assert(this->slider_h != NULL);
741  float hue, saturation, value;
742  current.getHSVValue(hue, saturation, value);
743  if ( ! wysiwyg ) {
744    saturation = 1.0f;
745    value = 1.0f;
746  }
747  SoTexture2 * texture = SO_GET_PART(this->slider_h, "surfaceTexture", SoTexture2);
748  assert(texture);
749  texture->wrapS.setValue(SoTexture2::CLAMP);
750  texture->wrapT.setValue(SoTexture2::CLAMP);
751  SbVec2s size(256, 1);
752  int nc = 3;
753  texture->image.setValue(size, nc, NULL);
754  texture->model.setValue(SoTexture2::DECAL);
755  unsigned char * bytes = texture->image.startEditing(size, nc);
756  int x, y;
757  for ( x = 0; x < size[0]; x++ ) {
758    const float hue = (float) x / (float) (size[0] - 1);
759    for ( y = 0; y < size[1]; y++ ) {
760      float r = 0.0f, g = 0.0f, b = 0.0f;
761      SbColor color(r, g, b);
762      color.setHSVValue(hue, saturation, value);
763      color.getValue(r, g, b);
764      bytes[(size[0]*y+x)*nc+0] = (unsigned char) (r * 255.0f);
765      bytes[(size[0]*y+x)*nc+1] = (unsigned char) (g * 255.0f);
766      bytes[(size[0]*y+x)*nc+2] = (unsigned char) (b * 255.0f);
767      // if ( nc > 3 ) bytes[(size[0]*y+x)*nc+4] = 255;
768    }
769  }
770  texture->image.finishEditing();
771}
772
773void
774ColorEditor::generateSliderTextureS(const SbColor & current, SbBool wysiwyg)
775{
776  assert(this->slider_s != NULL);
777  float hue, saturation, value;
778  current.getHSVValue(hue, saturation, value);
779  if ( ! wysiwyg ) {
780    hue = 0.0f;
781    value = 1.0f;
782  }
783  SoTexture2 * texture = SO_GET_PART(this->slider_s, "surfaceTexture", SoTexture2);
784  assert(texture);
785  texture->wrapS.setValue(SoTexture2::CLAMP);
786  texture->wrapT.setValue(SoTexture2::CLAMP);
787  SbVec2s size(256, 1);
788  int nc = 3;
789  texture->image.setValue(size, nc, NULL);
790  texture->model.setValue(SoTexture2::DECAL);
791  unsigned char * bytes = texture->image.startEditing(size, nc);
792  int x, y;
793  for ( x = 0; x < size[0]; x++ ) {
794    const float saturation = (float) x / (float) (size[0] - 1);
795    for ( y = 0; y < size[1]; y++ ) {
796      float r = 0.0f, g = 0.0f, b = 0.0f;
797      SbColor color(r, g, b);
798      color.setHSVValue(hue, saturation, value);
799      color.getValue(r, g, b);
800      bytes[(size[0]*y+x)*nc+0] = (unsigned char) (r * 255.0f);
801      bytes[(size[0]*y+x)*nc+1] = (unsigned char) (g * 255.0f);
802      bytes[(size[0]*y+x)*nc+2] = (unsigned char) (b * 255.0f);
803      // if ( nc > 3 ) bytes[(size[0]*y+x)*nc+4] = 255;
804    }
805  }
806  texture->image.finishEditing();
807}
808
809void
810ColorEditor::generateSliderTextureV(const SbColor & current, SbBool wysiwyg)
811{
812  assert(this->slider_v != NULL);
813  float hue, saturation, value;
814  current.getHSVValue(hue, saturation, value);
815  if ( ! wysiwyg ) {
816    hue = 0.0f;
817    saturation = 1.0f;
818  }
819  SoTexture2 * texture = SO_GET_PART(this->slider_v, "surfaceTexture", SoTexture2);
820  assert(texture);
821  texture->wrapS.setValue(SoTexture2::CLAMP);
822  texture->wrapT.setValue(SoTexture2::CLAMP);
823  SbVec2s size(256, 1);
824  int nc = 3;
825  texture->image.setValue(size, nc, NULL);
826  texture->model.setValue(SoTexture2::DECAL);
827  unsigned char * bytes = texture->image.startEditing(size, nc);
828  int x, y;
829  for ( x = 0; x < size[0]; x++ ) {
830    const float value = (float) x / (float) (size[0] - 1);
831    for ( y = 0; y < size[1]; y++ ) {
832      float r = 0.0f, g = 0.0f, b = 0.0f;
833      SbColor color(r, g, b);
834      color.setHSVValue(hue, saturation, value);
835      color.getValue(r, g, b);
836      bytes[(size[0]*y+x)*nc+0] = (unsigned char) (r * 255.0f);
837      bytes[(size[0]*y+x)*nc+1] = (unsigned char) (g * 255.0f);
838      bytes[(size[0]*y+x)*nc+2] = (unsigned char) (b * 255.0f);
839      // if ( nc > 3 ) bytes[(size[0]*y+x)*nc+4] = 255;
840    }
841  }
842  texture->image.finishEditing();
843}
844
845void
846ColorEditor::generateSliderTextureHSV(const SbColor & current, SbBool wysiwyg)
847{
848  assert(this->slider_wheel != NULL);
849  float hue, saturation, value;
850  current.getHSVValue(hue, saturation, value);
851  if ( ! wysiwyg ) {
852    value = 1.0f;
853  }
854
855  SoTexture2 * texture = SO_GET_PART(this->slider_wheel, "surfaceTexture", SoTexture2);
856  assert(texture);
857  texture->wrapS.setValue(SoTexture2::CLAMP);
858  texture->wrapT.setValue(SoTexture2::CLAMP);
859  SbVec2s size(256, 256);
860  int nc = 3;
861  texture->image.setValue(size, nc, NULL);
862  texture->model.setValue(SoTexture2::DECAL);
863  unsigned char * bytes = texture->image.startEditing(size, nc);
864  int x, y;
865  const float halfx = (float) size[0] / 2.0f;
866  const float halfy = (float) size[1] / 2.0f;
867  for ( y = 0; y < size[1]; y++ ) {
868    const float ypos = ((float) y - halfy) / halfy;
869    for ( x = 0; x < size[0]; x++ ) {
870      const float xpos = ((float) x - halfx) / halfx;
871      const float saturation = (float) sqrt(xpos * xpos + ypos * ypos);
872      float hue = ColorEditor::calculateHue(xpos, ypos);
873      float red = 0.0f, green = 0.0f, blue = 0.0f;
874      SbColor color(red, green, blue);
875      if ( saturation <= 1.0f ) color.setHSVValue(hue, saturation, value);
876      color.getValue(red, green, blue);
877      bytes[(size[0]*y+x)*nc+0] = (unsigned char) (red * 255.0f);
878      bytes[(size[0]*y+x)*nc+1] = (unsigned char) (green * 255.0f);
879      bytes[(size[0]*y+x)*nc+2] = (unsigned char) (blue * 255.0f);
880      // if ( nc > 3 ) bytes[(size[0]*y+x)*nc+4] = 255;
881    }
882  }
883  texture->image.finishEditing();
884}
885
886// *************************************************************************
887
888#undef PUBLIC
889#undef PRIVATE
890
891