Added osgFX - Marco Jez's special effects nodekit.
This commit is contained in:
236
src/osgFX/AnisotropicLighting.cpp
Normal file
236
src/osgFX/AnisotropicLighting.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#include <osgFX/AnisotropicLighting>
|
||||
#include <osgFX/Registry>
|
||||
|
||||
#include <osg/VertexProgram>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/TexEnv>
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class ViewMatrixExtractor: public osg::StateAttribute {
|
||||
public:
|
||||
ViewMatrixExtractor()
|
||||
: osg::StateAttribute(),
|
||||
vp_(0),
|
||||
param_(0)
|
||||
{
|
||||
}
|
||||
|
||||
ViewMatrixExtractor(const ViewMatrixExtractor ©, const osg::CopyOp ©op)
|
||||
: osg::StateAttribute(copy, copyop),
|
||||
vp_(static_cast<osg::VertexProgram *>(copyop(copy.vp_.get()))),
|
||||
param_(copy.param_)
|
||||
{
|
||||
}
|
||||
|
||||
ViewMatrixExtractor(osg::VertexProgram *vp, int param)
|
||||
: osg::StateAttribute(),
|
||||
vp_(vp),
|
||||
param_(param)
|
||||
{
|
||||
}
|
||||
|
||||
META_StateAttribute(osgFX, ViewMatrixExtractor, 0x564d4548);
|
||||
|
||||
int compare(const osg::StateAttribute &sa) const
|
||||
{
|
||||
COMPARE_StateAttribute_Types(ViewMatrixExtractor, sa);
|
||||
if (vp_.get() != rhs.vp_.get()) return -1;
|
||||
if (param_ < rhs.param_) return -1;
|
||||
if (param_ > rhs.param_) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apply(osg::State &state) const
|
||||
{
|
||||
if (vp_.valid()) {
|
||||
osg::Matrix M = state.getInitialInverseViewMatrix();
|
||||
for (int i=0; i<4; ++i) {
|
||||
vp_->setProgramLocalParameter(param_+i, osg::Vec4(M(0, i), M(1, i), M(2, i), M(3, i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
mutable osg::ref_ptr<osg::VertexProgram> vp_;
|
||||
int param_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
osg::Image *create_default_image()
|
||||
{
|
||||
const int texture_size = 16;
|
||||
osg::ref_ptr<osg::Image> image = new osg::Image;
|
||||
image->setImage(texture_size, texture_size, 1, 3, GL_RGB, GL_UNSIGNED_BYTE, new unsigned char[3*texture_size*texture_size], osg::Image::USE_NEW_DELETE);
|
||||
for (int i=0; i<texture_size; ++i) {
|
||||
for (int j=0; j<texture_size; ++j) {
|
||||
float s = static_cast<float>(j) / (texture_size-1);
|
||||
float t = static_cast<float>(i) / (texture_size-1);
|
||||
float lum = t * 0.75f;
|
||||
float red = lum + 0.2f * powf(cosf(s*10), 3.0f);
|
||||
float green = lum;
|
||||
float blue = lum + 0.2f * powf(sinf(s*10), 3.0f);
|
||||
if (red > 1) red = 1;
|
||||
if (red < 0) red = 0;
|
||||
if (blue > 1) blue = 1;
|
||||
if (blue < 0) blue = 0;
|
||||
*(image->data(j, i)+0) = static_cast<unsigned char>(red * 255);
|
||||
*(image->data(j, i)+1) = static_cast<unsigned char>(green * 255);
|
||||
*(image->data(j, i)+2) = static_cast<unsigned char>(blue * 255);
|
||||
}
|
||||
}
|
||||
return image.take();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
Registry::Proxy proxy(new AnisotropicLighting);
|
||||
|
||||
class DefaultTechnique: public Technique {
|
||||
public:
|
||||
|
||||
DefaultTechnique(int lightnum, osg::Texture2D *texture)
|
||||
: Technique(),
|
||||
lightnum_(lightnum),
|
||||
texture_(texture)
|
||||
{
|
||||
}
|
||||
|
||||
void getRequiredExtensions(std::vector<std::string> &extensions) const
|
||||
{
|
||||
extensions.push_back("GL_ARB_vertex_program");
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void define_passes()
|
||||
{
|
||||
std::ostringstream vp_oss;
|
||||
vp_oss <<
|
||||
"!!ARBvp1.0\n"
|
||||
"PARAM c5 = { 0, 0, 0, 1 };"
|
||||
"PARAM c4 = { 0, 0, 0, 0 };"
|
||||
"TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8, R9;"
|
||||
"ATTRIB v18 = vertex.normal;"
|
||||
"ATTRIB v16 = vertex.position;"
|
||||
"PARAM s259[4] = { state.matrix.mvp };"
|
||||
"PARAM s18 = state.light[" << lightnum_ << "].position;"
|
||||
"PARAM s223[4] = { state.matrix.modelview[0] };"
|
||||
"PARAM c0[4] = { program.local[0..3] };"
|
||||
" DP4 result.position.x, s259[0], v16;"
|
||||
" DP4 result.position.y, s259[1], v16;"
|
||||
" DP4 result.position.z, s259[2], v16;"
|
||||
" DP4 result.position.w, s259[3], v16;"
|
||||
" MOV R9, c0[0];"
|
||||
" MUL R0, R9.y, s223[1];"
|
||||
" MAD R0, R9.x, s223[0], R0;"
|
||||
" MAD R0, R9.z, s223[2], R0;"
|
||||
" MAD R8, R9.w, s223[3], R0;"
|
||||
" DP4 R0.x, R8, v16;"
|
||||
" MOV R7, c0[1];"
|
||||
" MUL R1, R7.y, s223[1];"
|
||||
" MAD R1, R7.x, s223[0], R1;"
|
||||
" MAD R1, R7.z, s223[2], R1;"
|
||||
" MAD R6, R7.w, s223[3], R1;"
|
||||
" DP4 R0.y, R6, v16;"
|
||||
" MOV R5, c0[2];"
|
||||
" MUL R1, R5.y, s223[1];"
|
||||
" MAD R1, R5.x, s223[0], R1;"
|
||||
" MAD R1, R5.z, s223[2], R1;"
|
||||
" MAD R4, R5.w, s223[3], R1;"
|
||||
" DP4 R0.z, R4, v16;"
|
||||
" MOV R3, c0[3];"
|
||||
" MUL R1, R3.y, s223[1];"
|
||||
" MAD R1, R3.x, s223[0], R1;"
|
||||
" MAD R1, R3.z, s223[2], R1;"
|
||||
" MAD R1, R3.w, s223[3], R1;"
|
||||
" DP4 R0.w, R1, v16;"
|
||||
" MOV R1.x, R9.w;"
|
||||
" MOV R1.y, R7.w;"
|
||||
" MOV R1.z, R5.w;"
|
||||
" MOV R1.w, R3.w;"
|
||||
" ADD R2, R1, -R0;"
|
||||
" DP4 R0.x, R2, R2;"
|
||||
" RSQ R1.x, R0.x;"
|
||||
" DP4 R0.x, R9, s18;"
|
||||
" DP4 R0.y, R7, s18;"
|
||||
" DP4 R0.z, R5, s18;"
|
||||
" DP4 R0.w, R3, s18;"
|
||||
" DP4 R1.y, R0, R0;"
|
||||
" RSQ R1.y, R1.y;"
|
||||
" MUL R3, R1.y, R0;"
|
||||
" MAD R2, R1.x, R2, R3;"
|
||||
" DP4 R1.x, R2, R2;"
|
||||
" RSQ R1.x, R1.x;"
|
||||
" MUL R1, R1.x, R2;"
|
||||
" DP3 R2.x, R8.xyzx, v18.xyzx;"
|
||||
" DP3 R2.y, R6.xyzx, v18.xyzx;"
|
||||
" DP3 R2.z, R4.xyzx, v18.xyzx;"
|
||||
" MOV R2.w, c4.x;"
|
||||
" DP4 R1.x, R1, R2;"
|
||||
" MAX result.texcoord[0].x, R1.x, c4.x;"
|
||||
" DP4 R0.x, R0, R2;"
|
||||
" MAX result.texcoord[0].y, R0.x, c4.x;"
|
||||
"END\n";
|
||||
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
|
||||
osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
|
||||
vp->setVertexProgram(vp_oss.str());
|
||||
ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
ss->setAttributeAndModes(new ViewMatrixExtractor(vp.get(), 0), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
ss->setTextureAttributeAndModes(0, texture_.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv;
|
||||
texenv->setMode(osg::TexEnv::DECAL);
|
||||
ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
addPass(ss.get());
|
||||
}
|
||||
|
||||
private:
|
||||
int lightnum_;
|
||||
osg::ref_ptr<osg::Texture2D> texture_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
AnisotropicLighting::AnisotropicLighting()
|
||||
: Effect(),
|
||||
lightnum_(0),
|
||||
texture_(new osg::Texture2D)
|
||||
{
|
||||
texture_->setImage(create_default_image());
|
||||
texture_->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);
|
||||
texture_->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);
|
||||
}
|
||||
|
||||
AnisotropicLighting::AnisotropicLighting(const AnisotropicLighting ©, const osg::CopyOp ©op)
|
||||
: Effect(copy, copyop),
|
||||
lightnum_(copy.lightnum_),
|
||||
texture_(static_cast<osg::Texture2D *>(copyop(copy.texture_.get())))
|
||||
{
|
||||
}
|
||||
|
||||
bool AnisotropicLighting::define_techniques()
|
||||
{
|
||||
addTechnique(new DefaultTechnique(lightnum_, texture_.get()));
|
||||
return true;
|
||||
}
|
||||
171
src/osgFX/Cartoon.cpp
Normal file
171
src/osgFX/Cartoon.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#include <osgFX/Cartoon>
|
||||
#include <osgFX/Registry>
|
||||
|
||||
#include <osg/PolygonOffset>
|
||||
#include <osg/Texture1D>
|
||||
#include <osg/VertexProgram>
|
||||
#include <osg/PolygonMode>
|
||||
#include <osg/CullFace>
|
||||
#include <osg/Image>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/LineWidth>
|
||||
#include <osg/Material>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
osg::Image *create_sharp_lighting_map(int levels = 4, int texture_size = 16)
|
||||
{
|
||||
osg::ref_ptr<osg::Image> image = new osg::Image;
|
||||
image->setImage(texture_size, 1, 1, 4, GL_RGBA, GL_UNSIGNED_BYTE, new unsigned char[4*texture_size], osg::Image::USE_NEW_DELETE);
|
||||
for (int i=0; i<texture_size; ++i) {
|
||||
float c = i/static_cast<float>(texture_size);
|
||||
c = (1+static_cast<int>(sqrtf(c) * (levels))) / static_cast<float>(levels+1);
|
||||
*(image->data(i, 0)+0) = static_cast<unsigned char>(c*255);
|
||||
*(image->data(i, 0)+1) = static_cast<unsigned char>(c*255);
|
||||
*(image->data(i, 0)+2) = static_cast<unsigned char>(c*255);
|
||||
*(image->data(i, 0)+3) = 255;
|
||||
}
|
||||
return image.take();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// register a prototype for this effect
|
||||
Registry::Proxy proxy(new Cartoon);
|
||||
|
||||
|
||||
// default technique class
|
||||
class DefaultTechnique: public Technique {
|
||||
public:
|
||||
DefaultTechnique(osg::Material *wf_mat, osg::LineWidth *wf_lw, int lightnum)
|
||||
: Technique(), wf_mat_(wf_mat), wf_lw_(wf_lw), lightnum_(lightnum) {}
|
||||
|
||||
void getRequiredExtensions(std::vector<std::string> &extensions) const
|
||||
{
|
||||
extensions.push_back("GL_ARB_vertex_program");
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void define_passes()
|
||||
{
|
||||
// implement pass #1 (solid surfaces)
|
||||
{
|
||||
std::ostringstream vp_oss;
|
||||
vp_oss <<
|
||||
"!!ARBvp1.0\n"
|
||||
"OPTION ARB_position_invariant;"
|
||||
"PARAM c0 = { 0, 0, 0, 0 };"
|
||||
"TEMP R0, R1;"
|
||||
"ATTRIB v18 = vertex.normal;"
|
||||
"PARAM s18 = state.light[" << lightnum_ << "].position;"
|
||||
"PARAM s16 = state.light[" << lightnum_ << "].diffuse;"
|
||||
"PARAM s1 = state.material.diffuse;"
|
||||
"PARAM s631[4] = { state.matrix.modelview[0].invtrans };"
|
||||
"MOV R0, s1;"
|
||||
"MUL result.color.front.primary, R0, s16;"
|
||||
"DP4 R0.x, s18, s18;"
|
||||
"RSQ R0.x, R0.x;"
|
||||
"MUL R1, R0.x, s18;"
|
||||
"DP4 R0.x, s631[0], v18;"
|
||||
"DP4 R0.y, s631[1], v18;"
|
||||
"DP4 R0.z, s631[2], v18;"
|
||||
"DP4 R0.w, s631[3], v18;"
|
||||
"DP4 R0.x, R1, R0;"
|
||||
"MAX result.texcoord[0].x, c0.x, R0.x;"
|
||||
"END";
|
||||
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
|
||||
osg::ref_ptr<osg::PolygonOffset> polyoffset = new osg::PolygonOffset;
|
||||
polyoffset->setFactor(1.0f);
|
||||
polyoffset->setUnits(1.0f);
|
||||
ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
|
||||
vp->setVertexProgram(vp_oss.str());
|
||||
ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
|
||||
|
||||
ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF);
|
||||
|
||||
osg::ref_ptr<osg::Texture1D> texture = new osg::Texture1D;
|
||||
texture->setImage(create_sharp_lighting_map());
|
||||
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);
|
||||
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);
|
||||
ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv;
|
||||
texenv->setMode(osg::TexEnv::MODULATE);
|
||||
ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
|
||||
|
||||
addPass(ss.get());
|
||||
}
|
||||
|
||||
// implement pass #2 (outlines)
|
||||
{
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode;
|
||||
polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
|
||||
ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::CullFace> cf = new osg::CullFace;
|
||||
cf->setMode(osg::CullFace::FRONT);
|
||||
ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
wf_lw_->setWidth(2);
|
||||
ss->setAttributeAndModes(wf_lw_.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON);
|
||||
|
||||
wf_mat_->setColorMode(osg::Material::OFF);
|
||||
wf_mat_->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
|
||||
wf_mat_->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
|
||||
wf_mat_->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
|
||||
wf_mat_->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
|
||||
ss->setAttributeAndModes(wf_mat_.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
|
||||
ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
|
||||
|
||||
addPass(ss.get());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
osg::ref_ptr<osg::Material> wf_mat_;
|
||||
osg::ref_ptr<osg::LineWidth> wf_lw_;
|
||||
int lightnum_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Cartoon::Cartoon()
|
||||
: Effect(),
|
||||
wf_mat_(new osg::Material),
|
||||
wf_lw_(new osg::LineWidth),
|
||||
lightnum_(0)
|
||||
{
|
||||
}
|
||||
|
||||
Cartoon::Cartoon(const Cartoon ©, const osg::CopyOp ©op)
|
||||
: Effect(copy, copyop),
|
||||
wf_mat_(static_cast<osg::Material *>(copyop(copy.wf_mat_.get()))),
|
||||
wf_lw_(static_cast<osg::LineWidth *>(copyop(copy.wf_lw_.get()))),
|
||||
lightnum_(copy.lightnum_)
|
||||
{
|
||||
}
|
||||
|
||||
bool Cartoon::define_techniques()
|
||||
{
|
||||
addTechnique(new DefaultTechnique(wf_mat_.get(), wf_lw_.get(), lightnum_));
|
||||
return true;
|
||||
}
|
||||
124
src/osgFX/Effect.cpp
Normal file
124
src/osgFX/Effect.cpp
Normal file
@@ -0,0 +1,124 @@
|
||||
#include <osgFX/Effect>
|
||||
#include <osgFX/Validator>
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/Notify>
|
||||
#include <osg/StateAttribute>
|
||||
#include <osg/Geometry>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
Effect::Effect()
|
||||
: osg::Node(),
|
||||
enabled_(true),
|
||||
global_sel_tech_(AUTO_DETECT),
|
||||
techs_defined_(false)
|
||||
{
|
||||
build_dummy_node();
|
||||
}
|
||||
|
||||
Effect::Effect(const Effect ©, const osg::CopyOp ©op)
|
||||
: osg::Node(copy, copyop),
|
||||
enabled_(copy.enabled_),
|
||||
global_sel_tech_(copy.global_sel_tech_),
|
||||
techs_defined_(false),
|
||||
child_(static_cast<osg::Node *>(copyop(copy.child_.get())))
|
||||
{
|
||||
build_dummy_node();
|
||||
}
|
||||
|
||||
bool Effect::computeBound() const
|
||||
{
|
||||
_bsphere.init();
|
||||
_bsphere_computed = true;
|
||||
|
||||
if (child_.valid()) {
|
||||
_bsphere.expandBy(child_->getBound());
|
||||
}
|
||||
|
||||
return _bsphere.valid();
|
||||
}
|
||||
|
||||
void Effect::traverse(osg::NodeVisitor &nv)
|
||||
{
|
||||
typedef osg::Node Inherited;
|
||||
|
||||
if (!child_.valid()) return;
|
||||
|
||||
// we are not a Group, so children will not notify us when their
|
||||
// bounding box has changed. We need to recompute it at each traversal... :(
|
||||
dirtyBound();
|
||||
|
||||
if (!enabled_) {
|
||||
child_->accept(nv);
|
||||
Inherited::traverse(nv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!techs_defined_) {
|
||||
|
||||
// clear existing techniques if necessary
|
||||
techs_.clear();
|
||||
sel_tech_.clear();
|
||||
tech_selected_.clear();
|
||||
|
||||
// define new techniques
|
||||
techs_defined_ = define_techniques();
|
||||
if (!techs_defined_) {
|
||||
osg::notify(osg::WARN) << "Warning: osgFX::Effect: could not define techniques for effect " << className() << std::endl;
|
||||
return;
|
||||
}
|
||||
if (techs_.empty()) {
|
||||
osg::notify(osg::WARN) << "Warning: osgFX::Effect: no techniques defined for effect " << className() << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Technique *tech = 0;
|
||||
|
||||
if (global_sel_tech_ == AUTO_DETECT) {
|
||||
bool none_selected = true;
|
||||
for (unsigned i=0; i<tech_selected_.size(); ++i) {
|
||||
if (tech_selected_[i] != 0) {
|
||||
none_selected = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (none_selected) {
|
||||
dummy_for_validation_->accept(nv);
|
||||
}
|
||||
|
||||
int max_index = -1;
|
||||
for (unsigned j=0; j<sel_tech_.size(); ++j) {
|
||||
if (tech_selected_[j] != 0) {
|
||||
if (sel_tech_[j] > max_index) {
|
||||
max_index = sel_tech_[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (max_index >= 0) {
|
||||
tech = techs_[max_index].get();
|
||||
}
|
||||
|
||||
} else {
|
||||
tech = techs_[global_sel_tech_].get();
|
||||
}
|
||||
|
||||
if (tech) {
|
||||
tech->accept(nv, child_.get());
|
||||
} else {
|
||||
child_->accept(nv);
|
||||
}
|
||||
|
||||
Inherited::traverse(nv);
|
||||
}
|
||||
|
||||
void Effect::build_dummy_node()
|
||||
{
|
||||
dummy_for_validation_ = new osg::Geode;
|
||||
osg::ref_ptr<osg::Geometry> geo = new osg::Geometry;
|
||||
dummy_for_validation_->addDrawable(geo.get());
|
||||
dummy_for_validation_->getOrCreateStateSet()->setAttribute(new Validator(this));
|
||||
}
|
||||
21
src/osgFX/GNUmakefile
Normal file
21
src/osgFX/GNUmakefile
Normal file
@@ -0,0 +1,21 @@
|
||||
TOPDIR = ../..
|
||||
include $(TOPDIR)/Make/makedefs
|
||||
|
||||
CXXFILES =\
|
||||
AnisotropicLighting.cpp\
|
||||
Cartoon.cpp\
|
||||
Effect.cpp\
|
||||
Registry.cpp\
|
||||
Scribe.cpp\
|
||||
SpecularHighlights.cpp\
|
||||
Technique.cpp\
|
||||
Validator.cpp\
|
||||
|
||||
|
||||
LIBS += -losg -losgDB -losgUtil $(GL_LIBS) $(OTHER_LIBS) $(DYNAMICLIBRARYLIB)
|
||||
DEF += -DOSGFX_LIBRARY
|
||||
|
||||
TARGET_BASENAME = osgFX
|
||||
LIB = $(LIB_PREFIX)$(TARGET_BASENAME).$(LIB_EXT)
|
||||
|
||||
include $(TOPDIR)/Make/makerules
|
||||
9
src/osgFX/Registry.cpp
Normal file
9
src/osgFX/Registry.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include <osgFX/Registry>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
Registry *Registry::instance_ = 0;
|
||||
|
||||
Registry::Registry()
|
||||
{
|
||||
}
|
||||
99
src/osgFX/Scribe.cpp
Normal file
99
src/osgFX/Scribe.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include <osgFX/Scribe>
|
||||
#include <osgFX/Registry>
|
||||
|
||||
#include <osg/GL>
|
||||
#include <osg/PolygonOffset>
|
||||
#include <osg/Material>
|
||||
#include <osg/LineWidth>
|
||||
#include <osg/PolygonMode>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// register a prototype for this effect
|
||||
Registry::Proxy proxy(new Scribe);
|
||||
|
||||
|
||||
// default technique class
|
||||
class DefaultTechnique: public Technique {
|
||||
public:
|
||||
DefaultTechnique(osg::Material *wf_mat, osg::LineWidth *wf_lw)
|
||||
: Technique(), wf_mat_(wf_mat), wf_lw_(wf_lw) {}
|
||||
|
||||
bool validate(osg::State &) const
|
||||
{
|
||||
return strncmp((const char*)glGetString(GL_VERSION), "1.1", 3) >= 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void define_passes()
|
||||
{
|
||||
// implement pass #1
|
||||
{
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
|
||||
osg::ref_ptr<osg::PolygonOffset> polyoffset = new osg::PolygonOffset;
|
||||
polyoffset->setFactor(1.0f);
|
||||
polyoffset->setUnits(1.0f);
|
||||
ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
addPass(ss.get());
|
||||
}
|
||||
|
||||
// implement pass #2
|
||||
{
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
|
||||
osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode;
|
||||
polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
|
||||
ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
wf_lw_->setWidth(1);
|
||||
ss->setAttributeAndModes(wf_lw_.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
wf_mat_->setColorMode(osg::Material::OFF);
|
||||
wf_mat_->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
|
||||
wf_mat_->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
|
||||
wf_mat_->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
|
||||
wf_mat_->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
ss->setAttributeAndModes(wf_mat_.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
|
||||
ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
|
||||
|
||||
addPass(ss.get());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
osg::ref_ptr<osg::Material> wf_mat_;
|
||||
osg::ref_ptr<osg::LineWidth> wf_lw_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Scribe::Scribe()
|
||||
: Effect(),
|
||||
wf_mat_(new osg::Material),
|
||||
wf_lw_(new osg::LineWidth)
|
||||
{
|
||||
}
|
||||
|
||||
Scribe::Scribe(const Scribe ©, const osg::CopyOp ©op)
|
||||
: Effect(copy, copyop),
|
||||
wf_mat_(static_cast<osg::Material *>(copyop(copy.wf_mat_.get()))),
|
||||
wf_lw_(static_cast<osg::LineWidth *>(copyop(copy.wf_lw_.get())))
|
||||
{
|
||||
}
|
||||
|
||||
bool Scribe::define_techniques()
|
||||
{
|
||||
addTechnique(new DefaultTechnique(wf_mat_.get(), wf_lw_.get()));
|
||||
return true;
|
||||
}
|
||||
186
src/osgFX/SpecularHighlights.cpp
Normal file
186
src/osgFX/SpecularHighlights.cpp
Normal file
@@ -0,0 +1,186 @@
|
||||
#include <osgFX/SpecularHighlights>
|
||||
#include <osgFX/Registry>
|
||||
|
||||
#include <osg/TextureCubeMap>
|
||||
#include <osg/TexGen>
|
||||
#include <osg/TexEnv>
|
||||
#include <osg/ColorMatrix>
|
||||
|
||||
#include <osgUtil/HighlightMapGenerator>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class AutoTextureMatrix: public osg::StateAttribute {
|
||||
public:
|
||||
AutoTextureMatrix()
|
||||
: osg::StateAttribute(),
|
||||
lightnum_(0),
|
||||
active_(false)
|
||||
{
|
||||
}
|
||||
|
||||
AutoTextureMatrix(const AutoTextureMatrix ©, const osg::CopyOp ©op)
|
||||
: osg::StateAttribute(copy, copyop),
|
||||
lightnum_(copy.lightnum_),
|
||||
active_(copy.active_)
|
||||
{
|
||||
}
|
||||
|
||||
AutoTextureMatrix(int lightnum, bool active = true)
|
||||
: osg::StateAttribute(),
|
||||
lightnum_(lightnum),
|
||||
active_(active)
|
||||
{
|
||||
}
|
||||
|
||||
META_StateAttribute(osgFX, AutoTextureMatrix, osg::StateAttribute::TEXMAT);
|
||||
|
||||
virtual bool isTextureAttribute() const { return true; }
|
||||
|
||||
int compare(const osg::StateAttribute &sa) const
|
||||
{
|
||||
COMPARE_StateAttribute_Types(AutoTextureMatrix, sa);
|
||||
if (lightnum_ < rhs.lightnum_) return -1;
|
||||
if (lightnum_ > rhs.lightnum_) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apply(osg::State &state) const
|
||||
{
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
|
||||
if (active_) {
|
||||
osg::Matrix M = state.getInitialViewMatrix();
|
||||
M(3, 0) = 0; M(3, 1) = 0; M(3, 2) = 0;
|
||||
M(3, 3) = 1; M(0, 3) = 0; M(1, 3) = 0;
|
||||
M(2, 3) = 0;
|
||||
|
||||
osg::Vec4 lightvec;
|
||||
glGetLightfv(GL_LIGHT0+lightnum_, GL_POSITION, lightvec._v);
|
||||
|
||||
osg::Vec3 eye_light_ref = osg::Vec3(0, 0, 1) * M;
|
||||
|
||||
osg::Matrix LM = osg::Matrix::rotate(
|
||||
osg::Vec3(lightvec.x(), lightvec.y(), lightvec.z()),
|
||||
eye_light_ref);
|
||||
|
||||
glLoadMatrixf((LM * osg::Matrix::inverse(M)).ptr());
|
||||
|
||||
} else {
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
}
|
||||
|
||||
private:
|
||||
int lightnum_;
|
||||
bool active_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
Registry::Proxy proxy(new SpecularHighlights);
|
||||
|
||||
class DefaultTechnique: public Technique {
|
||||
public:
|
||||
|
||||
DefaultTechnique(int lightnum, int unit, const osg::Vec4 &color, float sexp)
|
||||
: Technique(),
|
||||
lightnum_(lightnum),
|
||||
unit_(unit),
|
||||
color_(color),
|
||||
sexp_(sexp)
|
||||
{
|
||||
}
|
||||
|
||||
void getRequiredExtensions(std::vector<std::string> &extensions)
|
||||
{
|
||||
extensions.push_back("GL_ARB_texture_env_add");
|
||||
}
|
||||
|
||||
bool validate(osg::State &state) const
|
||||
{
|
||||
if (!Technique::validate(state)) return false;
|
||||
|
||||
osg::TextureCubeMap::Extensions *ext =
|
||||
osg::TextureCubeMap::getExtensions(state.getContextID(), true);
|
||||
if (ext) {
|
||||
return ext->isCubeMapSupported();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void define_passes()
|
||||
{
|
||||
osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
|
||||
|
||||
ss->setTextureAttributeAndModes(unit_, new AutoTextureMatrix(lightnum_), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osgUtil::HighlightMapGenerator> hmg = new osgUtil::HighlightMapGenerator(osg::Vec3(0, 0, -1), color_, sexp_);
|
||||
hmg->generateMap(false);
|
||||
|
||||
osg::ref_ptr<osg::TextureCubeMap> texture = new osg::TextureCubeMap;
|
||||
texture->setImage(osg::TextureCubeMap::POSITIVE_X, hmg->getImage(osg::TextureCubeMap::POSITIVE_X));
|
||||
texture->setImage(osg::TextureCubeMap::POSITIVE_Y, hmg->getImage(osg::TextureCubeMap::POSITIVE_Y));
|
||||
texture->setImage(osg::TextureCubeMap::POSITIVE_Z, hmg->getImage(osg::TextureCubeMap::POSITIVE_Z));
|
||||
texture->setImage(osg::TextureCubeMap::NEGATIVE_X, hmg->getImage(osg::TextureCubeMap::NEGATIVE_X));
|
||||
texture->setImage(osg::TextureCubeMap::NEGATIVE_Y, hmg->getImage(osg::TextureCubeMap::NEGATIVE_Y));
|
||||
texture->setImage(osg::TextureCubeMap::NEGATIVE_Z, hmg->getImage(osg::TextureCubeMap::NEGATIVE_Z));
|
||||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
|
||||
ss->setTextureAttributeAndModes(unit_, texture.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::TexGen> texgen = new osg::TexGen;
|
||||
texgen->setMode(osg::TexGen::REFLECTION_MAP);
|
||||
ss->setTextureAttributeAndModes(unit_, texgen.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv;
|
||||
texenv->setMode(osg::TexEnv::ADD);
|
||||
ss->setTextureAttributeAndModes(unit_, texenv.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
|
||||
|
||||
addPass(ss.get());
|
||||
}
|
||||
|
||||
private:
|
||||
int lightnum_;
|
||||
int unit_;
|
||||
osg::Vec4 color_;
|
||||
float sexp_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
SpecularHighlights::SpecularHighlights()
|
||||
: Effect(),
|
||||
lightnum_(0),
|
||||
unit_(0),
|
||||
color_(1, 1, 1, 1),
|
||||
sexp_(16)
|
||||
{
|
||||
}
|
||||
|
||||
SpecularHighlights::SpecularHighlights(const SpecularHighlights ©, const osg::CopyOp ©op)
|
||||
: Effect(copy, copyop),
|
||||
lightnum_(copy.lightnum_),
|
||||
unit_(copy.unit_),
|
||||
color_(copy.color_),
|
||||
sexp_(copy.sexp_)
|
||||
{
|
||||
}
|
||||
|
||||
bool SpecularHighlights::define_techniques()
|
||||
{
|
||||
addTechnique(new DefaultTechnique(lightnum_, unit_, color_, sexp_));
|
||||
return true;
|
||||
}
|
||||
79
src/osgFX/Technique.cpp
Normal file
79
src/osgFX/Technique.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <osgFX/Technique>
|
||||
|
||||
#include <osg/GLExtensions>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
Technique::Technique()
|
||||
: osg::Referenced(),
|
||||
passes_defined_(false),
|
||||
control_node_(new osg::Group)
|
||||
{
|
||||
}
|
||||
|
||||
void Technique::addPass(osg::StateSet *ss)
|
||||
{
|
||||
osg::ref_ptr<osg::Group> pass = new osg::Group;
|
||||
control_node_->addChild(pass.get());
|
||||
|
||||
if (ss) {
|
||||
ss->setRenderBinDetails(static_cast<int>(control_node_->getNumChildren()), "RenderBin");
|
||||
pass->setStateSet(ss);
|
||||
}
|
||||
}
|
||||
|
||||
void Technique::addPass(osg::Group *pass)
|
||||
{
|
||||
control_node_->addChild(pass);
|
||||
}
|
||||
|
||||
bool Technique::validate(osg::State &) const
|
||||
{
|
||||
typedef std::vector<std::string> String_list;
|
||||
String_list extensions;
|
||||
|
||||
getRequiredExtensions(extensions);
|
||||
|
||||
for (String_list::const_iterator i=extensions.begin(); i!=extensions.end(); ++i) {
|
||||
if (!osg::isGLExtensionSupported(i->c_str())) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Technique::accept(osg::NodeVisitor &nv, osg::Node *child)
|
||||
{
|
||||
// define passes if necessary
|
||||
if (!passes_defined_) {
|
||||
|
||||
// clear existing pass nodes
|
||||
if (control_node_->getNumChildren() > 0) {
|
||||
control_node_->removeChild(0, control_node_->getNumChildren());
|
||||
}
|
||||
|
||||
define_passes();
|
||||
passes_defined_ = true;
|
||||
}
|
||||
|
||||
// update pass children if necessary
|
||||
if (child != prev_child_.get()) {
|
||||
for (unsigned i=0; i<control_node_->getNumChildren(); ++i) {
|
||||
osg::Group *pass = dynamic_cast<osg::Group *>(control_node_->getChild(i));
|
||||
if (pass) {
|
||||
if (pass->getNumChildren() > 0) {
|
||||
pass->removeChild(0, pass->getNumChildren());
|
||||
}
|
||||
osg::Node *oc = getOverrideChild(i);
|
||||
if (oc) {
|
||||
pass->addChild(oc);
|
||||
} else {
|
||||
pass->addChild(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
prev_child_ = child;
|
||||
}
|
||||
|
||||
// traverse the control node
|
||||
control_node_->accept(nv);
|
||||
}
|
||||
41
src/osgFX/Validator.cpp
Normal file
41
src/osgFX/Validator.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <osgFX/Validator>
|
||||
#include <osgFX/Effect>
|
||||
|
||||
#include <osg/Notify>
|
||||
|
||||
using namespace osgFX;
|
||||
|
||||
Validator::Validator()
|
||||
: osg::StateAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
Validator::Validator(Effect *effect)
|
||||
: osg::StateAttribute(),
|
||||
effect_(effect)
|
||||
{
|
||||
}
|
||||
|
||||
Validator::Validator(const Validator ©, const osg::CopyOp ©op)
|
||||
: osg::StateAttribute(copy, copyop),
|
||||
effect_(static_cast<Effect *>(copyop(copy.effect_.get())))
|
||||
{
|
||||
}
|
||||
|
||||
void Validator::apply(osg::State &state) const
|
||||
{
|
||||
if (!effect_.valid()) return;
|
||||
|
||||
if (effect_->tech_selected_[state.getContextID()] == 0) {
|
||||
Effect::Technique_list::iterator i;
|
||||
int j = 0;
|
||||
for (i=effect_->techs_.begin(); i!=effect_->techs_.end(); ++i, ++j) {
|
||||
if ((*i)->validate(state)) {
|
||||
effect_->sel_tech_[state.getContextID()] = j;
|
||||
effect_->tech_selected_[state.getContextID()] = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
osg::notify(osg::WARN) << "Warning: osgFX::Validator: could not find any techniques compatible with the current OpenGL context" << std::endl;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user