OpenSceneGraph/src/osg/Material.cpp

445 lines
13 KiB
C++

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* 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
* OpenSceneGraph Public License for more details.
*/
#include <osg/Material>
#include <osg/BoundsChecking>
#include <osg/Notify>
using namespace osg;
Material::Material()
{
_colorMode = OFF;
_ambientFrontAndBack = true;
_ambientFront.set(0.2f, 0.2f, 0.2f, 1.0f);
_ambientBack.set(0.2f, 0.2f, 0.2f, 1.0f);
_diffuseFrontAndBack = true;
_diffuseFront.set(0.8f, 0.8f, 0.8f, 1.0f);
_diffuseBack.set(0.8f, 0.8f, 0.8f, 1.0f);
_specularFrontAndBack = true;
_specularFront.set(0.0f, 0.0f, 0.0f, 1.0f);
_specularBack.set(0.0f, 0.0f, 0.0f, 1.0f);
_emissionFrontAndBack = true;
_emissionFront.set(0.0f, 0.0f, 0.0f, 1.0f);
_emissionBack.set(0.0f, 0.0f, 0.0f, 1.0f);
_shininessFrontAndBack = true;
_shininessFront = 0.0f;
_shininessBack = 0.0f;
}
Material::~Material()
{
}
Material& Material:: operator = (const Material& rhs)
{
if (&rhs==this) return *this;
_colorMode= rhs._colorMode;
_ambientFrontAndBack= rhs._ambientFrontAndBack;
_ambientFront= rhs._ambientFront;
_ambientBack= rhs._ambientBack;
_diffuseFrontAndBack= rhs._diffuseFrontAndBack;
_diffuseFront= rhs._diffuseFront;
_diffuseBack= rhs._diffuseBack;
_specularFrontAndBack= rhs._specularFrontAndBack;
_specularFront= rhs._specularFront;
_specularBack= rhs._specularBack;
_emissionFrontAndBack= rhs._emissionFrontAndBack;
_emissionFront= rhs._emissionFront;
_emissionBack= rhs._emissionBack;
_shininessFrontAndBack= rhs._shininessFrontAndBack;
_shininessFront= rhs._shininessFront;
_shininessBack= rhs._shininessBack;
return *this;
}
void Material::setAmbient(Face face, const Vec4& ambient )
{
switch(face)
{
case(FRONT):
_ambientFrontAndBack = false;
_ambientFront = ambient;
//clampArray4BetweenRange(_ambientFront,0.0f,1.0f,"osg::Material::setAmbient(..)");
break;
case(BACK):
_ambientFrontAndBack = false;
_ambientBack = ambient;
//clampArray4BetweenRange(_ambientBack,0.0f,1.0f,"Material::setAmbient(..)");
break;
case(FRONT_AND_BACK):
_ambientFrontAndBack = true;
_ambientFront = ambient;
//clampArray4BetweenRange(_ambientFront,0.0f,1.0f,"Material::setAmbient(..)");
_ambientBack = _ambientFront;
break;
default:
notify(NOTICE)<<"Notice: invalid Face passed to Material::setAmbient()."<<std::endl;
}
}
const Vec4& Material::getAmbient(Face face) const
{
switch(face)
{
case(FRONT):
return _ambientFront;
case(BACK):
return _ambientBack;
case(FRONT_AND_BACK):
if (!_ambientFrontAndBack)
{
notify(NOTICE)<<"Notice: Material::getAmbient(FRONT_AND_BACK) called on material "<< std::endl;
notify(NOTICE)<<" with separate FRONT and BACK ambient colors."<< std::endl;
}
return _ambientFront;
}
notify(NOTICE)<<"Notice: invalid Face passed to Material::getAmbient()."<< std::endl;
return _ambientFront;
}
void Material::setDiffuse(Face face, const Vec4& diffuse )
{
switch(face)
{
case(FRONT):
_diffuseFrontAndBack = false;
_diffuseFront = diffuse;
//clampArray4BetweenRange(_diffuseFront,0.0f,1.0f,"Material::setDiffuse(..)");
break;
case(BACK):
_diffuseFrontAndBack = false;
_diffuseBack = diffuse;
//clampArray4BetweenRange(_diffuseBack,0.0f,1.0f,"Material::setDiffuse(..)");
break;
case(FRONT_AND_BACK):
_diffuseFrontAndBack = true;
_diffuseFront = diffuse;
//clampArray4BetweenRange(_diffuseFront,0.0f,1.0f,"Material::setDiffuse(..)");
_diffuseBack = _diffuseFront;
break;
default:
notify(NOTICE)<<"Notice: invalid Face passed to Material::setDiffuse()."<< std::endl;
break;
}
}
const Vec4& Material::getDiffuse(Face face) const
{
switch(face)
{
case(FRONT):
return _diffuseFront;
case(BACK):
return _diffuseBack;
case(FRONT_AND_BACK):
if (!_diffuseFrontAndBack)
{
notify(NOTICE)<<"Notice: Material::getDiffuse(FRONT_AND_BACK) called on material "<< std::endl;
notify(NOTICE)<<" with separate FRONT and BACK diffuse colors."<< std::endl;
}
return _diffuseFront;
}
notify(NOTICE)<<"Notice: invalid Face passed to Material::getDiffuse()."<< std::endl;
return _diffuseFront;
}
void Material::setSpecular(Face face, const Vec4& specular )
{
switch(face)
{
case(FRONT):
_specularFrontAndBack = false;
_specularFront = specular;
//clampArray4BetweenRange(_specularFront,0.0f,1.0f,"Material::setSpecular(..)");
break;
case(BACK):
_specularFrontAndBack = false;
_specularBack = specular;
//clampArray4BetweenRange(_specularBack,0.0f,1.0f,"Material::setSpecular(..)");
break;
case(FRONT_AND_BACK):
_specularFrontAndBack = true;
_specularFront = specular;
//clampArray4BetweenRange(_specularFront,0.0f,1.0f,"Material::setSpecular(..)");
_specularBack = _specularFront;
break;
default:
notify(NOTICE)<<"Notice: invalid Face passed to Material::setSpecular()."<< std::endl;
break;
}
}
const Vec4& Material::getSpecular(Face face) const
{
switch(face)
{
case(FRONT):
return _specularFront;
case(BACK):
return _specularBack;
case(FRONT_AND_BACK):
if (!_specularFrontAndBack)
{
notify(NOTICE)<<"Notice: Material::getSpecular(FRONT_AND_BACK) called on material "<< std::endl;
notify(NOTICE)<<" with separate FRONT and BACK specular colors."<< std::endl;
}
return _specularFront;
}
notify(NOTICE)<<"Notice: invalid Face passed to Material::getSpecular()."<< std::endl;
return _specularFront;
}
void Material::setEmission(Face face, const Vec4& emission )
{
switch(face)
{
case(FRONT):
_emissionFrontAndBack = false;
_emissionFront = emission;
//clampArray4BetweenRange(_emissionFront,0.0f,1.0f,"Material::setEmission(..)");
break;
case(BACK):
_emissionFrontAndBack = false;
_emissionBack = emission;
//clampArray4BetweenRange(_emissionBack,0.0f,1.0f,"Material::setEmission(..)");
break;
case(FRONT_AND_BACK):
_emissionFrontAndBack = true;
_emissionFront = emission;
//clampArray4BetweenRange(_emissionFront,0.0f,1.0f,"Material::setEmission(..)");
_emissionBack = _emissionFront;
break;
default:
notify(NOTICE)<<"Notice: invalid Face passed to Material::setEmission()."<< std::endl;
break;
}
}
const Vec4& Material::getEmission(Face face) const
{
switch(face)
{
case(FRONT):
return _emissionFront;
case(BACK):
return _emissionBack;
case(FRONT_AND_BACK):
if (!_emissionFrontAndBack)
{
notify(NOTICE)<<"Notice: Material::getEmission(FRONT_AND_BACK) called on material "<< std::endl;
notify(NOTICE)<<" with separate FRONT and BACK emission colors."<< std::endl;
}
return _emissionFront;
}
notify(NOTICE)<<"Notice: invalid Face passed to Material::getEmission()."<< std::endl;
return _emissionFront;
}
void Material::setShininess(Face face, float shininess )
{
clampBetweenRange(shininess,0.0f,128.0f,"Material::setShininess()");
switch(face)
{
case(FRONT):
_shininessFrontAndBack = false;
_shininessFront = shininess;
break;
case(BACK):
_shininessFrontAndBack = false;
_shininessBack = shininess;
break;
case(FRONT_AND_BACK):
_shininessFrontAndBack = true;
_shininessFront = shininess;
_shininessBack = shininess;
break;
default:
notify(NOTICE)<<"Notice: invalid Face passed to Material::setShininess()."<< std::endl;
break;
}
}
float Material::getShininess(Face face) const
{
switch(face)
{
case(FRONT):
return _shininessFront;
case(BACK):
return _shininessBack;
case(FRONT_AND_BACK):
if (!_shininessFrontAndBack)
{
notify(NOTICE)<<"Notice: Material::getShininess(FRONT_AND_BACK) called on material "<< std::endl;
notify(NOTICE)<<" with separate FRONT and BACK shininess colors."<< std::endl;
}
return _shininessFront;
}
notify(NOTICE)<<"Notice: invalid Face passed to Material::getShininess()."<< std::endl;
return _shininessFront;
}
void Material::setTransparency(Face face,float transparency)
{
//clampBetweenRange(transparency,0.0f,1.0f,"Material::setTransparency()");
if (face==FRONT || face==FRONT_AND_BACK)
{
_ambientFront[3] = 1.0f-transparency;
_diffuseFront[3] = 1.0f-transparency;
_specularFront[3] = 1.0f-transparency;
_emissionFront[3] = 1.0f-transparency;
}
if (face==BACK || face==FRONT_AND_BACK)
{
_ambientBack[3] = 1.0f-transparency;
_diffuseBack[3] = 1.0f-transparency;
_specularBack[3] = 1.0f-transparency;
_emissionBack[3] = 1.0f-transparency;
}
}
void Material::setAlpha(Face face,float alpha)
{
clampBetweenRange(alpha,0.0f,1.0f,"Material::setAlpha()");
if (face==FRONT || face==FRONT_AND_BACK)
{
_ambientFront[3] = alpha;
_diffuseFront[3] = alpha;
_specularFront[3] = alpha;
_emissionFront[3] = alpha;
}
if (face==BACK || face==FRONT_AND_BACK)
{
_ambientBack[3] = alpha;
_diffuseBack[3] = alpha;
_specularBack[3] = alpha;
_emissionBack[3] = alpha;
}
}
void Material::apply(State&) const
{
#ifdef OSG_GL_FIXED_FUNCTION_AVAILABLE
#ifdef OSG_GL1_AVAILABLE
if (_colorMode==OFF)
{
glDisable(GL_COLOR_MATERIAL);
glColor4fv(_diffuseFront.ptr());
}
else
{
glColorMaterial(GL_FRONT_AND_BACK,(GLenum)_colorMode);
glEnable(GL_COLOR_MATERIAL);
switch(_colorMode)
{
case(AMBIENT): glColor4fv(_ambientFront.ptr()); break;
case(DIFFUSE): glColor4fv(_diffuseFront.ptr()); break;
case(SPECULAR): glColor4fv(_specularFront.ptr()); break;
case(EMISSION): glColor4fv(_emissionFront.ptr()); break;
case(AMBIENT_AND_DIFFUSE): glColor4fv(_diffuseFront.ptr()); break;
case(OFF): break;
}
}
#endif
if (_colorMode!=AMBIENT && _colorMode!=AMBIENT_AND_DIFFUSE)
{
if (_ambientFrontAndBack)
{
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, _ambientFront.ptr() );
}
else
{
glMaterialfv( GL_FRONT, GL_AMBIENT, _ambientFront.ptr() );
glMaterialfv( GL_BACK, GL_AMBIENT, _ambientBack.ptr() );
}
}
if (_colorMode!=DIFFUSE && _colorMode!=AMBIENT_AND_DIFFUSE)
{
if (_diffuseFrontAndBack)
{
glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, _diffuseFront.ptr() );
}
else
{
glMaterialfv( GL_FRONT, GL_DIFFUSE, _diffuseFront.ptr() );
glMaterialfv( GL_BACK, GL_DIFFUSE, _diffuseBack.ptr() );
}
}
if (_colorMode!=SPECULAR)
{
if (_specularFrontAndBack)
{
glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, _specularFront.ptr() );
}
else
{
glMaterialfv( GL_FRONT, GL_SPECULAR, _specularFront.ptr() );
glMaterialfv( GL_BACK, GL_SPECULAR, _specularBack.ptr() );
}
}
if (_colorMode!=EMISSION)
{
if (_emissionFrontAndBack)
{
glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, _emissionFront.ptr() );
}
else
{
glMaterialfv( GL_FRONT, GL_EMISSION, _emissionFront.ptr() );
glMaterialfv( GL_BACK, GL_EMISSION, _emissionBack.ptr() );
}
}
if (_shininessFrontAndBack)
{
glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, _shininessFront );
}
else
{
glMaterialf( GL_FRONT, GL_SHININESS, _shininessFront );
glMaterialf( GL_BACK, GL_SHININESS, _shininessBack );
}
#else
osg::notify(osg::NOTICE)<<"Warning: Material::apply(State&) - not supported."<<std::endl;
#endif
}