X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fmaterial%2FTextureBuilder.cxx;h=0c141c475c3415b627c354ad8cb53b4a1d52eb69;hb=aef8f13290c74359c1a7a54bd5e6e375b3f0c49e;hp=d7382e9219ad969d1a1c14d09d8de3b01eed8152;hpb=54c4055af3b106371ed57852c4ad5f1dd087badc;p=simgear.git diff --git a/simgear/scene/material/TextureBuilder.cxx b/simgear/scene/material/TextureBuilder.cxx index d7382e92..0c141c47 100644 --- a/simgear/scene/material/TextureBuilder.cxx +++ b/simgear/scene/material/TextureBuilder.cxx @@ -19,6 +19,7 @@ #endif #include "TextureBuilder.hxx" +#include "mipmap.hxx" #include "Pass.hxx" @@ -29,12 +30,15 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #include #include @@ -50,13 +54,14 @@ using namespace osg; using namespace effect; TexEnvCombine* buildTexEnvCombine(Effect* effect, - const SGPropertyNode* envProp); + const SGPropertyNode* envProp, + 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 osgDB::ReaderWriter::Options* + const SGReaderWriterOptions* options) { return EffectBuilder::buildFromType(effect, type, props, options); @@ -64,7 +69,7 @@ osg::Texture* TextureBuilder::buildFromType(Effect* effect, const string& type, typedef boost::tuple TexTuple; + string, MipMapTuple> TexTuple; EffectNameValue texEnvModesInit[] = { @@ -93,12 +98,12 @@ TexEnv* buildTexEnv(Effect* effect, const SGPropertyNode* prop) if (colorProp) env->setColor(toOsg(colorProp->getValue())); return env; - } +} void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -129,7 +134,9 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, 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); @@ -141,7 +148,8 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, } const SGPropertyNode* combineProp = prop->getChild("texenv-combine"); TexEnvCombine* combiner = 0; - if (combineProp && ((combiner = buildTexEnvCombine(effect, combineProp)))) + if (combineProp && ((combiner = buildTexEnvCombine(effect, combineProp, + options)))) pass->setTextureAttributeAndModes(unit, combiner); const SGPropertyNode* tgenProp = prop->getChild("texgen"); TexGen* tgen = 0; @@ -175,52 +183,70 @@ EffectNameValue wrapModesInit[] = }; EffectPropertyMap wrapModes(wrapModesInit); - TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props, - const osgDB::ReaderWriter::Options* options, + const SGReaderWriterOptions* options, const string& texType) { Texture::FilterMode minFilter = Texture::LINEAR_MIPMAP_LINEAR; - findAttr(filterModes, getEffectPropertyChild(effect, props, "filter"), - minFilter); + const SGPropertyNode* ep = 0; + if ((ep = getEffectPropertyChild(effect, props, "filter"))) + findAttr(filterModes, ep, minFilter); Texture::FilterMode magFilter = Texture::LINEAR; - findAttr(filterModes, getEffectPropertyChild(effect, props, - "mag-filter"), - magFilter); + if ((ep = getEffectPropertyChild(effect, props, "mag-filter"))) + findAttr(filterModes, ep, magFilter); const SGPropertyNode* pWrapS = getEffectPropertyChild(effect, props, "wrap-s"); Texture::WrapMode sWrap = Texture::CLAMP; - findAttr(wrapModes, pWrapS, sWrap); + if (pWrapS) + findAttr(wrapModes, pWrapS, sWrap); const SGPropertyNode* pWrapT = getEffectPropertyChild(effect, props, "wrap-t"); Texture::WrapMode tWrap = Texture::CLAMP; - findAttr(wrapModes, pWrapT, tWrap); + if (pWrapT) + findAttr(wrapModes, pWrapT, tWrap); const SGPropertyNode* pWrapR = getEffectPropertyChild(effect, props, "wrap-r"); Texture::WrapMode rWrap = Texture::CLAMP; - findAttr(wrapModes, pWrapR, rWrap); + if (pWrapR) + findAttr(wrapModes, pWrapR, rWrap); 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 osgDB::ReaderWriter::Options* 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 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) { @@ -250,7 +276,7 @@ class TexBuilder : public TextureBuilder public: TexBuilder(const string& texType) : _type(texType) {} Texture* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterOptions* options); protected: typedef map > TexMap; TexMap texMap; @@ -259,7 +285,7 @@ protected: template Texture* TexBuilder::build(Effect* effect, const SGPropertyNode* props, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterOptions* options) { TexTuple attrs = makeTexTuple(effect, props, options, _type); typename TexMap::iterator itr = texMap.find(attrs); @@ -283,11 +309,11 @@ class WhiteTextureBuilder : public TextureBuilder { public: Texture* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterOptions* options); }; Texture* WhiteTextureBuilder::build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterOptions* options) { return StateAttributeFactory::instance()->getWhiteTexture(); } @@ -297,6 +323,25 @@ namespace TextureBuilder::Registrar installWhite("white", new WhiteTextureBuilder); } +class TransparentTextureBuilder : public TextureBuilder +{ +public: + Texture* build(Effect* effect, const SGPropertyNode*, + const SGReaderWriterOptions* options); +}; + +Texture* TransparentTextureBuilder::build(Effect* effect, const SGPropertyNode*, + const SGReaderWriterOptions* options) +{ + return StateAttributeFactory::instance()->getTransparentTexture(); +} + +namespace +{ +TextureBuilder::Registrar installTransparent("transparent", + new TransparentTextureBuilder); +} + osg::Image* make3DNoiseImage(int texSize) { osg::Image* image = new osg::Image; @@ -346,14 +391,14 @@ class NoiseBuilder : public TextureBuilder { public: Texture* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterOptions* options); protected: typedef map > NoiseMap; NoiseMap _noises; }; Texture* NoiseBuilder::build(Effect* effect, const SGPropertyNode* props, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterOptions* options) { int texSize = 64; const SGPropertyNode* sizeProp = getEffectPropertyChild(effect, props, @@ -379,6 +424,230 @@ namespace TextureBuilder::Registrar installNoise("noise", new NoiseBuilder); } + + +// Image names for all sides +typedef boost::tuple CubeMapTuple; + +CubeMapTuple makeCubeMapTuple(Effect* effect, const SGPropertyNode* props) +{ + const SGPropertyNode* ep = 0; + + string positive_x; + if ((ep = getEffectPropertyChild(effect, props, "positive-x"))) + positive_x = ep->getStringValue(); + string negative_x; + if ((ep = getEffectPropertyChild(effect, props, "negative-x"))) + negative_x = ep->getStringValue(); + string positive_y; + if ((ep = getEffectPropertyChild(effect, props, "positive-y"))) + positive_y = ep->getStringValue(); + string negative_y; + if ((ep = getEffectPropertyChild(effect, props, "negative-y"))) + negative_y = ep->getStringValue(); + string positive_z; + if ((ep = getEffectPropertyChild(effect, props, "positive-z"))) + positive_z = ep->getStringValue(); + string negative_z; + if ((ep = getEffectPropertyChild(effect, props, "negative-z"))) + negative_z = ep->getStringValue(); + return CubeMapTuple(positive_x, negative_x, positive_y, negative_y, positive_z, negative_z); +} + + +class CubeMapBuilder : public TextureBuilder +{ +public: + Texture* build(Effect* effect, const SGPropertyNode*, + const SGReaderWriterOptions* options); +protected: + typedef map > CubeMap; + typedef map > 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; rowdata(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 SGReaderWriterOptions* options) +{ + // First check that there is a tag + const SGPropertyNode* texturesProp = getEffectPropertyChild(effect, props, "images"); + const SGPropertyNode* crossProp = getEffectPropertyChild(effect, props, "image"); + if (!texturesProp && !crossProp) { + throw BuilderException("no images defined for cube map"); + return NULL; // This is redundant + } + + // Using 6 separate images + if(texturesProp) { + + SG_LOG(SG_INPUT, SG_DEBUG, "try 6 images "); + + CubeMapTuple _tuple = makeCubeMapTuple(effect, texturesProp); + + CubeMap::iterator itr = _cubemaps.find(_tuple); + if (itr != _cubemaps.end()) + return itr->second.get(); + + 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; + } + + + // 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 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 combineParamInit[] = { {"replace", TexEnvCombine::REPLACE}, @@ -413,15 +682,16 @@ EffectPropertyMap sourceParams(sourceParamInit); EffectNameValue opParamInit[] = { - {"src_color", TexEnvCombine::SRC_COLOR}, - {"one_minus_src_color", TexEnvCombine::ONE_MINUS_SRC_COLOR}, - {"src_alpha", TexEnvCombine::SRC_ALPHA}, - {"one_minus_src_alpha", TexEnvCombine::ONE_MINUS_SRC_ALPHA} + {"src-color", TexEnvCombine::SRC_COLOR}, + {"one-minus-src-color", TexEnvCombine::ONE_MINUS_SRC_COLOR}, + {"src-alpha", TexEnvCombine::SRC_ALPHA}, + {"one-minus-src-alpha", TexEnvCombine::ONE_MINUS_SRC_ALPHA} }; EffectPropertyMap operandParams(opParamInit); -TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp) +TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp, + const SGReaderWriterOptions* options) { if (!isAttributeActive(effect, envProp)) return 0; @@ -435,7 +705,7 @@ TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp) if ((p = getEffectPropertyChild(effect, envProp, "combine-alpha"))) { TexEnvCombine::CombineParam calpha = TexEnvCombine::MODULATE; findAttr(combineParams, p, calpha); - result->setCombine_RGB(calpha); + result->setCombine_Alpha(calpha); } if ((p = getEffectPropertyChild(effect, envProp, "source0-rgb"))) { TexEnvCombine::SourceParam source = TexEnvCombine::TEXTURE; @@ -516,7 +786,8 @@ TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp) const SGPropertyNode* colorNode = envProp->getChild("constant-color"); if (colorNode) initFromParameters(effect, colorNode, result, - &TexEnvCombine::setConstantColor, colorFields); + &TexEnvCombine::setConstantColor, colorFields, + options); return result; } @@ -546,25 +817,19 @@ TexGen* buildTexGen(Effect* effect, const SGPropertyNode* tgenProp) if (!isAttributeActive(effect, tgenProp)) return 0; TexGen* result = new TexGen; - const SGPropertyNode* p = 0; TexGen::Mode mode = TexGen::OBJECT_LINEAR; - if (findAttr(tgenModes, getEffectPropertyChild(effect, tgenProp, "mode"), - mode)) - result->setMode(mode); + findAttr(tgenModes, getEffectPropertyChild(effect, tgenProp, "mode"), mode); + result->setMode(mode); const SGPropertyNode* planesNode = tgenProp->getChild("planes"); if (planesNode) { for (int i = 0; i < planesNode->nChildren(); ++i) { const SGPropertyNode* planeNode = planesNode->getChild(i); TexGen::Coord coord; - if (!findAttr(tgenCoords, planeNode->getName(), coord)) { - SG_LOG(SG_INPUT, SG_ALERT, "Unknown TexGen plane " - << planeNode->getName()); - } else { - const SGPropertyNode* realNode - = getEffectPropertyNode(effect, planeNode); - SGVec4d plane = realNode->getValue(); - result->setPlane(coord, toOsg(plane)); - } + findAttr(tgenCoords, planeNode->getName(), coord); + const SGPropertyNode* realNode + = getEffectPropertyNode(effect, planeNode); + SGVec4d plane = realNode->getValue(); + result->setPlane(coord, toOsg(plane)); } } return result; @@ -577,8 +842,8 @@ bool makeTextureParameters(SGPropertyNode* paramRoot, const StateSet* ss) const Texture2D* texture = dynamic_cast(tex); makeChild(texUnit, "unit")->setValue(0); if (!tex) { + // The default shader-based technique ignores active makeChild(texUnit, "active")->setValue(false); - makeChild(texUnit, "type")->setValue("white"); return false; } const Image* image = texture->getImage(); @@ -592,10 +857,16 @@ bool makeTextureParameters(SGPropertyNode* paramRoot, const StateSet* ss) } makeChild(texUnit, "active")->setValue(true); makeChild(texUnit, "type")->setValue("2d"); + string filter = findName(filterModes, + texture->getFilter(Texture::MIN_FILTER)); + string magFilter = findName(filterModes, + texture->getFilter(Texture::MAG_FILTER)); string wrapS = findName(wrapModes, texture->getWrap(Texture::WRAP_S)); string wrapT = findName(wrapModes, texture->getWrap(Texture::WRAP_T)); string wrapR = findName(wrapModes, texture->getWrap(Texture::WRAP_R)); makeChild(texUnit, "image")->setStringValue(imageName); + makeChild(texUnit, "filter")->setStringValue(filter); + makeChild(texUnit, "mag-filter")->setStringValue(magFilter); makeChild(texUnit, "wrap-s")->setStringValue(wrapS); makeChild(texUnit, "wrap-t")->setStringValue(wrapT); makeChild(texUnit, "wrap-r")->setStringValue(wrapR);