Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next

This commit is contained in:
gallaert 2017-11-17 18:46:21 +00:00
commit 12bed8e8ad
45 changed files with 974 additions and 165 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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
(

View File

@ -19,6 +19,8 @@
# include <simgear_config.h>
#endif
#include <algorithm>
#include <simgear/compiler.h>
#include "HLAArrayDataType.hxx"

View File

@ -19,6 +19,8 @@
# include <simgear_config.h>
#endif
#include <algorithm>
#include <simgear/compiler.h>
#include "HLADataType.hxx"

View File

@ -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"

View File

@ -19,10 +19,11 @@
# include <simgear_config.h>
#endif
#include <algorithm>
#include <simgear/compiler.h>
#include "HLAFixedRecordDataType.hxx"
#include "HLADataTypeVisitor.hxx"
#include "HLAFixedRecordDataElement.hxx"

View File

@ -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"

View File

@ -19,6 +19,8 @@
# include <simgear_config.h>
#endif
#include <algorithm>
#include <simgear/compiler.h>
#include "HLAObjectClass.hxx"

View File

@ -19,10 +19,11 @@
# include <simgear_config.h>
#endif
#include <algorithm>
#include <simgear/compiler.h>
#include "HLAVariantRecordDataType.hxx"
#include "HLADataTypeVisitor.hxx"
#include "HLAVariantRecordDataElement.hxx"

View File

@ -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 {

View File

@ -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

View File

@ -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;
}

View File

@ -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
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -39,7 +39,7 @@ namespace nasal
}
//----------------------------------------------------------------------------
bad_nasal_cast::~bad_nasal_cast() throw()
bad_nasal_cast::~bad_nasal_cast()
{
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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();

View File

@ -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,

View File

@ -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.
*/

View File

@ -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;

View File

@ -9,6 +9,7 @@
#include <simgear/compiler.h>
#include <algorithm>
#include <memory> // std::unique_ptr
#include <iostream>
#include <map>

View File

@ -85,7 +85,7 @@ BuilderException::BuilderException(const std::string& message,
{
}
BuilderException::~BuilderException() throw()
BuilderException::~BuilderException()
{
}

View File

@ -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();
};
}

View File

@ -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()));
}

View File

@ -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

View File

@ -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");
}
};

View File

@ -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);

View File

@ -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

View File

@ -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()

View File

@ -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
View 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
View 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

View File

@ -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 );
}

View File

@ -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}
)

View File

@ -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; }

View File

@ -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
*/

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -22,6 +22,8 @@
# include <simgear_config.h>
#endif
#include <algorithm>
#include <simgear/debug/logstream.hxx>
#include <simgear/timing/timestamp.hxx>