File: [Development] / inventor / apps / samples / widgets / MySimpleMtlEditor.c++ (download)
Revision 1.2, Sun Oct 29 15:04:17 2000 UTC (16 years, 11 months ago) by jlim
Branch: MAIN
CVS Tags: release-2_1_5-9, release-2_1_5-8, release-2_1_5-10, HEAD Changes since 1.1: +4 -4
lines
Eliminated or reduced compiler errors and warnings, as tested with
egcs-2.91.66 (on Red Hat 6.0) and gcc 2.96 (on Red Hat 6.2).
|
/*
*
* Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
*
*/
/*
* Copyright (C) 1991-93 Silicon Graphics, Inc.
*
_______________________________________________________________________
______________ S I L I C O N G R A P H I C S I N C . ____________
|
| $Revision: 1.2 $
|
| Classes:
| MySimpleMaterialEditor
|
| Author(s): Alain Dumesny
|
|
______________ S I L I C O N G R A P H I C S I N C . ____________
_______________________________________________________________________
*/
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <Xm/Text.h>
#include <Xm/Form.h>
#include <Xm/LabelG.h>
#include <Xm/Scale.h>
#include <Xm/PushBG.h>
#include <Inventor/SbLinear.h>
#include <Inventor/SoDB.h>
#include <Inventor/SoInput.h>
#include <Inventor/SoPath.h>
#include <Inventor/SoLists.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoBaseColor.h>
#include <Inventor/actions/SoGLRenderAction.h>
#include <Inventor/actions/SoSearchAction.h>
#include <Inventor/Xt/SoXtClipboard.h>
#include <Inventor/Xt/SoXtRenderArea.h>
#include <Inventor/errors/SoDebugError.h>
#include "MyColorWheel.h"
#include "MyColorSlider.h"
#include "MySimpleMaterialEditor.h"
/*
* static vars
*/
static char *geometryBuffer = "\
#Inventor V1.0 ascii\n\
\
Separator { \
OrthographicCamera { \
position 0 0 2 \
nearDistance 1 \
farDistance 3 \
height 2 \
} \
LightModel { model BASE_COLOR } \
BaseColor { rgb [.3 .3 .3, .5 .5 .5, .5 .5 .5, .3 .3 .3] } \
MaterialBinding { value PER_FACE } \
Coordinate3 { point [ \
-3 3 0, 0 3 0, 3 3 0, \
-3 0 0, 0 0 0, 3 0 0, \
-3 -3 0, 0 -3 0, 3 -3 0 ] \
} \
QuadMesh { verticesPerColumn 3 verticesPerRow 3 } \
LightModel { model PHONG } \
DirectionalLight { direction .556 -.623 -.551} \
DirectionalLight { direction -.556 -.623 -.551} \
Material {} \
Complexity { value .8 } \
Sphere { radius .85 } \
} ";
////////////////////////////////////////////////////////////////////////
//
// Public constructor - build the widget right now
//
MySimpleMaterialEditor::MySimpleMaterialEditor(
Widget parent,
const char *name,
SbBool buildInsideParent,
SbBool showName)
: SoXtComponent(
parent,
name,
buildInsideParent)
//
////////////////////////////////////////////////////////////////////////
{
// In this case, this component is what the app wants, so buildNow = TRUE
constructorCommon(showName, TRUE);
}
////////////////////////////////////////////////////////////////////////
//
// SoEXTENDER constructor - the subclass tells us whether to build or not
//
MySimpleMaterialEditor::MySimpleMaterialEditor(
Widget parent,
const char *name,
SbBool buildInsideParent,
SbBool showName,
SbBool buildNow)
: SoXtComponent(
parent,
name,
buildInsideParent)
//
////////////////////////////////////////////////////////////////////////
{
// In this case, this component may be what the app wants,
// or it may want a subclass of this component. Pass along buildNow
// as it was passed to us.
constructorCommon(showName, buildNow);
}
////////////////////////////////////////////////////////////////////////
//
// Called by the constructors
//
// private
//
void
MySimpleMaterialEditor::constructorCommon(SbBool showName, SbBool buildNow)
//
//////////////////////////////////////////////////////////////////////
{
// init local vars
setClassName("MySimpleMaterialEditor");
materialName = NULL;
savedMaterialName = NULL;
savedMaterial = new SoMaterial;
savedMaterial->ref();
ignoreCallback = FALSE;
clipboard = NULL;
nameVisible = showName;
// init widget vars
nameField = NULL;
for (int i=0; i<3; i++)
sldWidgets[i] = NULL;
renderArea = NULL;
colWheel = NULL;
colSlider = NULL;
// Build the widget tree, and let SoXtComponent know about our base widget.
if (buildNow) {
Widget w = buildWidget(getParentWidget());
setBaseWidget(w);
}
}
////////////////////////////////////////////////////////////////////////
//
// Destructor.
//
MySimpleMaterialEditor::~MySimpleMaterialEditor()
//
////////////////////////////////////////////////////////////////////////
{
delete renderArea;
delete colWheel;
delete colSlider;
delete clipboard;
savedMaterial->unref();
if (materialName != NULL)
free(materialName);
if (savedMaterialName != NULL)
free(savedMaterialName);
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// set the new material
//
// Use: public
void
MySimpleMaterialEditor::setMaterial(const SoMaterial *mtl)
//
////////////////////////////////////////////////////////////////////////
{
// out with the old...
copyMaterial(material, mtl);
// update the screen and save the values
calculateMaterialFactors();
updateMaterialUI();
saveMaterialFactors();
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// set the new material name
//
// Use: public
void
MySimpleMaterialEditor::setMaterialName(const char *name)
//
////////////////////////////////////////////////////////////////////////
{
if (! nameVisible)
return;
// out with the old...
if (materialName != NULL)
free(materialName);
materialName = (name != NULL) ? strdup(name) : NULL;
// save the name
if (savedMaterialName != NULL)
free(savedMaterialName);
savedMaterialName = (materialName != NULL) ? strdup(materialName) : NULL;
// update text field
if (nameField != NULL) {
char *str = (materialName != NULL) ? materialName : (char *) "";
XmTextSetString(nameField, str);
}
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Buils the editor layout
//
// Use: protected
Widget
MySimpleMaterialEditor::buildWidget(Widget parent)
//
////////////////////////////////////////////////////////////////////////
{
#if 0
// force the window to resize in fixed increments from the
// window minimum size. This will guarantee that the color wheel
// has a 1/1 aspect ratio.
int baseHeight = nameVisible ? 275 : 240;
if ( XtIsShell(parent) )
XtVaSetValues(parent,
XmNbaseWidth, 210,
XmNbaseHeight, baseHeight,
XmNminAspectX, 2,
XmNmaxAspectX, 2,
XmNminAspectY, 1,
XmNmaxAspectY, 1,
NULL);
#endif
int n, i;
Arg args[12];
// create a top level form to hold everything together
n = 0;
XtSetArg(args[n], XmNfractionBase, 100); n++;
Widget form = XmCreateForm(parent, "", args, n);
// create all the parts
renderArea = new SoXtRenderArea(form);
renderArea->setSize(SbVec2s(1, 1)); // col wheel will set the window size
renderArea->setTransparencyType(SoGLRenderAction::BLEND); // spheres are last
Widget raWidget = renderArea->getWidget();
colWheel = new MyColorWheel(form);
colWheel->setSize(SbVec2s(126, 120));
colWheel->addValueChangedCallback(MySimpleMaterialEditor::colWheelCB, this);
colWheel->setWYSIWYG(TRUE);
Widget colWheelWidget = colWheel->getWidget();
colSlider = new MyColorSlider(form, NULL, TRUE, MyColorSlider::VALUE_SLIDER);
colSlider->setNumericFieldVisible(FALSE);
colSlider->setSize(SbVec2s(126, 24));
colSlider->addValueChangedCallback(MySimpleMaterialEditor::colSliderCB, this);
colSlider->setWYSIWYG(TRUE);
Widget colSliderWidget = colSlider->getWidget();
//
// read scene graph in
//
SoInput in;
in.setBuffer((void *)geometryBuffer, (size_t) strlen(geometryBuffer));
SoNode *node;
SbBool ok = SoDB::read(&in, node);
if (!ok || node == NULL) {
#ifdef DEBUG
SoDebugError::post("MySimpleMaterialEditor::buildWidget",
"couldn't read geometry");
#endif
exit(1);
}
renderArea->setSceneGraph(node);
// search for the material node
SoSearchAction sa;
sa.setType(SoMaterial::getClassTypeId());
sa.apply(node);
SoFullPath *fullPath = (SoFullPath *) sa.getPath();
if (fullPath == NULL) {
#ifdef DEBUG
SoDebugError::post("MySimpleMaterialEditor::buildWidget",
"couldn't find material node");
#endif
exit(1);
}
material = (SoMaterial *) fullPath->getTail();
// create the slider labels
Widget sldLabels[6];
sldLabels[0] = XmCreateLabelGadget(form, "opaque", NULL, 0);
sldLabels[1] = XmCreateLabelGadget(form, "transp", NULL, 0);
sldLabels[2] = XmCreateLabelGadget(form, "rough", NULL, 0);
sldLabels[3] = XmCreateLabelGadget(form, "smooth", NULL, 0);
sldLabels[4] = XmCreateLabelGadget(form, "plastic", NULL, 0);
sldLabels[5] = XmCreateLabelGadget(form, "metal", NULL, 0);
// create the sliders
n = 0;
XtSetArg(args[n], XmNminimum, 0); n++;
XtSetArg(args[n], XmNmaximum, 1000); n++;
XtSetArg(args[n], XmNhighlightThickness, 0); n++;
XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
for (i=0; i<3; i++) {
sldWidgets[i] = XmCreateScale(form, "sld", args, n);
XtAddCallback(sldWidgets[i], XmNvalueChangedCallback,
(XtCallbackProc) MySimpleMaterialEditor::sldWidgetsCB, (XtPointer) this);
XtAddCallback(sldWidgets[i], XmNdragCallback,
(XtCallbackProc) MySimpleMaterialEditor::sldWidgetsCB, (XtPointer) this);
}
// create the text field and label
Widget fieldLabel;
if (nameVisible) {
fieldLabel = XmCreateLabelGadget(form, "Name:", NULL, 0);
char *str = (materialName != NULL) ? materialName : (char *) "";
n = 0;
XtSetArg(args[n], XmNvalue, str); n++;
XtSetArg(args[n], XmNhighlightThickness, 1); n++;
nameField = XmCreateText(form, "text", args, n);
fieldChanged = FALSE;
XtAddCallback(nameField, XmNvalueChangedCallback,
(XtCallbackProc) MySimpleMaterialEditor::fieldChangedCB, (XtPointer) this);
XtAddCallback(nameField, XmNactivateCallback,
(XtCallbackProc) MySimpleMaterialEditor::nameFieldCB, (XtPointer) this);
XtAddCallback(nameField, XmNlosingFocusCallback,
(XtCallbackProc) MySimpleMaterialEditor::nameFieldCB, (XtPointer) this);
}
// create the push buttons
Widget buttons[4];
n = 0;
XtSetArg(args[n], XmNhighlightThickness, 0); n++;
buttons[0] = XmCreatePushButtonGadget(form, "Apply", args, n);
buttons[1] = XmCreatePushButtonGadget(form, "Reset", args, n);
buttons[2] = XmCreatePushButtonGadget(form, "Copy", args, n);
buttons[3] = XmCreatePushButtonGadget(form, "Paste", args, n);
XtAddCallback(buttons[0], XmNactivateCallback,
(XtCallbackProc) MySimpleMaterialEditor::applyCB, (XtPointer) this);
XtAddCallback(buttons[1], XmNactivateCallback,
(XtCallbackProc) MySimpleMaterialEditor::resetCB, (XtPointer) this);
XtAddCallback(buttons[2], XmNactivateCallback,
(XtCallbackProc) MySimpleMaterialEditor::copyCB, (XtPointer) this);
XtAddCallback(buttons[3], XmNactivateCallback,
(XtCallbackProc) MySimpleMaterialEditor::pasteCB, (XtPointer) this);
// makes sure things are up to date
setMaterial(material);
//
// Layout
//
#define SX 3
#define DX 1
n = 0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomOffset, 7); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition, SX);
XtSetArg(args[n+1], XmNrightPosition, 25-DX);
XtSetValues(buttons[0], args, n+2);
XtSetArg(args[n], XmNleftPosition, 25+DX);
XtSetArg(args[n+1], XmNrightPosition, 50-DX);
XtSetValues(buttons[1], args, n+2);
XtSetArg(args[n], XmNleftPosition, 50+DX);
XtSetArg(args[n+1], XmNrightPosition, 75-DX);
XtSetValues(buttons[2], args, n+2);
XtSetArg(args[n], XmNleftPosition, 75+DX);
XtSetArg(args[n+1], XmNrightPosition, 100-SX);
XtSetValues(buttons[3], args, n+2);
if (nameVisible) {
n = 0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, 5); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, buttons[0]); n++;
XtSetArg(args[n], XmNbottomOffset, 12); n++;
XtSetValues(fieldLabel, args, n);
n = 0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, fieldLabel); n++;
XtSetArg(args[n], XmNbottomOffset, -4); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftWidget, fieldLabel); n++;
XtSetArg(args[n], XmNleftOffset, 4); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, 5); n++;
XtSetValues(nameField, args, n);
}
n = 0;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition, 30); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition, 70); n++;
XtSetArg(args[n], XmNbottomWidget, nameVisible ? nameField : buttons[0]);
XtSetArg(args[n+1], XmNbottomOffset, 10);
XtSetValues(sldWidgets[0], args, n+2);
XtSetArg(args[n], XmNbottomWidget, sldWidgets[0]);
XtSetArg(args[n+1], XmNbottomOffset, 6);
XtSetValues(sldWidgets[1], args, n+2);
XtSetArg(args[n], XmNbottomWidget, sldWidgets[1]);
XtSetValues(sldWidgets[2], args, n+2);
n = 0;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNrightOffset, 5); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
for (i=0; i<3; i++) {
XtSetArg(args[n], XmNrightWidget, sldWidgets[i]);
XtSetArg(args[n+1], XmNbottomWidget, sldWidgets[i]);
XtSetValues(sldLabels[i*2], args, n+2);
}
n = 0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNleftOffset, 5); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
for (i=0; i<3; i++) {
XtSetArg(args[n], XmNleftWidget, sldWidgets[i]);
XtSetArg(args[n+1], XmNbottomWidget, sldWidgets[i]);
XtSetValues(sldLabels[i*2 + 1], args, n+2);
}
n = 0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftOffset, 5); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset, 5); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, sldWidgets[2]); n++;
XtSetArg(args[n], XmNbottomOffset, 10); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNrightPosition, 50); n++;
XtSetValues(raWidget, args, n);
n = 0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition, 50); n++;
XtSetArg(args[n], XmNleftOffset, 4); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, 5); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, raWidget); n++;
XtSetValues(colSliderWidget, args, n);
n = 0;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
XtSetArg(args[n], XmNleftPosition, 50); n++;
XtSetArg(args[n], XmNleftOffset, 4); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNbottomWidget, colSliderWidget); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightOffset, 5); n++;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNtopOffset, 5); n++;
XtSetValues(colWheelWidget, args, n);
// manage those children
XtManageChildren(buttons, 4);
if (nameVisible) {
XtManageChild(fieldLabel);
XtManageChild(nameField);
}
XtManageChildren(sldWidgets, 3);
XtManageChildren(sldLabels, 6);
XtManageChild(raWidget);
XtManageChild(colSliderWidget);
XtManageChild(colWheelWidget);
return form;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// copies material2 onto material1
//
// Use: private
void
MySimpleMaterialEditor::copyMaterial(SoMaterial *mat1, const SoMaterial *mat2)
//
////////////////////////////////////////////////////////////////////////
{
mat1->ambientColor = mat2->ambientColor[0];
mat1->diffuseColor = mat2->diffuseColor[0];
mat1->specularColor = mat2->specularColor[0];
mat1->emissiveColor = mat2->emissiveColor[0];
mat1->shininess = mat2->shininess[0];
mat1->transparency = mat2->transparency[0];
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// saves the material factors for later reset.
//
// Use: private
void
MySimpleMaterialEditor::saveMaterialFactors()
//
////////////////////////////////////////////////////////////////////////
{
copyMaterial(savedMaterial, material);
savedMetalness = metalness;
savedSmoothness = smoothness;
savedBaseColor = baseColor;
}
#define AMB_FACT 0.25
#define SHIN_FACT 1.2
////////////////////////////////////////////////////////////////////////
//
// Description:
// update the material node based on the current mat factors.
//
// Use: private
void
MySimpleMaterialEditor::updateMaterial()
//
////////////////////////////////////////////////////////////////////////
{
float trnsp = material->transparency[0];
float smooth = smoothness * 0.8;
float rd = (1.0 - smooth) * (1.0 - trnsp);
SbVec3f vecOne(1, 1, 1);
material->diffuseColor = (baseColor * rd * (1.0 - metalness * smooth)).getValue();
material->ambientColor = AMB_FACT * material->diffuseColor[0];
material->specularColor = (1.0 - trnsp - rd) * (vecOne + metalness *
(baseColor - vecOne));
material->shininess = powf(smoothness, SHIN_FACT);
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// given the current material, figure the best metalness and
// smoothness factors which represent it.
//
// Use: private
void
MySimpleMaterialEditor::calculateMaterialFactors()
//
////////////////////////////////////////////////////////////////////////
{
// given that
// shin = smooth ^ SHIN_FACT;
//
smoothness = powf(material->shininess[0], 1.0 / SHIN_FACT);
// make a best guess at what the baseColor could be
// based on the diffuse color.
baseColor = material->diffuseColor[0];
float hsv[3];
baseColor.getHSVValue(hsv);
hsv[2] = 1; // scale intensity all the way
baseColor.setHSVValue(hsv);
// now find the metalness based on the object specular
// color, given that
// spec = (1 - trnsp - rd) * (1 + met * (color -1))
//
float trnsp = material->transparency[0];
float smooth = smoothness * 0.8;
float rd = (1 - smooth) * (1 - trnsp);
float A = (1 - trnsp - rd);
if (A != 0) {
// get the metalness by averaging the values found for r,g and b
int num = 0;
float met = 0.0;
SbColor spec = material->specularColor[0];
for (int i=0; i<3; i++)
if (baseColor[i] != 1 && spec[0] != A) {
met += (spec[0] - A) / (A * (baseColor[i] - 1)) ;
num++;
}
if (num != 0)
metalness = met / num;
else
metalness = 0;
}
else
metalness = 0;
if (metalness < 0)
metalness = 0;
else if (metalness > 1)
metalness = 1;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// updates the color wheel, color slider and motif sliders to the
// current material.
//
// Use: private
void
MySimpleMaterialEditor::updateMaterialUI()
//
////////////////////////////////////////////////////////////////////////
{
// if nothing built, return (they will be updated when built)
if (sldWidgets[0] == NULL)
return;
// update the metal/smooth/transp sliders
int val = (int) (metalness * 1000);
XmScaleSetValue(sldWidgets[2], val);
val = (int) (smoothness * 1000);
XmScaleSetValue(sldWidgets[1], val);
val = (int) (material->transparency[0] * 1000);
XmScaleSetValue(sldWidgets[0], val);
// update color slider and color wheel
float hsv[3];
baseColor.getHSVValue(hsv);
ignoreCallback = TRUE;
colWheel->setBaseColor(hsv);
colSlider->setBaseColor(hsv);
ignoreCallback = FALSE;
}
//
// redefine those generic virtual functions
//
const char *
MySimpleMaterialEditor::getDefaultWidgetName() const
{ return "MySimpleMaterialEditor"; }
const char *
MySimpleMaterialEditor::getDefaultTitle() const
{ return "Simple Material Editor"; }
const char *
MySimpleMaterialEditor::getDefaultIconTitle() const
{ return "Mat Editor"; }
//
////////////////////////////////////////////////////////////////////////
// static callbacks stubs
////////////////////////////////////////////////////////////////////////
//
//
// called by the color wheel when the color changes
//
void
MySimpleMaterialEditor::colWheelCB(void *pt, const float hsv[3])
{
MySimpleMaterialEditor *p = (MySimpleMaterialEditor *)pt;
if (p->ignoreCallback)
return;
// convert to rgb and update slider and material
p->baseColor.setHSVValue(hsv);
p->ignoreCallback = TRUE;
p->colSlider->setBaseColor(hsv);
p->ignoreCallback = FALSE;
p->updateMaterial();
}
//
// called by color slider when the color changes
//
void
MySimpleMaterialEditor::colSliderCB(void *pt, float)
{
MySimpleMaterialEditor *p = (MySimpleMaterialEditor *)pt;
if (p->ignoreCallback)
return;
// assign new color, update color wheel and material
const float *hsv = p->colSlider->getBaseColor();
p->baseColor.setHSVValue(hsv);
p->ignoreCallback = TRUE;
p->colWheel->setBaseColor(hsv);
p->ignoreCallback = FALSE;
p->updateMaterial();
}
//
// called by the XmNvalueChangedCallback. This sets a flag for later use
//
void
MySimpleMaterialEditor::fieldChangedCB(Widget, MySimpleMaterialEditor *p, void *)
{
p->fieldChanged = TRUE;
}
//
// called whenever the use types a new material name
//
void
MySimpleMaterialEditor::nameFieldCB(Widget w, MySimpleMaterialEditor *p, void *)
{
if (! p->fieldChanged)
return;
p->fieldChanged = FALSE;
// get the new material name
char *str = XmTextGetString(w);
if (p->materialName != NULL)
free(p->materialName);
p->materialName = (str[0] != '\0') ? strdup(str) : NULL;
XtFree(str);
// make the text field loose the focus
XmProcessTraversal(XtParent(w), XmTRAVERSE_CURRENT);
}
//
// called whenever any of the three sliders (metal, smooth, transp)
// changes values.
//
void
MySimpleMaterialEditor::sldWidgetsCB(Widget sld, MySimpleMaterialEditor *p, void *)
{
// get the slider new value
int v;
XmScaleGetValue(sld, &v);
float val = v / 1000.0;
//
// now update the material based on which slider changed
//
if (sld == p->sldWidgets[2]) {
// metalness has changed
p->metalness = val;
p->updateMaterial();
}
else if (sld == p->sldWidgets[1]) {
// smothness has changed
p->smoothness = val;
p->updateMaterial();
}
else {
// transparency has changed
p->material->transparency = val;
}
}
//
// called whenever the apply push button gets pressed
//
void
MySimpleMaterialEditor::applyCB(Widget, MySimpleMaterialEditor *p, void *)
{
p->callbackList.invokeCallbacks((void *)p);
p->saveMaterialFactors();
// save material name
if (p->savedMaterialName != NULL)
free(p->savedMaterialName);
p->savedMaterialName = (p->materialName != NULL) ? strdup(p->materialName) : NULL;
}
//
// called whenever the reset push button gets pressed
//
void
MySimpleMaterialEditor::resetCB(Widget, MySimpleMaterialEditor *p, void *)
{
//
// reset the material factors
//
p->copyMaterial(p->material, p->savedMaterial);
p->metalness = p->savedMetalness;
p->smoothness = p->savedSmoothness;
p->baseColor = p->savedBaseColor;
p->updateMaterialUI();
//
// reset the material name
//
if (p->materialName != NULL)
free(p->materialName);
p->materialName = (p->savedMaterialName != NULL) ? strdup(p->savedMaterialName) : NULL;
// update text field
if (p->nameField != NULL) {
char *str = (p->materialName != NULL) ? p->materialName : (char *) "";
XmTextSetString(p->nameField, str);
}
}
//
// called whenever the copy push button gets pressed
//
void
MySimpleMaterialEditor::copyCB(Widget, MySimpleMaterialEditor *p, XmAnyCallbackStruct *cb)
{
if (p->clipboard == NULL)
p->clipboard = new SoXtClipboard(p->getWidget());
//
// copy the material and also copy the current color (from the
// wheel) to enable pasting into the color editor.
//
// construct a path list which has the Material and BaseColor nodes
SoBaseColor *color = new SoBaseColor;
color->rgb.setValue(p->baseColor);
SoPathList *pathList = new SoPathList(2);
SoPath *path1 = new SoPath(p->material);
SoPath *path2 = new SoPath(color);
path1->ref();
path2->ref();
pathList->append(path1);
pathList->append(path2);
Time eventTime = cb->event->xbutton.time;
p->clipboard->copy(pathList, eventTime);
// delete the paths and the list color->unref();
path1->unref();
path2->unref();
delete pathList;
}
//
// called whenever the paste push button gets pressed
//
void
MySimpleMaterialEditor::pasteCB(Widget, MySimpleMaterialEditor *p, XmAnyCallbackStruct *cb)
{
if (p->clipboard == NULL)
p->clipboard = new SoXtClipboard(p->getWidget());
Time eventTime = cb->event->xbutton.time;
p->clipboard->paste(eventTime, MySimpleMaterialEditor::pasteDone, p);
}
//
// called whenever the X server is done doing the paste
//
void
MySimpleMaterialEditor::pasteDone(void *pt, SoPathList *pathList)
{
MySimpleMaterialEditor *p = (MySimpleMaterialEditor *)pt;
SoSearchAction sa;
SoFullPath *fullPath = NULL;
//
// search for first material in that pasted scene
//
sa.setType(SoMaterial::getClassTypeId());
for (int i=0; i < pathList->getLength(); i++) {
sa.apply( (*pathList)[i] );
if ( (fullPath = (SoFullPath *) sa.getPath()) != NULL) {
// assign new material
p->copyMaterial(p->material, (SoMaterial *) fullPath->getTail());
p->calculateMaterialFactors();
p->updateMaterialUI();
break;
}
}
//
// else search for the first base color in the scene, which will
// be used for the color wheel.
//
if (fullPath == NULL) {
sa.setType(SoBaseColor::getClassTypeId());
for (int i=0; i < pathList->getLength(); i++) {
sa.apply( (*pathList)[i] );
if ( (fullPath = (SoFullPath *) sa.getPath()) != NULL) {
// assign new color, update color UI + material
float hsv[3];
SoBaseColor *node = (SoBaseColor *) fullPath->getTail();
p->baseColor = node->rgb[0];
p->baseColor.getHSVValue(hsv);
p->ignoreCallback = TRUE;
p->colSlider->setBaseColor(hsv);
p->colWheel->setBaseColor(hsv);
p->ignoreCallback = FALSE;
p->updateMaterial();
break;
}
}
}
// ??? We delete the callback data when done with it.
delete pathList;
}