| 1 | #include <osgFX/Cartoon> |
|---|
| 2 | #include <osgFX/Registry> |
|---|
| 3 | |
|---|
| 4 | #include <osg/PolygonOffset> |
|---|
| 5 | #include <osg/Texture1D> |
|---|
| 6 | #include <osg/VertexProgram> |
|---|
| 7 | #include <osg/PolygonMode> |
|---|
| 8 | #include <osg/CullFace> |
|---|
| 9 | #include <osg/Image> |
|---|
| 10 | #include <osg/TexEnv> |
|---|
| 11 | #include <osg/LineWidth> |
|---|
| 12 | #include <osg/Material> |
|---|
| 13 | #include <osg/Program> |
|---|
| 14 | #include <osg/Shader> |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | #include <sstream> |
|---|
| 18 | |
|---|
| 19 | using namespace osgFX; |
|---|
| 20 | |
|---|
| 21 | namespace |
|---|
| 22 | { |
|---|
| 23 | |
|---|
| 24 | osg::Image* create_sharp_lighting_map(int levels = 4, int texture_size = 16) |
|---|
| 25 | { |
|---|
| 26 | osg::ref_ptr<osg::Image> image = new osg::Image; |
|---|
| 27 | image->setImage(texture_size, 1, 1, 4, GL_RGBA, GL_UNSIGNED_BYTE, new unsigned char[4*texture_size], osg::Image::USE_NEW_DELETE); |
|---|
| 28 | for (int i=0; i<texture_size; ++i) { |
|---|
| 29 | float c = i/static_cast<float>(texture_size); |
|---|
| 30 | c = (1+static_cast<int>(sqrtf(c) * (levels))) / static_cast<float>(levels+1); |
|---|
| 31 | *(image->data(i, 0)+0) = static_cast<unsigned char>(c*255); |
|---|
| 32 | *(image->data(i, 0)+1) = static_cast<unsigned char>(c*255); |
|---|
| 33 | *(image->data(i, 0)+2) = static_cast<unsigned char>(c*255); |
|---|
| 34 | *(image->data(i, 0)+3) = 255; |
|---|
| 35 | } |
|---|
| 36 | return image.release(); |
|---|
| 37 | } |
|---|
| 38 | |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | |
|---|
| 42 | namespace |
|---|
| 43 | { |
|---|
| 44 | |
|---|
| 45 | |
|---|
| 46 | Registry::Proxy proxy(new Cartoon); |
|---|
| 47 | |
|---|
| 48 | |
|---|
| 49 | class DefaultTechnique: public Technique { |
|---|
| 50 | public: |
|---|
| 51 | DefaultTechnique(osg::Material* wf_mat, osg::LineWidth *wf_lw, int lightnum) |
|---|
| 52 | : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw), _lightnum(lightnum) {} |
|---|
| 53 | |
|---|
| 54 | void getRequiredExtensions(std::vector<std::string>& extensions) const |
|---|
| 55 | { |
|---|
| 56 | extensions.push_back("GL_ARB_vertex_program"); |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | protected: |
|---|
| 60 | |
|---|
| 61 | void define_passes() |
|---|
| 62 | { |
|---|
| 63 | |
|---|
| 64 | { |
|---|
| 65 | std::ostringstream vp_oss; |
|---|
| 66 | vp_oss << |
|---|
| 67 | "!!ARBvp1.0\n" |
|---|
| 68 | "OPTION ARB_position_invariant;" |
|---|
| 69 | "PARAM c0 = { 0, 0, 0, 0 };" |
|---|
| 70 | "TEMP R0, R1;" |
|---|
| 71 | "ATTRIB v18 = vertex.normal;" |
|---|
| 72 | "PARAM s18 = state.light[" << _lightnum << "].position;" |
|---|
| 73 | "PARAM s16 = state.light[" << _lightnum << "].diffuse;" |
|---|
| 74 | "PARAM s1 = state.material.diffuse;" |
|---|
| 75 | "PARAM s631[4] = { state.matrix.modelview.invtrans };" |
|---|
| 76 | "MOV R0, s1;" |
|---|
| 77 | "MUL result.color.front.primary, R0, s16;" |
|---|
| 78 | "DP4 R0.x, s18, s18;" |
|---|
| 79 | "RSQ R0.x, R0.x;" |
|---|
| 80 | "MUL R1, R0.x, s18;" |
|---|
| 81 | "DP4 R0.x, s631[0], v18;" |
|---|
| 82 | "DP4 R0.y, s631[1], v18;" |
|---|
| 83 | "DP4 R0.z, s631[2], v18;" |
|---|
| 84 | "DP4 R0.w, s631[3], v18;" |
|---|
| 85 | "DP4 R0.x, R1, R0;" |
|---|
| 86 | "MAX result.texcoord[0].x, c0.x, R0.x;" |
|---|
| 87 | "END"; |
|---|
| 88 | |
|---|
| 89 | osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; |
|---|
| 90 | |
|---|
| 91 | osg::ref_ptr<osg::PolygonOffset> polyoffset = new osg::PolygonOffset; |
|---|
| 92 | polyoffset->setFactor(1.0f); |
|---|
| 93 | polyoffset->setUnits(1.0f); |
|---|
| 94 | ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 95 | |
|---|
| 96 | osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram; |
|---|
| 97 | vp->setVertexProgram(vp_oss.str()); |
|---|
| 98 | ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); |
|---|
| 99 | |
|---|
| 100 | ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF); |
|---|
| 101 | |
|---|
| 102 | osg::ref_ptr<osg::Texture1D> texture = new osg::Texture1D; |
|---|
| 103 | texture->setImage(create_sharp_lighting_map()); |
|---|
| 104 | texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); |
|---|
| 105 | texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); |
|---|
| 106 | ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); |
|---|
| 107 | |
|---|
| 108 | osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv; |
|---|
| 109 | texenv->setMode(osg::TexEnv::MODULATE); |
|---|
| 110 | ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); |
|---|
| 111 | |
|---|
| 112 | addPass(ss.get()); |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | |
|---|
| 116 | { |
|---|
| 117 | osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; |
|---|
| 118 | osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode; |
|---|
| 119 | polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); |
|---|
| 120 | ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 121 | |
|---|
| 122 | osg::ref_ptr<osg::CullFace> cf = new osg::CullFace; |
|---|
| 123 | cf->setMode(osg::CullFace::FRONT); |
|---|
| 124 | ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 125 | |
|---|
| 126 | ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); |
|---|
| 127 | |
|---|
| 128 | _wf_mat->setColorMode(osg::Material::OFF); |
|---|
| 129 | _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); |
|---|
| 130 | _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); |
|---|
| 131 | _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); |
|---|
| 132 | |
|---|
| 133 | |
|---|
| 134 | |
|---|
| 135 | |
|---|
| 136 | ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 137 | |
|---|
| 138 | ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 139 | ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); |
|---|
| 140 | ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); |
|---|
| 141 | |
|---|
| 142 | addPass(ss.get()); |
|---|
| 143 | |
|---|
| 144 | } |
|---|
| 145 | } |
|---|
| 146 | |
|---|
| 147 | private: |
|---|
| 148 | osg::ref_ptr<osg::Material> _wf_mat; |
|---|
| 149 | osg::ref_ptr<osg::LineWidth> _wf_lw; |
|---|
| 150 | int _lightnum; |
|---|
| 151 | }; |
|---|
| 152 | |
|---|
| 153 | } |
|---|
| 154 | |
|---|
| 155 | |
|---|
| 156 | |
|---|
| 157 | |
|---|
| 158 | |
|---|
| 159 | |
|---|
| 160 | |
|---|
| 161 | |
|---|
| 162 | namespace |
|---|
| 163 | { |
|---|
| 164 | class OGLSL_Technique : public Technique { |
|---|
| 165 | public: |
|---|
| 166 | OGLSL_Technique(osg::Material* wf_mat, osg::LineWidth *wf_lw, int lightnum) |
|---|
| 167 | : Technique(), _wf_mat(wf_mat), _wf_lw(wf_lw), _lightnum(lightnum) {} |
|---|
| 168 | |
|---|
| 169 | void getRequiredExtensions(std::vector<std::string>& extensions) const |
|---|
| 170 | { |
|---|
| 171 | extensions.push_back( "GL_ARB_shader_objects" ); |
|---|
| 172 | extensions.push_back( "GL_ARB_vertex_shader" ); |
|---|
| 173 | extensions.push_back( "GL_ARB_fragment_shader" ); |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | protected: |
|---|
| 177 | |
|---|
| 178 | void define_passes() |
|---|
| 179 | { |
|---|
| 180 | |
|---|
| 181 | { |
|---|
| 182 | const char * vert_source = |
|---|
| 183 | "const vec3 LightPosition = vec3( 0.0, 2.0, 4.0 );" |
|---|
| 184 | "varying float CartoonTexCoord;" |
|---|
| 185 | "void main( void )" |
|---|
| 186 | "{" |
|---|
| 187 | "vec3 eye_space_normal = normalize(gl_NormalMatrix * gl_Normal);" |
|---|
| 188 | "CartoonTexCoord = max(0.0, dot(normalize(LightPosition), eye_space_normal));" |
|---|
| 189 | "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" |
|---|
| 190 | "}"; |
|---|
| 191 | |
|---|
| 192 | const char * frag_source = |
|---|
| 193 | "uniform sampler1D CartoonTexUnit;" |
|---|
| 194 | "varying float CartoonTexCoord;" |
|---|
| 195 | "void main( void )" |
|---|
| 196 | "{" |
|---|
| 197 | "gl_FragColor = texture1D( CartoonTexUnit, CartoonTexCoord );" |
|---|
| 198 | "}"; |
|---|
| 199 | |
|---|
| 200 | osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; |
|---|
| 201 | |
|---|
| 202 | osg::ref_ptr<osg::PolygonOffset> polyoffset = new osg::PolygonOffset; |
|---|
| 203 | polyoffset->setFactor(1.0f); |
|---|
| 204 | polyoffset->setUnits(1.0f); |
|---|
| 205 | ss->setAttributeAndModes(polyoffset.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 206 | |
|---|
| 207 | osg::ref_ptr<osg::Program> program = new osg::Program; |
|---|
| 208 | program->addShader( new osg::Shader( osg::Shader::VERTEX, vert_source ) ); |
|---|
| 209 | program->addShader( new osg::Shader( osg::Shader::FRAGMENT, frag_source ) ); |
|---|
| 210 | |
|---|
| 211 | ss->addUniform( new osg::Uniform("CartoonTexUnit", 0)); |
|---|
| 212 | ss->setAttributeAndModes( program.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); |
|---|
| 213 | |
|---|
| 214 | |
|---|
| 215 | ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF); |
|---|
| 216 | |
|---|
| 217 | osg::ref_ptr<osg::Texture1D> texture = new osg::Texture1D; |
|---|
| 218 | texture->setImage(create_sharp_lighting_map()); |
|---|
| 219 | texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); |
|---|
| 220 | texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); |
|---|
| 221 | ss->setTextureAttributeAndModes(0, texture.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); |
|---|
| 222 | |
|---|
| 223 | osg::ref_ptr<osg::TexEnv> texenv = new osg::TexEnv; |
|---|
| 224 | texenv->setMode(osg::TexEnv::MODULATE); |
|---|
| 225 | ss->setTextureAttributeAndModes(0, texenv.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); |
|---|
| 226 | |
|---|
| 227 | addPass(ss.get()); |
|---|
| 228 | } |
|---|
| 229 | |
|---|
| 230 | |
|---|
| 231 | { |
|---|
| 232 | osg::ref_ptr<osg::StateSet> ss = new osg::StateSet; |
|---|
| 233 | osg::ref_ptr<osg::PolygonMode> polymode = new osg::PolygonMode; |
|---|
| 234 | polymode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE); |
|---|
| 235 | ss->setAttributeAndModes(polymode.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 236 | |
|---|
| 237 | osg::ref_ptr<osg::CullFace> cf = new osg::CullFace; |
|---|
| 238 | cf->setMode(osg::CullFace::FRONT); |
|---|
| 239 | ss->setAttributeAndModes(cf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 240 | |
|---|
| 241 | ss->setAttributeAndModes(_wf_lw.get(), osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON); |
|---|
| 242 | |
|---|
| 243 | _wf_mat->setColorMode(osg::Material::OFF); |
|---|
| 244 | _wf_mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); |
|---|
| 245 | _wf_mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); |
|---|
| 246 | _wf_mat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1)); |
|---|
| 247 | |
|---|
| 248 | |
|---|
| 249 | |
|---|
| 250 | |
|---|
| 251 | ss->setAttributeAndModes(_wf_mat.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 252 | |
|---|
| 253 | ss->setMode(GL_LIGHTING, osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON); |
|---|
| 254 | ss->setTextureMode(0, GL_TEXTURE_1D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); |
|---|
| 255 | ss->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); |
|---|
| 256 | |
|---|
| 257 | addPass(ss.get()); |
|---|
| 258 | |
|---|
| 259 | } |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | private: |
|---|
| 263 | osg::ref_ptr<osg::Material> _wf_mat; |
|---|
| 264 | osg::ref_ptr<osg::LineWidth> _wf_lw; |
|---|
| 265 | int _lightnum; |
|---|
| 266 | }; |
|---|
| 267 | |
|---|
| 268 | } |
|---|
| 269 | |
|---|
| 270 | |
|---|
| 271 | |
|---|
| 272 | Cartoon::Cartoon() |
|---|
| 273 | : Effect(), |
|---|
| 274 | _wf_mat(new osg::Material), |
|---|
| 275 | _wf_lw(new osg::LineWidth(2.0f)), |
|---|
| 276 | _lightnum(0) |
|---|
| 277 | { |
|---|
| 278 | setOutlineColor(osg::Vec4(0, 0, 0, 1)); |
|---|
| 279 | } |
|---|
| 280 | |
|---|
| 281 | Cartoon::Cartoon(const Cartoon& copy, const osg::CopyOp& copyop) |
|---|
| 282 | : Effect(copy, copyop), |
|---|
| 283 | _wf_mat(static_cast<osg::Material* >(copyop(copy._wf_mat.get()))), |
|---|
| 284 | _wf_lw(static_cast<osg::LineWidth *>(copyop(copy._wf_lw.get()))), |
|---|
| 285 | _lightnum(copy._lightnum) |
|---|
| 286 | { |
|---|
| 287 | } |
|---|
| 288 | |
|---|
| 289 | bool Cartoon::define_techniques() |
|---|
| 290 | { |
|---|
| 291 | addTechnique(new DefaultTechnique(_wf_mat.get(), _wf_lw.get(), _lightnum)); |
|---|
| 292 | addTechnique(new OGLSL_Technique(_wf_mat.get(), _wf_lw.get(), _lightnum)); |
|---|
| 293 | return true; |
|---|
| 294 | } |
|---|