Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
commit
12bed8e8ad
@ -343,7 +343,7 @@ SET(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on wi
|
||||
|
||||
# isnan might not be real symbol, so can't check using function_exists
|
||||
check_cxx_source_compiles(
|
||||
"#include <cstdlib>
|
||||
"#include <cmath>
|
||||
int main() { return std::isnan(0.0);} "
|
||||
HAVE_STD_ISNAN)
|
||||
|
||||
|
@ -10,12 +10,13 @@
|
||||
#
|
||||
# Created by Erik Hofman.
|
||||
|
||||
FIND_PATH(AAX_INCLUDE_DIR aax/aeonwave.hpp
|
||||
FIND_PATH(AAX_INCLUDE_DIR aax/aax.h
|
||||
HINTS
|
||||
$ENV{AAXDIR}
|
||||
$ENV{ProgramFiles}/aax
|
||||
$ENV{ProgramFiles}/AeonWave
|
||||
$ENV{ProgramFiles}/Adalin/AeonWave
|
||||
${CMAKE_SOURCE_DIR}/aax
|
||||
PATH_SUFFIXES include
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
@ -26,23 +27,35 @@ FIND_PATH(AAX_INCLUDE_DIR aax/aeonwave.hpp
|
||||
)
|
||||
|
||||
FIND_LIBRARY(AAX_LIBRARY
|
||||
NAMES AAX aax AAX32 libAAX32
|
||||
NAMES AAX aax AAX32
|
||||
HINTS
|
||||
$ENV{AAXDIR}
|
||||
$ENV{ProgramFiles}/AAX
|
||||
$ENV{ProgramFiles}/AeonWave
|
||||
$ENV{ProgramFiles}/Adalin/AeonWave
|
||||
${CMAKE_BUILD_DIR}/aax
|
||||
PATH_SUFFIXES bin lib lib/${CMAKE_LIBRARY_ARCHITECTURE} lib64 libs64 libs libs/Win32 libs/Win64
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr
|
||||
/opt
|
||||
/usr/local
|
||||
)
|
||||
|
||||
SET(AAX_FOUND "NO")
|
||||
IF(AAX_LIBRARY AND AAX_INCLUDE_DIR)
|
||||
SET(AAX_FOUND "YES")
|
||||
ELSE(AAX_LIBRARY AND AAX_INCLUDE_DIR)
|
||||
IF(NOT AAX_INCLUDE_DIR)
|
||||
MESSAGE(FATAL_ERROR "Unable to find the AAX library development files.")
|
||||
SET(AAX_FOUND "NO")
|
||||
ENDIF(NOT AAX_INCLUDE_DIR)
|
||||
IF(NOT AAX_LIBRARY)
|
||||
IF(SINGLE_PACKAGE)
|
||||
SET(AAX_LIBRARY "${aax_BUILD_DIR}/aax/AAX32.dll")
|
||||
SET(AAX_FOUND "YES")
|
||||
ELSE(SINGLE_PACKAGE)
|
||||
ENDIF(SINGLE_PACKAGE)
|
||||
ENDIF(NOT AAX_LIBRARY)
|
||||
ENDIF(AAX_LIBRARY AND AAX_INCLUDE_DIR)
|
||||
|
||||
|
@ -7,6 +7,7 @@ find_dependency(Threads)
|
||||
|
||||
set(SIMGEAR_HEADLESS @SIMGEAR_HEADLESS@)
|
||||
set(SIMGEAR_SOUND @ENABLE_SOUND@)
|
||||
set(USE_AEONWAVE @USE_AEONWAVE@)
|
||||
|
||||
# OpenAL isn't a public dependency, so maybe not needed
|
||||
#if (SIMGEAR_SOUND)
|
||||
|
@ -433,6 +433,7 @@ namespace canvas
|
||||
osg::Vec2f Element::posToLocal(const osg::Vec2f& pos) const
|
||||
{
|
||||
getMatrix();
|
||||
if (! _transform) return osg::Vec2f(pos[0], pos[1]);
|
||||
const osg::Matrix& m = _transform->getInverseMatrix();
|
||||
return osg::Vec2f
|
||||
(
|
||||
|
@ -19,6 +19,8 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "HLAArrayDataType.hxx"
|
||||
|
@ -19,6 +19,8 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "HLADataType.hxx"
|
||||
|
@ -21,11 +21,11 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "HLAEnumeratedDataType.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "HLAEnumeratedDataType.hxx"
|
||||
#include "HLADataTypeVisitor.hxx"
|
||||
|
||||
|
@ -19,10 +19,11 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "HLAFixedRecordDataType.hxx"
|
||||
|
||||
#include "HLADataTypeVisitor.hxx"
|
||||
#include "HLAFixedRecordDataElement.hxx"
|
||||
|
||||
|
@ -19,12 +19,12 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "HLAInteractionClass.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include "HLAInteractionClass.hxx"
|
||||
#include "HLADataElement.hxx"
|
||||
#include "HLAFederate.hxx"
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "HLAObjectClass.hxx"
|
||||
|
@ -19,10 +19,11 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include "HLAVariantRecordDataType.hxx"
|
||||
|
||||
#include "HLADataTypeVisitor.hxx"
|
||||
#include "HLAVariantRecordDataElement.hxx"
|
||||
|
||||
|
@ -22,9 +22,13 @@
|
||||
//
|
||||
|
||||
#include <simgear_config.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "DNSClient.hxx"
|
||||
#include <udns.h>
|
||||
#include <time.h>
|
||||
#include <ctime>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
namespace simgear {
|
||||
|
@ -296,7 +296,10 @@ bool Dir::isEmpty() const
|
||||
|
||||
int n = 0;
|
||||
dirent* d;
|
||||
while( (d = readdir(dp)) !=NULL && (n < 4) ) n++;
|
||||
while (n < 3 && (d = readdir(dp)) != nullptr) {
|
||||
n++;
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
|
||||
return (n == 2); // '.' and '..' always exist
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <simgear/io/iostreams/sgstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
#include "sg_dir.hxx"
|
||||
@ -34,11 +35,35 @@ void test_tempDir()
|
||||
d.remove();
|
||||
}
|
||||
|
||||
void test_isEmpty()
|
||||
{
|
||||
simgear::Dir d = simgear::Dir::tempDir("FlightGear");
|
||||
SG_VERIFY(!d.isNull() && d.exists() && d.isEmpty());
|
||||
SGPath f = d.file("some file");
|
||||
|
||||
{ sg_ofstream file(f); } // create and close the file
|
||||
SG_VERIFY(!d.isEmpty());
|
||||
|
||||
f.remove();
|
||||
SG_VERIFY(d.isEmpty());
|
||||
|
||||
simgear::Dir subDir{d.file("some subdir")};
|
||||
subDir.create(0777);
|
||||
SG_VERIFY(!d.isEmpty());
|
||||
|
||||
subDir.remove();
|
||||
SG_VERIFY(d.isEmpty());
|
||||
|
||||
d.remove();
|
||||
SG_VERIFY(d.isEmpty()); // eek, but that's how it is
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
test_isNull();
|
||||
test_setRemoveOnDestroy();
|
||||
test_tempDir();
|
||||
test_isEmpty();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -29,10 +29,7 @@
|
||||
#include <cstring> // strerror_r() and strerror_s()
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
|
||||
#if defined(HAVE_CPP11_CODECVT)
|
||||
#include <codecvt> // new in C++11
|
||||
#endif
|
||||
#include <cassert>
|
||||
|
||||
#include "strutils.hxx"
|
||||
|
||||
@ -44,6 +41,8 @@
|
||||
|
||||
#if defined(SG_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#endif
|
||||
|
||||
using std::string;
|
||||
@ -656,25 +655,85 @@ static std::string convertWStringToMultiByte(DWORD encoding, const std::wstring&
|
||||
|
||||
std::wstring convertUtf8ToWString(const std::string& a)
|
||||
{
|
||||
#ifdef SG_WINDOWS
|
||||
return convertMultiByteToWString(CP_UTF8, a);
|
||||
#elif defined(HAVE_CPP11_CODECVT)
|
||||
#if defined(SG_WINDOWS)
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> ucs2conv;
|
||||
return ucs2conv.from_bytes(a);
|
||||
#else
|
||||
return std::wstring();
|
||||
assert(sizeof(wchar_t) == 4);
|
||||
std::wstring result;
|
||||
int expectedContinuationCount = 0;
|
||||
wchar_t wc = 0;
|
||||
|
||||
for (uint8_t utf8CodePoint : a) {
|
||||
// ASCII 7-bit range
|
||||
if (utf8CodePoint <= 0x7f) {
|
||||
if (expectedContinuationCount != 0) {
|
||||
throw sg_format_exception();
|
||||
}
|
||||
|
||||
result.push_back(static_cast<wchar_t>(utf8CodePoint));
|
||||
} else if (expectedContinuationCount > 0) {
|
||||
if ((utf8CodePoint & 0xC0) != 0x80) {
|
||||
throw sg_format_exception();
|
||||
}
|
||||
|
||||
wc = (wc << 6) | (utf8CodePoint & 0x3F);
|
||||
if (--expectedContinuationCount == 0) {
|
||||
result.push_back(wc);
|
||||
}
|
||||
} else {
|
||||
if ((utf8CodePoint & 0xE0) == 0xC0) {
|
||||
expectedContinuationCount = 1;
|
||||
wc = utf8CodePoint & 0x1f;
|
||||
} else if ((utf8CodePoint & 0xF0) == 0xE0) {
|
||||
expectedContinuationCount = 2;
|
||||
wc = utf8CodePoint & 0x0f;
|
||||
} else if ((utf8CodePoint & 0xF8) == 0xF0) {
|
||||
expectedContinuationCount = 3;
|
||||
wc =utf8CodePoint & 0x07;
|
||||
} else {
|
||||
// illegal UTF-8 encoding
|
||||
throw sg_format_exception();
|
||||
}
|
||||
}
|
||||
} // of UTF-8 code point iteration
|
||||
|
||||
return result;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
std::string convertWStringToUtf8(const std::wstring& w)
|
||||
{
|
||||
#ifdef SG_WINDOWS
|
||||
return convertWStringToMultiByte(CP_UTF8, w);
|
||||
#elif defined(HAVE_CPP11_CODECVT)
|
||||
#if defined(SG_WINDOWS)
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> ucs2conv;
|
||||
return ucs2conv.to_bytes(w);
|
||||
#else
|
||||
return std::string();
|
||||
assert(sizeof(wchar_t) == 4);
|
||||
std::string result;
|
||||
|
||||
for (wchar_t cp : w) {
|
||||
if (cp <= 0x7f) {
|
||||
result.push_back(static_cast<uint8_t>(cp));
|
||||
} else if (cp <= 0x07ff) {
|
||||
result.push_back(0xC0 | ((cp >> 6) & 0x1f));
|
||||
result.push_back(0x80 | (cp & 0x3f));
|
||||
} else if (cp <= 0xffff) {
|
||||
result.push_back(0xE0 | ((cp >> 12) & 0x0f));
|
||||
result.push_back(0x80 | ((cp >> 6) & 0x3f));
|
||||
result.push_back(0x80 | (cp & 0x3f));
|
||||
} else if (cp < 0x10ffff) {
|
||||
result.push_back(0xF0 | ((cp >> 18) & 0x07));
|
||||
result.push_back(0x80 | ((cp >> 12) & 0x3f));
|
||||
result.push_back(0x80 | ((cp >> 6) & 0x3f));
|
||||
result.push_back(0x80 | (cp & 0x3f));
|
||||
} else {
|
||||
throw sg_format_exception();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -605,6 +605,20 @@ void test_readTime()
|
||||
SG_CHECK_EQUAL_EP(strutils::readTime("-0:0:28"), -28 * seconds);
|
||||
}
|
||||
|
||||
void test_utf8Convert()
|
||||
{
|
||||
// F, smiley emoticon, Maths summation symbol, section sign
|
||||
std::wstring a(L"\u0046\U0001F600\u2211\u00A7");
|
||||
|
||||
|
||||
std::string utf8A = strutils::convertWStringToUtf8(a);
|
||||
SG_VERIFY(utf8A == std::string("F\xF0\x9F\x98\x80\xE2\x88\x91\xC2\xA7"));
|
||||
|
||||
|
||||
std::wstring aRoundTrip = strutils::convertUtf8ToWString(utf8A);
|
||||
SG_VERIFY(a == aRoundTrip);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
test_strip();
|
||||
@ -624,6 +638,7 @@ int main(int argc, char* argv[])
|
||||
test_error_string();
|
||||
test_propPathMatch();
|
||||
test_readTime();
|
||||
test_utf8Convert();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -787,6 +787,11 @@ void naGCRelease(int key)
|
||||
naHash_delete(globals->save_hash, naNum(key));
|
||||
}
|
||||
|
||||
int naNumSaved()
|
||||
{
|
||||
return naHash_size(globals->save_hash) + naVec_size(globals->save);
|
||||
}
|
||||
|
||||
void naClearSaved()
|
||||
{
|
||||
naContext c;
|
||||
|
@ -139,10 +139,9 @@ namespace nasal
|
||||
template<class Base>
|
||||
ObjectHolder<Base>::ObjectHolder(naRef obj):
|
||||
_ref(obj),
|
||||
_gc_key(0)
|
||||
_gc_key(naIsNil(obj) ? 0 : naGCSave(obj))
|
||||
{
|
||||
if( !naIsNil(obj) )
|
||||
naGCSave(obj);
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
@ -159,7 +158,7 @@ namespace nasal
|
||||
SGSharedPtr<ObjectHolder<Base> >
|
||||
ObjectHolder<Base>::makeShared(naRef obj)
|
||||
{
|
||||
return SGSharedPtr<ObjectHolder<Base> >( new ObjectHolder<SGReferenced>(obj) );
|
||||
return SGSharedPtr<ObjectHolder<Base> >( new ObjectHolder<Base>(obj) );
|
||||
}
|
||||
|
||||
} // namespace nasal
|
||||
|
@ -39,7 +39,7 @@ namespace nasal
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bad_nasal_cast::~bad_nasal_cast() throw()
|
||||
bad_nasal_cast::~bad_nasal_cast()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ namespace nasal
|
||||
*/
|
||||
explicit bad_nasal_cast(const std::string& msg);
|
||||
|
||||
virtual ~bad_nasal_cast() throw();
|
||||
virtual ~bad_nasal_cast();
|
||||
|
||||
protected:
|
||||
std::string _msg;
|
||||
|
@ -2,6 +2,9 @@
|
||||
#include <BoostTestTargetConfig.h>
|
||||
|
||||
#include "TestContext.hxx"
|
||||
|
||||
#include <simgear/nasal/cppbind/NasalObjectHolder.hxx>
|
||||
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
@ -91,3 +94,47 @@ BOOST_AUTO_TEST_CASE( ghost_gc )
|
||||
|
||||
BOOST_REQUIRE(active_instances.empty());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
BOOST_AUTO_TEST_CASE( object_holder_gc )
|
||||
{
|
||||
TestContext c;
|
||||
BOOST_REQUIRE_EQUAL(naNumSaved(), 0);
|
||||
BOOST_REQUIRE(active_instances.empty());
|
||||
|
||||
//-----------------------------------------------
|
||||
// Put some ghosts in ObjectHolder and check if
|
||||
// they are saved from gc
|
||||
|
||||
naRef g1 = createTestGhost(c, 1),
|
||||
g2 = createTestGhost(c, 2);
|
||||
|
||||
nasal::ObjectHolder<> h1(g1);
|
||||
BOOST_CHECK_EQUAL(naNumSaved(), 1);
|
||||
BOOST_CHECK(naIsGhost(h1.get_naRef()));
|
||||
|
||||
nasal::ObjectHolder<> h2(g2);
|
||||
BOOST_CHECK_EQUAL(naNumSaved(), 2);
|
||||
BOOST_CHECK(naIsGhost(h2.get_naRef()));
|
||||
|
||||
c.runGC();
|
||||
|
||||
BOOST_CHECK_EQUAL(active_instances.size(), 2);
|
||||
BOOST_CHECK_EQUAL(naNumSaved(), 2);
|
||||
|
||||
h1.reset(naNum(1));
|
||||
h2.reset(naNum(2));
|
||||
BOOST_CHECK_EQUAL(naNumSaved(), 2);
|
||||
|
||||
//-----------------------------------------------
|
||||
// Check that the saved objects are released
|
||||
|
||||
h1.reset();
|
||||
BOOST_CHECK_EQUAL(naNumSaved(), 1);
|
||||
|
||||
h2.reset();
|
||||
BOOST_CHECK_EQUAL(naNumSaved(), 0);
|
||||
|
||||
c.runGC();
|
||||
BOOST_CHECK_EQUAL(active_instances.size(), 0);
|
||||
}
|
||||
|
@ -58,6 +58,10 @@ int naGCSave(naRef obj);
|
||||
// by the garbage collector.
|
||||
void naGCRelease(int key);
|
||||
|
||||
// Get the number of currently saved and not yet again released objects
|
||||
// (saved by naSave or naGCSave)
|
||||
int naNumSaved();
|
||||
|
||||
// Drop all saved references
|
||||
void naClearSaved();
|
||||
|
||||
|
@ -2443,7 +2443,8 @@ SGPropertyNode::fireValueChanged (SGPropertyNode * node)
|
||||
{
|
||||
if (_listeners != 0) {
|
||||
for (unsigned int i = 0; i < _listeners->size(); i++) {
|
||||
(*_listeners)[i]->valueChanged(node);
|
||||
if ((*_listeners)[i])
|
||||
(*_listeners)[i]->valueChanged(node);
|
||||
}
|
||||
}
|
||||
if (_parent != 0)
|
||||
@ -2581,53 +2582,77 @@ std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
|
||||
namespace simgear
|
||||
{
|
||||
#if !PROPS_STANDALONE
|
||||
template<>
|
||||
std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
stream >> result[i];
|
||||
template<>
|
||||
std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
stream >> result[i];
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
|
||||
{
|
||||
props::Type ltype = lhs.getType();
|
||||
props::Type rtype = rhs.getType();
|
||||
if (ltype != rtype)
|
||||
return false;
|
||||
switch (ltype) {
|
||||
case props::NONE:
|
||||
return true;
|
||||
case props::ALIAS:
|
||||
return false; // XXX Should we look in aliases?
|
||||
case props::BOOL:
|
||||
return lhs.getValue<bool>() == rhs.getValue<bool>();
|
||||
case props::INT:
|
||||
return lhs.getValue<int>() == rhs.getValue<int>();
|
||||
case props::LONG:
|
||||
return lhs.getValue<long>() == rhs.getValue<long>();
|
||||
case props::FLOAT:
|
||||
return lhs.getValue<float>() == rhs.getValue<float>();
|
||||
case props::DOUBLE:
|
||||
return lhs.getValue<double>() == rhs.getValue<double>();
|
||||
case props::STRING:
|
||||
case props::UNSPECIFIED:
|
||||
return !strcmp(lhs.getStringValue(), rhs.getStringValue());
|
||||
namespace
|
||||
{
|
||||
bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
|
||||
{
|
||||
props::Type ltype = lhs.getType();
|
||||
props::Type rtype = rhs.getType();
|
||||
if (ltype != rtype)
|
||||
return false;
|
||||
switch (ltype) {
|
||||
case props::NONE:
|
||||
return true;
|
||||
case props::ALIAS:
|
||||
return false; // XXX Should we look in aliases?
|
||||
case props::BOOL:
|
||||
return lhs.getValue<bool>() == rhs.getValue<bool>();
|
||||
case props::INT:
|
||||
return lhs.getValue<int>() == rhs.getValue<int>();
|
||||
case props::LONG:
|
||||
return lhs.getValue<long>() == rhs.getValue<long>();
|
||||
case props::FLOAT:
|
||||
return lhs.getValue<float>() == rhs.getValue<float>();
|
||||
case props::DOUBLE:
|
||||
return lhs.getValue<double>() == rhs.getValue<double>();
|
||||
case props::STRING:
|
||||
case props::UNSPECIFIED:
|
||||
return !strcmp(lhs.getStringValue(), rhs.getStringValue());
|
||||
#if !PROPS_STANDALONE
|
||||
case props::VEC3D:
|
||||
return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
|
||||
case props::VEC4D:
|
||||
return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
|
||||
case props::VEC3D:
|
||||
return lhs.getValue<SGVec3d>() == rhs.getValue<SGVec3d>();
|
||||
case props::VEC4D:
|
||||
return lhs.getValue<SGVec4d>() == rhs.getValue<SGVec4d>();
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SGPropertyNode::copy(SGPropertyNode *to)
|
||||
{
|
||||
if (nChildren())
|
||||
{
|
||||
for (int i = 0; i < nChildren(); i++) {
|
||||
SGPropertyNode *child = getChild(i);
|
||||
SGPropertyNode *to_child = to->getChild(child->getName());
|
||||
if (!to_child)
|
||||
to_child = to->addChild(child->getName());
|
||||
if (child->nChildren())
|
||||
{
|
||||
child->copy(to_child);
|
||||
}
|
||||
else
|
||||
{
|
||||
to_child->setValue(child->getStringValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
to->setValue(getStringValue());
|
||||
}
|
||||
|
||||
bool SGPropertyNode::compare(const SGPropertyNode& lhs,
|
||||
|
@ -1105,6 +1105,11 @@ public:
|
||||
*/
|
||||
SGPropertyNode * getNode (const char * relative_path, bool create = false);
|
||||
|
||||
/**
|
||||
* deep copy one node to another.
|
||||
*/
|
||||
void copy(SGPropertyNode *to);
|
||||
|
||||
/**
|
||||
* Get a pointer to another node by relative path.
|
||||
*/
|
||||
|
@ -161,8 +161,7 @@ setFlag( int& mode,
|
||||
string message = "Unrecognized flag value '";
|
||||
message += flag;
|
||||
message += '\'';
|
||||
// FIXME: add location info
|
||||
throw sg_io_exception(message, location, "SimGear Property Reader");
|
||||
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +176,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
string message = "Root element name is ";
|
||||
message += name;
|
||||
message += "; expected PropertyList";
|
||||
throw sg_io_exception(message, location, "SimGear Property Reader");
|
||||
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||
}
|
||||
|
||||
// Check for an include.
|
||||
@ -189,8 +188,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
{
|
||||
string message ="Cannot open file ";
|
||||
message += attval;
|
||||
throw sg_io_exception(message, location,
|
||||
"SimGear Property Reader");
|
||||
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||
}
|
||||
readProperties(path, _root, 0, _extended);
|
||||
} catch (sg_io_exception &e) {
|
||||
@ -277,7 +275,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
||||
{
|
||||
string message ="Cannot open file ";
|
||||
message += val;
|
||||
throw sg_io_exception(message, location, "SimGear Property Reader");
|
||||
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||
}
|
||||
readProperties(path, node, 0, _extended);
|
||||
}
|
||||
@ -352,8 +350,7 @@ PropsVisitor::endElement (const char * name)
|
||||
string message = "Unrecognized data type '";
|
||||
message += st.type;
|
||||
message += '\'';
|
||||
// FIXME: add location information
|
||||
throw sg_io_exception(message, location, "SimGear Property Reader");
|
||||
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||
}
|
||||
if( !ret )
|
||||
SG_LOG
|
||||
@ -770,7 +767,7 @@ copyPropertyValue(const SGPropertyNode *in, SGPropertyNode *out)
|
||||
break;
|
||||
string message = "Unknown internal SGPropertyNode type";
|
||||
message += in->getType();
|
||||
throw sg_error(message, "SimGear Property Reader");
|
||||
throw sg_error(message, SG_ORIGIN);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
@ -85,7 +85,7 @@ BuilderException::BuilderException(const std::string& message,
|
||||
{
|
||||
}
|
||||
|
||||
BuilderException::~BuilderException() throw()
|
||||
BuilderException::~BuilderException()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ public:
|
||||
BuilderException();
|
||||
BuilderException(const char* message, const char* origin = 0);
|
||||
BuilderException(const std::string& message, const std::string& = "");
|
||||
virtual ~BuilderException() throw();
|
||||
virtual ~BuilderException();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -832,3 +832,157 @@ SGSliderAnimation::setupCallbacks(SGSceneUserData* ud, osg::Group*)
|
||||
{
|
||||
ud->setPickCallback(new KnobSliderPickCallback(getConfig(), getModelRoot()));
|
||||
}
|
||||
|
||||
/*
|
||||
* touch screen is a 2d surface that will pass parameters to the callbacks indicating the
|
||||
* normalized coordinates of hover or touch. Touch is defined as a button click.
|
||||
* For compatibility with touchscreen operations this class does not differentiate between
|
||||
* which buttons are touched, simply because this isn't how touchscreens work.
|
||||
* Some touchscreens (e.g. SAW) can have a Z-axis indicating the pressure. This is not
|
||||
* simulated.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Handle picking events on object with a canvas placed onto
|
||||
*/
|
||||
class TouchPickCallback : public SGPickCallback {
|
||||
public:
|
||||
TouchPickCallback(const SGPropertyNode* configNode,
|
||||
SGPropertyNode* modelRoot) :
|
||||
_repeatable(configNode->getBoolValue("repeatable", false)),
|
||||
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)),
|
||||
SGPickCallback(PriorityPanel)
|
||||
{
|
||||
std::vector<SGPropertyNode_ptr> bindings;
|
||||
|
||||
bindings = configNode->getChildren("touch");
|
||||
for (unsigned int i = 0; i < bindings.size(); ++i) {
|
||||
_touches.insert(bindings[i]->getIntValue());
|
||||
}
|
||||
|
||||
_bindingsTouched = readBindingList(configNode->getChildren("binding"), modelRoot);
|
||||
readOptionalBindingList(configNode, modelRoot, "mod-up", _bindingsReleased);
|
||||
|
||||
if (configNode->hasChild("cursor")) {
|
||||
_cursorName = configNode->getStringValue("cursor");
|
||||
}
|
||||
}
|
||||
|
||||
void addHoverBindings(const SGPropertyNode* hoverNode,
|
||||
SGPropertyNode* modelRoot)
|
||||
{
|
||||
_hover = readBindingList(hoverNode->getChildren("binding"), modelRoot);
|
||||
}
|
||||
|
||||
virtual bool buttonPressed(int touchIdx,
|
||||
const osgGA::GUIEventAdapter& event,
|
||||
const Info& info)
|
||||
{
|
||||
if (_touches.find(touchIdx) == _touches.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!anyBindingEnabled(_bindingsTouched)) {
|
||||
return false;
|
||||
}
|
||||
SGPropertyNode_ptr params(new SGPropertyNode);
|
||||
params->setDoubleValue("x", info.uv[0]);
|
||||
params->setDoubleValue("y", info.uv[1]);
|
||||
|
||||
_repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat
|
||||
fireBindingList(_bindingsTouched, params.ptr());
|
||||
return true;
|
||||
}
|
||||
virtual void buttonReleased(int keyModState,
|
||||
const osgGA::GUIEventAdapter&,
|
||||
const Info* info)
|
||||
{
|
||||
SG_UNUSED(keyModState);
|
||||
SGPropertyNode_ptr params(new SGPropertyNode);
|
||||
params->setDoubleValue("x", info->uv[0]);
|
||||
params->setDoubleValue("y", info->uv[1]);
|
||||
fireBindingList(_bindingsReleased, params.ptr());
|
||||
}
|
||||
|
||||
virtual void update(double dt, int keyModState)
|
||||
{
|
||||
SG_UNUSED(keyModState);
|
||||
if (!_repeatable)
|
||||
return;
|
||||
|
||||
_repeatTime += dt;
|
||||
while (_repeatInterval < _repeatTime) {
|
||||
_repeatTime -= _repeatInterval;
|
||||
fireBindingList(_bindingsTouched);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool hover(const osg::Vec2d& windowPos,
|
||||
const Info& info)
|
||||
{
|
||||
if (!anyBindingEnabled(_hover)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SGPropertyNode_ptr params(new SGPropertyNode);
|
||||
params->setDoubleValue("x", info.uv[0]);
|
||||
params->setDoubleValue("y", info.uv[1]);
|
||||
fireBindingList(_hover, params.ptr());
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string getCursor() const
|
||||
{
|
||||
return _cursorName;
|
||||
}
|
||||
|
||||
virtual bool needsUV() const { return true; }
|
||||
|
||||
private:
|
||||
SGBindingList _bindingsTouched;
|
||||
SGBindingList _bindingsReleased;
|
||||
SGBindingList _hover;
|
||||
std::set<int> _touches;
|
||||
std::string _cursorName;
|
||||
bool _repeatable;
|
||||
double _repeatInterval;
|
||||
double _repeatTime;
|
||||
};
|
||||
|
||||
SGTouchAnimation::SGTouchAnimation(simgear::SGTransientModelData &modelData) :
|
||||
SGPickAnimation(modelData)
|
||||
{
|
||||
}
|
||||
|
||||
osg::Group* SGTouchAnimation::createMainGroup(osg::Group* pr)
|
||||
{
|
||||
SGRotateTransform* transform = new SGRotateTransform();
|
||||
pr->addChild(transform);
|
||||
return transform;
|
||||
}
|
||||
|
||||
void SGTouchAnimation::setupCallbacks(SGSceneUserData* ud, osg::Group*)
|
||||
{
|
||||
TouchPickCallback* touchCb = NULL;
|
||||
|
||||
// add actions that become macro and command invocations
|
||||
std::vector<SGPropertyNode_ptr> actions;
|
||||
actions = getConfig()->getChildren("action");
|
||||
for (unsigned int i = 0; i < actions.size(); ++i) {
|
||||
touchCb = new TouchPickCallback(actions[i], getModelRoot());
|
||||
ud->addPickCallback(touchCb);
|
||||
}
|
||||
|
||||
if (getConfig()->hasChild("hovered")) {
|
||||
if (!touchCb) {
|
||||
// make a trivial PickCallback to hang the hovered off of
|
||||
SGPropertyNode_ptr dummyNode(new SGPropertyNode);
|
||||
touchCb = new TouchPickCallback(dummyNode.ptr(), getModelRoot());
|
||||
ud->addPickCallback(touchCb);
|
||||
}
|
||||
|
||||
touchCb->addHoverBindings(getConfig()->getNode("hovered"), getModelRoot());
|
||||
}
|
||||
// ud->setPickCallback(new TouchPickCallback(getConfig(), getModelRoot()));
|
||||
}
|
||||
|
@ -114,5 +114,19 @@ private:
|
||||
SGSharedPtr<SGExpressiond const> _animationValue;
|
||||
};
|
||||
|
||||
class SGTouchAnimation : public SGPickAnimation
|
||||
{
|
||||
public:
|
||||
SGTouchAnimation(simgear::SGTransientModelData &modelData);
|
||||
|
||||
|
||||
protected:
|
||||
virtual osg::Group* createMainGroup(osg::Group* pr);
|
||||
|
||||
virtual void setupCallbacks(SGSceneUserData* ud, osg::Group* parent);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif // of SG_SCENE_PICK_ANIMATION_HXX
|
||||
|
||||
|
@ -226,7 +226,7 @@ namespace {
|
||||
{
|
||||
string typeString(aNode->getStringValue("type"));
|
||||
// exclude these so we don't show yellow outlines in preview mode
|
||||
return (typeString == "pick") || (typeString == "knob") || (typeString == "slider");
|
||||
return (typeString == "pick") || (typeString == "knob") || (typeString == "slider") || (typeString == "touch");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -497,6 +497,9 @@ SGAnimation::animate(simgear::SGTransientModelData &modelData)
|
||||
} else if (type == "slider") {
|
||||
SGSliderAnimation anim(modelData);
|
||||
anim.apply(modelData.getNode());
|
||||
} else if (type == "touch") {
|
||||
SGTouchAnimation anim(modelData);
|
||||
anim.apply(modelData.getNode());
|
||||
} else if (type == "range") {
|
||||
SGRangeAnimation anim(modelData);
|
||||
anim.apply(modelData);
|
||||
@ -769,7 +772,7 @@ bool SGAnimation::setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& cente
|
||||
object_group->setNodeMask(0);
|
||||
}
|
||||
else
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Could find a valid line segment for animation: " << axis_object_name);
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Could not find a valid line segment for animation: " << axis_object_name);
|
||||
}
|
||||
else if (can_warn)
|
||||
SG_LOG(SG_INPUT, SG_ALERT, "Could not find at least one of the following objects for axis animation: " << axis_object_name);
|
||||
|
@ -23,6 +23,7 @@
|
||||
//
|
||||
// $Id$
|
||||
|
||||
#include <utility>
|
||||
|
||||
#ifndef _SG_INLINES_H
|
||||
#define _SG_INLINES_H
|
||||
@ -108,5 +109,20 @@ inline void SG_NORMALIZE_RANGE( T &val, const T min, const T max ) {
|
||||
#define SG_DISABLE_COPY(Class) \
|
||||
Class(const Class &); \
|
||||
Class &operator=(const Class &);
|
||||
|
||||
|
||||
namespace simgear {
|
||||
|
||||
// A swap() that is guaranteed to be 'noexcept' as long as compilation
|
||||
// succeeds. Idea and implementation from
|
||||
// <https://akrzemi1.wordpress.com/2011/06/10/using-noexcept/>.
|
||||
template<typename T>
|
||||
void noexceptSwap(T& a, T& b) noexcept
|
||||
{
|
||||
using std::swap;
|
||||
static_assert(noexcept(swap(a, b)), "this swap() is not 'noexcept'" );
|
||||
swap(a, b);
|
||||
}
|
||||
|
||||
} // of namespace simgear
|
||||
|
||||
#endif // _SG_INLINES_H
|
||||
|
@ -4,16 +4,15 @@ set(HEADERS
|
||||
sample.hxx
|
||||
sample_group.hxx
|
||||
xmlsound.hxx
|
||||
readwav.hxx
|
||||
soundmgr.hxx
|
||||
filters.hxx
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
sample.cxx
|
||||
sample_group.cxx
|
||||
xmlsound.cxx
|
||||
readwav.cxx
|
||||
soundmgr_openal_private.hxx
|
||||
filters.cxx
|
||||
)
|
||||
|
||||
if (USE_AEONWAVE)
|
||||
@ -21,8 +20,13 @@ if (USE_AEONWAVE)
|
||||
soundmgr_aeonwave.cxx
|
||||
)
|
||||
else()
|
||||
set(HEADERS ${HEADERS}
|
||||
readwav.hxx
|
||||
)
|
||||
set(SOURCES ${SOURCES}
|
||||
soundmgr_openal.cxx
|
||||
soundmgr_openal_private.hxx
|
||||
readwav.cxx
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -66,15 +66,15 @@ int main( int argc, char *argv[] )
|
||||
std::cout << "Vendor: " << _vendor << std::endl;
|
||||
std::cout << "Renderer: " << _renderer << std::endl;
|
||||
|
||||
aax::Matrix64 mtx64;
|
||||
mtx64.translate(-5000.0, 12500.0, 1000.0);
|
||||
aax::Matrix mtx;
|
||||
mtx.translate(-5000.0, 12500.0, 1000.0);
|
||||
|
||||
aax::Matrix mtx = mtx64.toMatrix();
|
||||
emitter.matrix(mtx);
|
||||
aax::Matrix64 mtx64 = mtx.toMatrix64();
|
||||
emitter.matrix(mtx64);
|
||||
|
||||
mtx.translate(-5.0, 2.0, 1.0);
|
||||
mtx.inverse();
|
||||
aax.sensor_matrix(mtx);
|
||||
mtx64.inverse();
|
||||
aax.sensor_matrix(mtx64);
|
||||
|
||||
aax.set(AAX_PLAYING);
|
||||
emitter.set(AAX_PLAYING);
|
||||
|
169
simgear/sound/filters.cxx
Normal file
169
simgear/sound/filters.cxx
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2007-2017 by Erik Hofman.
|
||||
* Copyright 2009-2017 by Adalin B.V.
|
||||
*
|
||||
* This file is part of SimGear
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the Lesser GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Lesser GNU General Public License
|
||||
* along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include "filters.hxx"
|
||||
|
||||
namespace simgear {
|
||||
|
||||
FreqFilter::FreqFilter(int order, float sample_freq, float cutoff_freq, float Qfactor) {
|
||||
|
||||
Q = Qfactor;
|
||||
fs = sample_freq;
|
||||
no_stages = order / 2;
|
||||
gain = order;
|
||||
|
||||
butterworth_compute(cutoff_freq);
|
||||
|
||||
for (unsigned int i = 0; i < 2*SG_FREQFILTER_MAX_STAGES; ++i) {
|
||||
hist[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
FreqFilter::~FreqFilter() {
|
||||
}
|
||||
|
||||
void FreqFilter::update( int16_t *data, unsigned int num) {
|
||||
|
||||
if (num) {
|
||||
float k = gain;
|
||||
for (unsigned int stage = 0; stage < no_stages; ++stage) {
|
||||
|
||||
float h0 = hist[2*stage + 0];
|
||||
float h1 = hist[2*stage + 1];
|
||||
unsigned int i = num;
|
||||
do {
|
||||
float nsmp, smp = data[i] * k;
|
||||
smp = smp + h0 * coeff[4*stage + 0];
|
||||
nsmp = smp + h1 * coeff[4*stage + 1];
|
||||
smp = nsmp + h0 * coeff[4*stage + 2];
|
||||
smp = smp + h1 * coeff[4*stage + 3];
|
||||
|
||||
h1 = h0;
|
||||
h0 = nsmp;
|
||||
data[i] = smp;
|
||||
}
|
||||
while (--i);
|
||||
|
||||
hist[2*stage + 0] = h0;
|
||||
hist[2*stage + 1] = h1;
|
||||
k = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void FreqFilter::bilinear(float a0, float a1, float a2,
|
||||
float b0, float b1, float b2,
|
||||
float *k, int stage) {
|
||||
a2 *= 4.0f;
|
||||
b2 *= 4.0f;
|
||||
a1 *= 2.0f;
|
||||
b1 *= 2.0f;
|
||||
|
||||
float ad = a2 + a1 + a0;
|
||||
float bd = b2 + b1 + b0;
|
||||
|
||||
*k *= ad/bd;
|
||||
|
||||
coeff[4*stage + 0] = 2.0f*(-b2 + b0) / bd;
|
||||
coeff[4*stage + 1] = (b2 - b1 + b0) / bd;
|
||||
coeff[4*stage + 2] = 2.0f*(-a2 + a0) / ad;
|
||||
coeff[4*stage + 3] = (a2 - a1 + a0) / ad;
|
||||
|
||||
// negate to prevent this is required every time the filter is applied.
|
||||
coeff[4*stage + 0] = -coeff[4*stage + 0];
|
||||
coeff[4*stage + 1] = -coeff[4*stage + 1];
|
||||
}
|
||||
|
||||
// convert from S-domain to Z-domain
|
||||
inline void FreqFilter::bilinear_s2z(float *a0, float *a1, float *a2,
|
||||
float *b0, float *b1, float *b2,
|
||||
float fc, float fs, float *k, int stage) {
|
||||
// prewarp
|
||||
float wp = 2.0f*tanf(SG_PI * fc/fs);
|
||||
|
||||
*a2 /= wp*wp;
|
||||
*b2 /= wp*wp;
|
||||
*a1 /= wp;
|
||||
*b1 /= wp;
|
||||
|
||||
bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, stage);
|
||||
}
|
||||
|
||||
void FreqFilter::butterworth_compute(float fc) {
|
||||
|
||||
// http://www.ti.com/lit/an/sloa049b/sloa049b.pdf
|
||||
static const float _Q[SG_FREQFILTER_MAX_STAGES][SG_FREQFILTER_MAX_STAGES]= {
|
||||
{ 0.7071f, 1.0f, 1.0f, 1.0f }, // 2nd order
|
||||
{ 0.5412f, 1.3605f, 1.0f, 1.0f }, // 4th order
|
||||
{ 0.5177f, 0.7071f, 1.9320f, 1.0f }, // 6th roder
|
||||
{ 0.5098f, 0.6013f, 0.8999f, 2.5628f } // 8th order
|
||||
};
|
||||
|
||||
gain = 1.0f;
|
||||
|
||||
int pos = no_stages-1;
|
||||
for (unsigned i = 0; i < no_stages; ++i)
|
||||
{
|
||||
float a2 = 0.0f;
|
||||
float a1 = 0.0f;
|
||||
float a0 = 1.0f;
|
||||
|
||||
float b2 = 1.0f;
|
||||
float b1 = 1.0f/(_Q[pos][i] * Q);
|
||||
float b0 = 1.0f;
|
||||
|
||||
// fill the filter coefficients
|
||||
bilinear_s2z(&a0, &a1, &a2, &b0, &b1, &b2, fc, fs, &gain, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
BitCrusher::BitCrusher(float level) {
|
||||
|
||||
float bits = level * 15.0f;
|
||||
factor = powf(2.0f, bits);
|
||||
devider = 1.0f/factor;
|
||||
}
|
||||
|
||||
BitCrusher::~BitCrusher() {
|
||||
}
|
||||
|
||||
void BitCrusher::update( int16_t *data, unsigned int num ) {
|
||||
|
||||
if (num && factor < 1.0f) {
|
||||
unsigned int i = num;
|
||||
do {
|
||||
float integral;
|
||||
|
||||
modff(data[i]*devider, &integral);
|
||||
data[i] = integral*factor;
|
||||
} while (--i);
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace simgear
|
||||
|
77
simgear/sound/filters.hxx
Normal file
77
simgear/sound/filters.hxx
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2007-2017 by Erik Hofman.
|
||||
* Copyright 2009-2017 by Adalin B.V.
|
||||
*
|
||||
* This file is part of SimGear
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the Lesser GNU General Public License as published
|
||||
* by the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the Lesser GNU General Public License
|
||||
* along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||
*/
|
||||
|
||||
#ifndef _SIMGEAR_FREQUENCY_FILTER_HXX
|
||||
#define _SIMGEAR_FREQUENCY_FILTER_HXX
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace simgear {
|
||||
|
||||
// Every stage is a 2nd order filter
|
||||
// Four stages therefore equals to an 8th order filter with a 48dB/oct slope.
|
||||
#define SG_FREQFILTER_MAX_STAGES 4
|
||||
|
||||
class FreqFilter {
|
||||
|
||||
private:
|
||||
|
||||
float fs, Q, gain;
|
||||
float coeff[4*SG_FREQFILTER_MAX_STAGES];
|
||||
float hist[2*SG_FREQFILTER_MAX_STAGES];
|
||||
unsigned char no_stages;
|
||||
|
||||
void butterworth_compute(float fc);
|
||||
void bilinear(float a0, float a1, float a2,
|
||||
float b0, float b1, float b2,
|
||||
float *k, int stage);
|
||||
void bilinear_s2z(float *a0, float *a1, float *a2,
|
||||
float *b0, float *b1, float *b2,
|
||||
float fc, float fs, float *k, int stage);
|
||||
|
||||
public:
|
||||
|
||||
FreqFilter(int order, float fs, float cutoff, float Qfactor = 1.0f);
|
||||
~FreqFilter();
|
||||
|
||||
void update( int16_t *data, unsigned int num );
|
||||
};
|
||||
|
||||
|
||||
|
||||
class BitCrusher {
|
||||
|
||||
private:
|
||||
float factor, devider;
|
||||
|
||||
public:
|
||||
|
||||
// level ranges from 0.0f (all muted) to 1.0f (no change)
|
||||
BitCrusher(float level);
|
||||
~BitCrusher();
|
||||
|
||||
void update( int16_t *data, unsigned int num );
|
||||
};
|
||||
|
||||
}; // namespace simgear
|
||||
|
||||
#endif // _SIMGEAR_FREQUENCY_FILTER_HXX
|
@ -92,14 +92,14 @@ public:
|
||||
}
|
||||
|
||||
void init() {
|
||||
_mtx = aax::Matrix();
|
||||
_mtx = aax::Matrix64();
|
||||
}
|
||||
|
||||
void update_pos_and_orientation()
|
||||
{
|
||||
SGVec3d sgv_at = _orientation.backTransform(-SGVec3d::e3());
|
||||
SGVec3d sgv_up = _orientation.backTransform(SGVec3d::e2());
|
||||
SGVec3f pos = SGVec3f::zeros();
|
||||
SGVec3d pos = SGVec3d::zeros();
|
||||
|
||||
_mtx.set(pos.data(), toVec3f(sgv_at).data(), toVec3f(sgv_up).data());
|
||||
|
||||
@ -107,7 +107,7 @@ public:
|
||||
}
|
||||
|
||||
aax::AeonWave _aax;
|
||||
aax::Matrix _mtx;
|
||||
aax::Matrix64 _mtx;
|
||||
|
||||
SGVec3d _absolute_pos;
|
||||
SGVec3d _base_pos;
|
||||
@ -338,7 +338,7 @@ void SGSoundMgr::update( double dt )
|
||||
TRY( dsp.set(AAX_SOUND_VELOCITY, 340.3f) );
|
||||
TRY( d->_aax.set(dsp) );
|
||||
#endif
|
||||
aax::Matrix mtx = d->_mtx;
|
||||
aax::Matrix64 mtx = d->_mtx;
|
||||
mtx.inverse();
|
||||
TRY( d->_aax.sensor_matrix(mtx) );
|
||||
|
||||
@ -465,7 +465,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
|
||||
}
|
||||
|
||||
bufid = d->_buffer_id++;
|
||||
d->_buffers.insert( std::make_pair<unsigned int,aax::Buffer&>(bufid,buf) );
|
||||
d->_buffers.insert( {bufid, buf} );
|
||||
|
||||
if ( !sample->is_file() ) {
|
||||
enum aaxFormat format = AAX_FORMAT_NONE;
|
||||
@ -493,7 +493,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
|
||||
unsigned int no_samples = sample->get_no_samples();
|
||||
unsigned int no_tracks = sample->get_no_tracks();
|
||||
unsigned int frequency = sample->get_frequency();
|
||||
TRY( buf.set(d->_aax, no_samples, no_tracks, format) );
|
||||
buf.set(d->_aax, no_samples, no_tracks, format);
|
||||
TRY( buf.set(AAX_FREQUENCY, frequency) );
|
||||
TRY( buf.fill(sample->get_data()) );
|
||||
|
||||
@ -659,11 +659,11 @@ void SGSoundMgr::update_sample_config( SGSoundSample *sample, SGVec3d& position,
|
||||
aax::Emitter& emitter = d->get_emitter(sample->get_source());
|
||||
aax::dsp dsp;
|
||||
|
||||
aax::Vector pos = toVec3f(position).data();
|
||||
aax::Vector64 pos = position.data();
|
||||
aax::Vector ori = orientation.data();
|
||||
aax::Vector vel = velocity.data();
|
||||
|
||||
aax::Matrix mtx(pos, ori);
|
||||
aax::Matrix64 mtx(pos, ori);
|
||||
TRY( emitter.matrix(mtx) );
|
||||
TRY( emitter.velocity(vel) );
|
||||
|
||||
@ -763,7 +763,8 @@ void SGSoundMgr::set_position( const SGVec3d& pos, const SGGeod& pos_geod )
|
||||
|
||||
SGVec3f SGSoundMgr::get_direction() const
|
||||
{
|
||||
aaxVec3f pos, at, up;
|
||||
aaxVec3f at, up;
|
||||
aaxVec3d pos;
|
||||
d->_mtx.get(pos, at, up);
|
||||
return SGVec3f( at );
|
||||
}
|
||||
|
@ -60,14 +60,13 @@ add_executable(test_expressions expression_test.cxx)
|
||||
target_link_libraries(test_expressions ${TEST_LIBS})
|
||||
add_test(expressions ${EXECUTABLE_OUTPUT_PATH}/test_expressions)
|
||||
|
||||
add_executable(test_shared_ptr shared_ptr_test.cpp)
|
||||
target_link_libraries(test_shared_ptr ${TEST_LIBS})
|
||||
add_test(shared_ptr ${EXECUTABLE_OUTPUT_PATH}/test_shared_ptr)
|
||||
|
||||
endif(ENABLE_TESTS)
|
||||
|
||||
add_boost_test(function_list
|
||||
SOURCES function_list_test.cxx
|
||||
LIBRARIES ${TEST_LIBS}
|
||||
)
|
||||
|
||||
add_boost_test(shared_ptr
|
||||
SOURCES shared_ptr_test.cpp
|
||||
LIBRARIES ${TEST_LIBS}
|
||||
)
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
|
||||
static unsigned get(const SGReferenced* ref)
|
||||
{ if (ref) return ++(ref->_refcount); else return 0; }
|
||||
static unsigned put(const SGReferenced* ref)
|
||||
static unsigned put(const SGReferenced* ref) noexcept
|
||||
{ if (ref) return --(ref->_refcount); else return 0; }
|
||||
static unsigned count(const SGReferenced* ref)
|
||||
{ if (ref) return ref->_refcount; else return 0; }
|
||||
|
@ -20,8 +20,9 @@
|
||||
#ifndef SGSharedPtr_HXX
|
||||
#define SGSharedPtr_HXX
|
||||
|
||||
#include <simgear/sg_inlines.h>
|
||||
|
||||
#include "SGReferenced.hxx"
|
||||
#include <algorithm>
|
||||
|
||||
template<typename T>
|
||||
class SGWeakPtr;
|
||||
@ -50,12 +51,16 @@ class SGSharedPtr {
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
SGSharedPtr(void) : _ptr(0)
|
||||
SGSharedPtr(void) noexcept
|
||||
: _ptr(0)
|
||||
{}
|
||||
SGSharedPtr(T* ptr) : _ptr(ptr)
|
||||
{ get(_ptr); }
|
||||
SGSharedPtr(const SGSharedPtr& p) : _ptr(p.get())
|
||||
{ get(_ptr); }
|
||||
SGSharedPtr(SGSharedPtr&& other) noexcept
|
||||
: SGSharedPtr()
|
||||
{ swap(other); }
|
||||
template<typename U>
|
||||
SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.get())
|
||||
{ get(_ptr); }
|
||||
@ -64,9 +69,20 @@ public:
|
||||
{ reset(p.lock().get()); }
|
||||
~SGSharedPtr(void)
|
||||
{ reset(); }
|
||||
|
||||
|
||||
SGSharedPtr& operator=(const SGSharedPtr& p)
|
||||
{ reset(p.get()); return *this; }
|
||||
|
||||
SGSharedPtr& operator=(SGSharedPtr&& p) noexcept
|
||||
{ // Whether self-move is to be supported at all is controversial, let's
|
||||
// take the conservative approach for now
|
||||
if (this != &p) {
|
||||
swap(p);
|
||||
p.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
SGSharedPtr& operator=(const SGSharedPtr<U>& p)
|
||||
{ reset(p.get()); return *this; }
|
||||
@ -86,7 +102,7 @@ public:
|
||||
{ return _ptr; }
|
||||
T* release()
|
||||
{ T* tmp = _ptr; _ptr = 0; T::put(tmp); return tmp; }
|
||||
void reset()
|
||||
void reset() noexcept
|
||||
{ if (!T::put(_ptr)) delete _ptr; _ptr = 0; }
|
||||
void reset(T* p)
|
||||
{ SGSharedPtr(p).swap(*this); }
|
||||
@ -101,8 +117,8 @@ public:
|
||||
|
||||
void clear()
|
||||
{ reset(); }
|
||||
void swap(SGSharedPtr& other)
|
||||
{ std::swap(_ptr, other._ptr); }
|
||||
void swap(SGSharedPtr& other) noexcept
|
||||
{ simgear::noexceptSwap(_ptr, other._ptr); }
|
||||
|
||||
private:
|
||||
void assignNonRef(T* p)
|
||||
@ -118,6 +134,12 @@ private:
|
||||
friend class SGWeakPtr;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
void swap(SGSharedPtr<T>& a, SGSharedPtr<T>& b) noexcept
|
||||
{
|
||||
a.swap(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for boost::mem_fn
|
||||
*/
|
||||
|
@ -49,7 +49,7 @@ sg_location::sg_location (const char* path, int line, int column)
|
||||
setPath(path);
|
||||
}
|
||||
|
||||
sg_location::~sg_location () throw ()
|
||||
sg_location::~sg_location ()
|
||||
{
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ sg_throwable::sg_throwable (const char* message, const char* origin)
|
||||
setOrigin(origin);
|
||||
}
|
||||
|
||||
sg_throwable::~sg_throwable () throw ()
|
||||
sg_throwable::~sg_throwable ()
|
||||
{
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ sg_throwable::setOrigin (const char* origin)
|
||||
}
|
||||
}
|
||||
|
||||
const char* sg_throwable::what() const throw()
|
||||
const char* sg_throwable::what() const noexcept
|
||||
{
|
||||
try {
|
||||
return getMessage();
|
||||
@ -215,7 +215,7 @@ sg_error::sg_error(const std::string& message, const std::string& origin)
|
||||
{
|
||||
}
|
||||
|
||||
sg_error::~sg_error () throw ()
|
||||
sg_error::~sg_error ()
|
||||
{
|
||||
}
|
||||
|
||||
@ -239,7 +239,7 @@ sg_exception::sg_exception( const std::string& message,
|
||||
{
|
||||
}
|
||||
|
||||
sg_exception::~sg_exception () throw ()
|
||||
sg_exception::~sg_exception ()
|
||||
{
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ sg_io_exception::sg_io_exception( const std::string& message,
|
||||
{
|
||||
}
|
||||
|
||||
sg_io_exception::~sg_io_exception () throw ()
|
||||
sg_io_exception::~sg_io_exception ()
|
||||
{
|
||||
}
|
||||
|
||||
@ -335,7 +335,7 @@ sg_format_exception::sg_format_exception( const std::string& message,
|
||||
setText(text.c_str());
|
||||
}
|
||||
|
||||
sg_format_exception::~sg_format_exception () throw ()
|
||||
sg_format_exception::~sg_format_exception ()
|
||||
{
|
||||
}
|
||||
|
||||
@ -379,7 +379,7 @@ sg_range_exception::sg_range_exception(const std::string& message,
|
||||
{
|
||||
}
|
||||
|
||||
sg_range_exception::~sg_range_exception () throw ()
|
||||
sg_range_exception::~sg_range_exception ()
|
||||
{
|
||||
}
|
||||
// end of exception.cxx
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
sg_location(const std::string& path, int line = -1, int column = -1);
|
||||
sg_location(const SGPath& path, int line = -1, int column = -1);
|
||||
explicit sg_location(const char* path, int line = -1, int column = -1);
|
||||
virtual ~sg_location() throw ();
|
||||
virtual ~sg_location();
|
||||
virtual const char* getPath() const;
|
||||
virtual void setPath (const char* path);
|
||||
virtual int getLine () const;
|
||||
@ -58,13 +58,13 @@ public:
|
||||
enum {MAX_TEXT_LEN = 1024};
|
||||
sg_throwable ();
|
||||
sg_throwable (const char* message, const char* origin = 0);
|
||||
virtual ~sg_throwable () throw ();
|
||||
virtual ~sg_throwable ();
|
||||
virtual const char* getMessage () const;
|
||||
virtual const std::string getFormattedMessage () const;
|
||||
virtual void setMessage (const char* message);
|
||||
virtual const char* getOrigin () const;
|
||||
virtual void setOrigin (const char *origin);
|
||||
virtual const char* what() const throw();
|
||||
virtual const char* what() const noexcept;
|
||||
private:
|
||||
char _message[MAX_TEXT_LEN];
|
||||
char _origin[MAX_TEXT_LEN];
|
||||
@ -87,7 +87,7 @@ public:
|
||||
sg_error ();
|
||||
sg_error (const char* message, const char* origin = 0);
|
||||
sg_error (const std::string& message, const std::string& origin = "");
|
||||
virtual ~sg_error () throw ();
|
||||
virtual ~sg_error ();
|
||||
};
|
||||
|
||||
|
||||
@ -111,7 +111,7 @@ public:
|
||||
sg_exception ();
|
||||
sg_exception (const char* message, const char* origin = 0);
|
||||
sg_exception (const std::string& message, const std::string& = "");
|
||||
virtual ~sg_exception () throw ();
|
||||
virtual ~sg_exception ();
|
||||
};
|
||||
|
||||
|
||||
@ -136,8 +136,8 @@ public:
|
||||
sg_io_exception (const std::string &message, const std::string &origin = "");
|
||||
sg_io_exception (const std::string &message, const sg_location &location,
|
||||
const std::string &origin = "");
|
||||
|
||||
virtual ~sg_io_exception () throw ();
|
||||
|
||||
virtual ~sg_io_exception ();
|
||||
virtual const std::string getFormattedMessage () const;
|
||||
virtual const sg_location &getLocation () const;
|
||||
virtual void setLocation (const sg_location &location);
|
||||
@ -165,7 +165,7 @@ public:
|
||||
const char* origin = 0);
|
||||
sg_format_exception (const std::string& message, const std::string& text,
|
||||
const std::string& origin = "");
|
||||
virtual ~sg_format_exception () throw ();
|
||||
virtual ~sg_format_exception ();
|
||||
virtual const char* getText () const;
|
||||
virtual void setText (const char* text);
|
||||
private:
|
||||
@ -190,7 +190,7 @@ public:
|
||||
const char* origin = 0);
|
||||
sg_range_exception (const std::string& message,
|
||||
const std::string& origin = "");
|
||||
virtual ~sg_range_exception () throw ();
|
||||
virtual ~sg_range_exception ();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,6 +1,13 @@
|
||||
/// Unit tests for reference counting and smart pointer classes
|
||||
#define BOOST_TEST_MODULE structure
|
||||
#include <BoostTestTargetConfig.h>
|
||||
// -*- coding: utf-8 -*-
|
||||
//
|
||||
// Unit tests for reference counting and smart pointer classes
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include <cstdlib> // EXIT_SUCCESS
|
||||
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
|
||||
#include "SGSharedPtr.hxx"
|
||||
#include "SGWeakPtr.hxx"
|
||||
@ -21,33 +28,152 @@ struct ReferenceCounted:
|
||||
};
|
||||
typedef SGSharedPtr<ReferenceCounted> RefPtr;
|
||||
|
||||
BOOST_AUTO_TEST_CASE( shared_ptr )
|
||||
void test_SGSharedPtr()
|
||||
{
|
||||
BOOST_REQUIRE_EQUAL( ReferenceCounted::count(0), 0 );
|
||||
std::cout << "Testing SGSharedPtr and SGReferenced" << std::endl;
|
||||
|
||||
SG_CHECK_EQUAL( ReferenceCounted::count(0), 0 );
|
||||
|
||||
RefPtr ptr( new ReferenceCounted() );
|
||||
BOOST_REQUIRE_EQUAL( instance_count, 1 );
|
||||
BOOST_REQUIRE_EQUAL( ReferenceCounted::count(ptr.get()), 1 );
|
||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 1 );
|
||||
SG_CHECK_EQUAL( instance_count, 1 );
|
||||
SG_CHECK_EQUAL( ReferenceCounted::count(ptr.get()), 1 );
|
||||
SG_CHECK_EQUAL( ptr.getNumRefs(), 1 );
|
||||
|
||||
// Test SGSharedPtr's copy assignment operator
|
||||
RefPtr ptr2 = ptr;
|
||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 2 );
|
||||
BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptr.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptr2.getNumRefs(), 2 );
|
||||
|
||||
BOOST_REQUIRE_EQUAL( ptr, ptr2 );
|
||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() );
|
||||
SG_CHECK_EQUAL( ptr, ptr2 );
|
||||
SG_CHECK_EQUAL( ptr.get(), ptr2.get() );
|
||||
|
||||
// Test SGSharedPtr::reset() with no argument
|
||||
ptr.reset();
|
||||
BOOST_REQUIRE( !ptr.get() );
|
||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 0 );
|
||||
BOOST_REQUIRE_EQUAL( ReferenceCounted::count(ptr2.get()), 1 );
|
||||
BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 1 );
|
||||
SG_CHECK_IS_NULL( ptr.get() );
|
||||
SG_CHECK_EQUAL( ptr.getNumRefs(), 0 );
|
||||
SG_CHECK_EQUAL( ReferenceCounted::count(ptr2.get()), 1 );
|
||||
SG_CHECK_EQUAL( ptr2.getNumRefs(), 1 );
|
||||
|
||||
ptr2.reset();
|
||||
BOOST_REQUIRE( !ptr2.get() );
|
||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 0 );
|
||||
BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 0 );
|
||||
BOOST_REQUIRE_EQUAL( instance_count, 0) ;
|
||||
SG_CHECK_IS_NULL( ptr2.get() );
|
||||
SG_CHECK_EQUAL( ptr.getNumRefs(), 0 );
|
||||
SG_CHECK_EQUAL( ptr2.getNumRefs(), 0 );
|
||||
SG_CHECK_EQUAL( instance_count, 0) ;
|
||||
|
||||
// Test operator==() and operator!=() for SGSharedPtr
|
||||
{
|
||||
RefPtr ptrA(new ReferenceCounted());
|
||||
RefPtr ptrB(ptrA);
|
||||
RefPtr ptrC(new ReferenceCounted());
|
||||
RefPtr emptyPtr{};
|
||||
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||
SG_CHECK_EQUAL( ptrA.get(), ptrB.get() ); // same thing by definition
|
||||
SG_CHECK_NE( ptrA, ptrC );
|
||||
SG_CHECK_NE( ptrA.get(), ptrC.get() );
|
||||
SG_CHECK_NE( ptrB, ptrC );
|
||||
SG_CHECK_NE( ptrA, emptyPtr );
|
||||
SG_CHECK_EQUAL( emptyPtr, emptyPtr );
|
||||
}
|
||||
|
||||
// Test SGSharedPtr::reset(T* p) and SGSharedPtr::operator T*()
|
||||
{
|
||||
RefPtr ptrA(new ReferenceCounted());
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 1 );
|
||||
|
||||
RefPtr ptrB(new ReferenceCounted());
|
||||
SG_CHECK_NE( ptrA, ptrB );
|
||||
ptrB.reset(ptrA);
|
||||
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||
|
||||
RefPtr ptrC(new ReferenceCounted());
|
||||
SG_CHECK_NE( ptrA, ptrC );
|
||||
SG_CHECK_EQUAL( ptrC.getNumRefs(), 1 );
|
||||
// ptrA is implicit converted to ReferenceCounted*
|
||||
ptrC.reset(ptrA);
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 3 );
|
||||
SG_CHECK_EQUAL( ptrB.getNumRefs(), 3 );
|
||||
SG_CHECK_EQUAL( ptrC.getNumRefs(), 3 );
|
||||
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||
SG_CHECK_EQUAL( ptrB, ptrC );
|
||||
}
|
||||
|
||||
// Test SGSharedPtr's copy constructor
|
||||
{
|
||||
RefPtr ptrA(new ReferenceCounted());
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 1 );
|
||||
|
||||
RefPtr ptrB(ptrA);
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||
}
|
||||
|
||||
// Test SGSharedPtr's move constructor
|
||||
{
|
||||
RefPtr ptrA(new ReferenceCounted());
|
||||
RefPtr ptrB(ptrA);
|
||||
RefPtr ptrC(std::move(ptrA));
|
||||
|
||||
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptrC.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptrB, ptrC );
|
||||
// Although our implementation has these two properties, they are
|
||||
// absolutely *not* guaranteed by the C++ move semantics:
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 0 );
|
||||
SG_CHECK_IS_NULL( ptrA.get() );
|
||||
}
|
||||
|
||||
// Test SGSharedPtr's move assignment operator: self-move, supposedly
|
||||
// undefined behavior but certainly safer as a no-op---which the
|
||||
// copy-and-swap idiom offers for free.
|
||||
{
|
||||
RefPtr ptrA(new ReferenceCounted());
|
||||
RefPtr ptrB(ptrA);
|
||||
|
||||
ptrA = std::move(ptrA);
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||
SG_CHECK_IS_NOT_NULL( ptrA.get() );
|
||||
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||
}
|
||||
|
||||
// Test SGSharedPtr's move assignment operator: move to an empty SGSharedPtr
|
||||
{
|
||||
RefPtr ptrA;
|
||||
RefPtr ptrB(new ReferenceCounted());
|
||||
|
||||
ptrA = std::move(ptrB);
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 1 );
|
||||
SG_CHECK_IS_NOT_NULL( ptrA.get() );
|
||||
// Implementation detail that is *not* guaranteed by the C++ move
|
||||
// semantics:
|
||||
SG_CHECK_EQUAL( ptrB.getNumRefs(), 0 );
|
||||
SG_CHECK_IS_NULL( ptrB.get() );
|
||||
}
|
||||
|
||||
// Test SGSharedPtr's move assignment operator: move to a non-empty
|
||||
// SGSharedPtr
|
||||
{
|
||||
RefPtr ptrA(new ReferenceCounted());
|
||||
RefPtr ptrB(ptrA);
|
||||
RefPtr ptrC(new ReferenceCounted());
|
||||
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptrC.getNumRefs(), 1 );
|
||||
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||
SG_CHECK_NE( ptrA, ptrC );
|
||||
|
||||
ptrA = std::move(ptrC);
|
||||
SG_CHECK_EQUAL( ptrA.getNumRefs(), 1 );
|
||||
SG_CHECK_EQUAL( ptrB.getNumRefs(), 1 );
|
||||
SG_CHECK_NE( ptrA, ptrB );
|
||||
// Implementation detail that is *not* guaranteed by the C++ move
|
||||
// semantics:
|
||||
SG_CHECK_IS_NULL( ptrC.get() );
|
||||
}
|
||||
}
|
||||
|
||||
class Base1:
|
||||
@ -63,31 +189,41 @@ class VirtualDerived:
|
||||
public Base2
|
||||
{};
|
||||
|
||||
BOOST_AUTO_TEST_CASE( virtual_weak_ptr )
|
||||
void test_SGWeakPtr()
|
||||
{
|
||||
std::cout << "Testing SGWeakPtr and SGVirtualWeakReferenced" << std::endl;
|
||||
|
||||
SGSharedPtr<VirtualDerived> ptr( new VirtualDerived() );
|
||||
SGWeakPtr<VirtualDerived> weak_ptr( ptr );
|
||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 1 );
|
||||
SG_CHECK_EQUAL( ptr.getNumRefs(), 1 );
|
||||
|
||||
SGSharedPtr<Base1> ptr1( weak_ptr.lock() );
|
||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 2 );
|
||||
SG_CHECK_EQUAL( ptr.getNumRefs(), 2 );
|
||||
|
||||
// converting constructor
|
||||
BOOST_REQUIRE_EQUAL( SGSharedPtr<Base1>(weak_ptr), ptr1 );
|
||||
SG_CHECK_EQUAL( SGSharedPtr<Base1>(weak_ptr), ptr1 );
|
||||
|
||||
SGSharedPtr<Base2> ptr2( weak_ptr.lock() );
|
||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 3 );
|
||||
SG_CHECK_EQUAL( ptr.getNumRefs(), 3 );
|
||||
|
||||
BOOST_REQUIRE( ptr != NULL );
|
||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr1.get() );
|
||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() );
|
||||
SG_CHECK_IS_NOT_NULL( ptr );
|
||||
SG_CHECK_EQUAL( ptr.get(), ptr1.get() );
|
||||
SG_CHECK_EQUAL( ptr.get(), ptr2.get() );
|
||||
|
||||
SGWeakPtr<Base1> weak_base1( ptr );
|
||||
SGWeakPtr<Base2> weak_base2( ptr );
|
||||
ptr1 = dynamic_cast<VirtualDerived*>(weak_base1.lock().get());
|
||||
ptr2 = dynamic_cast<VirtualDerived*>(weak_base2.lock().get());
|
||||
|
||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr1.get() );
|
||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() );
|
||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 3 );
|
||||
SG_CHECK_EQUAL( ptr.get(), ptr1.get() );
|
||||
SG_CHECK_EQUAL( ptr.get(), ptr2.get() );
|
||||
SG_CHECK_EQUAL( ptr.getNumRefs(), 3 );
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
test_SGSharedPtr();
|
||||
test_SGWeakPtr();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
# include <simgear_config.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/timing/timestamp.hxx>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user