#endif
#include "TextureBuilder.hxx"
+#include "mipmap.hxx"
#include "Pass.hxx"
#include <osg/TextureRectangle>
#include <osg/TextureCubeMap>
#include <osgDB/FileUtils>
+#include <osgDB/ReadFile>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
-#include <simgear/scene/model/SGReaderWriterXMLOptions.hxx>
+#include <simgear/scene/util/SGReaderWriterOptions.hxx>
#include <simgear/scene/util/SGSceneFeatures.hxx>
#include <simgear/scene/util/StateAttributeFactory.hxx>
#include <simgear/math/SGMath.hxx>
TexEnvCombine* buildTexEnvCombine(Effect* effect,
const SGPropertyNode* envProp,
- const SGReaderWriterXMLOptions* options);
+ const SGReaderWriterOptions* options);
TexGen* buildTexGen(Effect* Effect, const SGPropertyNode* tgenProp);
// Hack to force inclusion of TextureBuilder.cxx in library
osg::Texture* TextureBuilder::buildFromType(Effect* effect, const string& type,
const SGPropertyNode*props,
- const SGReaderWriterXMLOptions*
+ const SGReaderWriterOptions*
options)
{
return EffectBuilder<Texture>::buildFromType(effect, type, props, options);
typedef boost::tuple<string, Texture::FilterMode, Texture::FilterMode,
Texture::WrapMode, Texture::WrapMode, Texture::WrapMode,
- string> TexTuple;
+ string, MipMapTuple> TexTuple;
EffectNameValue<TexEnv::Mode> texEnvModesInit[] =
{
if (colorProp)
env->setColor(toOsg(colorProp->getValue<SGVec4d>()));
return env;
- }
+}
void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
const SGPropertyNode* prop,
- const SGReaderWriterXMLOptions* options)
+ const SGReaderWriterOptions* options)
{
if (!isAttributeActive(effect, prop))
return;
options);
}
catch (BuilderException& e) {
- SG_LOG(SG_INPUT, SG_ALERT, "No image file for texture, using white ");
+ SG_LOG(SG_INPUT, SG_ALERT, e.getFormattedMessage() << ", "
+ << "maybe the reader did not set the filename attribute, "
+ << "using white for type '" << type << "' on '" << pass->getName() << "', in " << prop->getPath() );
texture = StateAttributeFactory::instance()->getWhiteTexture();
}
pass->setTextureAttributeAndModes(unit, texture);
};
EffectPropertyMap<Texture::WrapMode> wrapModes(wrapModesInit);
-
TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props,
- const SGReaderWriterXMLOptions* options,
+ const SGReaderWriterOptions* options,
const string& texType)
{
Texture::FilterMode minFilter = Texture::LINEAR_MIPMAP_LINEAR;
const SGPropertyNode* pImage
= getEffectPropertyChild(effect, props, "image");
string imageName;
+ string absFileName;
if (pImage)
+ {
imageName = pImage->getStringValue();
- string absFileName = osgDB::findDataFile(imageName, options);
+ absFileName = SGModelLib::findDataFile(imageName, options);
+ if (absFileName.empty())
+ {
+ SG_LOG(SG_INPUT, SG_ALERT, "Texture file not found: '"
+ << imageName << "'");
+ }
+ }
+
+ const SGPropertyNode* pMipmapControl
+ = getEffectPropertyChild(effect, props, "mipmap-control");
+ MipMapTuple mipmapFunctions( AUTOMATIC, AUTOMATIC, AUTOMATIC, AUTOMATIC );
+ if ( pMipmapControl )
+ mipmapFunctions = makeMipMapTuple(effect, pMipmapControl, options);
+
return TexTuple(absFileName, minFilter, magFilter, sWrap, tWrap, rWrap,
- texType);
+ texType, mipmapFunctions);
}
void setAttrs(const TexTuple& attrs, Texture* tex,
- const SGReaderWriterXMLOptions* options)
+ const SGReaderWriterOptions* options)
{
const string& imageName = attrs.get<0>();
if (imageName.empty()) {
throw BuilderException("no image file");
} else {
- osgDB::ReaderWriter::ReadResult result
- = osgDB::Registry::instance()->readImage(imageName, options);
+ osgDB::ReaderWriter::ReadResult result;
+ result = osgDB::readImageFile(imageName, options);
if (result.success()) {
- osg::Image* image = result.getImage();
- tex->setImage(GL_FRONT_AND_BACK, image);
+ osg::ref_ptr<osg::Image> image = result.getImage();
+ image = computeMipmap( image.get(), attrs.get<7>() );
+ tex->setImage(GL_FRONT_AND_BACK, image.get());
int s = image->s();
int t = image->t();
if (s <= t && 32 <= s) {
public:
TexBuilder(const string& texType) : _type(texType) {}
Texture* build(Effect* effect, const SGPropertyNode*,
- const SGReaderWriterXMLOptions* options);
+ const SGReaderWriterOptions* options);
protected:
typedef map<TexTuple, ref_ptr<T> > TexMap;
TexMap texMap;
template<typename T>
Texture* TexBuilder<T>::build(Effect* effect, const SGPropertyNode* props,
- const SGReaderWriterXMLOptions* options)
+ const SGReaderWriterOptions* options)
{
TexTuple attrs = makeTexTuple(effect, props, options, _type);
typename TexMap::iterator itr = texMap.find(attrs);
{
public:
Texture* build(Effect* effect, const SGPropertyNode*,
- const SGReaderWriterXMLOptions* options);
+ const SGReaderWriterOptions* options);
};
Texture* WhiteTextureBuilder::build(Effect* effect, const SGPropertyNode*,
- const SGReaderWriterXMLOptions* options)
+ const SGReaderWriterOptions* options)
{
return StateAttributeFactory::instance()->getWhiteTexture();
}
{
public:
Texture* build(Effect* effect, const SGPropertyNode*,
- const SGReaderWriterXMLOptions* options);
+ const SGReaderWriterOptions* options);
};
Texture* TransparentTextureBuilder::build(Effect* effect, const SGPropertyNode*,
- const SGReaderWriterXMLOptions* options)
+ const SGReaderWriterOptions* options)
{
return StateAttributeFactory::instance()->getTransparentTexture();
}
{
public:
Texture* build(Effect* effect, const SGPropertyNode*,
- const SGReaderWriterXMLOptions* options);
+ const SGReaderWriterOptions* options);
protected:
typedef map<int, ref_ptr<Texture3D> > NoiseMap;
NoiseMap _noises;
};
Texture* NoiseBuilder::build(Effect* effect, const SGPropertyNode* props,
- const SGReaderWriterXMLOptions* options)
+ const SGReaderWriterOptions* options)
{
int texSize = 64;
const SGPropertyNode* sizeProp = getEffectPropertyChild(effect, props,
}
+
// Image names for all sides
typedef boost::tuple<string, string, string, string, string, string> CubeMapTuple;
{
public:
Texture* build(Effect* effect, const SGPropertyNode*,
- const SGReaderWriterXMLOptions* options);
+ const SGReaderWriterOptions* options);
protected:
typedef map<CubeMapTuple, ref_ptr<TextureCubeMap> > CubeMap;
+ typedef map<string, ref_ptr<TextureCubeMap> > CrossCubeMap;
CubeMap _cubemaps;
+ CrossCubeMap _crossmaps;
};
+// I use this until osg::CopyImage is fixed
+// This one assumes images are the same format and sizes are correct
+void copySubImage(const osg::Image* srcImage, int src_s, int src_t, int width, int height,
+ osg::Image* destImage, int dest_s, int dest_t)
+{
+ for(int row = 0; row<height; ++row)
+ {
+ const unsigned char* srcData = srcImage->data(src_s, src_t+row, 0);
+ unsigned char* destData = destImage->data(dest_s, dest_t+row, 0);
+ memcpy(destData, srcData, (width*destImage->getPixelSizeInBits())/8);
+ }
+}
+
+
Texture* CubeMapBuilder::build(Effect* effect, const SGPropertyNode* props,
- const SGReaderWriterXMLOptions* options)
+ const SGReaderWriterOptions* options)
{
// First check that there is a <images> tag
const SGPropertyNode* texturesProp = getEffectPropertyChild(effect, props, "images");
- if (!texturesProp) {
- throw BuilderException("no <images> for cube map");
+ const SGPropertyNode* crossProp = getEffectPropertyChild(effect, props, "image");
+ if (!texturesProp && !crossProp) {
+ throw BuilderException("no images defined for cube map");
return NULL; // This is redundant
}
- CubeMapTuple _tuple = makeCubeMapTuple(effect, texturesProp);
+ // Using 6 separate images
+ if(texturesProp) {
- CubeMap::iterator itr = _cubemaps.find(_tuple);
- if (itr != _cubemaps.end())
- return itr->second.get();
+ SG_LOG(SG_INPUT, SG_DEBUG, "try 6 images ");
- TextureCubeMap* cubeTexture = new osg::TextureCubeMap;
+ CubeMapTuple _tuple = makeCubeMapTuple(effect, texturesProp);
- // TODO: Read these from effect file? Maybe these are sane for all cuebmaps?
- cubeTexture->setFilter(osg::Texture3D::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
- cubeTexture->setFilter(osg::Texture3D::MAG_FILTER, osg::Texture::LINEAR);
- cubeTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
- cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
- cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
+ CubeMap::iterator itr = _cubemaps.find(_tuple);
+ if (itr != _cubemaps.end())
+ return itr->second.get();
- osgDB::ReaderWriter::ReadResult result =
- osgDB::Registry::instance()->readImage(_tuple.get<0>(), options);
- if(result.success()) {
- osg::Image* image = result.getImage();
- cubeTexture->setImage(TextureCubeMap::POSITIVE_X, image);
- }
- result = osgDB::Registry::instance()->readImage(_tuple.get<1>(), options);
- if(result.success()) {
- osg::Image* image = result.getImage();
- cubeTexture->setImage(TextureCubeMap::NEGATIVE_X, image);
- }
- result = osgDB::Registry::instance()->readImage(_tuple.get<2>(), options);
- if(result.success()) {
- osg::Image* image = result.getImage();
- cubeTexture->setImage(TextureCubeMap::POSITIVE_Y, image);
- }
- result = osgDB::Registry::instance()->readImage(_tuple.get<3>(), options);
- if(result.success()) {
- osg::Image* image = result.getImage();
- cubeTexture->setImage(TextureCubeMap::NEGATIVE_Y, image);
- }
- result = osgDB::Registry::instance()->readImage(_tuple.get<4>(), options);
- if(result.success()) {
- osg::Image* image = result.getImage();
- cubeTexture->setImage(TextureCubeMap::POSITIVE_Z, image);
- }
- result = osgDB::Registry::instance()->readImage(_tuple.get<5>(), options);
- if(result.success()) {
- osg::Image* image = result.getImage();
- cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, image);
+ TextureCubeMap* cubeTexture = new osg::TextureCubeMap;
+
+ // TODO: Read these from effect file? Maybe these are sane for all cuebmaps?
+ cubeTexture->setFilter(osg::Texture3D::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
+ cubeTexture->setFilter(osg::Texture3D::MAG_FILTER, osg::Texture::LINEAR);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
+
+ osgDB::ReaderWriter::ReadResult result;
+ result = osgDB::readImageFile(_tuple.get<0>(), options);
+ if(result.success()) {
+ osg::Image* image = result.getImage();
+ cubeTexture->setImage(TextureCubeMap::POSITIVE_X, image);
+ }
+ result = osgDB::readImageFile(_tuple.get<1>(), options);
+ if(result.success()) {
+ osg::Image* image = result.getImage();
+ cubeTexture->setImage(TextureCubeMap::NEGATIVE_X, image);
+ }
+ result = osgDB::readImageFile(_tuple.get<2>(), options);
+ if(result.success()) {
+ osg::Image* image = result.getImage();
+ cubeTexture->setImage(TextureCubeMap::POSITIVE_Y, image);
+ }
+ result = osgDB::readImageFile(_tuple.get<3>(), options);
+ if(result.success()) {
+ osg::Image* image = result.getImage();
+ cubeTexture->setImage(TextureCubeMap::NEGATIVE_Y, image);
+ }
+ result = osgDB::readImageFile(_tuple.get<4>(), options);
+ if(result.success()) {
+ osg::Image* image = result.getImage();
+ cubeTexture->setImage(TextureCubeMap::POSITIVE_Z, image);
+ }
+ result = osgDB::readImageFile(_tuple.get<5>(), options);
+ if(result.success()) {
+ osg::Image* image = result.getImage();
+ cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, image);
+ }
+
+ _cubemaps[_tuple] = cubeTexture;
+
+ return cubeTexture;
}
- _cubemaps[_tuple] = cubeTexture;
- return cubeTexture;
+ // Using 1 cross image
+ else if(crossProp) {
+ SG_LOG(SG_INPUT, SG_DEBUG, "try cross map ");
+
+ std::string texname = crossProp->getStringValue();
+
+ // Try to find existing cube map
+ CrossCubeMap::iterator itr = _crossmaps.find(texname);
+ if (itr != _crossmaps.end())
+ return itr->second.get();
+
+ osgDB::ReaderWriter::ReadResult result;
+ result = osgDB::readImageFile(texname, options);
+ if(result.success()) {
+ osg::Image* image = result.getImage();
+ image->flipVertical(); // Seems like the image coordinates are somewhat funny, flip to get better ones
+
+ //cubeTexture->setResizeNonPowerOfTwoHint(false);
+
+ // Size of a single image, 4 rows and 3 columns
+ int width = image->s() / 3;
+ int height = image->t() / 4;
+ int depth = image->r();
+
+ TextureCubeMap* cubeTexture = new osg::TextureCubeMap;
+
+ // Copy the 6 sub-images and push them
+ for(int n=0; n<6; n++) {
+
+ SG_LOG(SG_INPUT, SG_DEBUG, "Copying the " << n << "th sub-images and pushing it" );
+
+ osg::ref_ptr<osg::Image> subimg = new osg::Image();
+ subimg->allocateImage(width, height, depth, image->getPixelFormat(), image->getDataType()); // Copy attributes
+
+ // Choose correct image
+ switch(n) {
+ case 0: // Front
+ copySubImage(image, width, 0, width, height, subimg.get(), 0, 0);
+ cubeTexture->setImage(TextureCubeMap::POSITIVE_Y, subimg.get());
+ cubeTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
+ break;
+ case 1: // Left
+ copySubImage(image, 0, height, width, height, subimg.get(), 0, 0);
+ cubeTexture->setImage(TextureCubeMap::NEGATIVE_X, subimg.get());
+ cubeTexture->setWrap(osg::Texture2D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
+ break;
+ case 2: // Top
+ copySubImage(image, width, height, width, height, subimg.get(), 0, 0);
+ cubeTexture->setImage(TextureCubeMap::POSITIVE_Z, subimg.get());
+ cubeTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
+ break;
+ case 3: // Right
+ copySubImage(image, width*2, height, width, height, subimg.get(), 0, 0);
+ cubeTexture->setImage(TextureCubeMap::POSITIVE_X, subimg.get());
+ cubeTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
+ break;
+ case 4: // Back
+ copySubImage(image, width, height*2, width, height, subimg.get(), 0, 0);
+ cubeTexture->setImage(TextureCubeMap::NEGATIVE_Y, subimg.get());
+ cubeTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
+ break;
+ case 5: // Bottom
+ copySubImage(image, width, height*3, width, height, subimg.get(), 0, 0);
+ cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, subimg.get());
+ cubeTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
+ cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
+ break;
+ };
+
+ }
+
+ _crossmaps[texname] = cubeTexture;
+
+ return cubeTexture;
+
+ } else {
+ throw BuilderException("Could not load cube cross");
+ }
+ }
+
+ return NULL;
}
namespace {
TextureBuilder::Registrar installCubeMap("cubemap", new CubeMapBuilder);
}
-
-
EffectNameValue<TexEnvCombine::CombineParam> combineParamInit[] =
{
{"replace", TexEnvCombine::REPLACE},
EffectPropertyMap<TexEnvCombine::OperandParam> operandParams(opParamInit);
TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp,
- const SGReaderWriterXMLOptions* options)
+ const SGReaderWriterOptions* options)
{
if (!isAttributeActive(effect, envProp))
return 0;
if (!isAttributeActive(effect, tgenProp))
return 0;
TexGen* result = new TexGen;
- const SGPropertyNode* p = 0;
TexGen::Mode mode = TexGen::OBJECT_LINEAR;
findAttr(tgenModes, getEffectPropertyChild(effect, tgenProp, "mode"), mode);
result->setMode(mode);