Merge branch 'next' of https://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
commit
72dd45388f
@ -125,9 +125,14 @@ option(ENABLE_SOUND "Set to OFF to disable building SimGear's sound support"
|
|||||||
option(USE_AEONWAVE "Set to ON to use AeonWave instead of OpenAL" ON)
|
option(USE_AEONWAVE "Set to ON to use AeonWave instead of OpenAL" ON)
|
||||||
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
|
option(ENABLE_PKGUTIL "Set to ON to build the sg_pkgutil application (default)" ON)
|
||||||
option(ENABLE_DNS "Set to ON to use udns library and DNS service resolver" ON)
|
option(ENABLE_DNS "Set to ON to use udns library and DNS service resolver" ON)
|
||||||
option(ENABLE_SIMD "Enable SSE/SSE2 support for x86 compilers" ON)
|
option(ENABLE_SIMD "Enable SSE/SSE2 support for compilers" ON)
|
||||||
|
option(ENABLE_SIMD_CODE "Enable SSE/SSE2 support code for compilers" OFF)
|
||||||
option(ENABLE_OPENMP "Enable OpenMP compiler support" OFF)
|
option(ENABLE_OPENMP "Enable OpenMP compiler support" OFF)
|
||||||
|
|
||||||
|
if (NOT ENABLE_SIMD AND ENABLE_SIMD_CODE)
|
||||||
|
set(ENABLE_SIMD_CODE OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
include (DetectArch)
|
include (DetectArch)
|
||||||
|
|
||||||
# until the fstream fix is applied and generally available in OSG,
|
# until the fstream fix is applied and generally available in OSG,
|
||||||
@ -412,8 +417,8 @@ if(CMAKE_COMPILER_IS_GNUCXX)
|
|||||||
"${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline")
|
"${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline")
|
||||||
elseif (ENABLE_SIMD)
|
elseif (ENABLE_SIMD)
|
||||||
if (X86 OR X86_64)
|
if (X86 OR X86_64)
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -440,8 +445,8 @@ if (CLANG)
|
|||||||
"${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions")
|
"${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions")
|
||||||
elseif (ENABLE_SIMD)
|
elseif (ENABLE_SIMD)
|
||||||
if (X86 OR X86_64)
|
if (X86 OR X86_64)
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -1193,7 +1193,7 @@ VG_API_CALL VGboolean vgInterpolatePath(VGPath dstPath, VGPath startPath,
|
|||||||
SHfloat *procData1, *procData2;
|
SHfloat *procData1, *procData2;
|
||||||
SHint procSegCount1=0, procSegCount2=0;
|
SHint procSegCount1=0, procSegCount2=0;
|
||||||
SHint procDataCount1=0, procDataCount2=0;
|
SHint procDataCount1=0, procDataCount2=0;
|
||||||
SHuint8 *newSegs, *newData;
|
SHuint8 *newSegs, *newData=0;
|
||||||
void *userData[4];
|
void *userData[4];
|
||||||
SHint segment1, segment2;
|
SHint segment1, segment2;
|
||||||
SHint segindex, s,d,i;
|
SHint segindex, s,d,i;
|
||||||
|
@ -71,8 +71,12 @@ namespace canvas
|
|||||||
|
|
||||||
canvas::Text *_text_element;
|
canvas::Text *_text_element;
|
||||||
|
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,5,6)
|
||||||
void computePositions(unsigned int contextID) const override;
|
void computePositions(unsigned int contextID) const override;
|
||||||
};
|
#else
|
||||||
|
void computePositionsImplementation() override;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
class TextLine
|
class TextLine
|
||||||
{
|
{
|
||||||
@ -122,6 +126,8 @@ namespace canvas
|
|||||||
|
|
||||||
_quads = &text->_textureGlyphQuadMap.begin()->second;
|
_quads = &text->_textureGlyphQuadMap.begin()->second;
|
||||||
|
|
||||||
|
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,5,6)
|
||||||
GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers;
|
GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers;
|
||||||
GlyphQuads::LineNumbers::const_iterator begin_it =
|
GlyphQuads::LineNumbers::const_iterator begin_it =
|
||||||
std::lower_bound(line_numbers.begin(), line_numbers.end(), _line);
|
std::lower_bound(line_numbers.begin(), line_numbers.end(), _line);
|
||||||
@ -133,6 +139,10 @@ namespace canvas
|
|||||||
_begin = begin_it - line_numbers.begin();
|
_begin = begin_it - line_numbers.begin();
|
||||||
_end = std::upper_bound(begin_it, line_numbers.end(), _line)
|
_end = std::upper_bound(begin_it, line_numbers.end(), _line)
|
||||||
- line_numbers.begin();
|
- line_numbers.begin();
|
||||||
|
#else
|
||||||
|
//OSG:TODO: Need 3.5.6 version of this
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -163,16 +173,15 @@ namespace canvas
|
|||||||
return pos;
|
return pos;
|
||||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||||
#else
|
#elif OSG_VERSION_LESS_THAN(3,5,6)
|
||||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||||
#endif
|
|
||||||
size_t global_i = _begin + i;
|
size_t global_i = _begin + i;
|
||||||
|
|
||||||
if( global_i == _begin )
|
if (global_i == _begin)
|
||||||
// before first character of line
|
// before first character of line
|
||||||
pos.x() = coords[_begin * 4].x();
|
pos.x() = coords[_begin * 4].x();
|
||||||
else if( global_i == _end )
|
else if (global_i == _end)
|
||||||
// After Last character of line
|
// After Last character of line
|
||||||
pos.x() = coords[(_end - 1) * 4 + 2].x();
|
pos.x() = coords[(_end - 1) * 4 + 2].x();
|
||||||
else
|
else
|
||||||
@ -181,7 +190,7 @@ namespace canvas
|
|||||||
prev_r = coords[(global_i - 1) * 4 + 2].x(),
|
prev_r = coords[(global_i - 1) * 4 + 2].x(),
|
||||||
cur_l = coords[global_i * 4].x();
|
cur_l = coords[global_i * 4].x();
|
||||||
|
|
||||||
if( prev_l == prev_r )
|
if (prev_l == prev_r)
|
||||||
// If previous character width is zero set to begin of next character
|
// If previous character width is zero set to begin of next character
|
||||||
// (Happens eg. with spaces)
|
// (Happens eg. with spaces)
|
||||||
pos.x() = cur_l;
|
pos.x() = cur_l;
|
||||||
@ -189,6 +198,9 @@ namespace canvas
|
|||||||
// position at center between characters
|
// position at center between characters
|
||||||
pos.x() = 0.5 * (prev_r + cur_l);
|
pos.x() = 0.5 * (prev_r + cur_l);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
//OSG:TODO: need 3.5.7 version of this.
|
||||||
|
#endif
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
@ -200,12 +212,12 @@ namespace canvas
|
|||||||
return cursorPos(0);
|
return cursorPos(0);
|
||||||
|
|
||||||
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
|
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
|
||||||
#if OSG_VERSION_LESS_THAN(3,3,5)
|
#if OSG_VERSION_LESS_THAN(3,3,5)
|
||||||
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
GlyphQuads::Coords2 const& coords = _quads->_coords;
|
||||||
#else
|
#elif OSG_VERSION_LESS_THAN(3,5,6)
|
||||||
|
|
||||||
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
GlyphQuads::Coords2 refCoords = _quads->_coords;
|
||||||
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
|
||||||
#endif
|
|
||||||
|
|
||||||
float const HIT_FRACTION = 0.6;
|
float const HIT_FRACTION = 0.6;
|
||||||
float const character_width = _text->getCharacterHeight()
|
float const character_width = _text->getCharacterHeight()
|
||||||
@ -225,6 +237,10 @@ namespace canvas
|
|||||||
}
|
}
|
||||||
|
|
||||||
return cursorPos(i - _begin);
|
return cursorPos(i - _begin);
|
||||||
|
#else
|
||||||
|
//OSG:TODO: need 3.5.7 version of this.
|
||||||
|
return cursorPos(0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -640,7 +656,7 @@ namespace canvas
|
|||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
#if OSG_VERSION_LESS_THAN(3,5,6)
|
||||||
void Text::TextOSG::computePositions(unsigned int contextID) const
|
void Text::TextOSG::computePositions(unsigned int contextID) const
|
||||||
{
|
{
|
||||||
if( _textureGlyphQuadMap.empty() || _layout == VERTICAL )
|
if( _textureGlyphQuadMap.empty() || _layout == VERTICAL )
|
||||||
@ -710,6 +726,14 @@ namespace canvas
|
|||||||
return osgText::Text::computePositions(contextID);
|
return osgText::Text::computePositions(contextID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
void Text::TextOSG::computePositionsImplementation()
|
||||||
|
{
|
||||||
|
TextBase::computePositionsImplementation();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
const std::string Text::TYPE_NAME = "text";
|
const std::string Text::TYPE_NAME = "text";
|
||||||
|
|
||||||
|
@ -518,7 +518,7 @@ public:
|
|||||||
|
|
||||||
// SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured
|
// SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured
|
||||||
// separately and thus it makes more sense to allow these message through.
|
// separately and thus it makes more sense to allow these message through.
|
||||||
if (p == SG_OSG) return true;
|
if (static_cast<unsigned>(p) == static_cast<unsigned>(SG_OSG)) return true;
|
||||||
|
|
||||||
p = translatePriority(p);
|
p = translatePriority(p);
|
||||||
if (p >= SG_INFO) return true;
|
if (p >= SG_INFO) return true;
|
||||||
|
@ -44,6 +44,10 @@ SGPrecipitation::SGPrecipitation() :
|
|||||||
void SGPrecipitation::setEnabled( bool value )
|
void SGPrecipitation::setEnabled( bool value )
|
||||||
{
|
{
|
||||||
_enabled = value;
|
_enabled = value;
|
||||||
|
if (!_enabled) {
|
||||||
|
_precipitationEffect->snow(0);
|
||||||
|
_precipitationEffect->rain(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGPrecipitation::setDropletExternal( bool value )
|
void SGPrecipitation::setDropletExternal( bool value )
|
||||||
@ -64,6 +68,9 @@ bool SGPrecipitation::getEnabled() const
|
|||||||
*/
|
*/
|
||||||
osg::Group* SGPrecipitation::build(void)
|
osg::Group* SGPrecipitation::build(void)
|
||||||
{
|
{
|
||||||
|
if (!_enabled)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
osg::ref_ptr<osg::Group> group = new osg::Group;
|
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||||
|
|
||||||
_precipitationEffect->snow(0);
|
_precipitationEffect->snow(0);
|
||||||
@ -227,6 +234,9 @@ void SGPrecipitation::setWindProperty(double heading, double speed)
|
|||||||
*/
|
*/
|
||||||
bool SGPrecipitation::update(void)
|
bool SGPrecipitation::update(void)
|
||||||
{
|
{
|
||||||
|
if (!_enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (this->_freeze) {
|
if (this->_freeze) {
|
||||||
if (this->_rain_intensity > 0) {
|
if (this->_rain_intensity > 0) {
|
||||||
this->_snow_intensity = this->_rain_intensity;
|
this->_snow_intensity = this->_rain_intensity;
|
||||||
|
@ -273,6 +273,10 @@ void Client::makeRequest(const Request_ptr& r)
|
|||||||
curl_easy_setopt(curlRequest, CURLOPT_USERAGENT, d->userAgent.c_str());
|
curl_easy_setopt(curlRequest, CURLOPT_USERAGENT, d->userAgent.c_str());
|
||||||
curl_easy_setopt(curlRequest, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
curl_easy_setopt(curlRequest, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||||
|
|
||||||
|
if (sglog().would_log(SG_TERRASYNC, SG_DEBUG)) {
|
||||||
|
curl_easy_setopt(curlRequest, CURLOPT_VERBOSE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
curl_easy_setopt(curlRequest, CURLOPT_FOLLOWLOCATION, 1);
|
curl_easy_setopt(curlRequest, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
|
|
||||||
if (!d->proxy.empty()) {
|
if (!d->proxy.empty()) {
|
||||||
|
@ -64,6 +64,31 @@ SGFile::SGFile( int existingFd ) :
|
|||||||
SGFile::~SGFile() {
|
SGFile::~SGFile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include <simgear/misc/sg_hash.hxx>
|
||||||
|
#include <simgear/structure/exception.hxx>
|
||||||
|
#include "simgear/misc/strutils.hxx"
|
||||||
|
|
||||||
|
std::string SGFile::computeHash()
|
||||||
|
{
|
||||||
|
if (!file_name.exists())
|
||||||
|
return std::string();
|
||||||
|
simgear::sha1nfo info;
|
||||||
|
sha1_init(&info);
|
||||||
|
char* buf = static_cast<char*>(malloc(1024 * 1024));
|
||||||
|
size_t readLen;
|
||||||
|
SGBinaryFile f(file_name);
|
||||||
|
if (!f.open(SG_IO_IN)) {
|
||||||
|
throw sg_io_exception("Couldn't open file for compute hash", file_name);
|
||||||
|
}
|
||||||
|
while ((readLen = f.read(buf, 1024 * 1024)) > 0) {
|
||||||
|
sha1_write(&info, buf, readLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
f.close();
|
||||||
|
free(buf);
|
||||||
|
std::string hashBytes((char*)sha1_result(&info), HASH_LENGTH);
|
||||||
|
return simgear::strutils::encodeHex(hashBytes);
|
||||||
|
}
|
||||||
|
|
||||||
// open the file based on specified direction
|
// open the file based on specified direction
|
||||||
bool SGFile::open( const SGProtocolDir d ) {
|
bool SGFile::open( const SGProtocolDir d ) {
|
||||||
|
@ -87,6 +87,9 @@ public:
|
|||||||
|
|
||||||
/** @return true of eof conditions exists */
|
/** @return true of eof conditions exists */
|
||||||
virtual bool eof() const { return eof_flag; };
|
virtual bool eof() const { return eof_flag; };
|
||||||
|
|
||||||
|
std::string computeHash();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class SGBinaryFile : public SGFile {
|
class SGBinaryFile : public SGFile {
|
||||||
|
@ -309,7 +309,7 @@ inline simd4_t<T,N> operator*(simd4_t<T,N> v, T f) {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_SIMD
|
#ifdef ENABLE_SIMD_CODE
|
||||||
|
|
||||||
# ifdef __SSE__
|
# ifdef __SSE__
|
||||||
namespace simd4
|
namespace simd4
|
||||||
@ -1305,7 +1305,7 @@ inline simd4_t<int,N> max(simd4_t<int,N> v1, const simd4_t<int,N>& v2) {
|
|||||||
|
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif /* ENABLE_SIMD */
|
#endif /* ENABLE_SIMD_CODE */
|
||||||
|
|
||||||
#endif /* __SIMD_H__ */
|
#endif /* __SIMD_H__ */
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ inline simd4x4_t<T,N> operator*(const simd4x4_t<T,N>& m1, const simd4x4_t<T,N>&
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_SIMD
|
#ifdef ENABLE_SIMD_CODE
|
||||||
|
|
||||||
# ifdef __SSE__
|
# ifdef __SSE__
|
||||||
template<>
|
template<>
|
||||||
@ -1191,7 +1191,7 @@ inline simd4_t<int,3> transform<int>(const simd4x4_t<int,4>& m, const simd4_t<in
|
|||||||
} /* namespace simd4x */
|
} /* namespace simd4x */
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif /* ENABLE_SIMD */
|
#endif /* ENABLE_SIMD_CODE */
|
||||||
|
|
||||||
#endif /* __SIMD4X4_H__ */
|
#endif /* __SIMD4X4_H__ */
|
||||||
|
|
||||||
|
@ -963,6 +963,11 @@ SGPropertyNode::alias (SGPropertyNode * target)
|
|||||||
{
|
{
|
||||||
if (target && (_type != props::ALIAS) && (!_tied))
|
if (target && (_type != props::ALIAS) && (!_tied))
|
||||||
{
|
{
|
||||||
|
/* loop protection: check alias chain; must not contain self */
|
||||||
|
for (auto p = target; p; p = ((p->_type == props::ALIAS) ? p->_value.alias : nullptr)) {
|
||||||
|
if (p == this) return false;
|
||||||
|
}
|
||||||
|
|
||||||
clearValue();
|
clearValue();
|
||||||
get(target);
|
get(target);
|
||||||
_value.alias = target;
|
_value.alias = target;
|
||||||
@ -973,7 +978,7 @@ SGPropertyNode::alias (SGPropertyNode * target)
|
|||||||
if (!target)
|
if (!target)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
SG_LOG(SG_GENERAL, SG_ALERT,
|
||||||
"Failed to create alias for " << getPath() << ". "
|
"Failed to set alias " << getPath() << ". "
|
||||||
"The target property does not exist.");
|
"The target property does not exist.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -981,15 +986,15 @@ SGPropertyNode::alias (SGPropertyNode * target)
|
|||||||
{
|
{
|
||||||
if (_value.alias == target)
|
if (_value.alias == target)
|
||||||
return true; // ok, identical alias requested
|
return true; // ok, identical alias requested
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT,
|
SG_LOG(SG_GENERAL, SG_ALERT, "alias(): "<< getPath() <<
|
||||||
"Failed to create alias at " << target->getPath() << ". "
|
" is already pointing to " << _value.alias->getPath() <<
|
||||||
"Source "<< getPath() << " is already aliasing another property.");
|
" so it cannot alias '" << target->getPath() << ". Use unalias() first.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (_tied)
|
if (_tied)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "Failed to create alias at " << target->getPath() << ". "
|
SG_LOG(SG_GENERAL, SG_ALERT, "alias(): " << getPath() <<
|
||||||
"Source " << getPath() << " is a tied property.");
|
" is a tied property. It cannot alias " << target->getPath() << ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -830,6 +830,9 @@ void reload_shaders()
|
|||||||
if (!fileName.empty()) {
|
if (!fileName.empty()) {
|
||||||
shader->loadShaderSourceFromFile(fileName);
|
shader->loadShaderSourceFromFile(fileName);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader: " << fileName);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -917,8 +920,13 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
|
|||||||
Shader::Type stype = (Shader::Type)shaderKey.second;
|
Shader::Type stype = (Shader::Type)shaderKey.second;
|
||||||
string fileName = SGModelLib::findDataFile(shaderName, options);
|
string fileName = SGModelLib::findDataFile(shaderName, options);
|
||||||
if (fileName.empty())
|
if (fileName.empty())
|
||||||
|
{
|
||||||
|
SG_LOG(SG_INPUT, SG_ALERT, "Could not locate shader" << shaderName);
|
||||||
|
|
||||||
|
|
||||||
throw BuilderException(string("couldn't find shader ") +
|
throw BuilderException(string("couldn't find shader ") +
|
||||||
shaderName);
|
shaderName);
|
||||||
|
}
|
||||||
resolvedKey.shaders.push_back(ShaderKey(fileName, stype));
|
resolvedKey.shaders.push_back(ShaderKey(fileName, stype));
|
||||||
}
|
}
|
||||||
ProgramMap::iterator resitr = resolvedProgramMap.find(resolvedKey);
|
ProgramMap::iterator resitr = resolvedProgramMap.find(resolvedKey);
|
||||||
@ -1405,8 +1413,11 @@ bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss)
|
|||||||
|
|
||||||
// Walk the techniques property tree, building techniques and
|
// Walk the techniques property tree, building techniques and
|
||||||
// passes.
|
// passes.
|
||||||
|
static SGMutex realizeTechniques_lock;
|
||||||
bool Effect::realizeTechniques(const SGReaderWriterOptions* options)
|
bool Effect::realizeTechniques(const SGReaderWriterOptions* options)
|
||||||
{
|
{
|
||||||
|
SGGuard<SGMutex> g(realizeTechniques_lock);
|
||||||
|
|
||||||
if (_isRealized)
|
if (_isRealized)
|
||||||
return true;
|
return true;
|
||||||
PropertyList tniqList = root->getChildren("technique");
|
PropertyList tniqList = root->getChildren("technique");
|
||||||
|
@ -76,7 +76,7 @@ osg::Texture* TextureBuilder::buildFromType(Effect* effect, Pass* pass, const st
|
|||||||
|
|
||||||
typedef boost::tuple<string, Texture::FilterMode, Texture::FilterMode,
|
typedef boost::tuple<string, Texture::FilterMode, Texture::FilterMode,
|
||||||
Texture::WrapMode, Texture::WrapMode, Texture::WrapMode,
|
Texture::WrapMode, Texture::WrapMode, Texture::WrapMode,
|
||||||
string, MipMapTuple> TexTuple;
|
string, MipMapTuple, ImageInternalFormat> TexTuple;
|
||||||
|
|
||||||
EffectNameValue<TexEnv::Mode> texEnvModesInit[] =
|
EffectNameValue<TexEnv::Mode> texEnvModesInit[] =
|
||||||
{
|
{
|
||||||
@ -239,6 +239,17 @@ TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SGPropertyNode* pInternalFormat = getEffectPropertyChild(effect, props, "internal-format");
|
||||||
|
pInternalFormat = props->getChild("internal-format");
|
||||||
|
ImageInternalFormat iformat = ImageInternalFormat::Unspecified;
|
||||||
|
if (pInternalFormat) {
|
||||||
|
std::string internalFormat = pInternalFormat->getStringValue();
|
||||||
|
if (internalFormat == "normalized") {
|
||||||
|
iformat = ImageInternalFormat::Normalized;
|
||||||
|
SG_LOG(SG_INPUT, SG_ALERT, "internal-format normalized '" << imageName << "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const SGPropertyNode* pMipmapControl
|
const SGPropertyNode* pMipmapControl
|
||||||
= getEffectPropertyChild(effect, props, "mipmap-control");
|
= getEffectPropertyChild(effect, props, "mipmap-control");
|
||||||
MipMapTuple mipmapFunctions( AUTOMATIC, AUTOMATIC, AUTOMATIC, AUTOMATIC );
|
MipMapTuple mipmapFunctions( AUTOMATIC, AUTOMATIC, AUTOMATIC, AUTOMATIC );
|
||||||
@ -246,7 +257,7 @@ TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props,
|
|||||||
mipmapFunctions = makeMipMapTuple(effect, pMipmapControl, options);
|
mipmapFunctions = makeMipMapTuple(effect, pMipmapControl, options);
|
||||||
|
|
||||||
return TexTuple(absFileName, minFilter, magFilter, sWrap, tWrap, rWrap,
|
return TexTuple(absFileName, minFilter, magFilter, sWrap, tWrap, rWrap,
|
||||||
texType, mipmapFunctions);
|
texType, mipmapFunctions, iformat);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setAttrs(const TexTuple& attrs, Texture* tex,
|
bool setAttrs(const TexTuple& attrs, Texture* tex,
|
||||||
@ -257,7 +268,19 @@ bool setAttrs(const TexTuple& attrs, Texture* tex,
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
osgDB::ReaderWriter::ReadResult result;
|
osgDB::ReaderWriter::ReadResult result;
|
||||||
|
|
||||||
|
// load texture for effect
|
||||||
|
SGReaderWriterOptions::LoadOriginHint origLOH = options->getLoadOriginHint();
|
||||||
|
if(attrs.get<8>() == ImageInternalFormat::Normalized)
|
||||||
|
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS_NORMALIZED);
|
||||||
|
else
|
||||||
|
options->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS);
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,2)
|
||||||
result = osgDB::readImageFile(imageName, options);
|
result = osgDB::readImageFile(imageName, options);
|
||||||
|
#else
|
||||||
|
result = osgDB::readRefImageFile(imageName, options);
|
||||||
|
#endif
|
||||||
|
options->setLoadOriginHint(origLOH);
|
||||||
osg::ref_ptr<osg::Image> image;
|
osg::ref_ptr<osg::Image> image;
|
||||||
if (result.success())
|
if (result.success())
|
||||||
image = result.getImage();
|
image = result.getImage();
|
||||||
@ -585,36 +608,64 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode*
|
|||||||
cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
|
cubeTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
|
||||||
|
|
||||||
osgDB::ReaderWriter::ReadResult result;
|
osgDB::ReaderWriter::ReadResult result;
|
||||||
|
SGReaderWriterOptions* wOpts = (SGReaderWriterOptions*)options;
|
||||||
|
SGReaderWriterOptions::LoadOriginHint origLOH = wOpts->getLoadOriginHint();
|
||||||
|
wOpts->setLoadOriginHint(SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS);
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
result = osgDB::readImageFile(_tuple.get<0>(), options);
|
result = osgDB::readImageFile(_tuple.get<0>(), options);
|
||||||
|
#else
|
||||||
|
result = osgDB::readRefImageFile(_tuple.get<0>(), options);
|
||||||
|
#endif
|
||||||
if(result.success()) {
|
if(result.success()) {
|
||||||
osg::Image* image = result.getImage();
|
osg::Image* image = result.getImage();
|
||||||
cubeTexture->setImage(TextureCubeMap::POSITIVE_X, image);
|
cubeTexture->setImage(TextureCubeMap::POSITIVE_X, image);
|
||||||
}
|
}
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
result = osgDB::readImageFile(_tuple.get<1>(), options);
|
result = osgDB::readImageFile(_tuple.get<1>(), options);
|
||||||
|
#else
|
||||||
|
result = osgDB::readRefImageFile(_tuple.get<1>(), options);
|
||||||
|
#endif
|
||||||
if(result.success()) {
|
if(result.success()) {
|
||||||
osg::Image* image = result.getImage();
|
osg::Image* image = result.getImage();
|
||||||
cubeTexture->setImage(TextureCubeMap::NEGATIVE_X, image);
|
cubeTexture->setImage(TextureCubeMap::NEGATIVE_X, image);
|
||||||
}
|
}
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
result = osgDB::readImageFile(_tuple.get<2>(), options);
|
result = osgDB::readImageFile(_tuple.get<2>(), options);
|
||||||
|
#else
|
||||||
|
result = osgDB::readRefImageFile(_tuple.get<2>(), options);
|
||||||
|
#endif
|
||||||
if(result.success()) {
|
if(result.success()) {
|
||||||
osg::Image* image = result.getImage();
|
osg::Image* image = result.getImage();
|
||||||
cubeTexture->setImage(TextureCubeMap::POSITIVE_Y, image);
|
cubeTexture->setImage(TextureCubeMap::POSITIVE_Y, image);
|
||||||
}
|
}
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
result = osgDB::readImageFile(_tuple.get<3>(), options);
|
result = osgDB::readImageFile(_tuple.get<3>(), options);
|
||||||
|
#else
|
||||||
|
result = osgDB::readRefImageFile(_tuple.get<3>(), options);
|
||||||
|
#endif
|
||||||
if(result.success()) {
|
if(result.success()) {
|
||||||
osg::Image* image = result.getImage();
|
osg::Image* image = result.getImage();
|
||||||
cubeTexture->setImage(TextureCubeMap::NEGATIVE_Y, image);
|
cubeTexture->setImage(TextureCubeMap::NEGATIVE_Y, image);
|
||||||
}
|
}
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
result = osgDB::readImageFile(_tuple.get<4>(), options);
|
result = osgDB::readImageFile(_tuple.get<4>(), options);
|
||||||
|
#else
|
||||||
|
result = osgDB::readRefImageFile(_tuple.get<4>(), options);
|
||||||
|
#endif
|
||||||
if(result.success()) {
|
if(result.success()) {
|
||||||
osg::Image* image = result.getImage();
|
osg::Image* image = result.getImage();
|
||||||
cubeTexture->setImage(TextureCubeMap::POSITIVE_Z, image);
|
cubeTexture->setImage(TextureCubeMap::POSITIVE_Z, image);
|
||||||
}
|
}
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
result = osgDB::readImageFile(_tuple.get<5>(), options);
|
result = osgDB::readImageFile(_tuple.get<5>(), options);
|
||||||
|
#else
|
||||||
|
result = osgDB::readRefImageFile(_tuple.get<5>(), options);
|
||||||
|
#endif
|
||||||
if(result.success()) {
|
if(result.success()) {
|
||||||
osg::Image* image = result.getImage();
|
osg::Image* image = result.getImage();
|
||||||
cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, image);
|
cubeTexture->setImage(TextureCubeMap::NEGATIVE_Z, image);
|
||||||
}
|
}
|
||||||
|
wOpts->setLoadOriginHint(origLOH);
|
||||||
|
|
||||||
if (itr == _cubemaps.end())
|
if (itr == _cubemaps.end())
|
||||||
_cubemaps[_tuple] = cubeTexture;
|
_cubemaps[_tuple] = cubeTexture;
|
||||||
@ -634,7 +685,11 @@ Texture* CubeMapBuilder::build(Effect* effect, Pass* pass, const SGPropertyNode*
|
|||||||
return cubeTexture.release();
|
return cubeTexture.release();
|
||||||
|
|
||||||
osgDB::ReaderWriter::ReadResult result;
|
osgDB::ReaderWriter::ReadResult result;
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
result = osgDB::readImageFile(texname, options);
|
result = osgDB::readImageFile(texname, options);
|
||||||
|
#else
|
||||||
|
result = osgDB::readRefImageFile(texname, options);
|
||||||
|
#endif
|
||||||
if(result.success()) {
|
if(result.success()) {
|
||||||
osg::Image* image = result.getImage();
|
osg::Image* image = result.getImage();
|
||||||
image->flipVertical(); // Seems like the image coordinates are somewhat funny, flip to get better ones
|
image->flipVertical(); // Seems like the image coordinates are somewhat funny, flip to get better ones
|
||||||
|
@ -227,7 +227,11 @@ SGMaterial::read_properties(const SGReaderWriterOptions* options,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
osg::Image* image = osgDB::readImageFile(fullMaskPath, options);
|
osg::Image* image = osgDB::readImageFile(fullMaskPath, options);
|
||||||
|
#else
|
||||||
|
osg::Image* image = osgDB::readRefImageFile(fullMaskPath, options);
|
||||||
|
#endif
|
||||||
if (image && image->valid())
|
if (image && image->valid())
|
||||||
{
|
{
|
||||||
Texture2DRef object_mask = new osg::Texture2D;
|
Texture2DRef object_mask = new osg::Texture2D;
|
||||||
|
@ -31,14 +31,18 @@ class Effect;
|
|||||||
class SGReaderWriterOptions;
|
class SGReaderWriterOptions;
|
||||||
|
|
||||||
namespace effect {
|
namespace effect {
|
||||||
enum MipMapFunction {
|
enum MipMapFunction {
|
||||||
AUTOMATIC,
|
AUTOMATIC,
|
||||||
AVERAGE,
|
AVERAGE,
|
||||||
SUM,
|
SUM,
|
||||||
PRODUCT,
|
PRODUCT,
|
||||||
MIN,
|
MIN,
|
||||||
MAX
|
MAX
|
||||||
};
|
};
|
||||||
|
enum ImageInternalFormat {
|
||||||
|
Unspecified,
|
||||||
|
Normalized,
|
||||||
|
};
|
||||||
|
|
||||||
typedef boost::tuple<MipMapFunction, MipMapFunction, MipMapFunction, MipMapFunction> MipMapTuple;
|
typedef boost::tuple<MipMapFunction, MipMapFunction, MipMapFunction, MipMapFunction> MipMapTuple;
|
||||||
|
|
||||||
|
@ -111,6 +111,11 @@ public:
|
|||||||
if (transform->getNumChildren())
|
if (transform->getNumChildren())
|
||||||
_group->addChild(transform.get());
|
_group->addChild(transform.get());
|
||||||
}
|
}
|
||||||
|
virtual void apply(BVHPageNode& leaf)
|
||||||
|
{
|
||||||
|
leaf.traverse(*this);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void apply(BVHLineGeometry&)
|
virtual void apply(BVHLineGeometry&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,11 @@ public:
|
|||||||
if (pagedLOD.getMinRange(i) <= 0) {
|
if (pagedLOD.getMinRange(i) <= 0) {
|
||||||
osg::ref_ptr<const osgDB::Options> options;
|
osg::ref_ptr<const osgDB::Options> options;
|
||||||
options = getOptions(pagedLOD.getDatabaseOptions(), pagedLOD.getDatabasePath());
|
options = getOptions(pagedLOD.getDatabaseOptions(), pagedLOD.getDatabasePath());
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
node = osgDB::readNodeFile(pagedLOD.getFileName(i), options.get());
|
||||||
|
#else
|
||||||
node = osgDB::readRefNodeFile(pagedLOD.getFileName(i), options.get());
|
node = osgDB::readRefNodeFile(pagedLOD.getFileName(i), options.get());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (!node.valid())
|
if (!node.valid())
|
||||||
node = new osg::Group;
|
node = new osg::Group;
|
||||||
@ -256,7 +260,11 @@ public:
|
|||||||
osg::ref_ptr<const osgDB::Options> options;
|
osg::ref_ptr<const osgDB::Options> options;
|
||||||
options = getOptions(proxyNode.getDatabaseOptions(), proxyNode.getDatabasePath());
|
options = getOptions(proxyNode.getDatabaseOptions(), proxyNode.getDatabasePath());
|
||||||
osg::ref_ptr<osg::Node> node;
|
osg::ref_ptr<osg::Node> node;
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
node = osgDB::readNodeFile(proxyNode.getFileName(i), options.get());
|
||||||
|
#else
|
||||||
node = osgDB::readRefNodeFile(proxyNode.getFileName(i), options.get());
|
node = osgDB::readRefNodeFile(proxyNode.getFileName(i), options.get());
|
||||||
|
#endif
|
||||||
if (!node.valid())
|
if (!node.valid())
|
||||||
node = new osg::Group;
|
node = new osg::Group;
|
||||||
if (i < proxyNode.getNumChildren())
|
if (i < proxyNode.getNumChildren())
|
||||||
@ -353,7 +361,11 @@ SGSharedPtr<BVHNode>
|
|||||||
BVHPageNodeOSG::load(const std::string& name, const osg::ref_ptr<const osg::Referenced>& options)
|
BVHPageNodeOSG::load(const std::string& name, const osg::ref_ptr<const osg::Referenced>& options)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::Node> node;
|
osg::ref_ptr<osg::Node> node;
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
node = osgDB::readNodeFile(name, dynamic_cast<const osgDB::Options*>(options.get()));
|
||||||
|
#else
|
||||||
node = osgDB::readRefNodeFile(name, dynamic_cast<const osgDB::Options*>(options.get()));
|
node = osgDB::readRefNodeFile(name, dynamic_cast<const osgDB::Options*>(options.get()));
|
||||||
|
#endif
|
||||||
if (!node.valid())
|
if (!node.valid())
|
||||||
return SGSharedPtr<BVHNode>();
|
return SGSharedPtr<BVHNode>();
|
||||||
|
|
||||||
|
@ -60,6 +60,8 @@
|
|||||||
#include <simgear/props/props.hxx>
|
#include <simgear/props/props.hxx>
|
||||||
#include <simgear/props/props_io.hxx>
|
#include <simgear/props/props_io.hxx>
|
||||||
#include <simgear/props/condition.hxx>
|
#include <simgear/props/condition.hxx>
|
||||||
|
#include <simgear/io/sg_file.hxx>
|
||||||
|
#include <simgear/threads/SGGuard.hxx>
|
||||||
|
|
||||||
#include "BoundingVolumeBuildVisitor.hxx"
|
#include "BoundingVolumeBuildVisitor.hxx"
|
||||||
#include "model.hxx"
|
#include "model.hxx"
|
||||||
@ -180,9 +182,34 @@ public:
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
static bool isPowerOfTwo(int width, int height)
|
static int nearestPowerOfTwo(unsigned int _v)
|
||||||
{
|
{
|
||||||
return (((width & (width - 1)) == 0) && ((height & (height - 1))) == 0);
|
// uint v; // compute the next highest power of 2 of 32-bit v
|
||||||
|
unsigned int v = (unsigned int)_v;
|
||||||
|
bool neg = _v < 0;
|
||||||
|
if (neg)
|
||||||
|
v = (unsigned int)(-_v);
|
||||||
|
|
||||||
|
v &= (2 << 16) - 1; // make +ve
|
||||||
|
|
||||||
|
// bit twiddle to round up to nearest pot.
|
||||||
|
v--;
|
||||||
|
v |= v >> 1;
|
||||||
|
v |= v >> 2;
|
||||||
|
v |= v >> 4;
|
||||||
|
v |= v >> 8;
|
||||||
|
v |= v >> 16;
|
||||||
|
v++;
|
||||||
|
|
||||||
|
if (neg)
|
||||||
|
_v = -(int)v;
|
||||||
|
else
|
||||||
|
_v = (int)v;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
static bool isPowerOfTwo(int v)
|
||||||
|
{
|
||||||
|
return ((v & (v - 1)) == 0);
|
||||||
}
|
}
|
||||||
osg::Node* DefaultProcessPolicy::process(osg::Node* node, const std::string& filename,
|
osg::Node* DefaultProcessPolicy::process(osg::Node* node, const std::string& filename,
|
||||||
const Options* opt)
|
const Options* opt)
|
||||||
@ -205,6 +232,139 @@ osg::Image* getImageByName(const std::string& filename)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
// a cache which evicts the least recently used item when it is full
|
||||||
|
#include <map>
|
||||||
|
#include <list>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
template<class Key, class Value>
|
||||||
|
class lru_cache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SGMutex _mutex;
|
||||||
|
|
||||||
|
typedef Key key_type;
|
||||||
|
typedef Value value_type;
|
||||||
|
typedef std::list<key_type> list_type;
|
||||||
|
typedef std::map<
|
||||||
|
key_type,
|
||||||
|
std::pair<value_type, typename list_type::iterator>
|
||||||
|
> map_type;
|
||||||
|
|
||||||
|
lru_cache(size_t capacity)
|
||||||
|
: m_capacity(capacity)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~lru_cache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
return m_map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity() const
|
||||||
|
{
|
||||||
|
return m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return m_map.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const key_type &key)
|
||||||
|
{
|
||||||
|
SGGuard<SGMutex> scopeLock(_mutex);
|
||||||
|
return m_map.find(key) != m_map.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(const key_type &key, const value_type &value)
|
||||||
|
{
|
||||||
|
SGGuard<SGMutex> scopeLock(_mutex);
|
||||||
|
typename map_type::iterator i = m_map.find(key);
|
||||||
|
if (i == m_map.end()) {
|
||||||
|
// insert item into the cache, but first check if it is full
|
||||||
|
if (size() >= m_capacity) {
|
||||||
|
// cache is full, evict the least recently used item
|
||||||
|
evict();
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the new item
|
||||||
|
m_list.push_front(key);
|
||||||
|
m_map[key] = std::make_pair(value, m_list.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boost::optional<key_type> findValue(const std::string &requiredValue)
|
||||||
|
{
|
||||||
|
SGGuard<SGMutex> scopeLock(_mutex);
|
||||||
|
for (typename map_type::iterator it = m_map.begin(); it != m_map.end(); ++it)
|
||||||
|
if (it->second.first == requiredValue)
|
||||||
|
return it->first;
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
boost::optional<value_type> get(const key_type &key)
|
||||||
|
{
|
||||||
|
SGGuard<SGMutex> scopeLock(_mutex);
|
||||||
|
// lookup value in the cache
|
||||||
|
typename map_type::iterator i = m_map.find(key);
|
||||||
|
if (i == m_map.end()) {
|
||||||
|
// value not in cache
|
||||||
|
return boost::none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the value, but first update its place in the most
|
||||||
|
// recently used list
|
||||||
|
typename list_type::iterator j = i->second.second;
|
||||||
|
if (j != m_list.begin()) {
|
||||||
|
// move item to the front of the most recently used list
|
||||||
|
m_list.erase(j);
|
||||||
|
m_list.push_front(key);
|
||||||
|
|
||||||
|
// update iterator in map
|
||||||
|
j = m_list.begin();
|
||||||
|
const value_type &value = i->second.first;
|
||||||
|
m_map[key] = std::make_pair(value, j);
|
||||||
|
|
||||||
|
// return the value
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// the item is already at the front of the most recently
|
||||||
|
// used list so just return it
|
||||||
|
return i->second.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
SGGuard<SGMutex> scopeLock(_mutex);
|
||||||
|
m_map.clear();
|
||||||
|
m_list.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void evict()
|
||||||
|
{
|
||||||
|
SGGuard<SGMutex> scopeLock(_mutex);
|
||||||
|
// evict item from the end of most recently used list
|
||||||
|
typename list_type::iterator i = --m_list.end();
|
||||||
|
m_map.erase(*i);
|
||||||
|
m_list.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
map_type m_map;
|
||||||
|
list_type m_list;
|
||||||
|
size_t m_capacity;
|
||||||
|
};
|
||||||
|
lru_cache < std::string, std::string> filename_hash_cache(100000);
|
||||||
|
lru_cache < std::string, bool> filesCleaned(100000);
|
||||||
|
static bool refreshCache = false;
|
||||||
|
|
||||||
ReaderWriter::ReadResult
|
ReaderWriter::ReadResult
|
||||||
ModelRegistry::readImage(const string& fileName,
|
ModelRegistry::readImage(const string& fileName,
|
||||||
@ -248,6 +408,8 @@ ModelRegistry::readImage(const string& fileName,
|
|||||||
|
|
||||||
if (cache_active) {
|
if (cache_active) {
|
||||||
if (fileExtension != "dds" && fileExtension != "gz") {
|
if (fileExtension != "dds" && fileExtension != "gz") {
|
||||||
|
const SGReaderWriterOptions* sgoptC = dynamic_cast<const SGReaderWriterOptions*>(opt);
|
||||||
|
|
||||||
std::string root = getPathRoot(absFileName);
|
std::string root = getPathRoot(absFileName);
|
||||||
std::string prr = getPathRelative(root, absFileName);
|
std::string prr = getPathRelative(root, absFileName);
|
||||||
std::string cache_root = SGSceneFeatures::instance()->getTextureCompressionPath().c_str();
|
std::string cache_root = SGSceneFeatures::instance()->getTextureCompressionPath().c_str();
|
||||||
@ -255,43 +417,128 @@ ModelRegistry::readImage(const string& fileName,
|
|||||||
|
|
||||||
SGPath file(absFileName);
|
SGPath file(absFileName);
|
||||||
std::stringstream tstream;
|
std::stringstream tstream;
|
||||||
|
|
||||||
|
// calucate and use hash for storing cached image. This also
|
||||||
|
// helps with sharing of identical images between models.
|
||||||
|
if (fileExists(absFileName)) {
|
||||||
|
SGFile f(absFileName);
|
||||||
|
std::string hash;
|
||||||
|
boost::optional<std::string> cachehash = filename_hash_cache.get(absFileName);
|
||||||
|
if (cachehash) {
|
||||||
|
hash = *cachehash;
|
||||||
|
// SG_LOG(SG_IO, SG_ALERT, "Hash for " + absFileName + " in cache " + hash);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// SG_LOG(SG_IO, SG_ALERT, "Creating hash for " + absFileName);
|
||||||
|
hash = f.computeHash();
|
||||||
|
filename_hash_cache.insert(absFileName, hash);
|
||||||
|
boost::optional<std::string> cacheFilename = filename_hash_cache.findValue(hash);
|
||||||
|
|
||||||
|
// possibly a shared texture - but warn the user to allow investigation.
|
||||||
|
if (cacheFilename && *cacheFilename != absFileName) {
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, " Already have " + hash + " : " + *cacheFilename + " not "+absFileName);
|
||||||
|
}
|
||||||
|
// SG_LOG(SG_IO, SG_ALERT, " >>>> " + hash + " :: " + newName);
|
||||||
|
}
|
||||||
|
newName = cache_root + "/" + hash.substr(0,2) + "/" + hash + ".cache.dds";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
tstream << std::hex << file.modTime();
|
tstream << std::hex << file.modTime();
|
||||||
newName += "." + tstream.str();
|
newName += "." + tstream.str();
|
||||||
|
|
||||||
newName += ".cache.dds";
|
newName += ".cache.dds";
|
||||||
|
}
|
||||||
|
bool doRefresh = refreshCache;
|
||||||
|
//if (fileExists(newName) && sgoptC && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS) {
|
||||||
|
// doRefresh = true;
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
|
||||||
|
if (fileExists(newName) && doRefresh) {
|
||||||
|
if (!filesCleaned.contains(newName)) {
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, "Removing previously cached effects image " + newName);
|
||||||
|
SGPath(newName).remove();
|
||||||
|
filesCleaned.insert(newName, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (!fileExists(newName)) {
|
if (!fileExists(newName)) {
|
||||||
res = registry->readImageImplementation(absFileName, opt);
|
res = registry->readImageImplementation(absFileName, opt);
|
||||||
|
|
||||||
if (res.validImage()) {
|
if (res.validImage()) {
|
||||||
osg::ref_ptr<osg::Image> srcImage = res.getImage();
|
osg::ref_ptr<osg::Image> srcImage = res.getImage();
|
||||||
int width = srcImage->s();
|
int width = srcImage->s();
|
||||||
bool transparent = srcImage->isImageTranslucent();
|
bool transparent = srcImage->isImageTranslucent();
|
||||||
|
bool isNormalMap = false;
|
||||||
|
bool isEffect = false;
|
||||||
|
/*
|
||||||
|
* decide if we need to compress this.
|
||||||
|
*/
|
||||||
|
bool can_compress = (transparent && compress_transparent) || (!transparent && compress_solid);
|
||||||
|
|
||||||
int height = srcImage->t();
|
int height = srcImage->t();
|
||||||
|
|
||||||
if (height >= max_texture_size)
|
// use the new file origin to determine any special processing
|
||||||
{
|
// we handle the following
|
||||||
SG_LOG(SG_IO, SG_WARN, "Image texture too high " << width << "," << height << absFileName);
|
// - normal maps
|
||||||
osg::ref_ptr<osg::Image> resizedImage;
|
// - images loaded from effects
|
||||||
int factor = height / max_texture_size;
|
if (sgoptC && transparent && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS_NORMALIZED) {
|
||||||
if (ImageUtils::resizeImage(srcImage, width / factor, height / factor, resizedImage))
|
isNormalMap = true;
|
||||||
srcImage = resizedImage;
|
|
||||||
width = srcImage->s();
|
|
||||||
height = srcImage->t();
|
|
||||||
}
|
}
|
||||||
if (width >= max_texture_size)
|
else if (sgoptC && transparent && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS) {
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, "From effects transparent " + absFileName);
|
||||||
|
isEffect = true;
|
||||||
|
// can_compress = false;
|
||||||
|
}
|
||||||
|
else if (sgoptC && transparent && sgoptC->getLoadOriginHint() == SGReaderWriterOptions::LoadOriginHint::ORIGIN_EFFECTS) {
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, "From effects " + absFileName);
|
||||||
|
isEffect = true;
|
||||||
|
}
|
||||||
|
if (can_compress)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_IO, SG_WARN, "Image texture too wide " << width << "," << height << absFileName);
|
std::string pot_message;
|
||||||
osg::ref_ptr<osg::Image> resizedImage;
|
bool resize = false;
|
||||||
|
if (!isPowerOfTwo(width)) {
|
||||||
|
width = nearestPowerOfTwo(width);
|
||||||
|
resize = true;
|
||||||
|
pot_message += std::string(" not POT: resized width to ") + std::to_string(width);
|
||||||
|
}
|
||||||
|
if (!isPowerOfTwo(height)) {
|
||||||
|
height = nearestPowerOfTwo(height);
|
||||||
|
resize = true;
|
||||||
|
pot_message += std::string(" not POT: resized height to ") + std::to_string(height);
|
||||||
|
}
|
||||||
|
if (pot_message.size())
|
||||||
|
SG_LOG(SG_IO, SG_WARN, pot_message << " " << absFileName);
|
||||||
|
|
||||||
|
// unlikely that after resizing in height the width will still be outside of the max texture size.
|
||||||
|
if (height > max_texture_size)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "Image texture too high (max " << max_texture_size << ") " << width << "," << height << " " << absFileName);
|
||||||
|
int factor = height / max_texture_size;
|
||||||
|
height /= factor;
|
||||||
|
width /= factor;
|
||||||
|
resize = true;
|
||||||
|
}
|
||||||
|
if (width > max_texture_size)
|
||||||
|
{
|
||||||
|
SG_LOG(SG_IO, SG_WARN, "Image texture too wide (max " << max_texture_size << ") " << width << "," << height << " " << absFileName);
|
||||||
int factor = width / max_texture_size;
|
int factor = width / max_texture_size;
|
||||||
if (ImageUtils::resizeImage(srcImage, width / factor, height / factor, resizedImage))
|
height /= factor;
|
||||||
|
width /= factor;
|
||||||
|
resize = true;
|
||||||
|
}
|
||||||
|
if (resize) {
|
||||||
|
osg::ref_ptr<osg::Image> resizedImage;
|
||||||
|
|
||||||
|
if (ImageUtils::resizeImage(srcImage, width, height, resizedImage))
|
||||||
srcImage = resizedImage;
|
srcImage = resizedImage;
|
||||||
width = srcImage->s();
|
|
||||||
height = srcImage->t();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// only cache power of two textures that are of a reasonable size
|
// only cache power of two textures that are of a reasonable size
|
||||||
if (width >= 64 && height >= 64 && isPowerOfTwo(width, height)) {
|
if (width >= 4 && height >= 4) {
|
||||||
|
|
||||||
simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE);
|
simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE);
|
||||||
|
|
||||||
SGPath filePath(newName);
|
SGPath filePath(newName);
|
||||||
@ -310,27 +557,53 @@ ModelRegistry::readImage(const string& fileName,
|
|||||||
|
|
||||||
nopt->setOptionString(optionstring + "ddsNoAutoFlipWrite");
|
nopt->setOptionString(optionstring + "ddsNoAutoFlipWrite");
|
||||||
|
|
||||||
/*
|
//GLenum srcImageType = srcImage->getDataType();
|
||||||
* decide if we need to compress this.
|
// printf("--- %-80s --> f=%8x t=%8x\n", newName.c_str(), srcImage->getPixelFormat(), srcImageType);
|
||||||
*/
|
|
||||||
bool compress = (transparent && compress_transparent) || (!transparent && compress_solid);
|
try
|
||||||
|
{
|
||||||
|
if (can_compress) {
|
||||||
|
osg::Texture::InternalFormatMode targetFormat = osg::Texture::USE_S3TC_DXT1_COMPRESSION;
|
||||||
|
if (isNormalMap) {
|
||||||
|
if (transparent) {
|
||||||
|
targetFormat = osg::Texture::USE_S3TC_DXT5_COMPRESSION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
targetFormat = osg::Texture::USE_S3TC_DXT5_COMPRESSION;
|
||||||
|
}
|
||||||
|
else if (isEffect)
|
||||||
|
{
|
||||||
|
if (transparent) {
|
||||||
|
targetFormat = osg::Texture::USE_S3TC_DXT5_COMPRESSION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
targetFormat = osg::Texture::USE_S3TC_DXT1_COMPRESSION;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if (transparent) {
|
||||||
|
targetFormat = osg::Texture::USE_S3TC_DXT3_COMPRESSION;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
targetFormat = osg::Texture::USE_S3TC_DXT1_COMPRESSION;
|
||||||
|
}
|
||||||
|
|
||||||
if (compress) {
|
|
||||||
if (processor)
|
if (processor)
|
||||||
{
|
{
|
||||||
if (transparent)
|
SG_LOG(SG_IO, SG_ALERT, "Creating " << targetFormat << " for " + absFileName);
|
||||||
processor->compress(*srcImage, osg::Texture::USE_S3TC_DXT5_COMPRESSION, true, true, osgDB::ImageProcessor::USE_CPU, osgDB::ImageProcessor::PRODUCTION);
|
// normal maps:
|
||||||
else
|
// nvdxt.exe - quality_highest - rescaleKaiser - Kaiser - dxt5nm - norm
|
||||||
processor->compress(*srcImage, osg::Texture::USE_S3TC_DXT1_COMPRESSION, true, true, osgDB::ImageProcessor::USE_CPU, osgDB::ImageProcessor::PRODUCTION);
|
processor->compress(*srcImage, targetFormat, true, true, osgDB::ImageProcessor::USE_CPU, osgDB::ImageProcessor::PRODUCTION);
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, "-- finished creating DDS: " + newName);
|
||||||
//processor->generateMipMap(*srcImage, true, osgDB::ImageProcessor::USE_CPU);
|
//processor->generateMipMap(*srcImage, true, osgDB::ImageProcessor::USE_CPU);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE);
|
simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE);
|
||||||
SG_LOG(SG_IO, SG_WARN, "Texture compression plugin (osg_nvtt) not available; storing uncompressed image: " << newName);
|
SG_LOG(SG_IO, SG_WARN, "Texture compression plugin (osg_nvtt) not available; storing uncompressed image: " << absFileName);
|
||||||
srcImage = simgear::effect::computeMipmap(srcImage, mipmapFunctions);
|
srcImage = simgear::effect::computeMipmap(srcImage, mipmapFunctions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, "Creating uncompressed DDS for " + absFileName);
|
||||||
if (processor) {
|
if (processor) {
|
||||||
processor->generateMipMap(*srcImage, true, osgDB::ImageProcessor::USE_CPU);
|
processor->generateMipMap(*srcImage, true, osgDB::ImageProcessor::USE_CPU);
|
||||||
}
|
}
|
||||||
@ -339,15 +612,36 @@ ModelRegistry::readImage(const string& fileName,
|
|||||||
srcImage = simgear::effect::computeMipmap(srcImage, mipmapFunctions);
|
srcImage = simgear::effect::computeMipmap(srcImage, mipmapFunctions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//}
|
||||||
|
//else
|
||||||
|
// printf("--- no compress or mipmap of format %s\n", newName.c_str());
|
||||||
registry->writeImage(*srcImage, newName, nopt);
|
registry->writeImage(*srcImage, newName, nopt);
|
||||||
|
{
|
||||||
|
std::string mdlDirectory = cache_root + "/cache-index.txt";
|
||||||
|
FILE *f = ::fopen(mdlDirectory.c_str(), "a");
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
::fprintf(f, "%s, %s\n", absFileName.c_str(), newName.c_str());
|
||||||
|
::fclose(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
absFileName = newName;
|
absFileName = newName;
|
||||||
}
|
}
|
||||||
|
catch (...) {
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, "Exception processing " << absFileName << " may be corrupted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
SG_LOG(SG_IO, SG_WARN, absFileName + " too small " << width << "," << height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
absFileName = newName;
|
absFileName = newName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res = registry->readImageImplementation(absFileName, opt);
|
res = registry->readImageImplementation(absFileName, opt);
|
||||||
|
|
||||||
if (!res.success()) {
|
if (!res.success()) {
|
||||||
@ -368,6 +662,18 @@ ModelRegistry::readImage(const string& fileName,
|
|||||||
if (srcImage1->getName().empty()) {
|
if (srcImage1->getName().empty()) {
|
||||||
srcImage1->setName(absFileName);
|
srcImage1->setName(absFileName);
|
||||||
}
|
}
|
||||||
|
if(cache_active && getFileExtension(absFileName) != "dds")
|
||||||
|
{
|
||||||
|
if (processor) {
|
||||||
|
processor->generateMipMap(*srcImage1, true, osgDB::ImageProcessor::USE_CPU);
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, "Created nvtt mipmaps DDS for " + absFileName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
simgear::effect::MipMapTuple mipmapFunctions(simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE, simgear::effect::AVERAGE);
|
||||||
|
srcImage1 = simgear::effect::computeMipmap(srcImage1, mipmapFunctions);
|
||||||
|
SG_LOG(SG_IO, SG_ALERT, "Created sg mipmaps DDS for " + absFileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (res.loadedFromCache())
|
if (res.loadedFromCache())
|
||||||
SG_LOG(SG_IO, SG_BULK, "Returning cached image \""
|
SG_LOG(SG_IO, SG_BULK, "Returning cached image \""
|
||||||
@ -449,19 +755,21 @@ ModelRegistry::readImage(const string& fileName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
osg::Node* DefaultCachePolicy::find(const string& fileName,
|
osg::ref_ptr<osg::Node> DefaultCachePolicy::find(const string& fileName, const Options* opt)
|
||||||
const Options* opt)
|
|
||||||
{
|
{
|
||||||
Registry* registry = Registry::instance();
|
Registry* registry = Registry::instance();
|
||||||
osg::Node* cached
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
= dynamic_cast<Node*>(registry->getFromObjectCache(fileName));
|
osg::ref_ptr<osg::Object> cachedObject = registry->getFromObjectCache(fileName);
|
||||||
if (cached)
|
#else
|
||||||
SG_LOG(SG_IO, SG_BULK, "Got cached model \""
|
osg::ref_ptr<osg::Object> cachedObject = registry->getRefFromObjectCache(fileName);
|
||||||
<< fileName << "\"");
|
#endif
|
||||||
|
|
||||||
|
ref_ptr<osg::Node> cachedNode = dynamic_cast<osg::Node*>(cachedObject.get());
|
||||||
|
if (cachedNode.valid())
|
||||||
|
SG_LOG(SG_IO, SG_BULK, "Got cached model \"" << fileName << "\"");
|
||||||
else
|
else
|
||||||
SG_LOG(SG_IO, SG_BULK, "Reading model \""
|
SG_LOG(SG_IO, SG_BULK, "Reading model \"" << fileName << "\"");
|
||||||
<< fileName << "\"");
|
return cachedNode;
|
||||||
return cached;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DefaultCachePolicy::addToCache(const string& fileName,
|
void DefaultCachePolicy::addToCache(const string& fileName,
|
||||||
|
@ -132,7 +132,7 @@ struct DefaultProcessPolicy {
|
|||||||
|
|
||||||
struct DefaultCachePolicy {
|
struct DefaultCachePolicy {
|
||||||
DefaultCachePolicy(const std::string& extension) {}
|
DefaultCachePolicy(const std::string& extension) {}
|
||||||
osg::Node* find(const std::string& fileName,
|
osg::ref_ptr<osg::Node> find(const std::string& fileName,
|
||||||
const osgDB::Options* opt);
|
const osgDB::Options* opt);
|
||||||
void addToCache(const std::string& filename, osg::Node* node);
|
void addToCache(const std::string& filename, osg::Node* node);
|
||||||
};
|
};
|
||||||
|
@ -56,7 +56,7 @@ using namespace std;
|
|||||||
using namespace simgear;
|
using namespace simgear;
|
||||||
using namespace osg;
|
using namespace osg;
|
||||||
|
|
||||||
static osg::Node *
|
static std::tuple<int, osg::Node *>
|
||||||
sgLoad3DModel_internal(const SGPath& path,
|
sgLoad3DModel_internal(const SGPath& path,
|
||||||
const osgDB::Options* options,
|
const osgDB::Options* options,
|
||||||
SGPropertyNode *overlay = 0);
|
SGPropertyNode *overlay = 0);
|
||||||
@ -89,7 +89,9 @@ SGReaderWriterXML::readNode(const std::string& name,
|
|||||||
return ReadResult::FILE_NOT_FOUND;
|
return ReadResult::FILE_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
result=sgLoad3DModel_internal(p, options);
|
static std::tuple<int, osg::Node *> retval;
|
||||||
|
int num_anims;
|
||||||
|
std::tie(num_anims, result) = sgLoad3DModel_internal(p, options);
|
||||||
} catch (const sg_exception &t) {
|
} catch (const sg_exception &t) {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load model: " << t.getFormattedMessage()
|
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load model: " << t.getFormattedMessage()
|
||||||
<< "\n\tfrom:" << fileName);
|
<< "\n\tfrom:" << fileName);
|
||||||
@ -254,14 +256,14 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static osg::Node *
|
static std::tuple<int, osg::Node *>
|
||||||
sgLoad3DModel_internal(const SGPath& path,
|
sgLoad3DModel_internal(const SGPath& path,
|
||||||
const osgDB::Options* dbOptions,
|
const osgDB::Options* dbOptions,
|
||||||
SGPropertyNode *overlay)
|
SGPropertyNode *overlay)
|
||||||
{
|
{
|
||||||
if (!path.exists()) {
|
if (!path.exists()) {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load file: \"" << path << "\"");
|
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load file: \"" << path << "\"");
|
||||||
return NULL;
|
return std::make_tuple(0, (osg::Node *) NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::ref_ptr<SGReaderWriterOptions> options;
|
osg::ref_ptr<SGReaderWriterOptions> options;
|
||||||
@ -270,6 +272,7 @@ sgLoad3DModel_internal(const SGPath& path,
|
|||||||
SGPath modelpath(path);
|
SGPath modelpath(path);
|
||||||
SGPath texturepath(path);
|
SGPath texturepath(path);
|
||||||
SGPath modelDir(modelpath.dir());
|
SGPath modelDir(modelpath.dir());
|
||||||
|
int animationcount = 0;
|
||||||
|
|
||||||
SGSharedPtr<SGPropertyNode> prop_root = options->getPropertyNode();
|
SGSharedPtr<SGPropertyNode> prop_root = options->getPropertyNode();
|
||||||
if (!prop_root.valid())
|
if (!prop_root.valid())
|
||||||
@ -296,7 +299,7 @@ sgLoad3DModel_internal(const SGPath& path,
|
|||||||
copyProperties(overlay, props);
|
copyProperties(overlay, props);
|
||||||
|
|
||||||
if (previewMode && props->hasChild("nopreview")) {
|
if (previewMode && props->hasChild("nopreview")) {
|
||||||
return NULL;
|
return std::make_tuple(0, (osg::Node *) NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props->hasValue("/path")) {
|
if (props->hasValue("/path")) {
|
||||||
@ -335,7 +338,11 @@ sgLoad3DModel_internal(const SGPath& path,
|
|||||||
|
|
||||||
options->setDatabasePath(texturepath.local8BitStr());
|
options->setDatabasePath(texturepath.local8BitStr());
|
||||||
osgDB::ReaderWriter::ReadResult modelResult;
|
osgDB::ReaderWriter::ReadResult modelResult;
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
modelResult = osgDB::readNodeFile(modelpath.local8BitStr(), options.get());
|
modelResult = osgDB::readNodeFile(modelpath.local8BitStr(), options.get());
|
||||||
|
#else
|
||||||
|
modelResult = osgDB::readRefNodeFile(modelpath.local8BitStr(), options.get());
|
||||||
|
#endif
|
||||||
if (!modelResult.validNode())
|
if (!modelResult.validNode())
|
||||||
throw sg_io_exception("Failed to load 3D model:" + modelResult.message(),
|
throw sg_io_exception("Failed to load 3D model:" + modelResult.message(),
|
||||||
modelpath);
|
modelpath);
|
||||||
@ -419,8 +426,10 @@ sgLoad3DModel_internal(const SGPath& path,
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
submodel = sgLoad3DModel_internal(submodelPath, options.get(),
|
int num_anims;
|
||||||
|
std::tie(num_anims, submodel) = sgLoad3DModel_internal(submodelPath, options.get(),
|
||||||
sub_props->getNode("overlay"));
|
sub_props->getNode("overlay"));
|
||||||
|
animationcount += num_anims;
|
||||||
} catch (const sg_exception &t) {
|
} catch (const sg_exception &t) {
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load submodel: " << t.getFormattedMessage()
|
SG_LOG(SG_INPUT, SG_ALERT, "Failed to load submodel: " << t.getFormattedMessage()
|
||||||
<< "\n\tfrom:" << t.getOrigin());
|
<< "\n\tfrom:" << t.getOrigin());
|
||||||
@ -481,7 +490,7 @@ sgLoad3DModel_internal(const SGPath& path,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dbOptions->getPluginStringData("SimGear::PARTICLESYSTEM") != "OFF") {
|
if (GlobalParticleCallback::getEnabled()){//dbOptions->getPluginStringData("SimGear::PARTICLESYSTEM") != "OFF") {
|
||||||
std::vector<SGPropertyNode_ptr> particle_nodes;
|
std::vector<SGPropertyNode_ptr> particle_nodes;
|
||||||
particle_nodes = props->getChildren("particlesystem");
|
particle_nodes = props->getChildren("particlesystem");
|
||||||
for (unsigned i = 0; i < particle_nodes.size(); ++i) {
|
for (unsigned i = 0; i < particle_nodes.size(); ++i) {
|
||||||
@ -544,12 +553,14 @@ sgLoad3DModel_internal(const SGPath& path,
|
|||||||
SGAnimation::animate(modelData);
|
SGAnimation::animate(modelData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
animationcount += animation_nodes.size();
|
||||||
|
|
||||||
if (!needTransform && group->getNumChildren() < 2) {
|
if (!needTransform && group->getNumChildren() < 2) {
|
||||||
model = group->getChild(0);
|
model = group->getChild(0);
|
||||||
group->removeChild(model.get());
|
group->removeChild(model.get());
|
||||||
if (data.valid())
|
if (data.valid())
|
||||||
data->modelLoaded(modelpath.utf8Str(), props, model.get());
|
data->modelLoaded(modelpath.utf8Str(), props, model.get());
|
||||||
return model.release();
|
return std::make_tuple(animationcount, model.release());
|
||||||
}
|
}
|
||||||
if (data.valid())
|
if (data.valid())
|
||||||
data->modelLoaded(modelpath.utf8Str(), props, group.get());
|
data->modelLoaded(modelpath.utf8Str(), props, group.get());
|
||||||
@ -559,6 +570,7 @@ sgLoad3DModel_internal(const SGPath& path,
|
|||||||
osgDB::writeNodeFile(*group, outputfile);
|
osgDB::writeNodeFile(*group, outputfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
return group.release();
|
SG_LOG(SG_GENERAL, SG_DEBUG, "Model " << path << " animation count: " << animationcount);
|
||||||
}
|
|
||||||
|
|
||||||
|
return std::make_tuple(animationcount, group.release());
|
||||||
|
}
|
||||||
|
@ -43,9 +43,18 @@ SGLoadTexture2D(bool staticTexture, const std::string& path,
|
|||||||
{
|
{
|
||||||
osg::Image* image;
|
osg::Image* image;
|
||||||
if (options)
|
if (options)
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
image = osgDB::readImageFile(path, options);
|
image = osgDB::readImageFile(path, options);
|
||||||
|
#else
|
||||||
|
image = osgDB::readRefImageFile(path, options);
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
image = osgDB::readImageFile(path);
|
image = osgDB::readImageFile(path);
|
||||||
|
#else
|
||||||
|
image = osgDB::readRefImageFile(path);
|
||||||
|
#endif
|
||||||
|
|
||||||
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
|
osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D;
|
||||||
texture->setImage(image);
|
texture->setImage(image);
|
||||||
if (staticTexture)
|
if (staticTexture)
|
||||||
@ -141,7 +150,11 @@ Texture2D* TextureUpdateVisitor::textureReplace(int unit, const StateAttribute*
|
|||||||
// If it is empty or they are identical then there is nothing to do
|
// If it is empty or they are identical then there is nothing to do
|
||||||
if (fullLiveryFile.empty() || fullLiveryFile == *fullFilePath)
|
if (fullLiveryFile.empty() || fullLiveryFile == *fullFilePath)
|
||||||
return 0;
|
return 0;
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
Image* newImage = readImageFile(fullLiveryFile);
|
Image* newImage = readImageFile(fullLiveryFile);
|
||||||
|
#else
|
||||||
|
Image* newImage = readRefImageFile(fullLiveryFile);
|
||||||
|
#endif
|
||||||
if (!newImage)
|
if (!newImage)
|
||||||
return 0;
|
return 0;
|
||||||
CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
|
CopyOp copyOp(CopyOp::DEEP_COPY_ALL & ~CopyOp::DEEP_COPY_IMAGES);
|
||||||
|
@ -101,7 +101,11 @@ osg::Node* loadFile(const string& path, SGReaderWriterOptions* options)
|
|||||||
options->setInstantiateEffects(true);
|
options->setInstantiateEffects(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
ref_ptr<Node> model = readNodeFile(path, options);
|
||||||
|
#else
|
||||||
ref_ptr<Node> model = readRefNodeFile(path, options);
|
ref_ptr<Node> model = readRefNodeFile(path, options);
|
||||||
|
#endif
|
||||||
if (!model)
|
if (!model)
|
||||||
return 0;
|
return 0;
|
||||||
else
|
else
|
||||||
|
@ -485,9 +485,11 @@ SGCloudLayer::rebuild()
|
|||||||
// repaint the cloud layer colors
|
// repaint the cloud layer colors
|
||||||
bool SGCloudLayer::repaint( const SGVec3f& fog_color ) {
|
bool SGCloudLayer::repaint( const SGVec3f& fog_color ) {
|
||||||
osg::Vec4f combineColor(toOsg(fog_color), cloud_alpha);
|
osg::Vec4f combineColor(toOsg(fog_color), cloud_alpha);
|
||||||
osg::TexEnvCombine* combiner
|
osg::StateAttribute* textureAtt = layer_root->getStateSet()->getTextureAttribute(1, osg::StateAttribute::TEXENV);
|
||||||
= dynamic_cast<osg::TexEnvCombine*>(layer_root->getStateSet()
|
osg::TexEnvCombine* combiner = dynamic_cast<osg::TexEnvCombine*>(textureAtt);
|
||||||
->getTextureAttribute(1, osg::StateAttribute::TEXENV));
|
|
||||||
|
if (combiner == nullptr)
|
||||||
|
return false;
|
||||||
combiner->setConstantColor(combineColor);
|
combiner->setConstantColor(combineColor);
|
||||||
|
|
||||||
// Set the fog color for the 3D clouds too.
|
// Set the fog color for the 3D clouds too.
|
||||||
|
@ -208,7 +208,11 @@ ReaderWriterSPT::readObject(const std::string& fileName, const osgDB::Options* o
|
|||||||
imageFileName = osgDB::concatPaths(imageFileName, "Globe");
|
imageFileName = osgDB::concatPaths(imageFileName, "Globe");
|
||||||
imageFileName = osgDB::concatPaths(imageFileName, "world.topo.bathy.200407.3x4096x2048.png");
|
imageFileName = osgDB::concatPaths(imageFileName, "world.topo.bathy.200407.3x4096x2048.png");
|
||||||
}
|
}
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
if (osg::Image* image = osgDB::readImageFile(imageFileName, options)) {
|
if (osg::Image* image = osgDB::readImageFile(imageFileName, options)) {
|
||||||
|
#else
|
||||||
|
if (osg::Image* image = osgDB::readRefImageFile(imageFileName, options)) {
|
||||||
|
#endif
|
||||||
osg::Texture2D* texture = new osg::Texture2D;
|
osg::Texture2D* texture = new osg::Texture2D;
|
||||||
texture->setImage(image);
|
texture->setImage(image);
|
||||||
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
|
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::REPEAT);
|
||||||
@ -256,7 +260,11 @@ ReaderWriterSPT::createTree(const BucketBox& bucketBox, const LocalOptions& opti
|
|||||||
if (bucketBox.getIsBucketSize()) {
|
if (bucketBox.getIsBucketSize()) {
|
||||||
std::string fileName;
|
std::string fileName;
|
||||||
fileName = bucketBox.getBucket().gen_index_str() + std::string(".stg");
|
fileName = bucketBox.getBucket().gen_index_str() + std::string(".stg");
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
return osgDB::readNodeFile(fileName, options._options);
|
||||||
|
#else
|
||||||
return osgDB::readRefNodeFile(fileName, options._options);
|
return osgDB::readRefNodeFile(fileName, options._options);
|
||||||
|
#endif
|
||||||
} else if (!topLevel && options.isPageLevel(bucketBox.getStartLevel())) {
|
} else if (!topLevel && options.isPageLevel(bucketBox.getStartLevel())) {
|
||||||
return createPagedLOD(bucketBox, options);
|
return createPagedLOD(bucketBox, options);
|
||||||
} else {
|
} else {
|
||||||
@ -314,7 +322,11 @@ ReaderWriterSPT::createPagedLOD(const BucketBox& bucketBox, const LocalOptions&
|
|||||||
std::string fileName = osgDB::findDataFile(lodPath + extensions[i], options._options);
|
std::string fileName = osgDB::findDataFile(lodPath + extensions[i], options._options);
|
||||||
if (fileName.empty())
|
if (fileName.empty())
|
||||||
continue;
|
continue;
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
osg::ref_ptr<osg::Node> node = osgDB::readNodeFile(fileName, options._options);
|
||||||
|
#else
|
||||||
osg::ref_ptr<osg::Node> node = osgDB::readRefNodeFile(fileName, options._options);
|
osg::ref_ptr<osg::Node> node = osgDB::readRefNodeFile(fileName, options._options);
|
||||||
|
#endif
|
||||||
if (!node.valid())
|
if (!node.valid())
|
||||||
continue;
|
continue;
|
||||||
pagedLOD->addChild(node.get(), range, std::numeric_limits<float>::max());
|
pagedLOD->addChild(node.get(), range, std::numeric_limits<float>::max());
|
||||||
@ -412,7 +424,11 @@ ReaderWriterSPT::getLowLODStateSet(const LocalOptions& options) const
|
|||||||
localOptions = static_cast<osgDB::Options*>(options._options->clone(osg::CopyOp()));
|
localOptions = static_cast<osgDB::Options*>(options._options->clone(osg::CopyOp()));
|
||||||
localOptions->setObjectCacheHint(osgDB::Options::CACHE_ALL);
|
localOptions->setObjectCacheHint(osgDB::Options::CACHE_ALL);
|
||||||
|
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
osg::ref_ptr<osg::Object> object = osgDB::readObjectFile("state.spt", localOptions.get());
|
||||||
|
#else
|
||||||
osg::ref_ptr<osg::Object> object = osgDB::readRefObjectFile("state.spt", localOptions.get());
|
osg::ref_ptr<osg::Object> object = osgDB::readRefObjectFile("state.spt", localOptions.get());
|
||||||
|
#endif
|
||||||
if (!dynamic_cast<osg::StateSet*>(object.get()))
|
if (!dynamic_cast<osg::StateSet*>(object.get()))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -156,7 +156,11 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
proxy->setCenterMode(osg::ProxyNode::UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED);
|
proxy->setCenterMode(osg::ProxyNode::UNION_OF_BOUNDING_SPHERE_AND_USER_DEFINED);
|
||||||
node = proxy;
|
node = proxy;
|
||||||
} else {
|
} else {
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
node = osgDB::readNodeFile(o._name, o._options.get());
|
||||||
|
#else
|
||||||
node = osgDB::readRefNodeFile(o._name, o._options.get());
|
node = osgDB::readRefNodeFile(o._name, o._options.get());
|
||||||
|
#endif
|
||||||
if (!node.valid()) {
|
if (!node.valid()) {
|
||||||
SG_LOG(SG_TERRAIN, SG_ALERT, o._errorLocation << ": Failed to load "
|
SG_LOG(SG_TERRAIN, SG_ALERT, o._errorLocation << ": Failed to load "
|
||||||
<< o._token << " '" << o._name << "'");
|
<< o._token << " '" << o._name << "'");
|
||||||
@ -553,7 +557,11 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
if (_foundBase) {
|
if (_foundBase) {
|
||||||
for (auto stgObject : _objectList) {
|
for (auto stgObject : _objectList) {
|
||||||
osg::ref_ptr<osg::Node> node;
|
osg::ref_ptr<osg::Node> node;
|
||||||
|
#if OSG_VERSION_LESS_THAN(3,4,0)
|
||||||
|
node = osgDB::readNodeFile(stgObject._name, stgObject._options.get());
|
||||||
|
#else
|
||||||
node = osgDB::readRefNodeFile(stgObject._name, stgObject._options.get());
|
node = osgDB::readRefNodeFile(stgObject._name, stgObject._options.get());
|
||||||
|
#endif
|
||||||
if (!node.valid()) {
|
if (!node.valid()) {
|
||||||
SG_LOG(SG_TERRAIN, SG_ALERT, stgObject._errorLocation << ": Failed to load "
|
SG_LOG(SG_TERRAIN, SG_ALERT, stgObject._errorLocation << ": Failed to load "
|
||||||
<< stgObject._token << " '" << stgObject._name << "'");
|
<< stgObject._token << " '" << stgObject._name << "'");
|
||||||
@ -586,7 +594,7 @@ struct ReaderWriterSTG::_ModelBin {
|
|||||||
i->_elev += elevation(*terrainGroup, SGGeod::fromDeg(i->_lon, i->_lat));
|
i->_elev += elevation(*terrainGroup, SGGeod::fromDeg(i->_lon, i->_lat));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_objectStaticList.empty() && _signList.empty()) {
|
if (_objectStaticList.empty() && _signList.empty() && (_buildingListList.size() == 0)) {
|
||||||
// The simple case, just return the terrain group
|
// The simple case, just return the terrain group
|
||||||
return terrainGroup.release();
|
return terrainGroup.release();
|
||||||
} else {
|
} else {
|
||||||
|
@ -689,12 +689,15 @@ public:
|
|||||||
triangleBuildingList.clear();
|
triangleBuildingList.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, "Random Buildings: " << ((bin) ? bin->getNumBuildings() : 0));
|
const int numBuildings = (bin) ? bin->getNumBuildings() : 0;
|
||||||
|
if (numBuildings > 0) {
|
||||||
|
SG_LOG(SG_TERRAIN, SG_DEBUG, "computed Random Buildings: " << numBuildings);
|
||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to mask: " << mask_dropped);
|
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to mask: " << mask_dropped);
|
||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to random object: " << random_dropped);
|
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to random object: " << random_dropped);
|
||||||
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to other buildings: " << building_dropped);
|
SG_LOG(SG_TERRAIN, SG_DEBUG, " Dropped due to other buildings: " << building_dropped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void computeRandomForest(std::vector<SGTriangleInfo>& matTris, float vegetation_density, SGTreeBinList& randomForest)
|
void computeRandomForest(std::vector<SGTriangleInfo>& matTris, float vegetation_density, SGTreeBinList& randomForest)
|
||||||
{
|
{
|
||||||
|
@ -38,12 +38,22 @@ namespace simgear
|
|||||||
|
|
||||||
class SGReaderWriterOptions : public osgDB::Options {
|
class SGReaderWriterOptions : public osgDB::Options {
|
||||||
public:
|
public:
|
||||||
|
enum LoadOriginHint
|
||||||
|
{
|
||||||
|
ORIGIN_MODEL,
|
||||||
|
ORIGIN_EFFECTS,
|
||||||
|
ORIGIN_EFFECTS_NORMALIZED,
|
||||||
|
};
|
||||||
|
|
||||||
|
//SGReaderWriterOptions* cloneOptions(const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) const { return static_cast<SGReaderWriterOptions*>(clone(copyop)); }
|
||||||
|
|
||||||
SGReaderWriterOptions() :
|
SGReaderWriterOptions() :
|
||||||
_materialLib(0),
|
_materialLib(0),
|
||||||
_load_panel(0),
|
_load_panel(0),
|
||||||
_model_data(0),
|
_model_data(0),
|
||||||
_instantiateEffects(false),
|
_instantiateEffects(false),
|
||||||
_instantiateMaterialEffects(false)
|
_instantiateMaterialEffects(false),
|
||||||
|
_LoadOriginHint(ORIGIN_MODEL)
|
||||||
{ }
|
{ }
|
||||||
SGReaderWriterOptions(const std::string& str) :
|
SGReaderWriterOptions(const std::string& str) :
|
||||||
osgDB::Options(str),
|
osgDB::Options(str),
|
||||||
@ -51,7 +61,8 @@ public:
|
|||||||
_load_panel(0),
|
_load_panel(0),
|
||||||
_model_data(0),
|
_model_data(0),
|
||||||
_instantiateEffects(false),
|
_instantiateEffects(false),
|
||||||
_instantiateMaterialEffects(false)
|
_instantiateMaterialEffects(false),
|
||||||
|
_LoadOriginHint(ORIGIN_MODEL)
|
||||||
{ }
|
{ }
|
||||||
SGReaderWriterOptions(const osgDB::Options& options,
|
SGReaderWriterOptions(const osgDB::Options& options,
|
||||||
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) :
|
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) :
|
||||||
@ -60,7 +71,8 @@ public:
|
|||||||
_load_panel(0),
|
_load_panel(0),
|
||||||
_model_data(0),
|
_model_data(0),
|
||||||
_instantiateEffects(false),
|
_instantiateEffects(false),
|
||||||
_instantiateMaterialEffects(false)
|
_instantiateMaterialEffects(false),
|
||||||
|
_LoadOriginHint(ORIGIN_MODEL)
|
||||||
{ }
|
{ }
|
||||||
SGReaderWriterOptions(const SGReaderWriterOptions& options,
|
SGReaderWriterOptions(const SGReaderWriterOptions& options,
|
||||||
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) :
|
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) :
|
||||||
@ -75,7 +87,8 @@ public:
|
|||||||
_instantiateEffects(options._instantiateEffects),
|
_instantiateEffects(options._instantiateEffects),
|
||||||
_instantiateMaterialEffects(options._instantiateMaterialEffects),
|
_instantiateMaterialEffects(options._instantiateMaterialEffects),
|
||||||
_materialName(options._materialName),
|
_materialName(options._materialName),
|
||||||
_sceneryPathSuffixes(options._sceneryPathSuffixes)
|
_sceneryPathSuffixes(options._sceneryPathSuffixes),
|
||||||
|
_LoadOriginHint(ORIGIN_MODEL)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
META_Object(simgear, SGReaderWriterOptions);
|
META_Object(simgear, SGReaderWriterOptions);
|
||||||
@ -139,6 +152,13 @@ public:
|
|||||||
const SGGeod& getLocation() const
|
const SGGeod& getLocation() const
|
||||||
{ return _geod; }
|
{ return _geod; }
|
||||||
|
|
||||||
|
// the load origin defines where the load request has come from.
|
||||||
|
// example usage; to allow the DDS Texture Cache (DTC) to ignore
|
||||||
|
// any texture that is used in a shader, as these often have special values
|
||||||
|
// encoded into the channels that aren't suitable for conversion.
|
||||||
|
void setLoadOriginHint(LoadOriginHint _v) const { _LoadOriginHint = _v; }
|
||||||
|
LoadOriginHint getLoadOriginHint() const { return _LoadOriginHint; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~SGReaderWriterOptions();
|
virtual ~SGReaderWriterOptions();
|
||||||
|
|
||||||
@ -157,6 +177,7 @@ private:
|
|||||||
string _materialName;
|
string _materialName;
|
||||||
string_list _sceneryPathSuffixes;
|
string_list _sceneryPathSuffixes;
|
||||||
SGGeod _geod;
|
SGGeod _geod;
|
||||||
|
mutable LoadOriginHint _LoadOriginHint;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,14 +40,14 @@
|
|||||||
|
|
||||||
SGSceneFeatures::SGSceneFeatures() :
|
SGSceneFeatures::SGSceneFeatures() :
|
||||||
_textureCompression(UseARBCompression),
|
_textureCompression(UseARBCompression),
|
||||||
_shaderLights(true),
|
|
||||||
_pointSpriteLights(true),
|
|
||||||
_distanceAttenuationLights(true),
|
|
||||||
_textureFilter(1),
|
|
||||||
_MaxTextureSize(4096),
|
_MaxTextureSize(4096),
|
||||||
_TextureCacheCompressionActive(true),
|
_TextureCacheCompressionActive(true),
|
||||||
_TextureCacheCompressionActiveTransparent(true),
|
_TextureCacheCompressionActiveTransparent(true),
|
||||||
_TextureCacheActive(false)
|
_TextureCacheActive(false),
|
||||||
|
_shaderLights(true),
|
||||||
|
_pointSpriteLights(true),
|
||||||
|
_distanceAttenuationLights(true),
|
||||||
|
_textureFilter(1)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,4 +27,5 @@
|
|||||||
#cmakedefine ENABLE_SOUND
|
#cmakedefine ENABLE_SOUND
|
||||||
#cmakedefine USE_AEONWAVE
|
#cmakedefine USE_AEONWAVE
|
||||||
#cmakedefine ENABLE_SIMD
|
#cmakedefine ENABLE_SIMD
|
||||||
|
#cmakedefine ENABLE_SIMD_CODE
|
||||||
#cmakedefine ENABLE_GDAL
|
#cmakedefine ENABLE_GDAL
|
||||||
|
@ -65,16 +65,16 @@ namespace
|
|||||||
else if (numChannels == 2 && bitsPerSample == 16) rv = SG_SAMPLE_STEREO16;
|
else if (numChannels == 2 && bitsPerSample == 16) rv = SG_SAMPLE_STEREO16;
|
||||||
else if (numChannels == 2 && bitsPerSample == 8) rv = SG_SAMPLE_STEREO8;
|
else if (numChannels == 2 && bitsPerSample == 8) rv = SG_SAMPLE_STEREO8;
|
||||||
else {
|
else {
|
||||||
char msg[65];
|
char msg[81];
|
||||||
snprintf(msg, 64, "Unsupported audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample);
|
snprintf(msg, 80, "Unsupported audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample);
|
||||||
throw sg_exception(msg);
|
throw sg_exception(msg);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (numChannels == 1 && bitsPerSample == 4) rv = SG_SAMPLE_ADPCM;
|
if (numChannels == 1 && bitsPerSample == 4) rv = SG_SAMPLE_ADPCM;
|
||||||
else if (numChannels == 1 && bitsPerSample == 8) rv = SG_SAMPLE_MULAW;
|
else if (numChannels == 1 && bitsPerSample == 8) rv = SG_SAMPLE_MULAW;
|
||||||
else {
|
else {
|
||||||
char msg[65];
|
char msg[81];
|
||||||
snprintf(msg, 64, "Unsupported compressed audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample);
|
snprintf(msg, 80, "Unsupported compressed audio format: tracks: %i, bits/sample: %i", numChannels, bitsPerSample);
|
||||||
throw sg_exception(msg);
|
throw sg_exception(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
// Modified for the new SoundSystem by Erik Hofman, October 2009
|
// Modified for the new SoundSystem by Erik Hofman, October 2009
|
||||||
//
|
//
|
||||||
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
|
// Copyright (C) 2001 Curtis L. Olson - http://www.flightgear.org/~curt
|
||||||
// Copyright (C) 2009 Erik Hofman <erik@ehofman.com>
|
// Copyright (C) 2009-2019 Erik Hofman <erik@ehofman.com>
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License as
|
// modify it under the terms of the GNU General Public License as
|
||||||
@ -418,8 +418,8 @@ void SGSoundMgr::release_source( unsigned int source )
|
|||||||
{
|
{
|
||||||
aax::Emitter& emitter = source_it->second;
|
aax::Emitter& emitter = source_it->second;
|
||||||
enum aaxState state = emitter.state();
|
enum aaxState state = emitter.state();
|
||||||
if (state == AAX_PLAYING || state == AAX_SUSPENDED) {
|
if (state != AAX_PROCESSED) {
|
||||||
TRY( emitter.set(AAX_STOPPED) );
|
TRY( emitter.set(AAX_PROCESSED) );
|
||||||
TRY( d->_aax.remove(emitter) );
|
TRY( d->_aax.remove(emitter) );
|
||||||
}
|
}
|
||||||
TRY( emitter.remove_buffer() );
|
TRY( emitter.remove_buffer() );
|
||||||
@ -555,7 +555,6 @@ void SGSoundMgr::sample_play( SGSoundSample *sample )
|
|||||||
if (bufid == SGSoundMgr::FAILED_BUFFER ||
|
if (bufid == SGSoundMgr::FAILED_BUFFER ||
|
||||||
bufid == SGSoundMgr::NO_BUFFER)
|
bufid == SGSoundMgr::NO_BUFFER)
|
||||||
{
|
{
|
||||||
printf("A: release: %i, bufid: %i (%i, %i)\n", sample->get_source(), bufid, SGSoundMgr::FAILED_BUFFER, SGSoundMgr::NO_BUFFER);
|
|
||||||
release_source(sample->get_source());
|
release_source(sample->get_source());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -590,8 +589,7 @@ void SGSoundMgr::sample_stop( SGSoundSample *sample )
|
|||||||
if ( sample->is_looping() && !stopped) {
|
if ( sample->is_looping() && !stopped) {
|
||||||
#ifdef ENABLE_SOUND
|
#ifdef ENABLE_SOUND
|
||||||
aax::Emitter& emitter = d->get_emitter(source);
|
aax::Emitter& emitter = d->get_emitter(source);
|
||||||
TRY( emitter.set(AAX_STOPPED) );
|
TRY( emitter.set(AAX_PROCESSED) );
|
||||||
TRY( d->_aax.remove(emitter) );
|
|
||||||
#endif
|
#endif
|
||||||
stopped = is_sample_stopped(sample);
|
stopped = is_sample_stopped(sample);
|
||||||
}
|
}
|
||||||
@ -610,8 +608,7 @@ void SGSoundMgr::sample_destroy( SGSoundSample *sample )
|
|||||||
unsigned int source = sample->get_source();
|
unsigned int source = sample->get_source();
|
||||||
if ( sample->is_playing() ) {
|
if ( sample->is_playing() ) {
|
||||||
aax::Emitter& emitter = d->get_emitter(source);
|
aax::Emitter& emitter = d->get_emitter(source);
|
||||||
TRY( emitter.set(AAX_STOPPED) );
|
TRY( emitter.set(AAX_PROCESSED) );
|
||||||
TRY( d->_aax.remove(emitter) );
|
|
||||||
}
|
}
|
||||||
release_source( source );
|
release_source( source );
|
||||||
#endif
|
#endif
|
||||||
|
@ -281,7 +281,7 @@ SGSubsystemGroup::incrementalInit()
|
|||||||
notifyDidChange(m->subsystem, State::INIT);
|
notifyDidChange(m->subsystem, State::INIT);
|
||||||
++_initPosition;
|
++_initPosition;
|
||||||
|
|
||||||
if (_initPosition < _members.size()) {
|
if (_initPosition < static_cast<int>(_members.size())) {
|
||||||
// start init of the next one
|
// start init of the next one
|
||||||
notifyWillChange( _members[_initPosition]->subsystem, State::INIT);
|
notifyWillChange( _members[_initPosition]->subsystem, State::INIT);
|
||||||
}
|
}
|
||||||
|
@ -72,13 +72,33 @@ static clockid_t getClockId()
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static bool qpc_init = false;
|
||||||
|
static LARGE_INTEGER s_frequency;
|
||||||
|
static BOOL s_use_qpc;
|
||||||
|
#endif
|
||||||
|
|
||||||
void SGTimeStamp::stamp()
|
void SGTimeStamp::stamp()
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
if (!qpc_init) {
|
||||||
|
s_use_qpc = QueryPerformanceFrequency(&s_frequency);
|
||||||
|
qpc_init = true;
|
||||||
|
}
|
||||||
|
if (qpc_init && s_use_qpc) {
|
||||||
|
LARGE_INTEGER now;
|
||||||
|
QueryPerformanceCounter(&now);
|
||||||
|
_sec = now.QuadPart / s_frequency.QuadPart;
|
||||||
|
_nsec = (1000000000LL * (now.QuadPart - _sec * s_frequency.QuadPart)) / s_frequency.QuadPart;
|
||||||
|
}
|
||||||
|
else {
|
||||||
unsigned int t;
|
unsigned int t;
|
||||||
|
|
||||||
t = timeGetTime();
|
t = timeGetTime();
|
||||||
_sec = t / 1000;
|
_sec = t / 1000;
|
||||||
_nsec = ( t - ( _sec * 1000 ) ) * 1000 * 1000;
|
_nsec = (t - (_sec * 1000)) * 1000 * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(_POSIX_TIMERS) && (0 < _POSIX_TIMERS)
|
#elif defined(_POSIX_TIMERS) && (0 < _POSIX_TIMERS)
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
clock_gettime(getClockId(), &ts);
|
clock_gettime(getClockId(), &ts);
|
||||||
|
Loading…
Reference in New Issue
Block a user