From 8f02db61e567c008bcf52f2fbb1480bcf7e1a018 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 18 Mar 2002 23:10:33 +0000 Subject: [PATCH] Added osg::TextureCubeMap. submission from Brede Johansen. --- VisualStudio/osg/osg.dsp | 8 + include/osg/TexGen | 16 +- include/osg/Texture | 3 + include/osg/TextureCubeMap | 64 ++++++ src/osg/Makefile | 2 + src/osg/TexGen.cpp | 14 ++ src/osg/TextureCubeMap.cpp | 457 +++++++++++++++++++++++++++++++++++++ 7 files changed, 561 insertions(+), 3 deletions(-) create mode 100644 include/osg/TextureCubeMap create mode 100644 src/osg/TextureCubeMap.cpp diff --git a/VisualStudio/osg/osg.dsp b/VisualStudio/osg/osg.dsp index 538fd25e7..d09affc97 100755 --- a/VisualStudio/osg/osg.dsp +++ b/VisualStudio/osg/osg.dsp @@ -305,6 +305,10 @@ SOURCE=..\..\src\osg\Texture.cpp # End Source File # Begin Source File +SOURCE=..\..\src\osg\TextureCubeMap.cpp +# End Source File +# Begin Source File + SOURCE=..\..\src\osg\Timer.cpp # End Source File # Begin Source File @@ -593,6 +597,10 @@ SOURCE=..\..\Include\Osg\Texture # End Source File # Begin Source File +SOURCE=..\..\Include\Osg\TextureCubeMap +# End Source File +# Begin Source File + SOURCE=..\..\Include\Osg\Timer # End Source File # Begin Source File diff --git a/include/osg/TexGen b/include/osg/TexGen index b87fbe98b..9f4c4b74a 100644 --- a/include/osg/TexGen +++ b/include/osg/TexGen @@ -11,6 +11,14 @@ namespace osg { +#ifndef GL_NORMAL_MAP_ARB +#define GL_NORMAL_MAP_ARB 0x8511 +#endif + +#ifndef GL_REFLECTION_MAP_ARB +#define GL_REFLECTION_MAP_ARB 0x8512 +#endif + /** TexGen - encapsulates the OpenGL glTexGen (texture coordinate generation) state.*/ class SG_EXPORT TexGen : public StateAttribute { @@ -69,9 +77,11 @@ class SG_EXPORT TexGen : public StateAttribute virtual void apply(State& state) const; enum Mode { - OBJECT_LINEAR = GL_OBJECT_LINEAR, - EYE_LINEAR = GL_EYE_LINEAR, - SPHERE_MAP = GL_SPHERE_MAP + OBJECT_LINEAR = GL_OBJECT_LINEAR, + EYE_LINEAR = GL_EYE_LINEAR, + SPHERE_MAP = GL_SPHERE_MAP, + NORMAL_MAP = GL_NORMAL_MAP_ARB, + REFLECTION_MAP = GL_REFLECTION_MAP_ARB }; inline void setMode( const Mode mode ) { _mode = mode; } diff --git a/include/osg/Texture b/include/osg/Texture index a018c08bb..d5ddb0ddd 100644 --- a/include/osg/Texture +++ b/include/osg/Texture @@ -81,6 +81,7 @@ class SG_EXPORT Texture : public StateAttribute _modifiedTag(), _textureObjectSize(text._textureObjectSize), _image(copyop(text._image.get())), + _target(text._target), _textureUnit(text._textureUnit), _wrap_s(text._wrap_s), _wrap_t(text._wrap_t), @@ -327,6 +328,8 @@ class SG_EXPORT Texture : public StateAttribute // which is const... mutable ref_ptr _image; + GLenum _target; // defaults to GL_TEXTURE_2D + unsigned int _textureUnit; WrapMode _wrap_s; diff --git a/include/osg/TextureCubeMap b/include/osg/TextureCubeMap new file mode 100644 index 000000000..a41534f46 --- /dev/null +++ b/include/osg/TextureCubeMap @@ -0,0 +1,64 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +// -*-c++-*- + +#ifndef OSG_TEXTURECUBEMAP +#define OSG_TEXTURECUBEMAP 1 + +#include + + +namespace osg { + +/** TextureCubeMap state class which encapsulates OpenGl texture cubemap functionality.*/ +class SG_EXPORT TextureCubeMap : public Texture +{ + + public : + + TextureCubeMap(); + + /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ + TextureCubeMap(const TextureCubeMap& cm,const CopyOp& copyop=CopyOp::SHALLOW_COPY): + Texture(cm,copyop) {} + + META_StateAttribute(TextureCubeMap,(Type)(TEXTURE_0+_textureUnit)); + + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/ + virtual int compare(const StateAttribute& rhs) const; + + enum Face { + POSITIVE_X=0, + NEGATIVE_X=1, + POSITIVE_Y=2, + NEGATIVE_Y=3, + POSITIVE_Z=4, + NEGATIVE_Z=5 + }; + + /** Set the texture image. */ + void setImage( const Face, Image* image); + + /** On first apply (unless already compiled), create the minmapped + * texture and bind it, subsequent apply will simple bind to texture.*/ + virtual void apply(State& state) const; + + /** Method which does the creation of the texture itself, and + * does not set or use texture binding. */ + virtual void applyImmediateMode(State& state) const; + virtual void applyFaceImmediateMode(GLenum facetarget, Image* image, State& state) const; + + protected : + + virtual ~TextureCubeMap(); + bool imagesValid() const; + void setImage(Image* image) {} // prevent call to Texture::setImage(Image* image) + + mutable ref_ptr _images[6]; +}; + +} + +#endif diff --git a/src/osg/Makefile b/src/osg/Makefile index 844c2764c..4fed11305 100644 --- a/src/osg/Makefile +++ b/src/osg/Makefile @@ -56,6 +56,7 @@ C++FILES = \ TexGen.cpp\ TexMat.cpp\ Texture.cpp\ + TextureCubeMap.cpp\ Timer.cpp\ Transform.cpp\ Transparency.cpp\ @@ -132,6 +133,7 @@ TARGET_INCLUDE_FILES = \ osg/TexGen\ osg/TexMat\ osg/Texture\ + osg/TextureCubeMap\ osg/Timer\ osg/Transform\ osg/Transparency\ diff --git a/src/osg/TexGen.cpp b/src/osg/TexGen.cpp index acd3bf1ab..8199f2ab4 100644 --- a/src/osg/TexGen.cpp +++ b/src/osg/TexGen.cpp @@ -77,6 +77,20 @@ void TexGen::apply(State&) const // note, R & Q will be disabled so R&Q settings won't // have an effect, see above comment in enable(). RO. + } + else if (_mode == NORMAL_MAP) + { + glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, _mode ); + glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, _mode ); + glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, _mode ); +// glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, _mode ); + } + else if (_mode == REFLECTION_MAP) + { + glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, _mode ); + glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, _mode ); + glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, _mode ); +// glTexGeni( GL_Q, GL_TEXTURE_GEN_MODE, _mode ); } else // SPHERE_MAP { diff --git a/src/osg/TextureCubeMap.cpp b/src/osg/TextureCubeMap.cpp new file mode 100644 index 000000000..434db0308 --- /dev/null +++ b/src/osg/TextureCubeMap.cpp @@ -0,0 +1,457 @@ +#if defined(_MSC_VER) + #pragma warning( disable : 4786 ) +#endif + +#include +#include +#include +#include +#include +#include + +#include + + +using namespace osg; + + +#ifndef GL_ARB_texture_cube_map +#define GL_ARB_texture_cube_map 1 +//#define GL_NORMAL_MAP_ARB 0x8511 // defined in TexGen +//#define GL_REFLECTION_MAP_ARB 0x8512 // --- '' --- +#define GL_TEXTURE_CUBE_MAP_ARB 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_ARB 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB 0x851C +#endif + + +#ifndef GL_EXT_texture_cube_map +#define GL_EXT_texture_cube_map 1 +//#define GL_NORMAL_MAP_EXT 0x8511 +//#define GL_REFLECTION_MAP_EXT 0x8512 +#define GL_TEXTURE_CUBE_MAP_EXT 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP_EXT 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT 0x851A +#define GL_PROXY_TEXTURE_CUBE_MAP_EXT 0x851B +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_EXT 0x851C +#endif + + +#ifdef GL_ARB_texture_cube_map +# define CUBE_MAP_POSITIVE_X GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB +# define CUBE_MAP_NEGATIVE_X GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB +# define CUBE_MAP_POSITIVE_Y GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB +# define CUBE_MAP_NEGATIVE_Y GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB +# define CUBE_MAP_POSITIVE_Z GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB +# define CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB +#elif GL_EXT_texture_cube_map +# define CUBE_MAP_POSITIVE_X GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT +# define CUBE_MAP_NEGATIVE_X GL_TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +# define CUBE_MAP_POSITIVE_Y GL_TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +# define CUBE_MAP_NEGATIVE_Y GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +# define CUBE_MAP_POSITIVE_Z GL_TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +# define CUBE_MAP_NEGATIVE_Z GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT +#endif + + +# if GL_EXT_texture_cube_map || GL_ARB_texture_cube_map +static GLenum faceTarget[6] = +{ + CUBE_MAP_POSITIVE_X, + CUBE_MAP_NEGATIVE_X, + CUBE_MAP_POSITIVE_Y, + CUBE_MAP_NEGATIVE_Y, + CUBE_MAP_POSITIVE_Z, + CUBE_MAP_NEGATIVE_Z +}; +#endif + + +TextureCubeMap::TextureCubeMap() +{ + _target = GL_TEXTURE_CUBE_MAP_ARB; // default to ARB extension +} + + +TextureCubeMap::~TextureCubeMap() +{ +} + + +int TextureCubeMap::compare(const StateAttribute& sa) const +{ + // check the types are equal and then create the rhs variable + // used by the COMPARE_StateAttribute_Paramter macro's below. + COMPARE_StateAttribute_Types(TextureCubeMap,sa) + + for (int n=0; n<6; n++) + { + if (_images[n]!=rhs._images[n]) // smart pointer comparison. + { + if (_images[n].valid()) + { + if (rhs._images[n].valid()) + { + if (_images[n]->getFileName()getFileName()) return -1; + else if (_images[n]->getFileName()>rhs._images[n]->getFileName()) return 1;; + } + else + { + return 1; // valid lhs._image is greater than null. + } + } + else if (rhs._images[n].valid()) + { + return -1; // valid rhs._image is greater than null. + } + } + } + + return 0; // passed all the above comparison macro's, must be equal. +} + + +void TextureCubeMap::setImage( const Face face, Image* image) +{ + // Quick and dirty implementation committed by ABJ. + if (face == 0) + { + // delete old texture objects. + for(TextureNameList::iterator itr=_handleList.begin(); + itr!=_handleList.end(); + ++itr) + { + if (*itr != 0) + { + // contact global texture object handler to delete texture objects + // in appropriate context. + // glDeleteTextures( 1L, (const GLuint *)itr ); + *itr = 0; + } + } + } + _images[face] = image; +} + + +bool TextureCubeMap::imagesValid() const +{ + for (int n=0; n<6; n++) + { + if (!_images[n].valid() || !_images[n]->data()) + return false; + } + return true; +} + + +void TextureCubeMap::apply(State& state) const +{ + static bool s_ARB_CubeMapSupported = isGLExtensionSupported("GL_ARB_texture_cube_map"); + static bool s_EXT_CubeMapSupported = isGLExtensionSupported("GL_EXT_texture_cube_map"); + + if (!s_ARB_CubeMapSupported /*&& !s_EXT_CubeMapSupported*/) + return; + + // get the contextID (user defined ID of 0 upwards) for the + // current OpenGL context. + const uint contextID = state.getContextID(); + + // get the globj for the current contextID. + GLuint& handle = getHandle(contextID); + + // For multi-texturing will need something like... + // glActiveTextureARB((GLenum)(GL_TEXTURE0_ARB+_textureUnit)); + + if (handle != 0) + { + if (_subloadMode == OFF) + { + glBindTexture( _target, handle ); + } + else if (imagesValid()) + { + uint& modifiedTag = getModifiedTag(contextID); + + modifiedTag = 0; + glBindTexture( _target, handle ); + for (int n=0; n<6; n++) + { + if ((_subloadMode == AUTO) || + (_subloadMode == IF_DIRTY && modifiedTag != _images[n]->getModifiedTag())) + { + glTexSubImage2D(faceTarget[n], 0, + _subloadOffsX, _subloadOffsY, + _images[n]->s(), _images[n]->t(), + (GLenum) _images[n]->pixelFormat(), (GLenum) _images[n]->dataType(), + _images[n]->data()); + // update the modified flag to show that the image has been loaded. + modifiedTag += _images[n]->getModifiedTag(); + } + } + } + } + else if (imagesValid()) + { + glGenTextures( 1L, (GLuint *)&handle ); + glBindTexture( _target, handle ); + + applyImmediateMode(state); + + for (int n=0; n<6; n++) + { + applyFaceImmediateMode( + faceTarget[n], _images[n].get(), state); + } + + // in theory the following line is redundent, but in practice + // have found that the first frame drawn doesn't apply the textures + // unless a second bind is called?!! + // perhaps it is the first glBind which is not required... + glBindTexture( _target, handle ); + + } +} + + +void TextureCubeMap::applyImmediateMode(State& state) const +{ + WrapMode ws = _wrap_s, wt = _wrap_t; + + // GL_IBM_texture_mirrored_repeat, fall-back REPEAT + static bool s_mirroredSupported = isGLExtensionSupported("GL_IBM_texture_mirrored_repeat"); + if (!s_mirroredSupported) + { + if (ws == MIRROR) + ws = REPEAT; + if (wt == MIRROR) + wt = REPEAT; + } + + // GL_EXT_texture_edge_clamp, fall-back CLAMP + static bool s_edgeClampSupported = isGLExtensionSupported("GL_EXT_texture_edge_clamp"); + if (!s_edgeClampSupported) + { + if (ws == CLAMP_TO_EDGE) + ws = CLAMP; + if (wt == CLAMP_TO_EDGE) + wt = CLAMP; + } + + static bool s_borderClampSupported = isGLExtensionSupported("GL_ARB_texture_border_clamp"); + if(!s_borderClampSupported) + { + if(ws == CLAMP_TO_BORDER) + ws = CLAMP; + if(wt == CLAMP_TO_BORDER) + wt = CLAMP; + } + + glTexParameteri( _target, GL_TEXTURE_WRAP_S, ws ); + glTexParameteri( _target, GL_TEXTURE_WRAP_T, wt ); + + glTexParameteri( _target, GL_TEXTURE_MIN_FILTER, _min_filter); + + if (_mag_filter == ANISOTROPIC) + { + // check for support for anisotropic filter, + // note since this is static varible it is intialised + // only on the first time entering this code block, + // is then never reevaluated on subsequent calls. + static bool s_anisotropicSupported = + isGLExtensionSupported("GL_EXT_texture_filter_anisotropic"); + + if (s_anisotropicSupported) + { + // note, GL_TEXTURE_MAX_ANISOTROPY_EXT will either be defined + // by gl.h (or via glext.h) or by include/osg/Texture. + glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2.f); + } + else + { + glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, LINEAR); + } + } + else + { + glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, _mag_filter); + } +} + + + +void TextureCubeMap::applyFaceImmediateMode(GLenum facetarget, Image* image, State& state) const +{ + // get the contextID (user defined ID of 0 upwards) for the + // current OpenGL context. + const uint contextID = state.getContextID(); + + // update the modified tag to show that it is upto date. + getModifiedTag(contextID) = image->getModifiedTag(); + + + if (_subloadMode == OFF) + image->ensureDimensionsArePowerOfTwo(); + + glPixelStorei(GL_UNPACK_ALIGNMENT,image->packing()); + + static bool s_ARB_Compression = isGLExtensionSupported("GL_ARB_texture_compression"); + static bool s_S3TC_Compression = isGLExtensionSupported("GL_EXT_texture_compression_s3tc"); + + // select the internalFormat required for the texture. + int internalFormat = image->internalFormat(); + switch(_internalFormatMode) + { + case(USE_IMAGE_DATA_FORMAT): + internalFormat = image->internalFormat(); + break; + + case(USE_ARB_COMPRESSION): + if (s_ARB_Compression) + { + switch(image->pixelFormat()) + { + case(1): internalFormat = GL_COMPRESSED_ALPHA_ARB; break; + case(2): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break; + case(3): internalFormat = GL_COMPRESSED_RGB_ARB; break; + case(4): internalFormat = GL_COMPRESSED_RGBA_ARB; break; + case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_ARB; break; + case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_ARB; break; + case(GL_ALPHA): internalFormat = GL_COMPRESSED_ALPHA_ARB; break; + case(GL_LUMINANCE): internalFormat = GL_COMPRESSED_LUMINANCE_ARB; break; + case(GL_LUMINANCE_ALPHA): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break; + case(GL_INTENSITY): internalFormat = GL_COMPRESSED_INTENSITY_ARB; break; + } + } + else internalFormat = image->internalFormat(); + break; + + case(USE_S3TC_DXT1_COMPRESSION): + if (s_S3TC_Compression) + { + switch(image->pixelFormat()) + { + case(3): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; + case(4): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; + case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; + case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break; + default: internalFormat = image->internalFormat(); break; + } + } + else internalFormat = image->internalFormat(); + break; + + case(USE_S3TC_DXT3_COMPRESSION): + if (s_S3TC_Compression) + { + switch(image->pixelFormat()) + { + case(3): + case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; + case(4): + case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break; + default: internalFormat = image->internalFormat(); break; + } + } + else internalFormat = image->internalFormat(); + break; + + case(USE_S3TC_DXT5_COMPRESSION): + if (s_S3TC_Compression) + { + switch(image->pixelFormat()) + { + case(3): + case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break; + case(4): + case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break; + default: internalFormat = image->internalFormat(); break; + } + } + else internalFormat = image->internalFormat(); + break; + + case(USE_USER_DEFINED_FORMAT): + internalFormat = _internalFormatValue; + break; + + } + + if (_subloadMode == OFF) + { + if( _min_filter == LINEAR || _min_filter == NEAREST ) + { + glTexImage2D( facetarget, 0, internalFormat, + image->s(), image->t(), 0, + (GLenum)image->pixelFormat(), + (GLenum)image->dataType(), + image->data() ); + + // just estimate estimate it right now.. + // note, ignores texture compression.. + _textureObjectSize = image->s()*image->t()*4; + + } + else + { + + gluBuild2DMipmaps( facetarget, internalFormat, + image->s(), image->t(), + (GLenum)image->pixelFormat(), (GLenum)image->dataType(), + image->data() ); + + // just estimate size it right now.. + // crude x2 multiplier to account for minmap storage. + // note, ignores texture compression.. + _textureObjectSize = image->s()*image->t()*4; + + } + + _textureWidth = image->s(); + _textureHeight = image->t(); + } + else + { + /* target=? ABJ + static bool s_SGIS_GenMipmap = isGLExtensionSupported("GL_SGIS_generate_mipmap"); + + if (s_SGIS_GenMipmap && (_min_filter != LINEAR && _min_filter != NEAREST)) { + glTexParameteri(_target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); + } + */ + // calculate texture dimension + _textureWidth = 1; + for (; _textureWidth < (_subloadOffsX + image->s()); _textureWidth <<= 1) + ; + + _textureHeight = 1; + for (; _textureHeight < (_subloadOffsY + image->t()); _textureHeight <<= 1) + ; + + // reserve appropriate texture memory + glTexImage2D(facetarget, 0, internalFormat, + _textureWidth, _textureHeight, 0, + (GLenum) image->pixelFormat(), (GLenum) image->dataType(), + NULL); + + glTexSubImage2D(facetarget, 0, + _subloadOffsX, _subloadOffsY, + image->s(), image->t(), + (GLenum) image->pixelFormat(), (GLenum) image->dataType(), + image->data()); + } + +} +