diff options
Diffstat (limited to 'src/system')
69 files changed, 11126 insertions, 0 deletions
diff --git a/src/system/Qt3DSArray.h b/src/system/Qt3DSArray.h new file mode 100644 index 0000000..805b8b0 --- /dev/null +++ b/src/system/Qt3DSArray.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once +#include "Qt3DSMemorySettings.h" +#include "Qt3DSMemory.h" +#include "Qt3DSPlatformSpecific.h" + +#ifdef WIN32 +#pragma warning(disable : 4625) // copy constructor could not be generated because a base class copy + // constructor is inaccessible +#pragma warning(disable : 4626) // assignment operator could not be generated because a base class + // assignment operator is inaccessible +#endif + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Constants +//============================================================================== +#define NVARRAY_NOTFOUND -1 + +//============================================================================== +/** + * Ordered Collection also knows as a vector. + * + * Use Reserve or the constructor parameter if you know how many slots + * will be needed to prevent frequent reallocations during growth. + * + * The array grows by DEFAULT_GROWFACTOR aka 20% whenever it overflows. By + * setting the factor to 0 it will still clamp to 1 and instead grow the + * array by one slot at a time. This is not ideal but given a pooled memory + * manager you will not thrash memory too much since you will grow inside + * each pool chunk and only reallocate when switching pools. + * + * Naming of CArray instances are used to enable memory tracking of arrays + * that have gone berzerk or less frequently used instances that could be + * released after usage. + * + * The FOR_ARRAY macro is the preferred way to process all array slots. + */ +template <class T> +class CArray +{ +//============================================================================== +// Constants +//============================================================================== +#define DEFAULT_GROWFACTOR 1.2f + + //============================================================================== + // Types + //============================================================================== +public: + typedef T TType; ///< Easy access to template type + + //============================================================================== + // Fields + //============================================================================== +protected: + CHAR m_Name[32]; ///< Allows easy ID using memory reporting + T *m_Data; ///< Allocated memory containing array data + INT32 m_Capacity; ///< Max number of slots possible + INT32 m_Count; ///< Current number of slots in array + FLOAT m_GrowFactor; ///< Factor by which array grows when out of space + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + inline CArray(const INT32 inCapacity = 0, const FLOAT inGrowFactor = DEFAULT_GROWFACTOR, + const CHAR *inName = NULL); + inline CArray(const CArray<T> &); + inline ~CArray(); + +public: // Management + inline void SetName(const CHAR *inName = NULL); + inline INT32 GetCount() const; + inline INT32 GetCapacity() const; + inline void Clear(const BOOL inRelease = true); + inline void Reserve(const INT32 inCapacity, const BOOL inExpand = false); + +public: // Stack access + void Push(const T &inValue); + inline const T &Pop(); + inline const T &Top() const; + +public: // Random access + inline INT32 GetIndex(const T &inValue) const; + inline T &operator[](const INT32 inIndex) const; + inline void Remove(const INT32 inIndex); + +public: // FOR_ARRAY iteration + inline T *Begin() const; + inline T *End() const; + +private: // Disabled Copy Construction + inline CArray<T> &operator=(const CArray<T> &); +}; + +} // namespace Q3DStudio + +//============================================================================== +// Template code +//============================================================================== +#include "Qt3DSArray.inl" diff --git a/src/system/Qt3DSArray.inl b/src/system/Qt3DSArray.inl new file mode 100644 index 0000000..a9667fd --- /dev/null +++ b/src/system/Qt3DSArray.inl @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2007 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor + * + * @param inCapacity preallocated number of slots to avoid growth reallocation + * @param inGrowFactor factor by which the array grows when out of space + * @param inName 32 byte unique identifier for memory tracking + */ +template <typename T> inline +CArray<T>::CArray( const INT32 inCapacity, const FLOAT inGrowFactor, const CHAR* inName ) : + m_Data( NULL ), + m_Capacity( 0 ), + m_Count( 0 ), + m_GrowFactor( inGrowFactor ) +{ + // Disallow negative growth + if ( m_GrowFactor < 1.0f ) + m_GrowFactor = DEFAULT_GROWFACTOR; + + SetName( inName ); + Reserve( inCapacity ); +} + +//============================================================================== +/** + * Berger's Copy Constructor. + */ +template <typename T> inline +CArray<T>::CArray( const CArray<T>& inOther ) : + m_Data( NULL ), + m_Capacity( 0 ), + m_Count( 0 ), + m_GrowFactor( inOther.m_GrowFactor ) +{ + // Disallow negative growth + if ( m_GrowFactor < 1.0f ) + m_GrowFactor = DEFAULT_GROWFACTOR; + + SetName( inOther.m_Name ); + Reserve( inOther.m_Capacity ); + FOR_ARRAY( T, theTemp, inOther ) + { + Push( *theTemp ); + } +} + +//============================================================================== +/** + * Destructor + */ +template <class T> inline +CArray<T>::~CArray( ) +{ + Clear( true ); +} + +//============================================================================== +/** + * Name an array instance to easily identify it during memory reporting. + * @param inName 32 byte unique identifier + */ +template <class T> inline +void CArray<T>::SetName( const CHAR* inName /*= NULL*/ ) +{ + Q3DStudio_sprintf( m_Name, sizeof( m_Name ), "%s", inName ? inName : "CArray<T>" ); +} + +//============================================================================== +/** + * Count is the number of elements in the array. + * @return current count of the array + */ +template <class T> inline +INT32 CArray<T>::GetCount( ) const +{ + return m_Count; +} + +//============================================================================== +/** + * Get the capacity of the array + * Capacity reflects the max count before reallocation happens. + * @return capacity of the array + */ +template <class T> inline +INT32 CArray<T>::GetCapacity( ) const +{ + return m_Capacity; +} + +//============================================================================== +/** + * Clear the array by reducing the number of elements to zero. + * + * Using the release flag keeps the memory load low but could be + * suboptimal in situations where you are always using roughly the same + * number of elements. In that scenario, the array would have to build up + * and reallocate up to the same number of elements every time causing + * stress on the system. Clearing but keeping the buffer by setting + * release to false is optimal in that case. + * + * @param inRelease true to release memory, false keeps old buffer + */ +template <class T> inline +void CArray<T>::Clear( const BOOL inRelease ) +{ + m_Count = 0; + + if ( inRelease ) + { + Q3DStudio_free( m_Data, T, m_Capacity ); + m_Capacity = 0; + m_Data = NULL; + } + else + Q3DStudio_memset( m_Data, 0 , sizeof( T ) * m_Capacity ); +} + +//============================================================================== +/** + * Allocate enough memory to store T. + * + * If current memory is not sufficient, new block of memory is allocated and + * data in current memory is copied to the new block of memory. Data pointer will + * point to the new block of memory and current memory is released. + * + * @param inCapacity indicate the amount of memory required. + * @param inExpand true to not only allocate but also extend array + */ +template <class T> inline +void CArray<T>::Reserve( const INT32 inCapacity, const BOOL inExpand ) +{ + if ( inCapacity > m_Capacity ) + { + T* theData = Q3DStudio_allocate_desc( T, inCapacity, m_Name ); + Q3DStudio_memset( theData, 0 , sizeof( T ) * inCapacity ); + if ( m_Data != NULL ) + { + Q3DStudio_memcpy( theData, m_Data, sizeof( T ) * m_Count ); + Q3DStudio_free( m_Data, T, m_Capacity ); + } + m_Data = theData; + m_Capacity = inCapacity; + } + + if ( inExpand ) + m_Count = inCapacity; +} + +//============================================================================== +/** + * Insert T to the end of the array + * @param inValue value of datatype T + */ +template <class T> inline +void CArray<T>::Push( const T& inValue ) +{ + if ( m_Count == m_Capacity ) + Reserve( static_cast<INT32>( m_GrowFactor * m_Capacity ) + 1 ); + + m_Data[m_Count++] = inValue; +} + +//============================================================================== +/** + * Remove and retrieve T which is at the end of the array + * @return value of datatype T + */ +template <class T> inline +const T& CArray<T>::Pop( ) +{ + return m_Data[--m_Count]; +} + +//============================================================================== +/** + * Get T which is at the end of the array + * @return reference of value of datatype T + */ +template <class T> inline +const T& CArray<T>::Top( ) const +{ + return m_Data[m_Count - 1]; +} + +//============================================================================== +/** + * Get index of first element that matches inValue + * @return index of element matching T or INDEX_NOTFOUND + */ +template <class T> inline +INT32 CArray<T>::GetIndex( const T& inValue ) const +{ + for ( INT32 theIndex = 0; theIndex < m_Count; ++theIndex ) + if ( inValue == m_Data[theIndex] ) + return theIndex; + return NVARRAY_NOTFOUND; +} + +//============================================================================== +/** + * Get the element at a particular index position of the array. + * @note Range checking is only done is debug builds. + * @param inIndex the index of the array + * @return reference of value of datatype T + */ +template <class T> inline +T& CArray<T>::operator[]( const INT32 inIndex ) const +{ + Q3DStudio_ASSERT( inIndex >= 0 && inIndex < m_Capacity ); + return m_Data[inIndex]; +} + +//============================================================================== +/** + * Remove T that resides at a particular index position of the array. + * Other T data with higher index value is shifted to occupy the empty slot + * created in the removal process. + * @param inIndex the index of the array + */ +template <class T> inline +void CArray<T>::Remove( const INT32 inIndex ) +{ + Q3DStudio_memmove( m_Data + inIndex, m_Data + inIndex + 1, sizeof( T ) * ( m_Count - inIndex - 1 ) ); + --m_Count; +} + +//============================================================================== +/** + * Get T at the first index of the array. + * Mainly used for FOR_ARRAY macro implementation + * @return pointer to first value in array + */ +template <class T> inline +T* CArray<T>::Begin( ) const +{ + return m_Data; +} + +//============================================================================== +/** + * Get T at the last index of the array. + * Mainly used for FOR_ARRAY macro implementation + * @return pointer to one beyond last value in array + */ +template <class T> inline +T* CArray<T>::End( ) const +{ + return m_Data + m_Count; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSAssert.cpp b/src/system/Qt3DSAssert.cpp new file mode 100644 index 0000000..63d3876 --- /dev/null +++ b/src/system/Qt3DSAssert.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSAssert.h" +#include "foundation/Qt3DSLogging.h" +//============================================================================== +// Platform Specific Includes +//============================================================================== +#if defined(_PCPLATFORM) +#pragma warning(push, 3) +#include <Windows.h> +#include <crtdbg.h> +#pragma warning(pop) +#endif // #if defined (_PCPLATFORM) + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Global Variables +//============================================================================== +CAssert::TFunction CAssert::s_AssertFunction = CAssert::Default; ///< Default assert function + +//============================================================================== +/** + * Default method for asserts + */ +void CAssert::Default(const CHAR *inAssert, const CHAR *inFile, INT32 inLine, + const CHAR *inFunction) +{ + // Use logger to report the string first + qCCritical (qt3ds::INTERNAL_ERROR) << "Assertion failed: " << inFile << " " << inLine + << " " << inAssert << " " << inFunction; + +#if defined(_DEBUG) && defined(_PCPLATFORM) && defined(QT3DS_VC) + if (_CrtDbgReport(_CRT_ASSERT, inFile, inLine, inFunction, "Assertion Failed") == 1) + ::DebugBreak(); +#endif // _DEBUG & _PCPLATFORM +} + +//============================================================================== +/** + * Method for setting the assert function + */ +void CAssert::SetFunction(TFunction inAssert) +{ + s_AssertFunction = inAssert; +} + +//============================================================================== +/** + * Method for getting the assert function + */ +CAssert::TFunction CAssert::GetFunction() +{ + return s_AssertFunction; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSAssert.h b/src/system/Qt3DSAssert.h new file mode 100644 index 0000000..a64ca7f --- /dev/null +++ b/src/system/Qt3DSAssert.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#include "Qt3DSTypes.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Static gateway for all asserts. + * + * By setting your own assert function you can redirect all Runtime asserts. + * By default it uses the internal Default method that uses CLog for output + * and displays a dialog on Windows PCs. + */ +class CAssert +{ + //============================================================================== + // Typedefs + //============================================================================== +public: + typedef void (*TFunction)(const Q3DStudio::CHAR *inAssert, const Q3DStudio::CHAR *inFile, + Q3DStudio::INT32 inLine, const Q3DStudio::CHAR *inFunction); + + //============================================================================== + // Fields + //============================================================================== +protected: + static TFunction s_AssertFunction; ///< Function pointer to active assert function + + //============================================================================== + // Methods + //============================================================================== +private: // Hidden Constructor + CAssert(); + +public: // Static Usage + static void Default(const Q3DStudio::CHAR *inAssert, const Q3DStudio::CHAR *inFile, + Q3DStudio::INT32 inLine, const Q3DStudio::CHAR *inFunction); + +public: // Static Configuration + static void SetFunction(TFunction inAssert); + static TFunction GetFunction(); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSAudioPlayer.h b/src/system/Qt3DSAudioPlayer.h new file mode 100644 index 0000000..3b6f3ef --- /dev/null +++ b/src/system/Qt3DSAudioPlayer.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2012 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +namespace Q3DStudio { + +class IAudioPlayer +{ +public: + virtual ~IAudioPlayer() {} + virtual bool PlaySoundFile(const char *inFilePath) = 0; +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSBasicPluginDLL.h b/src/system/Qt3DSBasicPluginDLL.h new file mode 100644 index 0000000..63a2d1f --- /dev/null +++ b/src/system/Qt3DSBasicPluginDLL.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//============================================================================== +// Includes +//============================================================================== +#pragma once + +#include <QtGlobal> + +#ifdef __cplusplus +extern "C" { +#endif + +//============================================================================== +// Enums +//============================================================================== +typedef enum _EDLLSTATUS { EDLLSTATUS_FAIL = 0, EDLLSTATUS_OK } EDLLSTATUS; + +// GetPluginType should return this +typedef enum _EDLLTYPE { + EDLLTYPE_UNKNOWN = 0, + EDLLTYPE_RENDERABLE_PLUGIN, + EDLLTYPE_CUSTOM_OBJECT, +} EDLLTYPE; + +//============================================================================== +// Function declarations +//============================================================================== + +//============================================================================== +/** + * Return the plugin type. + * @return plugin type + */ +typedef long (*PROC_GetPluginType)(); +Q_DECL_EXPORT long GetPluginType(); + +#ifdef __cplusplus +} +#endif diff --git a/src/system/Qt3DSBezierEval.h b/src/system/Qt3DSBezierEval.h new file mode 100644 index 0000000..c4d733a --- /dev/null +++ b/src/system/Qt3DSBezierEval.h @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +namespace Q3DStudio { + +//============================================================================== +/** + * Generic Bezier parametric curve evaluation at a given parametric value. + * @param inP0 control point P0 + * @param inP1 control point P1 + * @param inP2 control point P2 + * @param inP3 control point P3 + * @param inS the variable + * @return the evaluated value on the bezier curve + */ +inline FLOAT EvaluateBezierCurve(FLOAT inP0, FLOAT inP1, FLOAT inP2, FLOAT inP3, const FLOAT inS) +{ + // Using: + // Q(s) = Sum i=0 to 3 ( Pi * Bi,3(s)) + // where: + // Pi is a control point and + // Bi,3 is a basis function such that: + // + // B0,3(s) = (1 - s)^3 + // B1,3(s) = (3 * s) * (1 - s)^2 + // B2,3(s) = (3 * s^2) * (1 - s) + // B3,3(s) = s^3 + + /* FLOAT theSSquared = inS * inS; // + t^2 + FLOAT theSCubed = theSSquared * inS; // + t^3 + + FLOAT theSDifference = 1 - inS; // (1 - + t) + FLOAT theSDifferenceSquared = theSDifference * theSDifference; // (1 - + t)^2 + FLOAT theSDifferenceCubed = theSDifferenceSquared * theSDifference; // (1 - t)^3 + + FLOAT theFirstTerm = theSDifferenceCubed; // (1 - + t)^3 + FLOAT theSecondTerm = ( 3 * inS ) * theSDifferenceSquared; // (3 * t) * (1 + - t)^2 + FLOAT theThirdTerm = ( 3 * theSSquared ) * theSDifference; // (3 * t^2) * + (1 - t) + FLOAT theFourthTerm = theSCubed; // + t^3 + + // Q(t) = ( p0 * (1 - t)^3 ) + ( p1 * (3 * t) * (1 - t)^2 ) + ( p2 * (3 * t^2) * (1 - t) + ) + ( p3 * t^3 ) + return ( inP0 * theFirstTerm ) + ( inP1 * theSecondTerm ) + ( inP2 * theThirdTerm ) + ( + inP3 * theFourthTerm );*/ + + FLOAT theFactor = inS * inS; + inP1 *= 3 * inS; + inP2 *= 3 * theFactor; + theFactor *= inS; + inP3 *= theFactor; + + theFactor = 1 - inS; + inP2 *= theFactor; + theFactor *= 1 - inS; + inP1 *= theFactor; + theFactor *= 1 - inS; + inP0 *= theFactor; + + return inP0 + inP1 + inP2 + inP3; +} + +//============================================================================== +/** + * Inverse Bezier parametric curve evaluation to get parametric value for a given output. + * This is equal to finding the root(s) of the Bezier cubic equation. + * @param inP0 control point P0 + * @param inP1 control point P1 + * @param inP2 control point P2 + * @param inP3 control point P3 + * @param inX the variable + * @return the evaluated value + */ +inline FLOAT EvaluateInverseBezierCurve(const FLOAT inP0, const FLOAT inP1, const FLOAT inP2, + const FLOAT inP3, const FLOAT inX) +{ + FLOAT theResult = 0; + + // Using: + // Q(s) = Sum i=0 to 3 ( Pi * Bi,3(s)) + // where: + // Pi is a control point and + // Bi,3 is a basis function such that: + // + // B0,3(s) = (1 - s)^3 + // B1,3(s) = (3 * s) * (1 - s)^2 + // B2,3(s) = (3 * s^2) * (1 - s) + // B3,3(s) = s^3 + + // The Bezier cubic equation: + // inX = inP0*(1-s)^3 + inP1*(3*s)*(1-s)^2 + inP2*(3*s^2)*(1-s) + inP3*s^3 + // = s^3*( -inP0 + 3*inP1 - 3*inP2 +inP3 ) + s^2*( 3*inP0 - 6*inP1 + 3*inP2 ) + s*( -3*inP0 + // + 3*inP1 ) + inP0 + // For cubic eqn of the form: c[0] + c[1]*x + c[2]*x^2 + c[3]*x^3 = 0 + FLOAT theConstants[4]; + theConstants[0] = static_cast<FLOAT>(inP0 - inX); + theConstants[1] = static_cast<FLOAT>(-3 * inP0 + 3 * inP1); + theConstants[2] = static_cast<FLOAT>(3 * inP0 - 6 * inP1 + 3 * inP2); + theConstants[3] = static_cast<FLOAT>(-inP0 + 3 * inP1 - 3 * inP2 + inP3); + + FLOAT theSolution[3] = { 0 }; + + if (theConstants[3] == 0) { + if (theConstants[2] == 0) { + if (theConstants[1] == 0) + theResult = 0; + else + theResult = -theConstants[0] / theConstants[1]; // linear + } else { + // quadratic + INT32 theNumRoots = CCubicRoots::SolveQuadric(theConstants, theSolution); + theResult = static_cast<FLOAT>(theSolution[theNumRoots / 2]); + } + } else { + INT32 theNumRoots = CCubicRoots::SolveCubic(theConstants, theSolution); + theResult = static_cast<FLOAT>(theSolution[theNumRoots / 3]); + } + + return theResult; +} + +inline FLOAT EvaluateBezierKeyframe(FLOAT inTime, FLOAT inTime1, FLOAT inValue1, FLOAT inC1Time, + FLOAT inC1Value, FLOAT inC2Time, FLOAT inC2Value, FLOAT inTime2, + FLOAT inValue2) +{ + + // The special case of C1Time=0 and C2Time=0 is used to indicate Studio-native animation. + // Studio uses a simplified version of the bezier animation where the time control points + // are equally spaced between the starting and ending times. This avoids calling the expensive + // InverseBezierCurve function to find the right 's' given 't'. + FLOAT theParameter; + if (inC1Time == 0 && inC2Time == 0) { + // Special case signaling that it's ok to treat time as "s" + // This is done by assuming that Key1Val,Key1C1,Key1C2,Key2Val (aka P0,P1,P2,P3) + // are evenly distributed over time. + theParameter = (inTime - inTime1) / (inTime2 - inTime1); + } else { + // Compute the "s" parameter on the Bezier given the time + theParameter = EvaluateInverseBezierCurve(inTime1, inC1Time, inC2Time, inTime2, inTime); + if (theParameter <= 0.0f) + return inValue1; + if (theParameter >= 1.0f) + return inValue2; + } + + return EvaluateBezierCurve(inValue1, inC1Value, inC2Value, inValue2, theParameter); +} +} diff --git a/src/system/Qt3DSBoundingBox.cpp b/src/system/Qt3DSBoundingBox.cpp new file mode 100644 index 0000000..2a9331d --- /dev/null +++ b/src/system/Qt3DSBoundingBox.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSBoundingBox.h" +#include "Qt3DSMatrix.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor - creates an empty BoundingBox + */ +CBoundingBox::CBoundingBox() + : m_Min(1.0f, 1.0f, 1.0f) + , m_Max(-1.0f, -1.0f, -1.0f) +{ +} + +//============================================================================== +/** + * Make BoundingBox invalid + */ +void CBoundingBox::SetEmpty() +{ + m_Min.Set(1.0f, 1.0f, 1.0f); + m_Max.Set(-1.0f, -1.0f, -1.0f); +} + +//============================================================================== +/** + * Is the BoundingBox empty? + * @return true if bounding box is empty, false otherwise + */ +BOOL CBoundingBox::IsEmpty() const +{ + return (m_Min.m_X > m_Max.m_X); +} + +//============================================================================== +/** + * Add a point to the BoundingBox + * @param inPoint a 3D point + */ +void CBoundingBox::Add(const RuntimeVector3 &inPoint) +{ + if (IsEmpty()) { + m_Min = inPoint; + m_Max = inPoint; + } else { + m_Min.Minimize(inPoint); + m_Max.Maximize(inPoint); + } +} + +//============================================================================== +/** + * Add another BoundingBox to this BoundingBox + * @param inBox a 3D BoundingBox + */ +void CBoundingBox::Add(const CBoundingBox &inBox) +{ + if (!inBox.IsEmpty()) { + Add(inBox.GetMin()); + Add(inBox.GetMax()); + } +} + +//============================================================================== +/** + * Get the bounding box's smallest position + * @return the smallest position of the bounding box + */ +const RuntimeVector3 &CBoundingBox::GetMin() const +{ + return m_Min; +} + +//============================================================================== +/** + * Get the bounding box's largest position + * @return the largest position of the bounding box + */ +const RuntimeVector3 &CBoundingBox::GetMax() const +{ + return m_Max; +} + +//============================================================================== +/** + * Apply a transform to the BoundingBox + * @param inMatrix a 4x4 trasnform matrix + */ +void CBoundingBox::Transform(const RuntimeMatrix &inMatrix) +{ + // Apply transform to the 8 corners of the BoundingBox and renormalize to majox axes + CBoundingBox theTransformedBox; + RuntimeVector3 theCorners[8]; + + theCorners[0].Set(m_Min.m_X, m_Min.m_Y, m_Min.m_Z); + theCorners[1].Set(m_Min.m_X, m_Min.m_Y, m_Max.m_Z); + theCorners[2].Set(m_Min.m_X, m_Max.m_Y, m_Min.m_Z); + theCorners[3].Set(m_Min.m_X, m_Max.m_Y, m_Max.m_Z); + theCorners[4].Set(m_Max.m_X, m_Min.m_Y, m_Min.m_Z); + theCorners[5].Set(m_Max.m_X, m_Min.m_Y, m_Max.m_Z); + theCorners[6].Set(m_Max.m_X, m_Max.m_Y, m_Min.m_Z); + theCorners[7].Set(m_Max.m_X, m_Max.m_Y, m_Max.m_Z); + + for (INT32 theIndex = 0; theIndex < 8; ++theIndex) { + theCorners[theIndex].Transform(inMatrix); + theTransformedBox.Add(theCorners[theIndex]); + } + *this = theTransformedBox; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSBoundingBox.h b/src/system/Qt3DSBoundingBox.h new file mode 100644 index 0000000..988a9ba --- /dev/null +++ b/src/system/Qt3DSBoundingBox.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSVector3.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Forwards +//============================================================================== +class RuntimeMatrix; + +//============================================================================== +/** + * Axis aligned 3D bounding box construction and manipulation. + * + * Initial construction creates an inverted box signifying an Empty box instead + * of an infinitely small box at 0,0,0. Keep this in mind when asking for + * Min or max on a box that has had no points added to it. + * + * Transforming a box simply transforms all eight corners to span a new + * axis aligned bounding box. Successive transformations can thus create a + * non-optimal box, much larger than needed. + */ +class CBoundingBox +{ + //============================================================================== + // Fields + //============================================================================== +public: + RuntimeVector3 m_Min; ///< box minimum corner point + RuntimeVector3 m_Max; ///< box maximum corner point + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + CBoundingBox(); + +public: // Functions + BOOL IsEmpty() const; + void SetEmpty(); + void Add(const RuntimeVector3 &inPoint); + void Add(const CBoundingBox &inBox); + const RuntimeVector3 &GetMin() const; + const RuntimeVector3 &GetMax() const; + void Transform(const RuntimeMatrix &inMatrix); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSCircularArray.h b/src/system/Qt3DSCircularArray.h new file mode 100644 index 0000000..be92167 --- /dev/null +++ b/src/system/Qt3DSCircularArray.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Circular array. Not growable for now. + * The "streamlined" interface acts like a resource pool where construction of + * item T is minimized. + */ +template <class T> +class CCircularArray +{ + //============================================================================== + // Types + //============================================================================== +public: + typedef T TType; ///< Easy access to template type + + //============================================================================== + // Fields + //============================================================================== +protected: + CHAR m_Name[32]; ///< Allows easy ID if it grows too much + T *m_Data; ///< Allocated memory containing array data + INT32 m_Capacity; ///< Max number of elements possible + INT32 m_Count; ///< Current number of elements in array + + INT32 m_Begin; ///< circular list indices + INT32 m_End; ///< circular list indices + + // For 32-bit alignment + BOOL m_Full; ///< flag to indicate circular list is full + BOOL m_Paddings[3]; ///< Padding + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + inline CCircularArray(const INT32 inCapacity = 0, const CHAR *inName = NULL); + inline ~CCircularArray(); + +public: // Management + inline INT32 GetCount() const; + inline INT32 GetCapacity() const; + inline void Clear(const BOOL inRelease = false); + inline void Reserve(const INT32 inCapacity); + +public: // Stack access + inline T &NewEntry(); + inline void Pop(); + inline T &Top(); + +public: // Status + BOOL IsEmpty() const; + BOOL IsFull() const; + +protected: // Internal methods + void Increment(INT32 &outIndex); + void Decrement(INT32 &outIndex); + void UpdateFullStatus(); +}; + +} // namespace Q3DStudio + +//============================================================================== +// Template code +//============================================================================== +#include "Qt3DSCircularArray.inl" diff --git a/src/system/Qt3DSCircularArray.inl b/src/system/Qt3DSCircularArray.inl new file mode 100644 index 0000000..0d7f081 --- /dev/null +++ b/src/system/Qt3DSCircularArray.inl @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2007 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor + */ +template <typename T> inline +CCircularArray<T>::CCircularArray( const INT32 inCapacity, const CHAR* inName ) : + m_Data( NULL ), + m_Capacity( 0 ), + m_Count( 0 ), + m_Begin( 0 ), + m_End( 0 ), + m_Full( false ) +{ + Q3DStudio_sprintf( m_Name, sizeof( m_Name ), "%s", inName ? inName : "CircularArray" ); + Reserve( inCapacity ); +} + +//============================================================================== +/** + * Destructor + */ +template <class T> inline +CCircularArray<T>::~CCircularArray( ) +{ + Clear( true ); +} + +//============================================================================== +/** + * Get the number of items in the array + * @return the number of items in the array + */ +template <class T> inline +INT32 CCircularArray<T>::GetCount( ) const +{ + return m_Count; +} + +//============================================================================== +/** + * Get the capacity of the array + * @return the capacity of the array + */ +template <class T> inline +INT32 CCircularArray<T>::GetCapacity( ) const +{ + return m_Capacity; +} + +//============================================================================== +/** + * Remove all items from the array + * @param inRelease if true, release the allocated memory, if false, reset + * parameters back to zero. + */ +template <class T> inline +void CCircularArray<T>::Clear( const BOOL inRelease ) +{ + m_Count = 0; + m_Begin = 0; + m_End = 0; + m_Full = false; + + if ( inRelease ) + { + Q3DStudio_free( m_Data, T, m_Capacity ); + m_Capacity = 0; + m_Data = NULL; + } +} + +//============================================================================== +/** + * Change capacity of the array + * Assume no expansion for circular array + * @param inCapacity the new capacity to set + */ +template <class T> inline +void CCircularArray<T>::Reserve( const INT32 inCapacity ) +{ + Q3DStudio_ASSERT( !m_Data ); + T* theData = Q3DStudio_allocate_desc( T, inCapacity, m_Name ); + m_Data = theData; + m_Capacity = inCapacity; +} + +//============================================================================== +/** + * Create a new uninitialized item at the end of the array. + * The returned reference is used to initialize the item. + * @return a reference to the item + */ +template <class T> inline +T& CCircularArray<T>::NewEntry( ) +{ + Q3DStudio_ASSERT( !IsFull( ) ); + T& theResult = m_Data[m_End]; + Increment( m_End ); + UpdateFullStatus( ); + ++m_Count; + return theResult; +} + +//============================================================================== +/** + * Remove the top entry from the array + */ +template <class T> inline +void CCircularArray<T>::Pop( ) +{ + Q3DStudio_ASSERT( !IsEmpty( ) ); + Increment( m_Begin ); + m_Full = false; + --m_Count; +} + +//============================================================================== +/** + * Get the top item from the + * @return a reference to the item + */ +template <class T> inline +T& CCircularArray<T>::Top( ) +{ + Q3DStudio_ASSERT( !IsEmpty( ) ); + return m_Data[m_Begin]; +} + +//============================================================================== +/** + * Check if the array is empty + * @return true if empty, false otherwise. + */ +template <class T> inline +BOOL CCircularArray<T>::IsEmpty( ) const +{ + return ( m_Begin == m_End ) && !m_Full; +} + +//============================================================================== +/** + * Check if the array is full + * @return true if full, false otherwise. + */ +template <class T> inline +BOOL CCircularArray<T>::IsFull( ) const +{ + return m_Full; +} + +//============================================================================== +/** + * Increment index of the array + * @param outIndex the index to increment + */ +template <class T> inline +void CCircularArray<T>::Increment( INT32& outIndex ) +{ + ++outIndex; + // circular list wrap-around + if ( outIndex >= m_Capacity ) + outIndex = 0; +} + +//============================================================================== +/** + * Decrement index of the array + * @param outIndex the index to decrement + */ +template <class T> inline +void CCircularArray<T>::Decrement( INT32& outIndex ) +{ + --outIndex; + // circular list wrap-around + if ( outIndex < 0 ) + outIndex = m_Capacity - 1; +} + +//============================================================================== +/** + * Update the status of the m_Full flag. + * This is an internal method for use ONLY AFTER a item has been added to the array. + */ +template <class T> inline +void CCircularArray<T>::UpdateFullStatus( ) +{ + m_Full = ( m_End == m_Begin ); +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSColor.cpp b/src/system/Qt3DSColor.cpp new file mode 100644 index 0000000..a44d488 --- /dev/null +++ b/src/system/Qt3DSColor.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSColor.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor + * @param inColor 32 bit represenation of the color + */ +CColor::CColor(const Q3DStudio::UINT32 inColor) + : m_Color(inColor) +{ +} + +//============================================================================== +/** + * Constructor + * @param inRed 8 bit represenation of the red component + * @param inGreen 8 bit representation of the green component + * @param inBlue 8 bit representation of the blue component + * @param inAlpha 8 bit representation of the transparency component + */ +CColor::CColor(const UINT8 inRed, const UINT8 inGreen, const UINT8 inBlue, const UINT8 inAlpha) + : m_Red(inRed) + , m_Green(inGreen) + , m_Blue(inBlue) + , m_Alpha(inAlpha) +{ +} + +//============================================================================== +/** + * Set the color to a blend between the two given colors. + * @param inColor1 Color representing factor 0 + * @param inColor2 Color representing factor 1.0 + * @param inFactor Blend factor where 0.5 is an even mix of the two colors + */ +void CColor::Interpolate(const CColor &inColor1, const CColor &inColor2, const FLOAT inFactor) +{ + // m_Red = static_cast<UINT8>( rand() % 256 );//( 1.0f - inFactor ) * inColor1.m_Red + + //inFactor * inColor2.m_Red ); + // m_Green = static_cast<UINT8>( rand() % 256 );//( 1.0f - inFactor ) * inColor1.m_Green + + //inFactor * inColor2.m_Green ); + // m_Blue = static_cast<UINT8>( rand() % 256 );//( 1.0f - inFactor ) * inColor1.m_Blue + + //inFactor * inColor2.m_Blue ); + // m_Alpha = 255;//static_cast<UINT8>( ( 1.0f - inFactor ) * inColor1.m_Alpha + inFactor * + //inColor2.m_Alpha ); + + m_Red = static_cast<UINT8>((1.0f - inFactor) * inColor1.m_Red + inFactor * inColor2.m_Red); + m_Green = + static_cast<UINT8>((1.0f - inFactor) * inColor1.m_Green + inFactor * inColor2.m_Green); + m_Blue = static_cast<UINT8>((1.0f - inFactor) * inColor1.m_Blue + inFactor * inColor2.m_Blue); + m_Alpha = + static_cast<UINT8>((1.0f - inFactor) * inColor1.m_Alpha + inFactor * inColor2.m_Alpha); +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSColor.h b/src/system/Qt3DSColor.h new file mode 100644 index 0000000..b917f46 --- /dev/null +++ b/src/system/Qt3DSColor.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Express a color and transparency using 32 bits. + */ +class CColor +{ + //============================================================================== + // Fields + //============================================================================== +public: + union { + UINT32 m_Color; ///< 32bit representation of the color + struct + { + UINT8 m_Red; ///< Red component 0-255 + UINT8 m_Green; ///< Green component 0-255 + UINT8 m_Blue; ///< Blue component 0-255 + UINT8 m_Alpha; ///< Transparency component 0-255 + }; + }; + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + CColor(const UINT32 inColor); + CColor(const UINT8 inRed = 255, const UINT8 inGreen = 255, const UINT8 inBlue = 255, + const UINT8 inAlpha = 255); + +public: // Setters + void SetColor(const UINT32 inColor) { m_Color = inColor; } + void SetRed(const UINT8 inRed) { m_Red = inRed; } + void SetGreen(const UINT8 inGreen) { m_Green = inGreen; } + void SetBlue(const UINT8 inBlue) { m_Blue = inBlue; } + void SetAlpha(const UINT8 inAlpha) { m_Alpha = inAlpha; } + +public: // Getters + UINT32 GetColor() const { return m_Color; } + UINT8 GetRed() const { return m_Red; } + UINT8 GetGreen() const { return m_Green; } + UINT8 GetBlue() const { return m_Blue; } + UINT8 GetAlpha() const { return m_Alpha; } + +public: // Utilities + void Interpolate(const CColor &inColor1, const CColor &inColor2, const FLOAT inFactor); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSConfig.h b/src/system/Qt3DSConfig.h new file mode 100644 index 0000000..49c644d --- /dev/null +++ b/src/system/Qt3DSConfig.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// This file should only contain macros that configure the build environment +// and build options. +//============================================================================== +#include "Qt3DSMemorySettings.h" + +/// Number of chars to evaluate when generating a hash from a string. +/// Verify that hash strings are unique after changing this value. +#ifndef HASH_LIMIT +#define HASH_LIMIT 100 +#endif // HASH_LIMIT + +/// Define this macro use use sync primitives(mutex/critical sections) when accessing +/// shared data structures +#ifndef Q3DStudio_USE_SYNC_PRIMITIVES +#define Q3DStudio_USE_SYNC_PRIMITIVES 1 +#endif // Q3DStudio_USE_SYNC_PRIMITIVES diff --git a/src/system/Qt3DSCubicRoots.cpp b/src/system/Qt3DSCubicRoots.cpp new file mode 100644 index 0000000..ebcc54b --- /dev/null +++ b/src/system/Qt3DSCubicRoots.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSCubicRoots.h" +#include "Qt3DSDataLogger.h" +#include "Qt3DSCubicRootsImpl.h" diff --git a/src/system/Qt3DSCubicRoots.h b/src/system/Qt3DSCubicRoots.h new file mode 100644 index 0000000..b5ac053 --- /dev/null +++ b/src/system/Qt3DSCubicRoots.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Wrapper class to functions that solve cubic equations. + * + * The function suite is taken from Graphics Gems: + * Roots3And4.c + * + * Utility functions to find cubic and quartic roots, + * coefficients are passed like this: + * + * c[0] + c[1]*x + c[2]*x^2 + c[3]*x^3 + c[4]*x^4 = 0 + * + * The functions return the number of non-complex roots and + * put the values into the s array. + * + * Author: Jochen Schwarze (schwarze@isa.de) + * + * Jan 26, 1990 Version for Graphics Gems + * Oct 11, 1990 Fixed sign problem for negative q's in SolveQuartic + * (reported by Mark Podlipec), + * Old-style function definitions, + * IsZero() as a macro + * Nov 23, 1990 Some systems do not declare acos() and cbrt() in + * <math.h>, though the functions exist in the library. + * If large coefficients are used, EQN_EPS should be + * reduced considerably (e.g. to 1E-30), results will be + * correct but multiple roots might be reported more + * than once. + */ +class CCubicRoots +{ + //============================================================================== + // Methods + //============================================================================== +public: + static INT32 SolveQuadric(FLOAT inConstants[3], FLOAT outSolutions[2]); + static INT32 SolveCubic(FLOAT inConstants[4], FLOAT outSolutions[3]); + // static int SolveQuartic( FLOAT c[5], FLOAT s[4] ); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSCubicRootsImpl.h b/src/system/Qt3DSCubicRootsImpl.h new file mode 100644 index 0000000..8cca59f --- /dev/null +++ b/src/system/Qt3DSCubicRootsImpl.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Constants used by the functions +//============================================================================== +const FLOAT M_PHI = 3.14159265358979323846f; + +/* epsilon surrounding for near zero values */ +const FLOAT EQN_EPS = 1e-9f; + +#define ISZERO(x) ((x) > -EQN_EPS && (x) < EQN_EPS) + +// cube-root +#ifndef CUBEROOT +#define CUBEROOT(x) \ + ((x) > 0.0 ? static_cast<FLOAT>(pow((x), 1.0f / 3.0f)) \ + : ((x) < 0.0 ? -static_cast<FLOAT>(pow(-(x), 1.0f / 3.0f)) : 0.0f)) +#endif + +//============================================================================== +/** + * Find the root/s to a quadratic equation. + * + * The equation is of the form: c[2]*x^2 + c[1]*x + c[0] = 0 + * Note that this will fail if c[2] is zero, or this is a linear equation. + * + * @param inConstants The array of constants to the equation; see form above + * @param outSolutions The array of solutions to the equation + * @return the number of solutions for the equation + */ +INT32 CCubicRoots::SolveQuadric(FLOAT inConstants[3], FLOAT outSolutions[2]) +{ +#ifdef _PERF_LOG + PerfLogMathEvent1 thePerfLog(DATALOGGER_CUBICROOT); +#endif + FLOAT theP, theQ, theD; + INT32 theResult = 0; + + /* normal form: x^2 + px + theQ = 0 */ + + theP = inConstants[1] / (2 * inConstants[2]); + theQ = inConstants[0] / inConstants[2]; + + theD = theP * theP - theQ; + + if (ISZERO(theD)) { + outSolutions[0] = -theP; + theResult = 1; + } else if (theD < 0.0f) { + theResult = 0; + } else if (theD > 0.0f) { + FLOAT theSquareRootD = sqrtf(theD); + + outSolutions[0] = theSquareRootD - theP; + outSolutions[1] = -theSquareRootD - theP; + theResult = 2; + } + + return theResult; +} + +//============================================================================== +/** + * Find the root/s to a cubic equation. + * + * The equation is of the form: c[3]*x^3 + c[2]*x^2 + c[1]*x + c[0] = 0 + * Note that this will fail if c[3] is zero, or this is a quadratic equation. + * + * @param inConstants The array of constants to the equation; see form above + * @param outSolutions The array of solutions to the equation + * @return the number of solutions for the equation + */ +INT32 CCubicRoots::SolveCubic(FLOAT inConstants[4], FLOAT outSolutions[3]) +{ +#ifdef _PERF_LOG + PerfLogMathEvent1 thePerfLog(DATALOGGER_CUBICROOT); +#endif + + INT32 theResult; + FLOAT theSubstitute; + FLOAT theVariableA, theVariableB, theVariableC; + FLOAT theASquared, theVariableP, theVariableQ; + FLOAT thePCubed, theVariableD; + + /* normal form: x^3 + Ax^2 + Bx + C = 0 */ + + theVariableA = inConstants[2] / inConstants[3]; + theVariableB = inConstants[1] / inConstants[3]; + theVariableC = inConstants[0] / inConstants[3]; + + /* substitute x = y - A/3 to eliminate quadric term: + x^3 +px + q = 0 */ + + theASquared = theVariableA * theVariableA; + theVariableP = 1.0f / 3.0f * (-1.0f / 3.0f * theASquared + theVariableB); + theVariableQ = 1.0f / 2.0f * (2.0f / 27.0f * theVariableA * theASquared + - 1.0f / 3.0f * theVariableA * theVariableB + theVariableC); + + /* use Cardano's formula */ + + thePCubed = theVariableP * theVariableP * theVariableP; + theVariableD = theVariableQ * theVariableQ + thePCubed; + + if (ISZERO(theVariableD)) { + if (ISZERO(theVariableQ)) /* one triple solution */ + { + outSolutions[0] = 0; + theResult = 1; + } else /* one single and one double solution */ + { + FLOAT theVariableU = CUBEROOT(-theVariableQ); + outSolutions[0] = 2.0f * theVariableU; + outSolutions[1] = -theVariableU; + theResult = 2; + } + } else if (theVariableD < 0.0f) /* Casus irreducibilis: three real solutions */ + { + FLOAT thePhi = 1.0f / 3.0f * static_cast<FLOAT>(acos(-theVariableQ / sqrtf(-thePCubed))); + FLOAT theVariableT = 2.0f * sqrtf(-theVariableP); + + outSolutions[0] = theVariableT * static_cast<FLOAT>(cos(thePhi)); + outSolutions[1] = -theVariableT * static_cast<FLOAT>(cos(thePhi + M_PHI / 3.0f)); + outSolutions[2] = -theVariableT * static_cast<FLOAT>(cos(thePhi - M_PHI / 3.0f)); + theResult = 3; + } else /* one real solution */ + { + FLOAT theSquareRootD = sqrtf(theVariableD); + FLOAT theVariableU = CUBEROOT(theSquareRootD - theVariableQ); + FLOAT theVariableV = -CUBEROOT(theSquareRootD + theVariableQ); + + outSolutions[0] = theVariableU + theVariableV; + theResult = 1; + } + + /* resubstitute */ + theSubstitute = 1.0f / 3.0f * theVariableA; + + for (INT32 theIndex = 0; theIndex < theResult; ++theIndex) + outSolutions[theIndex] -= theSubstitute; + + return theResult; +} + +}; // namespace Q3DStudio diff --git a/src/system/Qt3DSDLLManager.cpp b/src/system/Qt3DSDLLManager.cpp new file mode 100644 index 0000000..c6f6d80 --- /dev/null +++ b/src/system/Qt3DSDLLManager.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//============================================================================== +// Includes +//============================================================================== +#include "SystemPrefix.h" +#include "Qt3DSDLLManager.h" +#include "Qt3DSBasicPluginDLL.h" +#include <QDebug> +#ifdef _LINUXPLATFORM +#include <dlfcn.h> +#endif + +using namespace Q3DStudio; + +//============================================================================== +/** + * Comparator for DLL instances. + * Compares by plugin type and handle + */ +namespace Q3DStudio { +bool operator==(const _SDLLInfo &inInfo1, const _SDLLInfo &inInfo2) +{ + return (inInfo1.m_Type == inInfo2.m_Type) && (inInfo1.m_Handle == inInfo2.m_Handle); +} +} + +//============================================================================== +/** + * Singleton getter + */ +CDLLManager &CDLLManager::GetDLLManager() +{ + static CDLLManager theDLLManager = CDLLManager(); + return theDLLManager; +} + +//============================================================================== +/** + * CTOR + */ +CDLLManager::CDLLManager() +{ +} + +//============================================================================== +/** + * DTOR + */ +CDLLManager::~CDLLManager() +{ +} + +//============================================================================== +/** + * Cleanup + */ +void CDLLManager::Cleanup() +{ + m_LoadedLibraries.Clear(true); +} + +//============================================================================== +/** + * Loads a DLL/shared library given a path to the library plugin and the plugin + * type to expect. + */ +long CDLLManager::LoadLibrary(const char *inLibraryPath, long inPluginType) +{ + long theEmptyIndex = NVARRAY_NOTFOUND; +#ifdef _PCPLATFORM + DLLHANDLE theHandle = ::LoadLibraryA(inLibraryPath); +#endif + +#ifdef _LINUXPLATFORM + DLLHANDLE theHandle = ::dlopen(inLibraryPath, RTLD_NOW); + + if (!theHandle) { + const char *error = ::dlerror(); + qWarning() << "Failed to load shared library, error:" << QStringLiteral("%1, full path: %2").arg(error).arg(inLibraryPath); + } + +#endif + +#ifdef _INTEGRITYPLATFORM + DLLHANDLE theHandle = 0; + qWarning() << "CDLLManager::LoadLibrary handle is zero!"; +#endif + + Q3DStudio_ASSERT(theHandle); + + if (theHandle != NULL) { + SDLLInfo theInfo; + PROC_GetPluginType theProc = + reinterpret_cast<PROC_GetPluginType>(GetProc("GetPluginType", theHandle)); + Q3DStudio_ASSERT(theProc); + + if (theProc) { + theInfo.m_Type = theProc(); + + if (theInfo.m_Type == inPluginType) { + theEmptyIndex = m_LoadedLibraries.GetIndex(theInfo); + theInfo.m_Handle = theHandle; + + if (theEmptyIndex == NVARRAY_NOTFOUND) { + m_LoadedLibraries.Push(theInfo); + theEmptyIndex = m_LoadedLibraries.GetCount() - 1; + } else + m_LoadedLibraries[theEmptyIndex] = theInfo; + } + } + + if (theEmptyIndex == NVARRAY_NOTFOUND) { +#ifdef _PCPLATFORM + ::FreeLibrary(theHandle); +#endif + +#ifdef _LINUXPLATFORM + ::dlclose(theHandle); +#endif + } + } + + return theEmptyIndex; +} + +//============================================================================== +/** + * Unloads a DLL given a handle + */ +void CDLLManager::UnloadLibrary(const long inHandle) +{ + if (inHandle >= 0 && inHandle < m_LoadedLibraries.GetCount()) { +#ifdef _PCPLATFORM + ::FreeLibrary(m_LoadedLibraries[inHandle].m_Handle); +#endif + +#ifdef _LINUXPLATFORM + ::dlclose(m_LoadedLibraries[inHandle].m_Handle); +#endif + + m_LoadedLibraries[inHandle] = SDLLInfo(); + } +} + +//============================================================================== +/** + * Retrieves a DLL proc given the proc name + */ +void *CDLLManager::GetProc(const char *inProcName, long inHandle) +{ + if (inHandle >= 0 && inHandle < m_LoadedLibraries.GetCount()) + return GetProc(inProcName, m_LoadedLibraries[inHandle].m_Handle); + + return NULL; +} + +//============================================================================== +/** + * Retrieves a DLL proc fiven the proc name + */ +void *CDLLManager::GetProc(const char *inProcName, const DLLHANDLE inHandle) +{ +#ifdef _PCPLATFORM +#ifdef QT3DS_VC + return ::GetProcAddress(inHandle, inProcName); +#else + return (void *)(::GetProcAddress(inHandle, inProcName)); +#endif +#endif + +#ifdef _LINUXPLATFORM + return ::dlsym(inHandle, inProcName); +#endif + +#ifdef _INTEGRITYPLATFORM + qWarning() << "CDLLManager::GetProc returns NULL!"; + return NULL; +#endif +} + +//============================================================================== +/** + * Retrieves the plugin type for the DLL + */ +template <typename EEnumType> +EEnumType CDLLManager::GetPluginType(long inHandle) +{ + if (inHandle >= 0 && inHandle < m_LoadedLibraries.GetCount()) + return static_cast<EEnumType>(m_LoadedLibraries[inHandle].m_Type); + + return 0; +} diff --git a/src/system/Qt3DSDLLManager.h b/src/system/Qt3DSDLLManager.h new file mode 100644 index 0000000..d670af2 --- /dev/null +++ b/src/system/Qt3DSDLLManager.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//============================================================================== +// Includes +//============================================================================== +#pragma once + +#ifdef _PCPLATFORM +#pragma warning(push, 3) +#include <windows.h> +#pragma warning(pop) +#endif + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +#ifdef _PCPLATFORM +typedef HMODULE DLLHANDLE; +#endif + +#if defined(_LINUXPLATFORM) || defined(_INTEGRITYPLATFORM) +typedef void *DLLHANDLE; +#endif + +typedef struct _SDLLInfo +{ + long m_Type; ///< Plugin type + DLLHANDLE m_Handle; ///< DLL handle + + _SDLLInfo() + : m_Type(0) + , m_Handle(NULL) + + { + } + +} SDLLInfo; + +//============================================================================== +/** + * Loads DLLs and queries for DLL functions + */ +class CDLLManager +{ +public: + static CDLLManager &GetDLLManager(); + +protected: + CDLLManager(); + virtual ~CDLLManager(); + +public: + long LoadLibrary(const char *inLibraryPath, long inPluginType); + void UnloadLibrary(const long inHandle); + void *GetProc(const char *inProcName, long inHandle); + template <typename EEnumType> + EEnumType GetPluginType(long inHandle); + void Cleanup(); + +protected: + void *GetProc(const char *inProcName, const DLLHANDLE inHandle); + +protected: + CArray<Q3DStudio::SDLLInfo> m_LoadedLibraries; +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSDataLogger.cpp b/src/system/Qt3DSDataLogger.cpp new file mode 100644 index 0000000..2f45f01 --- /dev/null +++ b/src/system/Qt3DSDataLogger.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSDataLogger.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +CDataLogger::SExternalFunctors CDataLogger::m_Functors; +CDataLogger::EDataLoggerLevel CDataLogger::m_LogLevel = CDataLogger::LOG_LEVEL_INVALID; +BOOL CDataLogger::m_Enabled = false; + +// Developers - change out the = NULL to = class::LogEntry to log specific stuff. +template <> +TPerfLogGeneralEvent1::TLogEntryInternal TPerfLogGeneralEvent1::m_InternalLogFunc = NULL; +template <> +TPerfLogGeneralEvent2::TLogEntryInternal TPerfLogGeneralEvent2::m_InternalLogFunc = NULL; + +template <> +TPerfLogRenderEvent1::TLogEntryInternal TPerfLogRenderEvent1::m_InternalLogFunc = NULL; +template <> +TPerfLogSceneEvent1::TLogEntryInternal TPerfLogSceneEvent1::m_InternalLogFunc = NULL; + +template <> +TPerfLogMathEvent1::TLogEntryInternal TPerfLogMathEvent1::m_InternalLogFunc = NULL; +template <> +TPerfLogPresentationEvent1::TLogEntryInternal TPerfLogPresentationEvent1::m_InternalLogFunc = NULL; +template <> +TPerfLogRenderEvent2::TLogEntryInternal TPerfLogRenderEvent2::m_InternalLogFunc = NULL; + +//============================================================================== +/** + * Set the application supplied functors to use for getting time and handling + * the writing out of data + */ +void CDataLogger::SetFunctors(SExternalFunctors inFunctors) +{ + m_Functors = inFunctors; +} + +//============================================================================== +/** +* Call into the specified functors to make stuff happen +*/ +void CDataLogger::LogEntry(UINT32 inEntryEnum, BOOL inStartFlag) +{ + if (m_Enabled && m_Functors.m_GetTimeFunc && m_Functors.m_WriteFunc && m_Functors.m_UserData) { + // Initialize to the correct values + SPerfLogEntry theEntry(inEntryEnum, inStartFlag, + m_Functors.m_GetTimeFunc(m_Functors.m_UserData)); + m_Functors.m_WriteFunc(m_Functors.m_UserData, theEntry); + } +} + +//============================================================================== +/** +* Enable logging +*/ +void CDataLogger::Enable() +{ + SetLogLevel(m_LogLevel); + m_Enabled = true; +} + +//============================================================================== +/** +* Disable logging +*/ +void CDataLogger::Disable() +{ + m_Enabled = false; +} + +//============================================================================== +/** + * XXX + */ +void CDataLogger::SetLogLevel(EDataLoggerLevel inLogLevel) +{ + switch (inLogLevel) { + // No logging + case LOG_LEVEL_NONE: + TPerfLogGeneralEvent1::Disable(); + TPerfLogGeneralEvent2::Disable(); + + TPerfLogRenderEvent1::Disable(); + TPerfLogSceneEvent1::Disable(); + + TPerfLogMathEvent1::Disable(); + TPerfLogPresentationEvent1::Disable(); + TPerfLogRenderEvent2::Disable(); + break; + + case LOG_LEVEL_3: + TPerfLogMathEvent1::Enable(); + TPerfLogPresentationEvent1::Enable(); + TPerfLogRenderEvent2::Enable(); + + case LOG_LEVEL_2: + TPerfLogRenderEvent1::Enable(); + TPerfLogSceneEvent1::Enable(); + + case LOG_LEVEL_1: + TPerfLogGeneralEvent1::Enable(); + TPerfLogGeneralEvent2::Enable(); + break; + + case LOG_LEVEL_INVALID: + default: + m_LogLevel = LOG_LEVEL_INVALID; + return; + break; + } + m_LogLevel = inLogLevel; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSDataLogger.h b/src/system/Qt3DSDataLogger.h new file mode 100644 index 0000000..b834eda --- /dev/null +++ b/src/system/Qt3DSDataLogger.h @@ -0,0 +1,226 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _DATA_LOGGER_H_ +#define _DATA_LOGGER_H_ + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSTypes.h" +#include "Qt3DSDataLoggerEnums.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +typedef TTimeUnit TDataLoggerTimeUnit; + +//============================================================================== +/** +* The structure that holds all the info we collect +*/ +struct SPerfLogEntry +{ + UINT32 m_EntryEnum : 31; + UINT32 m_StartBool : 1; + + TDataLoggerTimeUnit m_Time; + + SPerfLogEntry(UINT32 inEntryEnum, BOOL inStartFlag, TDataLoggerTimeUnit inTime) + : m_EntryEnum(inEntryEnum) + , m_StartBool(inStartFlag ? 1U : 0U) + , m_Time(inTime) + { + // Make sure our enums never use the high bit + Q3DStudio_ASSERT(false == (inEntryEnum & (1 << 31))); + } +}; + +//============================================================================== +/** +* The stack based helper class that wraps the actually logging of start and end messages +* for use with start/end time logging. +*/ +template <typename T> +class CPerfLogPairedEventWrapper +{ +public: + typedef void (*TLogEntryInternal)(UINT32 inEntryEnum, BOOL inStartFlag); + +private: + UINT32 m_EntryEnum; + static TLogEntryInternal m_InternalLogFunc; + +private: + static void LogEntry(UINT32 inEntryEnum, BOOL inStartFlag); + +public: + CPerfLogPairedEventWrapper(UINT32 inEntryEnum); + ~CPerfLogPairedEventWrapper(); + + static void Enable(); + static void Disable(); +}; + +//============================================================================== +/** +*/ +class CPerfLogPairedEventWrapperDummy +{ +public: + CPerfLogPairedEventWrapperDummy(UINT32 /*inEntryEnum*/) {} + ~CPerfLogPairedEventWrapperDummy() {} +}; + +// Dummy structs, so we get one 'type' of class per log event +// so we can turn things on and off +struct SPerfLogGeneralEvent1 +{ +}; +struct SPerfLogGeneralEvent2 +{ +}; + +struct SPerfLogRenderEvent1 +{ +}; +struct SPerfLogSceneEvent1 +{ +}; + +struct SPerfLogMathEvent1 +{ +}; +struct SPerfLogPresentationEvent1 +{ +}; +struct SPerfLogRenderEvent2 +{ +}; + +// level 0 +// no profiling at all... + +// level 1 +typedef CPerfLogPairedEventWrapper<SPerfLogGeneralEvent1> + TPerfLogGeneralEvent1; // Frame, update presentations, update scene, render scene +typedef CPerfLogPairedEventWrapper<SPerfLogGeneralEvent2> + TPerfLogGeneralEvent2; // Event processing and manager updates, +// call frame and slide callbacks, +// opaque, transparent, layer render, finalize drawlist and pick +// level 2 +typedef CPerfLogPairedEventWrapper<SPerfLogRenderEvent1> + TPerfLogRenderEvent1; // More detailed rendering +typedef CPerfLogPairedEventWrapper<SPerfLogSceneEvent1> + TPerfLogSceneEvent1; // More detailed scene update + +// level 3 +typedef CPerfLogPairedEventWrapper<SPerfLogMathEvent1> TPerfLogMathEvent1; // vector and matrix math +typedef CPerfLogPairedEventWrapper<SPerfLogPresentationEvent1> + TPerfLogPresentationEvent1; // More detailed scene update +typedef CPerfLogPairedEventWrapper<SPerfLogRenderEvent2> TPerfLogRenderEvent2; // + +// Defines +#ifdef _PERF_LOG +#define PerfLogGeneralEvent1(inEventID) TPerfLogGeneralEvent1 thePerfLog(inEventID); +#define PerfLogGeneralEvent2(inEventID) TPerfLogGeneralEvent2 thePerfLog(inEventID); + +#define PerfLogRenderEvent1(inEventID) TPerfLogRenderEvent1 thePerfLog(inEventID); +#define PerfLogSceneEvent1(inEventID) TPerfLogSceneEvent1 thePerfLog(inEventID); + +#define PerfLogMathEvent1(inEventID) TPerfLogMathEvent1 thePerfLog(inEventID); +#define PerfLogPresentationEvent1(inEventID) TPerfLogPresentationEvent1 thePerfLog(inEventID); +#define PerfLogRenderEvent2(inEventID) TPerfLogRenderEvent2 thePerfLog(inEventID); +#else +#define PerfLogGeneralEvent1(inEventID) +#define PerfLogGeneralEvent2(inEventID) + +#define PerfLogRenderEvent1(inEventID) +#define PerfLogSceneEvent1(inEventID) + +#define PerfLogMathEvent1(inEventID) +#define PerfLogPresentationEvent1(inEventID) +#define PerfLogRenderEvent2(inEventID) +#endif + +//============================================================================== +/** +*/ +class CDataLogger +{ +private: + // App level function to write this out to a stream/file... set externally + typedef void (*TDataLoggerWriteFunc)(void *inUserData, SPerfLogEntry inEntry); + typedef TDataLoggerTimeUnit (*TGetTimeFunc)(void *inUserData); + +public: + struct SExternalFunctors + { + void *m_UserData; + TDataLoggerWriteFunc m_WriteFunc; + TGetTimeFunc m_GetTimeFunc; + + SExternalFunctors() + : m_UserData(NULL) + , m_WriteFunc(NULL) + , m_GetTimeFunc(NULL) + { + } + }; + + enum EDataLoggerLevel { + LOG_LEVEL_NONE, + LOG_LEVEL_1, + LOG_LEVEL_2, + LOG_LEVEL_3, + LOG_LEVEL_INVALID, // use this if you want to selectively enable or disable loggers + }; + +private: + static SExternalFunctors m_Functors; + static EDataLoggerLevel m_LogLevel; + static BOOL m_Enabled; + +public: + static void SetFunctors(SExternalFunctors inFunctors); + static void LogEntry(UINT32 inEntryEnum, BOOL inStartFlag); + static void Enable(); + static void Disable(); + + static void SetLogLevel(EDataLoggerLevel inLogLevel); +}; + +} // namespace Q3DStudio + +#include "Qt3DSDataLogger.hpp" + +#endif // _DATA_LOGGER_H_ diff --git a/src/system/Qt3DSDataLogger.hpp b/src/system/Qt3DSDataLogger.hpp new file mode 100644 index 0000000..0900c4a --- /dev/null +++ b/src/system/Qt3DSDataLogger.hpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSDataLogger.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** +* Constructor +*/ +template <typename T> +CPerfLogPairedEventWrapper<T>::CPerfLogPairedEventWrapper(UINT32 inEntryEnum) + : m_EntryEnum(inEntryEnum) +{ + if (m_InternalLogFunc) + m_InternalLogFunc(m_EntryEnum, true); +} + +//============================================================================== +/** +* Destructor +*/ +template <typename T> +CPerfLogPairedEventWrapper<T>::~CPerfLogPairedEventWrapper() +{ + if (m_InternalLogFunc) + m_InternalLogFunc(m_EntryEnum, false); +} + +//============================================================================== +/** +* Logger functions +*/ +template <typename T> +void CPerfLogPairedEventWrapper<T>::LogEntry(UINT32 inEntryEnum, BOOL inStartFlag) +{ + CDataLogger::LogEntry(inEntryEnum, inStartFlag); +} + +//============================================================================== +/** + * Enable logging + */ +template <typename T> +void CPerfLogPairedEventWrapper<T>::Enable() +{ + m_InternalLogFunc = LogEntry; +} + +//============================================================================== +/** +* Disable logging +*/ +template <typename T> +void CPerfLogPairedEventWrapper<T>::Disable() +{ + m_InternalLogFunc = NULL; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSDataLoggerEnums.h b/src/system/Qt3DSDataLoggerEnums.h new file mode 100644 index 0000000..27320e1 --- /dev/null +++ b/src/system/Qt3DSDataLoggerEnums.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef _DATA_LOGGER_ENUMS_H_ +#define _DATA_LOGGER_ENUMS_H_ + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +// TODO ah - for now, these are all specific to paired events. Later we will +// extend this to support single events which may or may not have timestamps +// for example, every matrix multiple would log a single event with no time +enum EDataLoggerEvents { + // + DATALOGGER_FRAME, /// Time spent in a application frame ( UpdatePresentations, UpdateScenes, and + /// Render ) + + // DATALOGGER_FRAME + // CRuntime + DATALOGGER_UPDATEPRESENTATIONS, /// Time spent updating all presentations + DATALOGGER_UPDATESCENES, /// Time spent updating all scenes + DATALOGGER_RENDERSCENES, /// Time spent rendering all scenes + + // DATALOGGER_UPDATEPRESENTATIONS + // CPresentation::Update + DATALOGGER_PROCESSEVENTS, /// Time spent in ProcessEventCommandQueue + DATALOGGER_ELEMENTMANAGERUPDATE, /// Time spent in CElementManager::Update doing activate and + /// deactivate scans + DATALOGGER_ANIMATIONMANAGERUPDATE, /// Time spent in CAnimationManager::Update + + // More detailed presentation update + DATALOGGER_PROCESSCOMMAND, /// xxx + DATALOGGER_PROCESSEVENT, /// xxx + DATALOGGER_PROCESSEVENTBUBBLING, /// xxx + + // DATALOGGER_UPDATESCENES + // CScene::Update + DATALOGGER_PROCESSDIRTYLIST, /// Time spent in CScene::ProcessDirtyList + DATALOGGER_CALCULATETRANSFORM, /// Time spent in CScene::CalculateGlobalTransform + DATALOGGER_SCENEUPDATE, /// Time spent in CScene::Update recursion + + // More detailed scene update + DATALOGGER_SCANNODEATTRIBUTES, /// Time + DATALOGGER_PUSHNODE, /// Time + + // DATALOGGER_RENDERSCENES + // CRenderEngine + DATALOGGER_RENDERLAYER, /// Time spent rendering the contents of a layer + DATALOGGER_RENDEROPAQUE, /// Time spent rendering all opaque items + DATALOGGER_RENDERTRANSPARENT, /// Time spent rendering all transparent items + DATALOGGER_FINALIZEDRAWLIST, /// Time spent finalizing the draw list + DATALOGGER_PICK, /// Time spent in pick code + + // More detailed rendering + DATALOGGER_RENDER_SORTDISTANCE, /// asdf + DATALOGGER_RENDER_SETOPACITY, /// asdf + DATALOGGER_RENDER_DRAWMODEL, /// asdf + DATALOGGER_RENDER_DRAWTEXT, /// asdf + DATALOGGER_RENDER_CLEARBUFFER, /// asdf + DATALOGGER_RENDER_ZWRITEENABLE, /// asdf + DATALOGGER_RENDER_CHECKRESIZE, /// asdf + DATALOGGER_RENDER_SETATTRIBUTES, /// asdf + DATALOGGER_RENDER_TEXTUPDATE, /// asdf + DATALOGGER_RENDER_CAMERAUPDATE, /// asdf + + // super specific low level gl calls + DATALOGGER_TEXTURESTATE_APPLY, /// asdf + DATALOGGER_GEOMETRY_DRAW, /// asdf + DATALOGGER_MATERIAL_APPLY, /// asdf + DATALOGGER_SETSHADER, /// asdf + + // vector math + DATALOGGER_VECTOR, /// asdf + DATALOGGER_MATRIX, /// asdf + DATALOGGER_CUBICROOT, /// asdf + + // + DATALOGGER_COUNTERTEST, /// Time spent in counter test code + DATALOGGER_COUNTERTESTX, /// Time spent in counter test code + + DATALOGGEREVENTCOUNT /// Event count +}; + +// CPerfLogPairedEventWrapperx thePerfLog( xxx ); + +} // namespace Q3DStudio + +#endif // _DATA_LOGGER_ENUMS_H_ diff --git a/src/system/Qt3DSDataLoggerViewer.h b/src/system/Qt3DSDataLoggerViewer.h new file mode 100644 index 0000000..0eaf9f6 --- /dev/null +++ b/src/system/Qt3DSDataLoggerViewer.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AKDATALOGGERVIEWER_H_INCLUDED +#define AKDATALOGGERVIEWER_H_INCLUDED + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSTypes.h" +#include "Qt3DSDataLogger.h" +#include "Qt3DSDataLoggerEnums.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { +// Helps interpret and analyse data logger entries +class CDataLoggerViewer +{ +public: + typedef CArray<SPerfLogEntry> TPerfLogEntryList; + +public: + CDataLoggerViewer(TPerfLogEntryList *inPerfLogEntryList); + CDataLoggerViewer(const char *inFilename); + virtual ~CDataLoggerViewer(); + +public: + float GetAverageTimeInMsForEntry(enum EDataLoggerEvents inEventType); + void ResetPerfLogEntry(enum EDataLoggerEvents inEventType); + void ResetAllEntries(); + +public: + static bool ProcessKeyEvent(char inKey, TPerfLogEntryList *inList); + +protected: + TPerfLogEntryList *m_PerfLogEntryList; + bool m_Dispose; +}; + +} // namespace NVUI + +#endif // AKDATALOGGERVIEWER_H_INCLUDED diff --git a/src/system/Qt3DSEGLTimer.h b/src/system/Qt3DSEGLTimer.h new file mode 100644 index 0000000..4c9f4ce --- /dev/null +++ b/src/system/Qt3DSEGLTimer.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once +#include "Qt3DSTimer.h" +#include "Qt3DSTypes.h" + +// You have to include egl before including this file. + +typedef EGLuint64NV(EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)(void); +typedef EGLuint64NV(EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void); +extern EGLuint64NV eglSystemTimeFrequency; +extern PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC eglGetSystemTimeFrequencyNVProc; +extern PFNEGLGETSYSTEMTIMENVPROC eglGetSystemTimeNVProc; + +namespace Q3DStudio { + +struct SEGLTimeProvider : public Q3DStudio::ITimeProvider +{ +public: + Q3DStudio::INT64 m_TimeFrequency; + SEGLTimeProvider() + : m_TimeFrequency(0) + { + } + virtual Q3DStudio::INT64 GetCurrentTimeMicroSeconds() + { + // This can be called before EGL is initialized. + if (eglGetSystemTimeFrequencyNVProc == NULL || eglGetSystemTimeNVProc == NULL) + return 0; + + if (!m_TimeFrequency) { + // Time frequency converts to seconds. + m_TimeFrequency = eglGetSystemTimeFrequencyNVProc(); + // We need it to conver to microseconds + m_TimeFrequency = m_TimeFrequency / 1000000ULL; + } + Q3DStudio::INT64 currentTime = eglGetSystemTimeNVProc(); + currentTime = currentTime / m_TimeFrequency; + return currentTime; + } +}; +}
\ No newline at end of file diff --git a/src/system/Qt3DSEndian.h b/src/system/Qt3DSEndian.h new file mode 100644 index 0000000..f8913a7 --- /dev/null +++ b/src/system/Qt3DSEndian.h @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2010 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Constants +//============================================================================== + +#define QT3DS_LITTLE_ENDIAN false +#define QT3DS_BIG_ENDIAN true diff --git a/src/system/Qt3DSEulerAngles.cpp b/src/system/Qt3DSEulerAngles.cpp new file mode 100644 index 0000000..7c4364f --- /dev/null +++ b/src/system/Qt3DSEulerAngles.cpp @@ -0,0 +1,390 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include <math.h> +#include <float.h> +#include <string.h> +#include <stdio.h> +#include "Qt3DSEulerAngles.h" + +#ifdef _MSC_VER +#pragma warning(disable : 4365) // warnings on conversion from unsigned int to int +#endif + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor + */ +CEulerAngleConverter::CEulerAngleConverter() +{ + m_OrderInfoBuffer[0] = '\0'; +} + +//============================================================================== +/** + * Destructor + */ +CEulerAngleConverter::~CEulerAngleConverter() +{ +} + +//============================================================================== +/** + * Constructs a Euler angle & holds it in a EulerAngles struct + * @param theI x rotation ( radians ) + * @param theJ y rotation ( radians ) + * @param theH z rotation ( radians ) + * @param theOrder the order this angle is in namely XYZ( static ), etc. + * use the EulOrd**** macros to generate values + * 0 to 23 is valid + * @return the euler angle + */ +EulerAngles CEulerAngleConverter::Eul_(float theI, float theJ, float theH, int theOrder) +{ + EulerAngles theEulerAngle; + theEulerAngle.x = theI; + theEulerAngle.y = theJ; + theEulerAngle.z = theH; + theEulerAngle.w = (float)theOrder; + return theEulerAngle; +} + +//============================================================================== +/** + * Construct quaternion from Euler angles (in radians). + * @param theEulerAngle incoming angle( radians ) + * @return the Quaternion + */ +Quat CEulerAngleConverter::Eul_ToQuat(EulerAngles theEulerAngle) +{ + Quat theQuaternion; + double a[3], ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss; + int i, j, k, h, n, s, f; + + EulGetOrd((unsigned int)theEulerAngle.w, i, j, k, h, n, s, f); + if (f == EulFrmR) { + float t = theEulerAngle.x; + theEulerAngle.x = theEulerAngle.z; + theEulerAngle.z = t; + } + + if (n == EulParOdd) + theEulerAngle.y = -theEulerAngle.y; + + ti = theEulerAngle.x * 0.5; + tj = theEulerAngle.y * 0.5; + th = theEulerAngle.z * 0.5; + + ci = cos(ti); + cj = cos(tj); + ch = cos(th); + + si = sin(ti); + sj = sin(tj); + sh = sin(th); + + cc = ci * ch; + cs = ci * sh; + sc = si * ch; + ss = si * sh; + + if (s == EulRepYes) { + a[i] = cj * (cs + sc); /* Could speed up with */ + a[j] = sj * (cc + ss); /* trig identities. */ + a[k] = sj * (cs - sc); + theQuaternion.w = (float)(cj * (cc - ss)); + } else { + a[i] = cj * sc - sj * cs; + a[j] = cj * ss + sj * cc; + a[k] = cj * cs - sj * sc; + theQuaternion.w = (float)(cj * cc + sj * ss); + } + if (n == EulParOdd) + a[j] = -a[j]; + + theQuaternion.x = (float)a[X]; + theQuaternion.y = (float)a[Y]; + theQuaternion.z = (float)a[Z]; + return theQuaternion; +} + +//============================================================================== +/** + * Construct matrix from Euler angles (in radians). + * @param theEulerAngle incoming angle + * @param theMatrix outgoing matrix + */ +void CEulerAngleConverter::Eul_ToHMatrix(EulerAngles theEulerAngle, HMatrix theMatrix) +{ + double ti, tj, th, ci, cj, ch, si, sj, sh, cc, cs, sc, ss; + int i, j, k, h, n, s, f; + EulGetOrd((unsigned int)theEulerAngle.w, i, j, k, h, n, s, f); + + if (f == EulFrmR) { + float t = theEulerAngle.x; + theEulerAngle.x = theEulerAngle.z; + theEulerAngle.z = t; + } + + if (n == EulParOdd) { + theEulerAngle.x = -theEulerAngle.x; + theEulerAngle.y = -theEulerAngle.y; + theEulerAngle.z = -theEulerAngle.z; + } + + ti = theEulerAngle.x; + tj = theEulerAngle.y; + th = theEulerAngle.z; + + ci = cos(ti); + cj = cos(tj); + ch = cos(th); + + si = sin(ti); + sj = sin(tj); + sh = sin(th); + + cc = ci * ch; + cs = ci * sh; + sc = si * ch; + ss = si * sh; + + if (s == EulRepYes) { + theMatrix[i][i] = (float)cj; + theMatrix[i][j] = (float)(sj * si); + theMatrix[i][k] = (float)(sj * ci); + theMatrix[j][i] = (float)(sj * sh); + theMatrix[j][j] = (float)(-cj * ss + cc); + theMatrix[j][k] = (float)(-cj * cs - sc); + theMatrix[k][i] = (float)(-sj * ch); + theMatrix[k][j] = (float)(cj * sc + cs); + theMatrix[k][k] = (float)(cj * cc - ss); + } else { + theMatrix[i][i] = (float)(cj * ch); + theMatrix[i][j] = (float)(sj * sc - cs); + theMatrix[i][k] = (float)(sj * cc + ss); + theMatrix[j][i] = (float)(cj * sh); + theMatrix[j][j] = (float)(sj * ss + cc); + theMatrix[j][k] = (float)(sj * cs - sc); + theMatrix[k][i] = (float)(-sj); + theMatrix[k][j] = (float)(cj * si); + theMatrix[k][k] = (float)(cj * ci); + } + + theMatrix[W][X] = 0.0; + theMatrix[W][Y] = 0.0; + theMatrix[W][Z] = 0.0; + theMatrix[X][W] = 0.0; + theMatrix[Y][W] = 0.0; + theMatrix[Z][W] = 0.0; + theMatrix[W][W] = 1.0; +} + +//============================================================================== +/** + * Convert matrix to Euler angles (in radians). + * @param theMatrix incoming matrix + * @param theOrder 0-23, use EulOrd**** to generate this value + * @return a set of angles in radians!!!! + */ +EulerAngles CEulerAngleConverter::Eul_FromHMatrix(HMatrix theMatrix, int theOrder) +{ + EulerAngles theEulerAngle; + int i, j, k, h, n, s, f; + + EulGetOrd(theOrder, i, j, k, h, n, s, f); + if (s == EulRepYes) { + double sy = sqrt(theMatrix[i][j] * theMatrix[i][j] + theMatrix[i][k] * theMatrix[i][k]); + if (sy > 16 * FLT_EPSILON) { + theEulerAngle.x = (float)(atan2((double)theMatrix[i][j], (double)theMatrix[i][k])); + theEulerAngle.y = (float)(atan2((double)sy, (double)theMatrix[i][i])); + theEulerAngle.z = (float)(atan2((double)theMatrix[j][i], -(double)theMatrix[k][i])); + } else { + theEulerAngle.x = (float)(atan2(-(double)theMatrix[j][k], (double)theMatrix[j][j])); + theEulerAngle.y = (float)(atan2((double)sy, (double)theMatrix[i][i])); + theEulerAngle.z = 0; + } + } else { + double cy = sqrt(theMatrix[i][i] * theMatrix[i][i] + theMatrix[j][i] * theMatrix[j][i]); + if (cy > 16 * FLT_EPSILON) { + theEulerAngle.x = (float)(atan2((double)theMatrix[k][j], (double)theMatrix[k][k])); + theEulerAngle.y = (float)(atan2(-(double)theMatrix[k][i], (double)cy)); + theEulerAngle.z = (float)(atan2((double)theMatrix[j][i], (double)theMatrix[i][i])); + } else { + theEulerAngle.x = (float)(atan2(-(double)theMatrix[j][k], (double)theMatrix[j][j])); + theEulerAngle.y = (float)(atan2(-(double)theMatrix[k][i], (double)cy)); + theEulerAngle.z = 0; + } + } + + if (n == EulParOdd) { + theEulerAngle.x = -theEulerAngle.x; + theEulerAngle.y = -theEulerAngle.y; + theEulerAngle.z = -theEulerAngle.z; + } + + if (f == EulFrmR) { + float t = theEulerAngle.x; + theEulerAngle.x = theEulerAngle.z; + theEulerAngle.z = t; + } + theEulerAngle.w = (float)theOrder; + return theEulerAngle; +} + +//============================================================================== +/** + * Convert quaternion to Euler angles (in radians). + * @param theQuaternion incoming quaternion + * @param theOrder 0-23, use EulOrd**** to generate this value + * @return the generated angles ( radians ) + */ +EulerAngles CEulerAngleConverter::Eul_FromQuat(Quat theQuaternion, int theOrder) +{ + HMatrix theMatrix; + double Nq = theQuaternion.x * theQuaternion.x + theQuaternion.y * theQuaternion.y + + theQuaternion.z * theQuaternion.z + theQuaternion.w * theQuaternion.w; + double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0; + double xs = theQuaternion.x * s; + double ys = theQuaternion.y * s; + double zs = theQuaternion.z * s; + double wx = theQuaternion.w * xs; + double wy = theQuaternion.w * ys; + double wz = theQuaternion.w * zs; + double xx = theQuaternion.x * xs; + double xy = theQuaternion.x * ys; + double xz = theQuaternion.x * zs; + double yy = theQuaternion.y * ys; + double yz = theQuaternion.y * zs; + double zz = theQuaternion.z * zs; + + theMatrix[X][X] = (float)(1.0 - (yy + zz)); + theMatrix[X][Y] = (float)(xy - wz); + theMatrix[X][Z] = (float)(xz + wy); + theMatrix[Y][X] = (float)(xy + wz); + theMatrix[Y][Y] = (float)(1.0 - (xx + zz)); + theMatrix[Y][Z] = (float)(yz - wx); + theMatrix[Z][X] = (float)(xz - wy); + theMatrix[Z][Y] = (float)(yz + wx); + theMatrix[Z][Z] = (float)(1.0 - (xx + yy)); + theMatrix[W][X] = 0.0; + theMatrix[W][Y] = 0.0; + theMatrix[W][Z] = 0.0; + theMatrix[X][W] = 0.0; + theMatrix[Y][W] = 0.0; + theMatrix[Z][W] = 0.0; + theMatrix[W][W] = 1.0; + + return Eul_FromHMatrix(theMatrix, theOrder); +} + +//============================================================================== +/** + * Dump the Order information + */ +const char *CEulerAngleConverter::DumpOrderInfo() +{ + long theCount = 0; + long theOrder[24]; + char theOrderStr[24][16]; + + ::strcpy(theOrderStr[theCount++], "EulOrdXYZs"); + ::strcpy(theOrderStr[theCount++], "EulOrdXYXs"); + ::strcpy(theOrderStr[theCount++], "EulOrdXZYs"); + ::strcpy(theOrderStr[theCount++], "EulOrdXZXs"); + ::strcpy(theOrderStr[theCount++], "EulOrdYZXs"); + ::strcpy(theOrderStr[theCount++], "EulOrdYZYs"); + ::strcpy(theOrderStr[theCount++], "EulOrdYXZs"); + ::strcpy(theOrderStr[theCount++], "EulOrdYXYs"); + ::strcpy(theOrderStr[theCount++], "EulOrdZXYs"); + ::strcpy(theOrderStr[theCount++], "EulOrdZXZs"); + ::strcpy(theOrderStr[theCount++], "EulOrdZYXs"); + ::strcpy(theOrderStr[theCount++], "EulOrdZYZs"); + ::strcpy(theOrderStr[theCount++], "EulOrdZYXr"); + ::strcpy(theOrderStr[theCount++], "EulOrdXYXr"); + ::strcpy(theOrderStr[theCount++], "EulOrdYZXr"); + ::strcpy(theOrderStr[theCount++], "EulOrdXZXr"); + ::strcpy(theOrderStr[theCount++], "EulOrdXZYr"); + ::strcpy(theOrderStr[theCount++], "EulOrdYZYr"); + ::strcpy(theOrderStr[theCount++], "EulOrdZXYr"); + ::strcpy(theOrderStr[theCount++], "EulOrdYXYr"); + ::strcpy(theOrderStr[theCount++], "EulOrdYXZr"); + ::strcpy(theOrderStr[theCount++], "EulOrdZXZr"); + ::strcpy(theOrderStr[theCount++], "EulOrdXYZr"); + ::strcpy(theOrderStr[theCount++], "EulOrdZYZr"); + + theCount = 0; + theOrder[theCount++] = EulOrdXYZs; + theOrder[theCount++] = EulOrdXYXs; + theOrder[theCount++] = EulOrdXZYs; + theOrder[theCount++] = EulOrdXZXs; + theOrder[theCount++] = EulOrdYZXs; + theOrder[theCount++] = EulOrdYZYs; + theOrder[theCount++] = EulOrdYXZs; + theOrder[theCount++] = EulOrdYXYs; + theOrder[theCount++] = EulOrdZXYs; + theOrder[theCount++] = EulOrdZXZs; + theOrder[theCount++] = EulOrdZYXs; + theOrder[theCount++] = EulOrdZYZs; + + theOrder[theCount++] = EulOrdZYXr; + theOrder[theCount++] = EulOrdXYXr; + theOrder[theCount++] = EulOrdYZXr; + theOrder[theCount++] = EulOrdXZXr; + theOrder[theCount++] = EulOrdXZYr; + theOrder[theCount++] = EulOrdYZYr; + theOrder[theCount++] = EulOrdZXYr; + theOrder[theCount++] = EulOrdYXYr; + theOrder[theCount++] = EulOrdYXZr; + theOrder[theCount++] = EulOrdZXZr; + theOrder[theCount++] = EulOrdXYZr; + theOrder[theCount++] = EulOrdZYZr; + + char theSubBuf[256]; + m_OrderInfoBuffer[0] = '\0'; + for (long theIndex = 0; theIndex < 24; ++theIndex) { + ::sprintf(theSubBuf, " %16s - %ld\n ", theOrderStr[theIndex], theOrder[theIndex]); + ::strcat(m_OrderInfoBuffer, theSubBuf); + } + + return m_OrderInfoBuffer; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSEulerAngles.h b/src/system/Qt3DSEulerAngles.h new file mode 100644 index 0000000..d0f53c5 --- /dev/null +++ b/src/system/Qt3DSEulerAngles.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#include <qmath.h> + +namespace Q3DStudio { +//============================================================================== +// Description +//============================================================================== +// QuatTypes.h - Basic type declarations +// by Ken Shoemake, shoemake@graphics.cis.upenn.edu +// in "Graphics Gems IV", Academic Press, 1994 +typedef struct +{ + float x, y, z, w; +} Quat; /* Quaternion */ +typedef float HMatrix[4][4]; /* Right-handed, for column vectors */ +enum QuatPart { X, Y, Z, W }; +typedef Quat EulerAngles; /* (x,y,z)=ang 1,2,3, w=order code */ + +#define EulFrmS 0 +#define EulFrmR 1 +#define EulFrm(ord) ((unsigned)(ord)&1) +#define EulRepNo 0 +#define EulRepYes 1 +#define EulRep(ord) (((unsigned)(ord) >> 1) & 1) +#define EulParEven 0 +#define EulParOdd 1 +#define EulPar(ord) (((unsigned)(ord) >> 2) & 1) +#define EulSafe "\000\001\002\000" +#define EulNext "\001\002\000\001" +#define EulAxI(ord) ((int)(EulSafe[(((unsigned)(ord) >> 3) & 3)])) +#define EulAxJ(ord) ((int)(EulNext[EulAxI(ord) + (EulPar(ord) == EulParOdd)])) +#define EulAxK(ord) ((int)(EulNext[EulAxI(ord) + (EulPar(ord) != EulParOdd)])) +#define EulAxH(ord) ((EulRep(ord) == EulRepNo) ? EulAxK(ord) : EulAxI(ord)) + +// EulGetOrd unpacks all useful information about order simultaneously. +#define EulGetOrd(ord, i, j, k, h, n, s, f) \ + { \ + unsigned o = ord; \ + f = o & 1; \ + o = o >> 1; \ + s = o & 1; \ + o = o >> 1; \ + n = o & 1; \ + o = o >> 1; \ + i = EulSafe[o & 3]; \ + j = EulNext[i + n]; \ + k = EulNext[i + 1 - n]; \ + h = s ? k : i; \ + } + +// EulOrd creates an order value between 0 and 23 from 4-tuple choices. +#define EulOrd(i, p, r, f) (((((((i) << 1) + (p)) << 1) + (r)) << 1) + (f)) + +// Static axes +// X = 0, Y = 1, Z = 2 ref QuatPart +#define EulOrdXYZs EulOrd(0, EulParEven, EulRepNo, EulFrmS) +#define EulOrdXYXs EulOrd(0, EulParEven, EulRepYes, EulFrmS) +#define EulOrdXZYs EulOrd(0, EulParOdd, EulRepNo, EulFrmS) +#define EulOrdXZXs EulOrd(0, EulParOdd, EulRepYes, EulFrmS) +#define EulOrdYZXs EulOrd(1, EulParEven, EulRepNo, EulFrmS) +#define EulOrdYZYs EulOrd(1, EulParEven, EulRepYes, EulFrmS) +#define EulOrdYXZs EulOrd(1, EulParOdd, EulRepNo, EulFrmS) +#define EulOrdYXYs EulOrd(1, EulParOdd, EulRepYes, EulFrmS) +#define EulOrdZXYs EulOrd(2, EulParEven, EulRepNo, EulFrmS) +#define EulOrdZXZs EulOrd(2, EulParEven, EulRepYes, EulFrmS) +#define EulOrdZYXs EulOrd(2, EulParOdd, EulRepNo, EulFrmS) +#define EulOrdZYZs EulOrd(2, EulParOdd, EulRepYes, EulFrmS) + +// Rotating axes +#define EulOrdZYXr EulOrd(0, EulParEven, EulRepNo, EulFrmR) +#define EulOrdXYXr EulOrd(0, EulParEven, EulRepYes, EulFrmR) +#define EulOrdYZXr EulOrd(0, EulParOdd, EulRepNo, EulFrmR) +#define EulOrdXZXr EulOrd(0, EulParOdd, EulRepYes, EulFrmR) +#define EulOrdXZYr EulOrd(1, EulParEven, EulRepNo, EulFrmR) +#define EulOrdYZYr EulOrd(1, EulParEven, EulRepYes, EulFrmR) +#define EulOrdZXYr EulOrd(1, EulParOdd, EulRepNo, EulFrmR) +#define EulOrdYXYr EulOrd(1, EulParOdd, EulRepYes, EulFrmR) +#define EulOrdYXZr EulOrd(2, EulParEven, EulRepNo, EulFrmR) +#define EulOrdZXZr EulOrd(2, EulParEven, EulRepYes, EulFrmR) +#define EulOrdXYZr EulOrd(2, EulParOdd, EulRepNo, EulFrmR) +#define EulOrdZYZr EulOrd(2, EulParOdd, EulRepYes, EulFrmR) + +#ifndef M_PI +#define M_PI 3.1415926535898 +#endif + +#define TODEG(x) x = (float)(x * 180 / M_PI); +#define TORAD(x) x = (float)(x / 180 * M_PI); + +class CEulerAngleConverter +{ +private: + char m_OrderInfoBuffer[1024]; + +public: + CEulerAngleConverter(); + virtual ~CEulerAngleConverter(); + +public: + EulerAngles Eul_(float ai, float aj, float ah, int order); + Quat Eul_ToQuat(EulerAngles ea); + void Eul_ToHMatrix(EulerAngles ea, HMatrix M); + EulerAngles Eul_FromHMatrix(HMatrix M, int order); + EulerAngles Eul_FromQuat(Quat q, int order); + + // Debug Stuff + const char *DumpOrderInfo(); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSFNDTimer.h b/src/system/Qt3DSFNDTimer.h new file mode 100644 index 0000000..8241e2e --- /dev/null +++ b/src/system/Qt3DSFNDTimer.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once +#include "Qt3DSTimer.h" +#include "Qt3DSTypes.h" +#include "foundation/Qt3DSTime.h" + +namespace Q3DStudio { +class Qt3DSFNDTimer : public ITimeProvider +{ + Q3DStudio::INT64 GetCurrentTimeMicroSeconds() override + { + return qt3ds::foundation::Time::getCurrentTimeInTensOfNanoSeconds() / 100; + } +}; +} diff --git a/src/system/Qt3DSFile.cpp b/src/system/Qt3DSFile.cpp new file mode 100644 index 0000000..a26b735 --- /dev/null +++ b/src/system/Qt3DSFile.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSFile.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// OS level memory routines +//============================================================================== +#if defined(_XENONPLATFORM) || defined(_PCPLATFORM) || defined(_PS3PLATFORM) \ + || defined(_TEGRAPLATFORM) || defined(_LINUXPLATFORM) || defined(_INTEGRITYPLATFORM) +CFile::TOpen CFile::s_Open = &fopen; +CFile::TClose CFile::s_Close = &fclose; +CFile::TRead CFile::s_Read = &fread; +CFile::TWrite CFile::s_Write = &fwrite; +CFile::TTell CFile::s_Tell = &ftell; +CFile::TSeek CFile::s_Seek = &fseek; +#else +#error "A platform must be defined" +#endif + +//============================================================================== +/** + * Overrides basic memory allocation/deallocation routines + * @param inOpen fopen replacement method + * @param inClose fclose replacement method + * @param inRead fread replacement method + * @param inWrite fwrite replacement method + */ +void CFile::SetFileFunctions(const TOpen inOpen, const TClose inClose, const TRead inRead, + const TWrite inWrite, const TTell inTell, const TSeek inSeek) +{ + s_Open = inOpen; + s_Close = inClose; + s_Read = inRead; + s_Write = inWrite; + s_Tell = inTell; + s_Seek = inSeek; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSFile.h b/src/system/Qt3DSFile.h new file mode 100644 index 0000000..e970cd2 --- /dev/null +++ b/src/system/Qt3DSFile.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSTypes.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Single overridable exit point for all low level file calls. + */ +class CFile +{ + //============================================================================== + // Typedefs + //============================================================================== +public: + typedef enum _E_SEEK { + E_SEEK_SET = SEEK_SET, + E_SEEK_CUR = SEEK_CUR, + E_SEEK_END = SEEK_END + } E_SEEK; + + typedef TFile *(*TOpen)(const char *inFileName, const char *inMode); + typedef int (*TClose)(TFile *inFile); + typedef TFileSize (*TRead)(void *inBuffer, TFileSize inSize, TFileSize inCount, TFile *inFile); + typedef TFileSize (*TWrite)(const void *inBuffer, TFileSize inSize, TFileSize inCount, + TFile *inFile); + typedef long (*TTell)(TFile *inFile); + typedef int (*TSeek)(TFile *inFile, long inOffset, int inOrigin); + + //============================================================================== + // Fields + //============================================================================== +protected: + static TOpen s_Open; ///< function pointer to fopen operation + static TClose s_Close; ///< function pointer to fclose operation + static TRead s_Read; ///< function pointer to fread operation + static TWrite s_Write; ///< function pointer to fwrite operation + static TTell s_Tell; ///< function pointer to ftell operation + static TSeek s_Seek; ///< function pointer to fseek operation + + //============================================================================== + // Methods + //============================================================================== +public: // Memory override + static void SetFileFunctions(const TOpen inOpen, const TClose inClose, const TRead inRead, + const TWrite inWrite, const TTell inTell, const TSeek inSeek); + +public: // Function access + static TOpen Open() { return s_Open; } + static TClose Close() { return s_Close; } + static TRead Read() { return s_Read; } + static TWrite Write() { return s_Write; } + static TTell Tell() { return s_Tell; } + static TSeek Seek() { return s_Seek; } +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSFileStream.cpp b/src/system/Qt3DSFileStream.cpp new file mode 100644 index 0000000..202e4ae --- /dev/null +++ b/src/system/Qt3DSFileStream.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//============================================================================== +// Includes +//============================================================================== +#include "SystemPrefix.h" +#include "Qt3DSFile.h" +#include "Qt3DSFileStream.h" +#include "foundation/Qt3DSLogging.h" + +#include <QtCore/qthread.h> + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor + * @param inFilename the file to open + * @param inMode the file mode to use + */ +CFileStream::CFileStream(const CHAR *inFilePath, const CHAR *inMode, BOOL inKeepTrying) + : m_FileStream(NULL) + , m_Endian(QT3DS_LITTLE_ENDIAN) + , m_KeepTrying(inKeepTrying) +{ + m_TempBuffer.Reserve(sizeof(MATRIX16)); // Preallocated some space + if (inFilePath) + Open(inFilePath, inMode); +} + +//============================================================================== +/** + * Destructor + */ +CFileStream::~CFileStream() +{ + Close(); +} + +//============================================================================== +/** + * Open file. + * @param inFilename the file to open + * @param inMode the file mode ( read/write ) to use + */ +void CFileStream::Open(const CHAR *inFilePath, const CHAR *inMode) +{ + Close(); + m_FileStream = CFile::Open()(inFilePath, inMode); + while (m_KeepTrying && !m_FileStream) { + QThread::msleep(10); + m_FileStream = CFile::Open()(inFilePath, inMode); + } + + if (m_FileStream) + m_FilePath = inFilePath; +} + +//============================================================================== +/** + * Close file. + */ +void CFileStream::Close() +{ + if (m_FileStream) { + CFile::Close()(m_FileStream); + m_FileStream = NULL; + } +} + +//============================================================================== +/** + * Check if there is an opened file. + * @return TRUE if opened, FALSE otherwise. + */ +BOOL CFileStream::IsOpen() const +{ + return m_FileStream != NULL; +} + +//============================================================================== +/** + * Access the source path of a file stream. + * @return an empty string if the stream is not open + */ +const CHAR *CFileStream::GetFilePath() const +{ + return m_FilePath.toLatin1().constData(); +} + +//============================================================================== +/** + * Read from stream into memory. + * @param outMemory the destination of the read + * @param inByteCount the amount to read + * @return the number of bytes actually read + */ +INT32 CFileStream::ReadRawCopy(void *inDestination, const UINT32 inByteCount) +{ + INT32 lastRead = 0; + INT32 totalRead = 0; + do { + if (totalRead) { + qCWarning(qt3ds::INVALID_OPERATION) + << "Failed to read expected amount, retrying, expected " + << inByteCount << " bytes, got "<< totalRead <<" bytes"; + } + lastRead = static_cast<INT32>(CFile::Read()(((char *)inDestination) + totalRead, 1, + inByteCount - totalRead, m_FileStream)); + totalRead += lastRead; + } while (lastRead && totalRead < (INT32)inByteCount); + + if (totalRead != (INT32)inByteCount) { + qCWarning(qt3ds::INVALID_OPERATION) + << "Failed to read expected amount, retrying, expected " + << inByteCount << " bytes, got "<< totalRead <<" bytes"; + + // Zero out remaining destination buffer. + // This can, in some cases, avoid a crash and allow the system to survive a partial + // read. + INT32 amountLeft = inByteCount - totalRead; + memset(((char *)inDestination) + totalRead, 0, amountLeft); + } + return totalRead; +} + +//============================================================================== +/** + * Reads data into internal buffer and return the data pointer for it. + * @param outMemory pointer to internal data buffer + * @param inByteCount the amount to read + * @return the number of bytes actually read + */ +INT32 CFileStream::ReadRaw(const void *&inPtr, const UINT32 inByteCount) +{ + m_TempBuffer.Reserve(static_cast<INT32>(inByteCount)); + INT32 theReadSize = ReadRawCopy(m_TempBuffer.Begin(), inByteCount); + if (theReadSize != (INT32)inByteCount) { + qCWarning(qt3ds::INVALID_OPERATION) + << "Failed to read expected amount, retrying, expected "<< inByteCount + << " bytes, got "<< theReadSize <<" bytes"; + } + inPtr = m_TempBuffer.Begin(); + return theReadSize; +} + +//============================================================================== +/** + * Write from memory to stream. + * @param inMemory the buffer to write from + * @param inByteCount the amount to write + * @return the number of bytes actually written + */ +INT32 CFileStream::WriteRaw(const void *inSource, const UINT32 inByteCount) +{ + return static_cast<INT32>(CFile::Write()(inSource, 1, inByteCount, m_FileStream)); +} + +//============================================================================== +/** + * Offsets the file position by the specified number of bytes + */ +void CFileStream::Offset(const INT32 inByteCount) +{ + CFile::Seek()(m_FileStream, inByteCount, CFile::E_SEEK_CUR); +} + +//============================================================================== +/** + * Returns the current position of the file stream + */ +IStream::TStreamPosition CFileStream::Current() +{ + return static_cast<INT32>(CFile::Tell()(m_FileStream)); +} + +//============================================================================== +/** + * Sets the stream to the specified position within the file + */ +void CFileStream::Set(const TStreamPosition &inPosition) +{ + CFile::Seek()(m_FileStream, inPosition, CFile::E_SEEK_SET); +} + +//============================================================================== +/** + * Set the endianess of the file. + * @warning endian support not implemented + */ +void CFileStream::SetEndian(const BOOL inEndian) +{ + m_Endian = inEndian; +} + +//============================================================================== +/** + * Get the endianess of the file. + * @warning endian support not implemented + */ +BOOL CFileStream::GetEndian() +{ + return m_Endian; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSFileStream.h b/src/system/Qt3DSFileStream.h new file mode 100644 index 0000000..49e272f --- /dev/null +++ b/src/system/Qt3DSFileStream.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSIFileStream.h" +#include "Qt3DSArray.h" +#include "Qt3DSEndian.h" + +#include <QtCore/QString> + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * File stream base class. + */ +class CFileStream : public IFileStream +{ + //============================================================================== + // Methods + //============================================================================== +public: // Construction + CFileStream(const CHAR *inFilePath = NULL, const CHAR *inMode = "rb", + BOOL inKeepTrying = false); + virtual ~CFileStream(); + +public: // Serializing + INT32 ReadRawCopy(void *inDestination, const UINT32 inByteCount) override; + INT32 ReadRaw(const void *&inPtr, const UINT32 inByteCount) override; + INT32 WriteRaw(const void *inSource, const UINT32 inByteCount) override; + + // Seeking + void Offset(const INT32 inOffset) override; + TStreamPosition Current() override; + void Set(const TStreamPosition &inPosition) override; + +public: // File Operation + void Open(const CHAR *inFilePath, const CHAR *inMode) override; + void Close() override; + BOOL IsOpen() const override; + const CHAR *GetFilePath() const override; + +public: // Endianess + void SetEndian(const BOOL inEndian); + BOOL GetEndian(); + + //============================================================================== + // Fields + //============================================================================== +protected: + TFile *m_FileStream; + QString m_FilePath; + CArray<UINT8> m_TempBuffer; + BOOL m_Endian; + BOOL m_KeepTrying; + CHAR m_Unused[2]; ///< (padding) +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSFixedArray.h b/src/system/Qt3DSFixedArray.h new file mode 100644 index 0000000..9f971d8 --- /dev/null +++ b/src/system/Qt3DSFixedArray.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#include <QtCore/QDebug> + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Fixed size Ordered Collection that doesn't support growing. + */ +template <class T, int Size> +class CFixedArray +{ + //============================================================================== + // Typedefs + //============================================================================== +public: + typedef T TType; ///< Easy access to template type + + //============================================================================== + // Fields + //============================================================================== +protected: + T m_Data[Size]; ///< Allocated memory containing array data + INT32 m_Capacity; ///< Max number of elements possible + INT32 m_Count; ///< Current number of elements in array + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + inline CFixedArray(); + inline ~CFixedArray(); + +public: // Management + inline void Clear(); + inline INT32 GetCount() const; + inline INT32 GetCapacity() const; + +public: // Stack access + inline void Push(const T &inValue); + inline const T &Pop(); + +public: // Array access + inline T &operator[](const INT32 inIndex); + inline void Remove(const INT32 inIndex); +}; + +} // namespace Q3DStudio + +//============================================================================== +// Template code +//============================================================================== +#include "Qt3DSFixedArray.inl" diff --git a/src/system/Qt3DSFixedArray.inl b/src/system/Qt3DSFixedArray.inl new file mode 100644 index 0000000..5524224 --- /dev/null +++ b/src/system/Qt3DSFixedArray.inl @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 1999-2007 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor + */ +template <class T, int Size> +inline CFixedArray<T, Size>::CFixedArray() + : m_Capacity(Size) + , m_Count(0) +{ +} + +//============================================================================== +/** + * Destructor + */ +template <class T, int Size> +inline CFixedArray<T, Size>::~CFixedArray() +{ +} + +//============================================================================== +/** + * Remove all elements in the array + */ +template <class T, int Size> +inline void CFixedArray<T, Size>::Clear() +{ + m_Count = 0; +} + +//============================================================================== +/** + * Get current count of T in the array + * @return current count of the array + */ +template <class T, int Size> +inline INT32 CFixedArray<T, Size>::GetCount() const +{ + return m_Count; +} + +//============================================================================== +/** + * Get the capacity of the array + * Capacity reflects the allocated memory size + * @return capacity of the array + */ +template <class T, int Size> +inline INT32 CFixedArray<T, Size>::GetCapacity() const +{ + return m_Capacity; +} + +//============================================================================== +/** + * Insert T to the end of the array + * @param inValue value of datatype T + */ +template <class T, int Size> +inline void CFixedArray<T, Size>::Push(const T &inValue) +{ + if (m_Count == m_Capacity) { + qWarning("Trying to push to many objects onto a CFixedArray", "Capacity=%d", m_Capacity); + return; + } + + m_Data[m_Count] = inValue; + ++m_Count; +} + +//============================================================================== +/** + * Remove and retrieve T which is at the end of the array + * @return value of datatype T + */ +template <class T, int Size> +inline const T &CFixedArray<T, Size>::Pop() +{ + if (m_Count == 0) + return {}; + + --m_Count; + return m_Data[m_Count]; +} + +//============================================================================== +/** + * Get T at a particular index position of the array. + * Need to ensure only valid index is allowed + * Clear( ) will set the m_counter = 0 + * @param inIndex the index of the array + * @return reference of value of datatype T + */ +template <class T, int Size> +inline T &CFixedArray<T, Size>::operator[](const INT32 inIndex) +{ + Q3DStudio_ASSERT(inIndex < m_Capacity); + + return m_Data[inIndex]; +} + +//============================================================================== +/** + * Removes a specific entry from the array. + * Moves all entries below it up, expensive. + * @param inIndex the index of the entry + */ +template <class T, int Size> +inline void CFixedArray<T, Size>::Remove(const INT32 inIndex) +{ + Q3DStudio_memmove(m_Data + inIndex, m_Data + inIndex + 1, sizeof(T) * (m_Count - inIndex - 1)); + --m_Count; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSFunctionWrappers.cpp b/src/system/Qt3DSFunctionWrappers.cpp new file mode 100644 index 0000000..e96c3ce --- /dev/null +++ b/src/system/Qt3DSFunctionWrappers.cpp @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2010 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//============================================================================== +// Includes +//============================================================================== +#include "SystemPrefix.h" +#include "Qt3DSFunctionWrappers.h" + +using namespace Q3DStudio; + +//============================================================================== +/** +* CTOR +*/ +IFunctionWrapper::IFunctionWrapper() + : m_Cost(0) +{ +} + +//============================================================================== +/** +* Retrieve the cost associated with this function. +* Should be zero or greater +*/ +INT32 IFunctionWrapper::GetCost() +{ + return m_Cost; +} + +//============================================================================== +/** +* Sets the cost associated with this function. +*/ +void IFunctionWrapper::SetCost(const INT32 inCost) +{ + m_Cost = inCost; +}
\ No newline at end of file diff --git a/src/system/Qt3DSFunctionWrappers.h b/src/system/Qt3DSFunctionWrappers.h new file mode 100644 index 0000000..8fff62d --- /dev/null +++ b/src/system/Qt3DSFunctionWrappers.h @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2010 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== + +namespace Q3DStudio { + +//============================================================================== +/** +* Interface for a function wrapper with an associated cost. +*/ +class IFunctionWrapper +{ +public: + IFunctionWrapper(); + virtual ~IFunctionWrapper(){} + +public: + virtual void Execute() = 0; + INT32 GetCost(); + void SetCost(const INT32 inCost); + +protected: + INT32 m_Cost; +}; + +//============================================================================== +/** +* 2 arguments function wrapper +*/ +template <typename TArg1, typename TArg2> +class CFunctionWrapper2Args : public IFunctionWrapper +{ +public: + typedef void (*TFunction)(TArg1 inArg1, TArg2 inArg2); + +public: + CFunctionWrapper2Args(TFunction, TArg1 inArg1, TArg2 inArg2); + +public: + virtual void Execute(); + +protected: + TFunction m_Function; + TArg1 m_Arg1; + TArg2 m_Arg2; +}; + +// Unused +/* +template <typename TArg1, typename TArg2, typename TArg3> +class CFunctionWrapper3Args : public IFunctionWrapper +{ + public: + typedef void ( *TFunction )( TArg1 inArg1, TArg2 inArg2, TArg3 inArg3 ); + + public: + CFunctionWrapper3Args( TFunction inFunction, TArg1 inArg1, TArg2 inArg2, TArg3 +inArg3 ); + + public: + virtual void Execute( ); + + protected: + TFunction m_Function; + TArg1 m_Arg1; + TArg2 m_Arg2; + TArg3 m_Arg3; +}; + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4> +class CFunctionWrapper4Args : public IFunctionWrapper +{ + public: + typedef void ( *TFunction )( TArg1 inArg1, TArg2 inArg2, TArg3 inArg3, TArg4 inArg4 +); + + public: + CFunctionWrapper4Args( TFunction inFunction, TArg1 inArg1, TArg2 inArg2, TArg3 +inArg3, TArg4 inArg4 ); + + public: + virtual void Execute( ); + + protected: + TFunction m_Function; + TArg1 m_Arg1; + TArg2 m_Arg2; + TArg3 m_Arg3; + TArg4 m_Arg4; +}; + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4, typename TArg5, typename +TArg6, typename TArg7, typename TArg8> +class CFunctionWrapper8Args : public IFunctionWrapper +{ + public: + typedef void ( *TFunction )( TArg1 inArg1, TArg2 inArg2, TArg3 inArg3, TArg4 inArg4, +TArg5 inArg5, TArg6 inArg6, TArg7 inArg7, TArg8 inArg8 ); + + public: + CFunctionWrapper8Args( TFunction inFunction, TArg1 inArg1, TArg2 inArg2, TArg3 +inArg3, TArg4 inArg4, TArg5 inArg5, TArg6 inArg6, TArg7 inArg7, TArg8 inArg8 ); + + public: + virtual void Execute( ); + + protected: + TFunction m_Function; + TArg1 m_Arg1; + TArg2 m_Arg2; + TArg3 m_Arg3; + TArg4 m_Arg4; + TArg5 m_Arg5; + TArg6 m_Arg6; + TArg7 m_Arg7; + TArg8 m_Arg8; +}; + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4, typename TArg5, typename +TArg6, typename TArg7, typename TArg8, typename TArg9> +class CFunctionWrapper9Args : public IFunctionWrapper +{ + public: + typedef void ( *TFunction )( TArg1 inArg1, TArg2 inArg2, TArg3 inArg3, TArg4 inArg4, +TArg5 inArg5, TArg6 inArg6, TArg7 inArg7, TArg8 inArg8, TArg9 inArg9 ); + + public: + CFunctionWrapper9Args( TFunction inFunction, TArg1 inArg1, TArg2 inArg2, TArg3 +inArg3, TArg4 inArg4, TArg5 inArg5, TArg6 inArg6, TArg7 inArg7, TArg8 inArg8, TArg9 inArg9 ); + + public: + virtual void Execute( ); + + protected: + TFunction m_Function; + TArg1 m_Arg1; + TArg2 m_Arg2; + TArg3 m_Arg3; + TArg4 m_Arg4; + TArg5 m_Arg5; + TArg6 m_Arg6; + TArg7 m_Arg7; + TArg8 m_Arg8; + TArg9 m_Arg9; +}; +*/ + +//============================================================================== +/** +* 1 argument member function wrapper +*/ +template <typename TObject, typename TReturn, typename TArg1> +class CMemberFunctionWrapper1Args : public IFunctionWrapper +{ +public: + typedef TReturn (TObject::*TFunction)(TArg1 inArg1); + +public: + CMemberFunctionWrapper1Args(TObject *inObject, TFunction inFunction, TArg1 inArg1); + +public: + virtual void Execute(); + +protected: + TFunction m_Function; + TObject *m_Object; + TArg1 m_Arg1; +}; + +//============================================================================== +/** +* 2 argument member function wrapper +*/ +template <typename TObject, typename TReturn, typename TArg1, typename TArg2> +class CMemberFunctionWrapper2Args : public IFunctionWrapper +{ +public: + typedef TReturn (TObject::*TFunction)(TArg1 inArg1, TArg2 inArg2); + +public: + CMemberFunctionWrapper2Args(TObject *inObject, TFunction inFunction, TArg1 inArg1, + TArg2 inArg2); + +public: + virtual void Execute(); + +protected: + TFunction m_Function; + TObject *m_Object; + TArg1 m_Arg1; + TArg2 m_Arg2; +}; + +//============================================================================== +/** +* 6 argument member function wrapper +*/ +template <typename TObject, typename TReturn, typename TArg1, typename TArg2, typename TArg3, + typename TArg4, typename TArg5, typename TArg6> +class CMemberFunctionWrapper6Args : public IFunctionWrapper +{ +public: + typedef TReturn (TObject::*TFunction)(TArg1 inArg1, TArg2 inArg2, TArg3 inArg3, TArg4 inArg4, + TArg5 inArg5, TArg6 inArg6); + +public: + CMemberFunctionWrapper6Args(TObject *inObject, TFunction inFunction, TArg1 inArg1, TArg2 inArg2, + TArg3 inArg3, TArg4 inArg4, TArg5 inArg5, TArg6 inArg6); + +public: + virtual void Execute(); + +protected: + TFunction m_Function; + TObject *m_Object; + TArg1 m_Arg1; + TArg2 m_Arg2; + TArg3 m_Arg3; + TArg4 m_Arg4; + TArg5 m_Arg5; + TArg6 m_Arg6; +}; + +// Implementation +template <typename TArg1, typename TArg2> +CFunctionWrapper2Args<TArg1, TArg2>::CFunctionWrapper2Args(TFunction inFunction, TArg1 inArg1, + TArg2 inArg2) + : m_Function(inFunction) + , m_Arg1(inArg1) + , m_Arg2(inArg2) +{ +} + +template <typename TArg1, typename TArg2> +void CFunctionWrapper2Args<TArg1, TArg2>::Execute() +{ + m_Function(m_Arg1, m_Arg2); +} + +// Unused +/* +template <typename TArg1, typename TArg2, typename TArg3> +CFunctionWrapper3Args<TArg1, TArg2, TArg3>::CFunctionWrapper3Args( TFunction inFunction, TArg1 +inArg1, TArg2 inArg2, TArg3 inArg3 ) +: m_Function( inFunction ), + m_Arg1( inArg1 ), + m_Arg2( inArg2 ), + m_Arg3( inArg3 ) +{ +} + +template <typename TArg1, typename TArg2, typename TArg3> +void CFunctionWrapper3Args<TArg1, TArg2, TArg3>::Execute( ) +{ + m_Function( m_Arg1, m_Arg2, m_Arg3 ); +} + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4> +CFunctionWrapper4Args<TArg1, TArg2, TArg3, TArg4>::CFunctionWrapper4Args( TFunction inFunction, +TArg1 inArg1, TArg2 inArg2, TArg3 inArg3, TArg4 inArg4 ) +: m_Function( inFunction ), + m_Arg1( inArg1 ), + m_Arg2( inArg2 ), + m_Arg3( inArg3 ), + m_Arg4( inArg4 ) +{ +} + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4> +void CFunctionWrapper4Args<TArg1, TArg2, TArg3, TArg4>::Execute( ) +{ + m_Function( m_Arg1, m_Arg2, m_Arg3, m_Arg4 ); +} + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4, typename TArg5, typename +TArg6, typename TArg7, typename TArg8> +CFunctionWrapper8Args<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, +TArg8>::CFunctionWrapper8Args( TFunction inFunction, TArg1 inArg1, TArg2 inArg2, TArg3 inArg3, TArg4 +inArg4, TArg5 inArg5, TArg6 inArg6, TArg7 inArg7, TArg8 inArg8 ) +: m_Function( inFunction ), + m_Arg1( inArg1 ), + m_Arg2( inArg2 ), + m_Arg3( inArg3 ), + m_Arg4( inArg4 ), + m_Arg5( inArg5 ), + m_Arg6( inArg6 ), + m_Arg7( inArg7 ), + m_Arg8( inArg8 ) + +{ +} + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4, typename TArg5, typename +TArg6, typename TArg7, typename TArg8> +void CFunctionWrapper8Args<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8>::Execute( ) +{ + m_Function( m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, m_Arg8 ); +} + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4, typename TArg5, typename +TArg6, typename TArg7, typename TArg8, typename TArg9> +CFunctionWrapper9Args<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, +TArg9>::CFunctionWrapper9Args( TFunction inFunction, TArg1 inArg1, TArg2 inArg2, TArg3 inArg3, TArg4 +inArg4, TArg5 inArg5, TArg6 inArg6, TArg7 inArg7, TArg8 inArg8, TArg9 inArg9 ) +: m_Function( inFunction ), + m_Arg1( inArg1 ), + m_Arg2( inArg2 ), + m_Arg3( inArg3 ), + m_Arg4( inArg4 ), + m_Arg5( inArg5 ), + m_Arg6( inArg6 ), + m_Arg7( inArg7 ), + m_Arg8( inArg8 ), + m_Arg9( inArg9 ) +{ +} + +template <typename TArg1, typename TArg2, typename TArg3, typename TArg4, typename TArg5, typename +TArg6, typename TArg7, typename TArg8, typename TArg9> +void CFunctionWrapper9Args<TArg1, TArg2, TArg3, TArg4, TArg5, TArg6, TArg7, TArg8, TArg9>::Execute( +) +{ + m_Function( m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6, m_Arg7, m_Arg8, m_Arg9 ); +} +*/ + +template <typename TObject, typename TReturn, typename TArg1> +CMemberFunctionWrapper1Args<TObject, TReturn, TArg1>::CMemberFunctionWrapper1Args( + TObject *inObject, TFunction inFunction, TArg1 inArg1) + : m_Function(inFunction) + , m_Object(inObject) + , m_Arg1(inArg1) +{ +} + +template <typename TObject, typename TReturn, typename TArg1> +void CMemberFunctionWrapper1Args<TObject, TReturn, TArg1>::Execute() +{ + (m_Object->*m_Function)(m_Arg1); +} + +template <typename TObject, typename TReturn, typename TArg1, typename TArg2> +CMemberFunctionWrapper2Args<TObject, TReturn, TArg1, TArg2>::CMemberFunctionWrapper2Args( + TObject *inObject, TFunction inFunction, TArg1 inArg1, TArg2 inArg2) + : m_Function(inFunction) + , m_Object(inObject) + , m_Arg1(inArg1) + , m_Arg2(inArg2) +{ +} + +template <typename TObject, typename TReturn, typename TArg1, typename TArg2> +void CMemberFunctionWrapper2Args<TObject, TReturn, TArg1, TArg2>::Execute() +{ + (m_Object->*m_Function)(m_Arg1, m_Arg2); +} + +template <typename TObject, typename TReturn, typename TArg1, typename TArg2, typename TArg3, + typename TArg4, typename TArg5, typename TArg6> +CMemberFunctionWrapper6Args<TObject, TReturn, TArg1, TArg2, TArg3, TArg4, TArg5, + TArg6>::CMemberFunctionWrapper6Args(TObject *inObject, + TFunction inFunction, TArg1 inArg1, + TArg2 inArg2, TArg3 inArg3, + TArg4 inArg4, TArg5 inArg5, + TArg6 inArg6) + : m_Function(inFunction) + , m_Object(inObject) + , m_Arg1(inArg1) + , m_Arg2(inArg2) + , m_Arg3(inArg3) + , m_Arg4(inArg4) + , m_Arg5(inArg5) + , m_Arg6(inArg6) +{ +} + +template <typename TObject, typename TReturn, typename TArg1, typename TArg2, typename TArg3, + typename TArg4, typename TArg5, typename TArg6> +void CMemberFunctionWrapper6Args<TObject, TReturn, TArg1, TArg2, TArg3, TArg4, TArg5, + TArg6>::Execute() +{ + (m_Object->*m_Function)(m_Arg1, m_Arg2, m_Arg3, m_Arg4, m_Arg5, m_Arg6); +} +} diff --git a/src/system/Qt3DSHash.h b/src/system/Qt3DSHash.h new file mode 100644 index 0000000..8baa2db --- /dev/null +++ b/src/system/Qt3DSHash.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once +#include "Qt3DSConfig.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Utility class transforming a string into a hash value. + */ +class CHash +{ + //============================================================================== + // Methods + //============================================================================== +public: // Static utility + //============================================================================== + /** + * We use the hashing algorithm called "sdbm". + * + * This algorithm was created from sdbm (a public-domain reimplementation + * of ndbm) database library. It was found to do well in scrambling bits, + * causing better distribution of the keys and fewer splits. it also happens + * to be a good general hashing function with good distribution. the actual + * function is hash(i) = hash(i - 1) * 65599 + str[i]; what is included below + * is the faster version used in gawk. [there is even a faster, duff-device + * version] the magic constant 65599 was picked out of thin air while + * experimenting with different constants, and turns out to be a prime. this + * is one of the algorithms used in berkeley db (see sleepycat) and elsewhere. + * + * @param inString the string to hash + * @return the hash value + */ + static TStringHash HashString(const CHAR *inString) + { + TStringHash theHash = 0; + INT32 theChar = *inString; + INT32 theCount = 0; + while (theChar && (theCount < HASH_LIMIT)) { + theChar = *inString++; + theHash = theChar + (theHash << 6) + (theHash << 16) - theHash; + ++theCount; + } + + return theHash; + } + + //============================================================================== + /** + * 31-bit hash with MSB set to 0 + * + * @param inString the string to hash + * @return the 31-bit hash value + */ + static TEventCommandHash HashEventCommand(const CHAR *inString) + { + return HashString(inString) & 0x7fffffff; + } + + //============================================================================== + /** + * 26-bit hash with MSBs all set to 0 + * + * @param inString the string to hash + * @return the 26-bit hash value + */ + static TAttributeHash HashAttribute(const CHAR *inString) + { + return HashString(inString) & 0x03ffffff; + } +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSIFileStream.h b/src/system/Qt3DSIFileStream.h new file mode 100644 index 0000000..0b43260 --- /dev/null +++ b/src/system/Qt3DSIFileStream.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSIStream.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * File stream interface + */ +class IFileStream : public IStream +{ +public: + virtual void Open(const CHAR *inFilePath, const CHAR *inMode) = 0; + virtual void Close() = 0; + virtual BOOL IsOpen() const = 0; + virtual const CHAR *GetFilePath() const = 0; +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSIStream.h b/src/system/Qt3DSIStream.h new file mode 100644 index 0000000..a4c1195 --- /dev/null +++ b/src/system/Qt3DSIStream.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Pure virtual interface providing the stream for class serialization. + */ +class IStream +{ + //============================================================================== + // Typedef + //============================================================================== +public: + typedef INT32 TStreamPosition; + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + virtual ~IStream(){} + +public: // Serializing + virtual INT32 ReadRawCopy(void *inDestination, const UINT32 inByteCount) = 0; + virtual INT32 ReadRaw(const void *&inPtr, const UINT32 inByteCount) = 0; + virtual INT32 WriteRaw(const void *inSource, const UINT32 inByteCount) = 0; + + // Seeking + virtual void Offset(const INT32 inOffset) = 0; + virtual TStreamPosition Current() = 0; + virtual void Set(const TStreamPosition &inPosition) = 0; + +public: // Template Readers that make a copy + template <typename T> + INT32 ReadCopy(T &outValue); + template <typename T> + INT32 ReadArrayCopy(T *outValue, const UINT32 inCount); + +public: // Template Readers that access value directly + template <typename T> + INT32 Read(const T *&inPtr); + template <typename T> + INT32 ReadArray(const T *&inPtr, UINT32 inCount); + +public: // Template Writers + template <typename T> + INT32 Write(const T &inValue); + template <typename T> + INT32 WriteArray(const T *inValue, const UINT32 inCount); +}; + +/** Notes concerning usage of Read or ReadCopy (and ReadArray and ReadArrayCopy)**/ +/** +If the value being read fits into 4 bytes (i.e float, int/long), either Read/ReadCopy can be used. +However, if the read value is going to be accessed frequently (in loops etc), ReadCopy is +recommended so a copy is available instead of dereferencing. + +ReadCopy should be used if the data read is an array or is significantly larger than 4 bytes (like +vectors or matrixes). + +For cases where the value is to be stored in a persistant data structures, ReadCopy should be used. + +One important thing about Read/ReadArray, is that the pointer returned is only valid before the next +Read/ReadyArray is called. +There is no guarantee that the pointer data will remain unchanged during subsequent calls to +Read/ReadArray. +**/ + +//============================================================================== +/** + * Read and assign a value by copying. + */ +template <typename T> +INT32 IStream::ReadCopy(T &outValue) +{ + return ReadRawCopy(&outValue, sizeof(T)); +} + +//============================================================================== +/** + * Read and copy data to a preallocated array. + */ +template <typename T> +INT32 IStream::ReadArrayCopy(T *outValue, const UINT32 inCount) +{ + return ReadRawCopy(outValue, sizeof(T) * inCount); +} + +//============================================================================== +/** + * Obtain a pointer directly to the data. + */ +template <typename T> +INT32 IStream::Read(const T *&inPtr) +{ + return ReadRaw(reinterpret_cast<const void *&>(inPtr), sizeof(T)); +} + +//============================================================================== +/** + * Obtain a pointer directly to the array data. + */ +template <typename T> +INT32 IStream::ReadArray(const T *&inPtr, const UINT32 inCount) +{ + return ReadRaw(reinterpret_cast<const void *&>(inPtr), sizeof(T) * inCount); +} + +//============================================================================== +/** + * Write a value. + */ +template <typename T> +INT32 IStream::Write(const T &inValue) +{ + return WriteRaw(&inValue, sizeof(T)); +} + +//============================================================================== +/** + * Write an array of values. + */ +template <typename T> +INT32 IStream::WriteArray(const T *inValue, const UINT32 inCount) +{ + return WriteRaw(inValue, sizeof(T) * inCount); +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSITimer.h b/src/system/Qt3DSITimer.h new file mode 100644 index 0000000..e73fbb9 --- /dev/null +++ b/src/system/Qt3DSITimer.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * @interface ITimer + * The base functionality of the timer used by the Kernel + * + * Implement this interface per-platform to obtain the required functionality + */ +class ITimer +{ + //============================================================================== + // Methods + //============================================================================== +public: // Construction + virtual ~ITimer() {} + +public: // Operation + virtual void Start() = 0; + virtual void Stop() = 0; + virtual void Reset() = 0; + virtual TTimeUnit GetTimeMilliSecs() = 0; + virtual TMicroSeconds GetTimeMicroSecs() = 0; +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMacros.h b/src/system/Qt3DSMacros.h new file mode 100644 index 0000000..fbc40b4 --- /dev/null +++ b/src/system/Qt3DSMacros.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSAssert.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Easy iterations over arrays. + * @param array_type element type + * @param array_element element variable name getting each entry + * @param array_container element array we are traversing + */ +#define FOR_ARRAY(array_type, array_element, array_container) \ + for (array_type *array_element = (array_container).Begin(); \ + array_element != (array_container).End(); ++array_element) + +#define FOR_ARRAY_REVERSE(array_type, array_element, array_container) \ + for (array_type *array_element = (array_container).End() - 1; \ + array_element != (array_container).Begin() - 1; --array_element) + +//============================================================================== +/** + * Return the smallest of two numbers/objects. + * @param inA one value to compare + * @param inB another value to compare + * @return a reference, not a copy, to the smallest of the two values + */ +template <class T> +inline const T Q3DStudio_abs(const T &inVal) +{ + return inVal >= 0 ? inVal : -inVal; +} + +//============================================================================== +/** + * Return the smallest of two numbers/objects. + * @param inA one value to compare + * @param inB another value to compare + * @return a reference, not a copy, to the smallest of the two values + */ +template <typename T> +inline const T &Q3DStudio_min(const T &inA, const T &inB) +{ + return inA < inB ? inA : inB; +} + +//============================================================================== +/** + * Return the largest of two numbers/objects. + * @param inA one value to compare + * @param inB another value to compare + * @return a reference, not a copy, to the largest of the two values + */ +template <class T> +inline const T &Q3DStudio_max(const T &inA, const T &inB) +{ + return inA > inB ? inA : inB; +} + +//============================================================================== +/** + * Return the smallest of three values. + * @param inA one value to compare + * @param inB another value to compare + * @param inC a third value to compare + * @return a reference, not a copy, to the smallest of the three values + */ +template <class T> +inline const T &Q3DStudio_min3(const T &inA, const T &inB, const T &inC) +{ + return inA < inB ? Q3DStudio_min(inA, inC) : Q3DStudio_min(inB, inC); +} + +//============================================================================== +/** + * Return the largest of three values. + * @param inA one value to compare + * @param inB another value to compare + * @param inC a third value to compare + * @return a reference, not a copy, to the largest of the three values + */ +template <class T> +inline const T &Q3DStudio_max3(const T &inA, const T &inB, const T &inC) +{ + return inA > inB ? Q3DStudio_max(inA, inC) : Q3DStudio_max(inB, inC); +} + +//============================================================================== +/** + * Make sure a value is in-bounds between two other values. + * @param inVal the value to clamp + * @param inMin the lowest inclusive value + * @param inMax the highest inclusive value + * @return a reference to inVal if the value is in bounds, + inMin if lower than the minimum value, or + inMax if higher than maximum value. + */ +template <class T> +inline const T &Q3DStudio_clamp(const T &inVal, const T &inMin, const T &inMax) +{ + if (inVal <= inMin) + return inMin; + else if (inVal >= inMax) + return inMax; + + return inVal; +} + +//============================================================================== +/** + * Return the identified lower and higher values. + * @param inA one value to compare + * @param inB another value to compare + * @param outMin is assigned to the lower of the two compared values + * @param outMax is assigned to the higher of the two compared values + */ +template <class T> +inline void Q3DStudio_minmax(const T &inA, const T &inB, T &outMin, T &outMax) +{ + if (inA < inB) { + outMin = inA; + outMax = inB; + } else { + outMin = inB; + outMax = inA; + } +} + +//============================================================================== +/** + * Identify needed parameters that are not currently referenced. + */ +#define Q3DStudio_UNREFERENCED_PARAMETER(P) \ + { \ + (void)P; \ + } + +//============================================================================== +/** + * Assert + */ +#if defined(_DEBUG) || defined(_PROFILE) +#define Q3DStudio_ASSERT(inExpression) \ + { \ + if (!(inExpression)) \ + Q3DStudio::CAssert::GetFunction()(#inExpression, __FILE__, __LINE__, __FUNCTION__); \ + } +#else +#define Q3DStudio_ASSERT(inExpression) ((void)0) +#endif // _DEBUG or _PROFILE + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMatrix.cpp b/src/system/Qt3DSMatrix.cpp new file mode 100644 index 0000000..b5310d0 --- /dev/null +++ b/src/system/Qt3DSMatrix.cpp @@ -0,0 +1,897 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMatrix.h" +#include "Qt3DSVector3.h" +#include "Qt3DSEulerAngles.h" +#include "Qt3DSDataLogger.h" +#include <math.h> + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Constants +//============================================================================== +FLOAT g_IdentityInit[4][4] = { { 1.0f, 0.0f, 0.0f, 0.0f }, + { 0.0f, 1.0f, 0.0f, 0.0f }, + { 0.0f, 0.0f, 1.0f, 0.0f }, + { 0.0f, 0.0f, 0.0f, 1.0f } }; + +const RuntimeMatrix RuntimeMatrix::IDENTITY = RuntimeMatrix(g_IdentityInit); +extern const FLOAT RUNTIME_EPSILON; + +//============================================================================== +/** + * Empty constructor. + * Initializes this matrix to the identity matrix. + */ +RuntimeMatrix::RuntimeMatrix(const BOOL inInitializeIdentity /*= true*/) +{ + if (inInitializeIdentity) + Q3DStudio_memcpy(&m_Data, &IDENTITY, sizeof(m_Data)); +} + +//============================================================================== +/** + * Copy constructor. + * @param inMatrix the source matrix to copy + */ +RuntimeMatrix::RuntimeMatrix(const RuntimeMatrix &inMatrix) +{ + Q3DStudio_memcpy(&m_Data, &inMatrix.m_Data, sizeof(m_Data)); +} + +//============================================================================== +/** + * Assignment constructor. + * Initializes the matrix from an array. + * @param inComponents an array of 16 values + */ +RuntimeMatrix::RuntimeMatrix(const FLOAT inComponents[4][4]) +{ + if (inComponents) + Q3DStudio_memcpy(&m_Data, inComponents, sizeof(m_Data)); +} + +//============================================================================== +/** + * Sets this matrix to a NULL matrix with all values at zero. + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::Zero() +{ + Q3DStudio_memset(&m_Data, 0, sizeof(m_Data)); + return *this; +} + +//============================================================================== +/** + * Sets the matrix to the identity matrix. + * @return reference to this matrix + */ +RuntimeMatrix &RuntimeMatrix::Identity() +{ + Q3DStudio_memcpy(&m_Data, &IDENTITY, sizeof(m_Data)); + return *this; +} + +//============================================================================== +/** + * Copies the elements from another matrix. + * @param inMatrix the source matrix + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::Set(const RuntimeMatrix &inMatrix) +{ + Q3DStudio_memcpy(&m_Data, &inMatrix.m_Data, sizeof(m_Data)); + return *this; +} + +//============================================================================== +/** + * Copies the given components to this matrix. + * @param inComponents an array of 16 components + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::Set(const FLOAT inComponents[4][4]) +{ + if (inComponents) + Q3DStudio_memcpy(&m_Data, inComponents, sizeof(m_Data)); + return *this; +} + +//============================================================================== +/** + * Heavily optimized assignment method. This has the same result as creating + * four full 4x4 matrices and multiplying them together. + * @todo Look into optimized code. + * @param inTranslation translation coordinates + * @param inRotation Euler angle rotations + * @param inScale scaling dimensions + * @param inPivot pivot offset vector + * @param inRotationOrder rotation order + * @param inCoordinateSystem the coordindate system + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::Set(const RuntimeVector3 &inTranslation, const RuntimeVector3 &inRotation, + const RuntimeVector3 &inScale, const RuntimeVector3 &inPivot, const UINT8 inRotationOrder, + const UINT8 inCoordinateSystem) +{ + // *this = m_ScaleMatrix * m_PivotMatrix * m_RotMatrix * m_TransMatrix; // Distributed + //original - plain speak + + RuntimeVector3 theScaledPivot; + theScaledPivot.m_X = -inPivot.m_X * inScale.m_X; + theScaledPivot.m_Y = -inPivot.m_Y * inScale.m_Y; + theScaledPivot.m_Z = -inPivot.m_Z * inScale.m_Z; + + // This would take care of rotation in the right order + RuntimeMatrix theRotation; + theRotation.SetRotate(inRotation, inRotationOrder, inCoordinateSystem); + + Q3DStudio_memcpy(&m_Data, &IDENTITY, sizeof(m_Data)); + m_Data[0][0] = inScale.m_X; + m_Data[1][1] = inScale.m_Y; + m_Data[2][2] = inScale.m_Z; + + m_Data[3][0] = theScaledPivot.m_X; + m_Data[3][1] = theScaledPivot.m_Y; + + if (inCoordinateSystem == ORIENTATION_LEFT_HANDED) + m_Data[3][2] = theScaledPivot.m_Z; + else + m_Data[3][2] = -theScaledPivot.m_Z; + + MultiplyAffine(theRotation); // This could be optimized to only 9 multiplications instead of 16 + // if you do them by hand + + m_Data[3][0] += inTranslation.m_X; + m_Data[3][1] += inTranslation.m_Y; + + if (inCoordinateSystem == ORIENTATION_LEFT_HANDED) + m_Data[3][2] += inTranslation.m_Z; + else + m_Data[3][2] += -inTranslation.m_Z; + + if (inCoordinateSystem == ORIENTATION_LEFT_HANDED) + return FlipCoordinateSystem(); + + return *this; +} + +//============================================================================== +/** + * Sets the translation portion of the matrix without affecting the rest. + * + * If you want a pure translation matrix you must make sure to start with + * the identity matrix. + * @param inTranslate a translation vector + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::SetTranslate(const RuntimeVector3 &inTranslate) +{ + m_Data[3][0] = inTranslate.m_X; + m_Data[3][1] = inTranslate.m_Y; + m_Data[3][2] = inTranslate.m_Z; + return *this; +} + +//============================================================================== +/** + * Sets the rotation portion of the matrix without affecting the rest. + * + * FYI: The rotate and scale portions overlap. If you want a pure scale matrix + * you must make sure to start with the identity matrix. + * @param inRotation a quaternion describing the rotation + * @return reference to this modified matrix + */ +// CMatrix& CMatrix::SetRotate( const CQuaternion& inRotation ) +//{ +// inRotation.ToMatrix( *this ); +// return *this; +//} + +//============================================================================== +/** + * Sets the rotation portion of the matrix without affecting the rest. + * + * FYI: The rotate and scale portions overlap. If you want a pure rotation matrix + * you must make sure to start with the identity matrix. + * @param inRotation Euler angle rotation + * @param inRotationOrder rotation order + * @param inCoordinateSystem the coordindate system + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::SetRotate(const RuntimeVector3 &inRotation, const UINT8 inRotationOrder, + const UINT8 inCoordinateSystem) +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + Q3DStudio_UNREFERENCED_PARAMETER(inCoordinateSystem); + + EulerAngles theEulerAngles; + switch (inRotationOrder) { + case ROTATIONORDER_XYZ: + theEulerAngles.x = inRotation.m_X; + theEulerAngles.y = inRotation.m_Y; + theEulerAngles.z = inRotation.m_Z; + theEulerAngles.w = EulOrdXYZs; + break; + case ROTATIONORDER_XYZR: + theEulerAngles.x = inRotation.m_X; + theEulerAngles.y = inRotation.m_Y; + theEulerAngles.z = inRotation.m_Z; + theEulerAngles.w = EulOrdXYZr; + break; + case ROTATIONORDER_YZX: + theEulerAngles.x = inRotation.m_Y; + theEulerAngles.y = inRotation.m_Z; + theEulerAngles.z = inRotation.m_X; + theEulerAngles.w = EulOrdYZXs; + break; + case ROTATIONORDER_YZXR: + theEulerAngles.x = inRotation.m_Y; + theEulerAngles.y = inRotation.m_Z; + theEulerAngles.z = inRotation.m_X; + theEulerAngles.w = EulOrdYZXr; + break; + case ROTATIONORDER_ZXY: + theEulerAngles.x = inRotation.m_Z; + theEulerAngles.y = inRotation.m_X; + theEulerAngles.z = inRotation.m_Y; + theEulerAngles.w = EulOrdZXYs; + break; + case ROTATIONORDER_ZXYR: + theEulerAngles.x = inRotation.m_Z; + theEulerAngles.y = inRotation.m_X; + theEulerAngles.z = inRotation.m_Y; + theEulerAngles.w = EulOrdZXYr; + break; + case ROTATIONORDER_XZY: + theEulerAngles.x = inRotation.m_X; + theEulerAngles.y = inRotation.m_Z; + theEulerAngles.z = inRotation.m_Y; + theEulerAngles.w = EulOrdXZYs; + break; + case ROTATIONORDER_XZYR: + theEulerAngles.x = inRotation.m_X; + theEulerAngles.y = inRotation.m_Z; + theEulerAngles.z = inRotation.m_Y; + theEulerAngles.w = EulOrdXZYr; + break; + case ROTATIONORDER_YXZ: + theEulerAngles.x = inRotation.m_Y; + theEulerAngles.y = inRotation.m_X; + theEulerAngles.z = inRotation.m_Z; + theEulerAngles.w = EulOrdYXZs; + break; + case ROTATIONORDER_YXZR: + theEulerAngles.x = inRotation.m_Y; + theEulerAngles.y = inRotation.m_X; + theEulerAngles.z = inRotation.m_Z; + theEulerAngles.w = EulOrdYXZr; + break; + case ROTATIONORDER_ZYX: + theEulerAngles.x = inRotation.m_Z; + theEulerAngles.y = inRotation.m_Y; + theEulerAngles.z = inRotation.m_X; + theEulerAngles.w = EulOrdZYXs; + break; + case ROTATIONORDER_ZYXR: + theEulerAngles.x = inRotation.m_Z; + theEulerAngles.y = inRotation.m_Y; + theEulerAngles.z = inRotation.m_X; + theEulerAngles.w = EulOrdZYXr; + break; + default: // defaults to Studio's rotation type + theEulerAngles.x = inRotation.m_Y; + theEulerAngles.y = inRotation.m_X; + theEulerAngles.z = inRotation.m_Z; + theEulerAngles.w = EulOrdYXZs; + break; + } + + theEulerAngles.x *= -1; + theEulerAngles.y *= -1; + theEulerAngles.z *= -1; + + CEulerAngleConverter theConverter; + theConverter.Eul_ToHMatrix(theEulerAngles, m_Data); + + return *this; +} + +//============================================================================== +/** + * Sets the scale portion of the matrix without affecting the rest. + * + * FYI: The rotate and scale portions overlap. If you want a pure scale matrix + * you must make sure to start with the identity matrix. + * @param inScale scale vector + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::SetScale(const RuntimeVector3 &inScale) +{ + m_Data[0][0] = inScale.m_X; + m_Data[1][1] = inScale.m_Y; + m_Data[2][2] = inScale.m_Z; + return *this; +} + +//============================================================================== +/** + * Check this matrix against the identity matrix. + * @return true if this matrix is equivalent to the identity matrix + */ +BOOL RuntimeMatrix::IsIdentity() const +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + return *this == IDENTITY; +} + +//============================================================================== +/** + * Checks to see if this matrix is affine. + * An affine matrix has the last row being [ 0 0 0 1 ] + * @return true if the matrix is affine + */ +BOOL RuntimeMatrix::IsAffine() const +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + return m_Data[0][3] == 0 && m_Data[1][3] == 0 && m_Data[2][3] == 0 && m_Data[3][3] == 1.0f; +} + +//============================================================================== +/** + * Appends the matrix to include a translation. Equivalent to post-multiplying + * this matrix with a transformation matrix derived from the given vector. + * @param inTranslation transformation vector applied + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::Translate(const RuntimeVector3 &inTranslation) +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + m_Data[3][0] += inTranslation.m_X; + m_Data[3][1] += inTranslation.m_Y; + m_Data[3][2] += inTranslation.m_Z; + return *this; +} + +//============================================================================== +/** + * Appends the matrix to include a rotation. Equivalent to post-multiplying + * this matrix with a rotation matrix derived from the given quaternion. + * @param inRotation the rotation quaternion applied + * @return reference to this modified matrix + */ +// CMatrix& CMatrix::Rotate( const CQuaternion& inRotation ) +//{ +// CMatrix theRotation; +// return MultiplyAffine( inRotation.ToMatrix( theRotation ) ); +//} + +//============================================================================== +/** + * Appends the matrix to include scaling. Equivalent to post-multiplying + * this matrix with a scale matrix derived from the given vector. + * @param inScale the scale vector applied + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::Scale(const RuntimeVector3 &inScale) +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + m_Data[0][0] *= inScale.m_X; + m_Data[0][1] *= inScale.m_X; + m_Data[0][2] *= inScale.m_X; + + m_Data[1][0] *= inScale.m_Y; + m_Data[1][1] *= inScale.m_Y; + m_Data[1][2] *= inScale.m_Y; + + m_Data[2][0] *= inScale.m_Z; + m_Data[2][1] *= inScale.m_Z; + m_Data[2][2] *= inScale.m_Z; + return *this; +} + +//============================================================================== +/** + * Flips the matrix elements around the identity diagonal. + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::Transpose() +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + FLOAT theSwap = m_Data[1][0]; + m_Data[1][0] = m_Data[0][1]; + m_Data[0][1] = theSwap; + + theSwap = m_Data[2][0]; + m_Data[2][0] = m_Data[0][2]; + m_Data[0][2] = theSwap; + + theSwap = m_Data[3][0]; + m_Data[3][0] = m_Data[0][3]; + m_Data[0][3] = theSwap; + + theSwap = m_Data[2][1]; + m_Data[2][1] = m_Data[1][2]; + m_Data[1][2] = theSwap; + + theSwap = m_Data[3][1]; + m_Data[3][1] = m_Data[1][3]; + m_Data[1][3] = theSwap; + + theSwap = m_Data[3][2]; + m_Data[3][2] = m_Data[2][3]; + m_Data[2][3] = theSwap; + + return *this; +} + +//============================================================================== +/** + * Compute the inverse of a 3D affine matrix; i.e. a matrix with a + * dimensionality of 4 where the bottom row has the entries (0, 0, 0, 1). + * + * This procedure treats the 4 by 4 matrix as a block matrix and + * calculates the inverse of one submatrix for a significant performance + * improvement over a general procedure that can invert any non-singular matrix: +@code + | | -1 | -1 -1 | + | A C | | A -C A | + -1 | | | | + M = | | = | | + | 0 1 | | 0 1 | + | | | | +@endcode + * where M is a 4 by 4 matrix, + * A is the 3 by 3 upper left submatrix of M, + * C is the 3 by 1 upper right submatrix of M. + * + * @return the determinant of matrix + */ +FLOAT RuntimeMatrix::Invert() +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + const FLOAT PRECISIONLIMIT = 1.0e-07f; + FLOAT thePositiveDet = 0.0f; + FLOAT theNegativeDet = 0.0f; + FLOAT theTempDet; + + // Calculate the determinant of submatrix A and determine if the + // the matrix is singular as limited by the float precision. + theTempDet = m_Data[0][0] * m_Data[1][1] * m_Data[2][2]; + if (theTempDet >= 0.0f) + thePositiveDet += theTempDet; + else + theNegativeDet += theTempDet; + + theTempDet = m_Data[0][1] * m_Data[1][2] * m_Data[2][0]; + if (theTempDet >= 0.0f) + thePositiveDet += theTempDet; + else + theNegativeDet += theTempDet; + + theTempDet = m_Data[0][2] * m_Data[1][0] * m_Data[2][1]; + if (theTempDet >= 0.0f) + thePositiveDet += theTempDet; + else + theNegativeDet += theTempDet; + + theTempDet = -m_Data[0][2] * m_Data[1][1] * m_Data[2][0]; + if (theTempDet >= 0.0f) + thePositiveDet += theTempDet; + else + theNegativeDet += theTempDet; + + theTempDet = -m_Data[0][1] * m_Data[1][0] * m_Data[2][2]; + if (theTempDet >= 0.0f) + thePositiveDet += theTempDet; + else + theNegativeDet += theTempDet; + + theTempDet = -m_Data[0][0] * m_Data[1][2] * m_Data[2][1]; + if (theTempDet >= 0.0f) + thePositiveDet += theTempDet; + else + theNegativeDet += theTempDet; + + // Is the submatrix A nonsingular? (i.e. there is an inverse?) + FLOAT theDeterminant = thePositiveDet + theNegativeDet; + if (theDeterminant != 0 + || ::fabs(theDeterminant / (thePositiveDet - theNegativeDet)) >= PRECISIONLIMIT) { + RuntimeMatrix theInverse; + FLOAT theInvDeterminant = 1.0f / theDeterminant; + + // Calculate inverse(A) = adj(A) / det(A) + theInverse.m_Data[0][0] = + (m_Data[1][1] * m_Data[2][2] - m_Data[1][2] * m_Data[2][1]) * theInvDeterminant; + theInverse.m_Data[1][0] = + -(m_Data[1][0] * m_Data[2][2] - m_Data[1][2] * m_Data[2][0]) * theInvDeterminant; + theInverse.m_Data[2][0] = + (m_Data[1][0] * m_Data[2][1] - m_Data[1][1] * m_Data[2][0]) * theInvDeterminant; + theInverse.m_Data[0][1] = + -(m_Data[0][1] * m_Data[2][2] - m_Data[0][2] * m_Data[2][1]) * theInvDeterminant; + theInverse.m_Data[1][1] = + (m_Data[0][0] * m_Data[2][2] - m_Data[0][2] * m_Data[2][0]) * theInvDeterminant; + theInverse.m_Data[2][1] = + -(m_Data[0][0] * m_Data[2][1] - m_Data[0][1] * m_Data[2][0]) * theInvDeterminant; + theInverse.m_Data[0][2] = + (m_Data[0][1] * m_Data[1][2] - m_Data[0][2] * m_Data[1][1]) * theInvDeterminant; + theInverse.m_Data[1][2] = + -(m_Data[0][0] * m_Data[1][2] - m_Data[0][2] * m_Data[1][0]) * theInvDeterminant; + theInverse.m_Data[2][2] = + (m_Data[0][0] * m_Data[1][1] - m_Data[0][1] * m_Data[1][0]) * theInvDeterminant; + + // Calculate -C * inverse(A) + theInverse.m_Data[3][0] = + -(m_Data[3][0] * theInverse.m_Data[0][0] + m_Data[3][1] * theInverse.m_Data[1][0] + + m_Data[3][2] * theInverse.m_Data[2][0]); + theInverse.m_Data[3][1] = + -(m_Data[3][0] * theInverse.m_Data[0][1] + m_Data[3][1] * theInverse.m_Data[1][1] + + m_Data[3][2] * theInverse.m_Data[2][1]); + theInverse.m_Data[3][2] = + -(m_Data[3][0] * theInverse.m_Data[0][2] + m_Data[3][1] * theInverse.m_Data[1][2] + + m_Data[3][2] * theInverse.m_Data[2][2]); + + // assign ourselves to the inverse + *this = theInverse; + } + + return theDeterminant; +} + +//============================================================================== +/** + * Fast multiplication of two affine 4x4 matrices. No affine pre-check. + * @todo MF - Convert to SSE Assembly Code + * @param inMatrix the source matrix + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::MultiplyAffine(const RuntimeMatrix &inMatrix) +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + FLOAT theMult[4][4]; + + theMult[0][0] = m_Data[0][0] * inMatrix.m_Data[0][0] + m_Data[0][1] * inMatrix.m_Data[1][0] + + m_Data[0][2] * inMatrix.m_Data[2][0]; + theMult[0][1] = m_Data[0][0] * inMatrix.m_Data[0][1] + m_Data[0][1] * inMatrix.m_Data[1][1] + + m_Data[0][2] * inMatrix.m_Data[2][1]; + theMult[0][2] = m_Data[0][0] * inMatrix.m_Data[0][2] + m_Data[0][1] * inMatrix.m_Data[1][2] + + m_Data[0][2] * inMatrix.m_Data[2][2]; + theMult[0][3] = 0; + + theMult[1][0] = m_Data[1][0] * inMatrix.m_Data[0][0] + m_Data[1][1] * inMatrix.m_Data[1][0] + + m_Data[1][2] * inMatrix.m_Data[2][0]; + theMult[1][1] = m_Data[1][0] * inMatrix.m_Data[0][1] + m_Data[1][1] * inMatrix.m_Data[1][1] + + m_Data[1][2] * inMatrix.m_Data[2][1]; + theMult[1][2] = m_Data[1][0] * inMatrix.m_Data[0][2] + m_Data[1][1] * inMatrix.m_Data[1][2] + + m_Data[1][2] * inMatrix.m_Data[2][2]; + theMult[1][3] = 0; + + theMult[2][0] = m_Data[2][0] * inMatrix.m_Data[0][0] + m_Data[2][1] * inMatrix.m_Data[1][0] + + m_Data[2][2] * inMatrix.m_Data[2][0]; + theMult[2][1] = m_Data[2][0] * inMatrix.m_Data[0][1] + m_Data[2][1] * inMatrix.m_Data[1][1] + + m_Data[2][2] * inMatrix.m_Data[2][1]; + theMult[2][2] = m_Data[2][0] * inMatrix.m_Data[0][2] + m_Data[2][1] * inMatrix.m_Data[1][2] + + m_Data[2][2] * inMatrix.m_Data[2][2]; + theMult[2][3] = 0; + + theMult[3][0] = m_Data[3][0] * inMatrix.m_Data[0][0] + m_Data[3][1] * inMatrix.m_Data[1][0] + + m_Data[3][2] * inMatrix.m_Data[2][0] + inMatrix.m_Data[3][0]; + theMult[3][1] = m_Data[3][0] * inMatrix.m_Data[0][1] + m_Data[3][1] * inMatrix.m_Data[1][1] + + m_Data[3][2] * inMatrix.m_Data[2][1] + inMatrix.m_Data[3][1]; + theMult[3][2] = m_Data[3][0] * inMatrix.m_Data[0][2] + m_Data[3][1] * inMatrix.m_Data[1][2] + + m_Data[3][2] * inMatrix.m_Data[2][2] + inMatrix.m_Data[3][2]; + theMult[3][3] = 1.0f; + + return Set(theMult); +} + +//============================================================================== +/** + * Standard matrix multiplication + * @todo MF - Convert to SSE Assembly Code + * @param inMatrix matrix to multiply with + */ +RuntimeMatrix &RuntimeMatrix::Multiply(const RuntimeMatrix &inMatrix) +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + FLOAT theMult[4][4]; + + theMult[0][0] = m_Data[0][0] * inMatrix.m_Data[0][0] + m_Data[1][0] * inMatrix.m_Data[0][1] + + m_Data[2][0] * inMatrix.m_Data[0][2] + m_Data[3][0] * inMatrix.m_Data[0][3]; + theMult[0][1] = m_Data[0][1] * inMatrix.m_Data[0][0] + m_Data[1][1] * inMatrix.m_Data[0][1] + + m_Data[2][1] * inMatrix.m_Data[0][2] + m_Data[3][1] * inMatrix.m_Data[0][3]; + theMult[0][2] = m_Data[0][2] * inMatrix.m_Data[0][0] + m_Data[1][2] * inMatrix.m_Data[0][1] + + m_Data[2][2] * inMatrix.m_Data[0][2] + m_Data[3][2] * inMatrix.m_Data[0][3]; + theMult[0][3] = m_Data[0][3] * inMatrix.m_Data[0][0] + m_Data[1][3] * inMatrix.m_Data[0][1] + + m_Data[2][3] * inMatrix.m_Data[0][2] + m_Data[3][3] * inMatrix.m_Data[0][3]; + theMult[1][0] = m_Data[0][0] * inMatrix.m_Data[1][0] + m_Data[1][0] * inMatrix.m_Data[1][1] + + m_Data[2][0] * inMatrix.m_Data[1][2] + m_Data[3][0] * inMatrix.m_Data[1][3]; + theMult[1][1] = m_Data[0][1] * inMatrix.m_Data[1][0] + m_Data[1][1] * inMatrix.m_Data[1][1] + + m_Data[2][1] * inMatrix.m_Data[1][2] + m_Data[3][1] * inMatrix.m_Data[1][3]; + theMult[1][2] = m_Data[0][2] * inMatrix.m_Data[1][0] + m_Data[1][2] * inMatrix.m_Data[1][1] + + m_Data[2][2] * inMatrix.m_Data[1][2] + m_Data[3][2] * inMatrix.m_Data[1][3]; + theMult[1][3] = m_Data[0][3] * inMatrix.m_Data[1][0] + m_Data[1][3] * inMatrix.m_Data[1][1] + + m_Data[2][3] * inMatrix.m_Data[1][2] + m_Data[3][3] * inMatrix.m_Data[1][3]; + theMult[2][0] = m_Data[0][0] * inMatrix.m_Data[2][0] + m_Data[1][0] * inMatrix.m_Data[2][1] + + m_Data[2][0] * inMatrix.m_Data[2][2] + m_Data[3][0] * inMatrix.m_Data[2][3]; + theMult[2][1] = m_Data[0][1] * inMatrix.m_Data[2][0] + m_Data[1][1] * inMatrix.m_Data[2][1] + + m_Data[2][1] * inMatrix.m_Data[2][2] + m_Data[3][1] * inMatrix.m_Data[2][3]; + theMult[2][2] = m_Data[0][2] * inMatrix.m_Data[2][0] + m_Data[1][2] * inMatrix.m_Data[2][1] + + m_Data[2][2] * inMatrix.m_Data[2][2] + m_Data[3][2] * inMatrix.m_Data[2][3]; + theMult[2][3] = m_Data[0][3] * inMatrix.m_Data[2][0] + m_Data[1][3] * inMatrix.m_Data[2][1] + + m_Data[2][3] * inMatrix.m_Data[2][2] + m_Data[3][3] * inMatrix.m_Data[2][3]; + + theMult[3][0] = m_Data[0][0] * inMatrix.m_Data[3][0] + m_Data[1][0] * inMatrix.m_Data[3][1] + + m_Data[2][0] * inMatrix.m_Data[3][2] + m_Data[3][0] * inMatrix.m_Data[3][3]; + theMult[3][1] = m_Data[0][1] * inMatrix.m_Data[3][0] + m_Data[1][1] * inMatrix.m_Data[3][1] + + m_Data[2][1] * inMatrix.m_Data[3][2] + m_Data[3][1] * inMatrix.m_Data[3][3]; + theMult[3][2] = m_Data[0][2] * inMatrix.m_Data[3][0] + m_Data[1][2] * inMatrix.m_Data[3][1] + + m_Data[2][2] * inMatrix.m_Data[3][2] + m_Data[3][2] * inMatrix.m_Data[3][3]; + theMult[3][3] = m_Data[0][3] * inMatrix.m_Data[3][0] + m_Data[1][3] * inMatrix.m_Data[3][1] + + m_Data[2][3] * inMatrix.m_Data[3][2] + m_Data[3][3] * inMatrix.m_Data[3][3]; + + return Set(theMult); +} + +//============================================================================== +/** + * Toggle between left-hand and right-hand coordinate system + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::FlipCoordinateSystem() +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + // rotation conversion + m_Data[0][2] *= -1; + m_Data[1][2] *= -1; + m_Data[2][0] *= -1; + m_Data[2][1] *= -1; + + // translation conversion + m_Data[3][2] *= -1; + + return *this; +} + +//============================================================================== +/** + * Rotate this matrix to align with the rotation of the specified matrix. + * + * @param inMatrix the maxtrix we are cloning. + * @param inMirrorFlag flag indicating that we should flip the z and face the opposite + *direction. + * @return This matrix after the rotation. + */ +RuntimeMatrix &RuntimeMatrix::CloneRotation(const RuntimeMatrix &inMatrix, BOOL inMirrorFlag /*= false*/) +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + // Create the axes + RuntimeVector3 theZ(inMatrix.Get(2, 0), inMatrix.Get(2, 1), inMatrix.Get(2, 2)); + if (inMirrorFlag) + theZ *= -1; + RuntimeVector3 theY(inMatrix.Get(1, 0), inMatrix.Get(1, 1), inMatrix.Get(1, 2)); + RuntimeVector3 theX(theY); + theX.CrossProduct(theZ); + + // Normalize + theX.Normalize(); + theY.Normalize(); + theZ.Normalize(); + + // Copy it into the matrix + m_Data[0][0] = theX.m_X; + m_Data[0][1] = theX.m_Y; + m_Data[0][2] = theX.m_Z; + + m_Data[1][0] = theY.m_X; + m_Data[1][1] = theY.m_Y; + m_Data[1][2] = theY.m_Z; + + m_Data[2][0] = theZ.m_X; + m_Data[2][1] = theZ.m_Y; + m_Data[2][2] = theZ.m_Z; + + return *this; +} + +//============================================================================== +/** + * Compute the square distance between the position vectors of two transforms. + * @param inMatrix the other transform, signifying a global object position for example + * @return the square of the "distance" between the two transforms + */ +FLOAT RuntimeMatrix::SquareDistance(const RuntimeMatrix &inMatrix) const +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + FLOAT theResult = 0; + FLOAT theFactor; + + theFactor = m_Data[3][0] - inMatrix.m_Data[3][0]; + theFactor *= theFactor; + theResult += theFactor; + + theFactor = m_Data[3][1] - inMatrix.m_Data[3][1]; + theFactor *= theFactor; + theResult += theFactor; + + theFactor = m_Data[3][2] - inMatrix.m_Data[3][2]; + theFactor *= theFactor; + theResult += theFactor; + + return theResult; +} + +//============================================================================== +/** + * Simple assignment operator. + * @param inMatrix new matrix being assigned + * @return reference to this modified matrix + */ +RuntimeMatrix &RuntimeMatrix::operator=(const RuntimeMatrix &inMatrix) +{ + Q3DStudio_memcpy(&m_Data, &inMatrix.m_Data, sizeof(m_Data)); + return *this; +} + +//============================================================================== +/** + * Compares this matrix's elements with another matrix's and returns true + * if the matrices are equivalent. + * @param inMatrix the matrix we are comparing against + * @return true if all elements are within EPSILON of each other. + */ +BOOL RuntimeMatrix::operator==(const RuntimeMatrix &inMatrix) const +{ + PerfLogMathEvent1(DATALOGGER_MATRIX); + + for (INT32 iRow = 0; iRow < 4; ++iRow) { + for (INT32 iCol = 0; iCol < 4; ++iCol) { + if (::fabs(m_Data[iRow][iCol] - inMatrix.m_Data[iRow][iCol]) > RUNTIME_EPSILON) + return false; + } + } + return true; +} + +//============================================================================== +/** + * Compares this matrix's elements with another matrix's and returns true + * if the matrices are not equivalent. + * @param inMatrix the matrix we are comparing against + * @return true if one or more elements are more than EPSILON from each other + */ +BOOL RuntimeMatrix::operator!=(const RuntimeMatrix &inMatrix) const +{ + // Reuse same code path.. + return !(*this == inMatrix); +} + +//============================================================================== +/** + * Standardized conversion to string. + * @param outString string becoming a representation for the matrix + */ +// void CMatrix::ToString( AK_STRING& outString ) const +//{ +// INT8 theBuffer[ 256 ]; +// +// Q3DStudio_sprintf +// ( +// theBuffer, 255, +// "%.2f %.2f %.2f %.2f " +// "%.2f %.2f %.2f %.2f " +// "%.2f %.2f %.2f %.2f " +// "%.2f %.2f %.2f %.2f", +// +// m_Data.m[ 0 ][ 0 ], +// m_Data.m[ 0 ][ 1 ], +// m_Data.m[ 0 ][ 2 ], +// m_Data.m[ 0 ][ 3 ], +// +// m_Data.m[ 1 ][ 0 ], +// m_Data.m[ 1 ][ 1 ], +// m_Data.m[ 1 ][ 2 ], +// m_Data.m[ 1 ][ 3 ], +// +// m_Data.m[ 2 ][ 0 ], +// m_Data.m[ 2 ][ 1 ], +// m_Data.m[ 2 ][ 2 ], +// m_Data.m[ 2 ][ 3 ], +// +// m_Data.m[ 3 ][ 0 ], +// m_Data.m[ 3 ][ 1 ], +// m_Data.m[ 3 ][ 2 ], +// m_Data.m[ 3 ][ 3 ] +// ); +// +// outString = theBuffer; +//} +// +////============================================================================== +///** +// * Standardized conversion from string. +// * @param inString string being a representation for the matrix +// */ +// void CMatrix::FromString( const AK_STRING& inString ) +//{ +// std::sscanf +// ( +// inString.c_str( ), +// +// "%f %f %f %f " +// "%f %f %f %f " +// "%f %f %f %f " +// "%f %f %f %f", +// +// &m_Data.m[ 0 ][ 0 ], +// &m_Data.m[ 0 ][ 1 ], +// &m_Data.m[ 0 ][ 2 ], +// &m_Data.m[ 0 ][ 3 ], +// +// &m_Data.m[ 1 ][ 0 ], +// &m_Data.m[ 1 ][ 1 ], +// &m_Data.m[ 1 ][ 2 ], +// &m_Data.m[ 1 ][ 3 ], +// +// &m_Data.m[ 2 ][ 0 ], +// &m_Data.m[ 2 ][ 1 ], +// &m_Data.m[ 2 ][ 2 ], +// &m_Data.m[ 2 ][ 3 ], +// +// &m_Data.m[ 3 ][ 0 ], +// &m_Data.m[ 3 ][ 1 ], +// &m_Data.m[ 3 ][ 2 ], +// &m_Data.m[ 3 ][ 3 ] +// ); +//} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMatrix.h b/src/system/Qt3DSMatrix.h new file mode 100644 index 0000000..4ef7442 --- /dev/null +++ b/src/system/Qt3DSMatrix.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Forwards +//============================================================================== +class RuntimeVector3; + +//============================================================================== +/** + * A row major matrix for 3D transformation. + * + * Matrix[row][column] +@code + | 0 1 2 3 | or | 00 01 02 03 | or | Xx Xy Xz w | + | 4 5 6 7 | | 10 11 12 13 | | Yx Yy Yz w | + | 8 9 A B | | 20 21 22 23 | | Zx Zy Zz w | + | C D E F | | 30 31 32 33 | | Tx Ty Tz w | +@endcode + * Rotations are concatenated in the the following order: YXZ + * All rotations are clockwise when viewed down the positive axis + * towards the origin. + */ +class RuntimeMatrix +{ + //============================================================================== + // Enumerations + //============================================================================== +public: + enum ERotationOrder { + ROTATIONORDER_XYZ = 0, + ROTATIONORDER_YZX, + ROTATIONORDER_ZXY, + ROTATIONORDER_XZY, + ROTATIONORDER_YXZ, + ROTATIONORDER_ZYX, + + ROTATIONORDER_XYZR, + ROTATIONORDER_YZXR, + ROTATIONORDER_ZXYR, + ROTATIONORDER_XZYR, + ROTATIONORDER_YXZR, + ROTATIONORDER_ZYXR + }; + + enum EOrientation { ORIENTATION_LEFT_HANDED = 0, ORIENTATION_RIGHT_HANDED }; + + //============================================================================== + // Constants + //============================================================================== +public: + static const RuntimeMatrix IDENTITY; ///< Enabling fast initialization from static identity matrix + + //============================================================================== + // Fields + //============================================================================== +public: + FLOAT m_Data[4][4]; ///< 16 elements in a 4 x 4 + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + RuntimeMatrix(const BOOL inInitializeIdentity = true); + RuntimeMatrix(const RuntimeMatrix &inMatrix); + RuntimeMatrix(const FLOAT inComponents[4][4]); + +public: // Initialization + RuntimeMatrix &Zero(); + RuntimeMatrix &Identity(); + + RuntimeMatrix &Set(const RuntimeMatrix &inMatrix); + RuntimeMatrix &Set(const FLOAT inComponents[4][4]); + RuntimeMatrix &Set(const RuntimeVector3 &inTranslation, const RuntimeVector3 &inRotation, const RuntimeVector3 &inScale, + const RuntimeVector3 &inPivot, const UINT8 inRotationOrder, + const UINT8 inCoordinateSystem); + + RuntimeMatrix &SetTranslate(const RuntimeVector3 &inTranslate); + RuntimeMatrix &SetRotate(const RuntimeVector3 &inRotation, const UINT8 inRotationOrder = ROTATIONORDER_XYZ, + const UINT8 inCoordinateSystem = ORIENTATION_LEFT_HANDED); + RuntimeMatrix &SetScale(const RuntimeVector3 &inScale); + +public: // Functions + BOOL IsIdentity() const; + BOOL IsAffine() const; + RuntimeMatrix &Translate(const RuntimeVector3 &inTranslate); + RuntimeMatrix &Scale(const RuntimeVector3 &inScale); + RuntimeMatrix &Transpose(); + FLOAT Invert(); + RuntimeMatrix &MultiplyAffine(const RuntimeMatrix &inMatrix); + RuntimeMatrix &Multiply(const RuntimeMatrix &inMatrix); + RuntimeMatrix &FlipCoordinateSystem(); + RuntimeMatrix &CloneRotation(const RuntimeMatrix &inMatrix, BOOL inMirrorFlag = false); + FLOAT SquareDistance(const RuntimeMatrix &inMatrix) const; + +public: // Operators + RuntimeMatrix &operator=(const RuntimeMatrix &inMatrix); + BOOL operator==(const RuntimeMatrix &inMatrix) const; + BOOL operator!=(const RuntimeMatrix &inMatrix) const; + +public: // Script based accessors + inline FLOAT Get(const INT32 inRow, const INT32 inColumn) const + { + return m_Data[inRow][inColumn]; + } + inline void Set(const INT32 inRow, const INT32 inColumn, const FLOAT inValue) + { + m_Data[inRow][inColumn] = inValue; + } +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemory.cpp b/src/system/Qt3DSMemory.cpp new file mode 100644 index 0000000..17fa5c8 --- /dev/null +++ b/src/system/Qt3DSMemory.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemory.h" + +//============================================================================== +// OS level memory routines +//============================================================================== +Q3DStudio::CMemory::TMalloc Q3DStudio::CMemory::s_Malloc = NULL; +Q3DStudio::CMemory::TRealloc Q3DStudio::CMemory::s_Realloc = NULL; +Q3DStudio::CMemory::TFree Q3DStudio::CMemory::s_Free = NULL; + +//============================================================================== +/** + * Overrides basic memory allocation/deallocation routines + * @param inMalloc memory allocation routine + * @param inFree memory deallocation routine + * @param inRealloc memory reallocation routine + */ +void Q3DStudio::CMemory::SetMemoryFunctions(const TMalloc inMalloc, const TFree inFree, + const TRealloc inRealloc) +{ + s_Malloc = inMalloc; + s_Realloc = inRealloc; + s_Free = inFree; +} + +static Q3DStudio::CMemoryManager *s_globalManager = nullptr; +static Q3DStudio::CMemoryHeap *s_globalHeap = nullptr; + +//============================================================================== +/** + * Boot up the pooled memory manager and return it. + * @note The manager has to be initialized before use: + * GetMemoryManager( ).Initialize( "GlobalManager", g_ChunkSize, g_ChunkCount ); + * @return Q3DStudio::CMemoryManager reference to the global object + */ +Q3DStudio::CMemoryManager &GetMemoryManager() +{ + if (!s_globalManager) + s_globalManager = new Q3DStudio::CMemoryManager; + return *s_globalManager; +} + +//============================================================================== +/** + * Return a reference to the global heap object. + * @return Q3DStudio::CMemoryHeap reference to the global object + */ +Q3DStudio::CMemoryHeap &GetMemoryHeap() +{ + if (!s_globalHeap) + s_globalHeap = new Q3DStudio::CMemoryHeap; + return *s_globalHeap; +} + +//============================================================================== +// Q3DStudio_new operator prototypes (5 args) +//============================================================================== +void *operator new(size_t inReportedSize, size_t inOfficialSize, const char *inType, + const char *inFile, int inLine) +{ + Q3DStudio_UNREFERENCED_PARAMETER(inReportedSize); + Q3DStudio_ASSERT(inReportedSize == inOfficialSize); + + return Q3DStudio_HANDLER_NEW.Allocate(static_cast<const Q3DStudio::INT32>(inOfficialSize), + inType, inFile, inLine); +} + +//============================================================================== +/** + * Override 'operator delete' in order to track memory usage. + * + * So what's the use of the overloaded delete with special arguments? There is + * actually one case in which it will be called--when an exception is thrown + * during object construction. As you might recall, there is a contract implicit + * in the language that if an exception happens during the construction of an object, + * the memory for this object will be automatically deallocated. It so happens + * that during object's construction the compiler is still aware of which version + * of operator new was called to allocate memory. It is therefore able to generate + * a call to the corresponding version of delete, in case an exception is thrown. + * After the successful completion of construction, this information is no longer + * available and the compiler has no means to guess which version of global delete + * is appropriate for a given object. + */ +void operator delete(void *inReportedAddress, size_t inOfficialSize, const char *, const char *, + int) +{ + Q3DStudio_HANDLER_NEW.Free(inReportedAddress, + static_cast<const Q3DStudio::INT32>(inOfficialSize)); +} + +//============================================================================== +// Q3DStudio_virtual_new operators (4 args) +//============================================================================== +void *operator new(size_t inReportedSize, const char *inType, const char *inFile, int inLine) +{ + return Q3DStudio::CMemoryFilter::Allocate(static_cast<Q3DStudio::INT32>(inReportedSize), inType, + inFile, inLine, false); +} + +void operator delete(void *inReportedAddress, const char *, const char *, int) +{ + Q3DStudio::CMemoryFilter::Free(inReportedAddress); +} diff --git a/src/system/Qt3DSMemory.h b/src/system/Qt3DSMemory.h new file mode 100644 index 0000000..cc04bf7 --- /dev/null +++ b/src/system/Qt3DSMemory.h @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#ifndef _INTEGRITYPLATFORM +#include <memory.h> +#endif +#include "Qt3DSMemoryHeap.h" +#include "Qt3DSMemoryManager.h" +#include "Qt3DSMemoryFilter.h" +#include "Qt3DSMemoryStatistics.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Single overridable exit point for all low level memory calls. + */ +class CMemory +{ + //============================================================================== + // Typedefs + //============================================================================== +public: + typedef void *(*TMalloc)(size_t inSize); + typedef void (*TFree)(void *inPtr); + typedef void *(*TRealloc)(void *inPtr, size_t inSize); + + //============================================================================== + // Fields + //============================================================================== +protected: + static TMalloc s_Malloc; ///< function pointer to malloc operation + static TFree s_Free; ///< function pointer to free operation + static TRealloc s_Realloc; ///< function pointer to realloc operation + + //============================================================================== + // Methods + //============================================================================== +public: // Memory override + static void SetMemoryFunctions(const TMalloc inMalloc, const TFree inFree, + const TRealloc inRealloc); + +public: // Function access + static TMalloc Malloc() { return s_Malloc; } + static TFree Free() { return s_Free; } + static TRealloc Realloc() { return s_Realloc; } +}; + +} // namespace Q3DStudio + +//============================================================================== +// Globals +//============================================================================== +Q3DStudio::CMemoryManager &GetMemoryManager(); +Q3DStudio::CMemoryHeap &GetMemoryHeap(); + +//============================================================================== +// Handlers +//============================================================================== +#ifndef Q3DStudio_HANDLER_NEW +#define Q3DStudio_HANDLER_NEW GetMemoryManager() +#endif // Q3DStudio_HANDLER_NEW + +#ifndef Q3DStudio_HANDLER_ALLOC +#define Q3DStudio_HANDLER_ALLOC GetMemoryManager() +#endif // Q3DStudio_HANDLER_ALLOC + +#ifndef Q3DStudio_HANDLER_FILTER +#define Q3DStudio_HANDLER_FILTER GetMemoryManager() +#endif // Q3DStudio_HANDLER_FILTER + +//============================================================================== +// Q3DStudio new defines +//============================================================================== +#undef new +#undef delete + +#ifndef Q3DStudio_new +#define Q3DStudio_new(type) new (sizeof(type), "class " #type, __FILE__, __LINE__) +#endif // Q3DStudio_new + +#ifndef Q3DStudio_delete +#define Q3DStudio_delete(ptr, type) \ + if (ptr) { \ + reinterpret_cast<type *>(ptr)->~type(); \ + Q3DStudio_HANDLER_NEW.Free(ptr, sizeof(type)); \ + } +#endif // Q3DStudio_delete + +#ifndef Q3DStudio_virtual_new +#define Q3DStudio_virtual_new(type) new ("class " #type, __FILE__, __LINE__) +#endif // Q3DStudio_virtual_new + +#ifndef Q3DStudio_virtual_delete +#define Q3DStudio_virtual_delete(ptr, type) \ + if (ptr) { \ + static_cast<type *>(ptr)->~type(); \ + Q3DStudio::CMemoryFilter::Free(ptr); \ + } +#endif // Q3DStudio_virtual_delete + +//============================================================================== +// Q3DStudio alloc defines +//============================================================================== +#ifndef Q3DStudio_allocate +#define Q3DStudio_allocate(type, count) \ + reinterpret_cast<type *>(Q3DStudio_HANDLER_ALLOC.Allocate( \ + static_cast<Q3DStudio::INT32>(sizeof(type) * (count)), #type "[]", __FILE__, __LINE__)) +#endif // Q3DStudio_allocate + +#ifndef Q3DStudio_allocate_desc +#define Q3DStudio_allocate_desc(type, count, desc) \ + reinterpret_cast<type *>(Q3DStudio_HANDLER_ALLOC.Allocate( \ + static_cast<Q3DStudio::INT32>(sizeof(type) * (count)), desc, __FILE__, __LINE__)) +#endif // Q3DStudio_allocate_desc + +#ifndef Q3DStudio_reallocate +#define Q3DStudio_reallocate(ptr, type, oldcount, newcount) \ + reinterpret_cast<type *>(Q3DStudio_HANDLER_ALLOC.Reallocate( \ + ptr, static_cast<Q3DStudio::INT32>(sizeof(type) * (oldcount)), \ + static_cast<INT32>(sizeof(type) * (newcount)), #type "[]", __FILE__, __LINE__)) +#endif // Q3DStudio_reallocate + +#ifndef Q3DStudio_reallocate_desc +#define Q3DStudio_reallocate_desc(ptr, type, oldcount, newcount, desc) \ + reinterpret_cast<type *>(Q3DStudio_HANDLER_ALLOC.Reallocate( \ + ptr, static_cast<Q3DStudio::INT32>(sizeof(type) * (oldcount)), \ + static_cast<INT32>(sizeof(type) * (newcount)), desc, __FILE__, __LINE__)) +#endif // Q3DStudio_reallocate_desc + +#ifndef Q3DStudio_free +#define Q3DStudio_free(ptr, type, count) \ + Q3DStudio_HANDLER_ALLOC.Free(ptr, static_cast<Q3DStudio::INT32>(sizeof(type) * (count))) +#endif // Q3DStudio_free + +//============================================================================== +// Q3DStudio_new - operator prototypes (5 args) +//============================================================================== +void *operator new(size_t inReportedSize, size_t inOfficialSize, const char *inType, + const char *inFile, int inLine); +void operator delete(void *inReportedAddress, size_t inOfficialSize, const char *, const char *, + int); + +//============================================================================== +// Q3DStudio_virtual_new and new - operator prototypes (4 args) +//============================================================================== +void *operator new(size_t inReportedSize, const char *inType, const char *inFile, int inLine); +void operator delete(void *inReportedAddress, const char *, const char *, int); diff --git a/src/system/Qt3DSMemoryFilter.cpp b/src/system/Qt3DSMemoryFilter.cpp new file mode 100644 index 0000000..f6d6591 --- /dev/null +++ b/src/system/Qt3DSMemoryFilter.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemoryFilter.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Allocate a chunk of memory and add a header to track it. + * @param inSize size of requested memory block, in bytes + * @param inType allocation description + * @param inFile file name + * @param inFunction method name + * @param inLine line number + * @param inClear true to clear allocated memory to zero + * @return void* a pointer to a memory block large enough to hold inSize bytes + */ +void *CMemoryFilter::Allocate(const INT32 inSize, const CHAR *inType, const CHAR *inFile, + const INT32 inLine, const BOOL inClear) +{ + const INT32 theTotalSize = inSize + Q3DStudio_MEMORY_ALIGNMENT; + + INT32 *theMemory = reinterpret_cast<INT32 *>( + Q3DStudio_HANDLER_FILTER.Allocate(theTotalSize, inType, inFile, inLine)); + + theMemory[0] = FILTER_DOGTAG; + theMemory[1] = theTotalSize; + + if (inClear) + Q3DStudio_memset(reinterpret_cast<INT8 *>(theMemory) + Q3DStudio_MEMORY_ALIGNMENT, 0, + inSize); + + return reinterpret_cast<INT8 *>(theMemory) + Q3DStudio_MEMORY_ALIGNMENT; +} + +//============================================================================== +/** + * Free a block of memory that was allocated and tagged here. + * @param inPointer pointer given in a previous filter allocation + */ +void CMemoryFilter::Free(void *inPointer) +{ + if (!inPointer) + return; + + INT32 *theMemory = + reinterpret_cast<INT32 *>(reinterpret_cast<INT8 *>(inPointer) - Q3DStudio_MEMORY_ALIGNMENT); + + // Sanity check: Did we allocate this memory in the first place? + // If this throws we may be calling Q3DStudio_virtual_delete on memory that was getten from + // Q3DStudio_new + Q3DStudio_ASSERT(FILTER_DOGTAG == theMemory[0]); + Q3DStudio_HANDLER_FILTER.Free(theMemory, theMemory[1]); +} + +//============================================================================== +/** + * Re-allocate an existing chunk of memory and track it. + * @param inPointer pointer given in a previous allocation + * @param inNewSize size of requested memory block, in bytes + * @param inNewType new allocation description + * @param inFile file name + * @param inFunction method name + * @param inLine line number + * @return void* a pointer to a memory block large enough to hold inSize bytes + */ +void *CMemoryFilter::Reallocate(void *inPointer, const INT32 inNewSize, const CHAR *inNewType, + const CHAR *inFile, const INT32 inLine) +{ + INT32 *theNewMemory = NULL; + const INT32 theTotalSize = inNewSize + Q3DStudio_MEMORY_ALIGNMENT; + + // Dogtag is not valid if the old pointer is NULL + if (inPointer) { + INT32 *theOldMemory = reinterpret_cast<INT32 *>(reinterpret_cast<INT8 *>(inPointer) + - Q3DStudio_MEMORY_ALIGNMENT); + Q3DStudio_ASSERT(FILTER_DOGTAG == theOldMemory[0]); + theNewMemory = reinterpret_cast<INT32 *>(Q3DStudio_HANDLER_FILTER.Reallocate( + theOldMemory, theOldMemory[1], theTotalSize, inNewType, inFile, inLine)); + } else { + theNewMemory = reinterpret_cast<INT32 *>( + Q3DStudio_HANDLER_FILTER.Reallocate(NULL, 0, theTotalSize, inNewType, inFile, inLine)); + } + + theNewMemory[0] = FILTER_DOGTAG; + theNewMemory[1] = theTotalSize; + return reinterpret_cast<INT8 *>(theNewMemory) + Q3DStudio_MEMORY_ALIGNMENT; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryFilter.h b/src/system/Qt3DSMemoryFilter.h new file mode 100644 index 0000000..df9367d --- /dev/null +++ b/src/system/Qt3DSMemoryFilter.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Aggregation interface for legacy calls that don't remember allocation size. + * + * CMemoryManager and its pools require that the size must be sent along with + * any call, including the Free call. Normal memory calls do not require this + * information and this filter class is used to intercept these calls and + * add a header to each call before forwarded to the manager. This thin class + * allows old school calls such as malloc and free to still use the advantages + * of a pooled memory system without impacting the cleanliness and memory + * footprint of the modern system. + */ +class CMemoryFilter +{ + //============================================================================== + // Constants + //============================================================================== +protected: + const static INT32 FILTER_DOGTAG = 0x1337f1d0; + + //============================================================================== + // Methods + //============================================================================== +public: // Allocation Deallocation + static void *Allocate(const INT32 inSize, const CHAR *inType, const CHAR *inFile, + const INT32 inLine, const BOOL inClear); + static void Free(void *inPointer); + static void *Reallocate(void *inPointer, const INT32 inNewSize, const CHAR *inNewType, + const CHAR *inFile, const INT32 inLine); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryHeap.cpp b/src/system/Qt3DSMemoryHeap.cpp new file mode 100644 index 0000000..4ab3617 --- /dev/null +++ b/src/system/Qt3DSMemoryHeap.cpp @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemory.h" +#include "Qt3DSMemoryHeap.h" +#include "Qt3DSMemoryStatistics.h" +#include "Qt3DSIStream.h" +#include "foundation/Qt3DSLogging.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Static Initialzation +//============================================================================== +CMemoryProbe CMemoryHeap::s_Probe; + +#if Q3DStudio_MEMORY_HEAPTRACKING +CMemoryHeap::TMemoryReport CMemoryHeap::s_MemoryReport; +#endif // Q3DStudio_MEMORY_HEAPTRACKING + +//============================================================================== +/** + * Allocate a chunk of memory and potentially track it. + * @param inSize size of requested memory block, in bytes + * @param inDescription allocation description such as class name or pool name + * @param inFile file name + * @param inFunction method name + * @param inLine line number + * @return void* a pointer to a memory block large enough to hold inSize bytes + */ +void *CMemoryHeap::Allocate(const INT32 inSize, const CHAR *inDescription, const CHAR *inFile, + const INT32 inLine) +{ + // Always track stats and trigger snapshot if this is a new record + s_Probe.Allocate(inSize); + + // Check if we are exceeding the max memory limit + if (Q3DStudio_MEMORY_LIMIT > 0 + && s_Probe.GetBytes(Q3DStudio::MEMSCOPE_GLOBAL, Q3DStudio::MEMVALUE_CURRENT) + > Q3DStudio_MEMORY_LIMIT) { + qCCritical (qt3ds::OUT_OF_MEMORY) + << "Q3DStudio_MEMORY_UNIT exceeded " << Q3DStudio_MEMORY_LIMIT; + Q3DStudio_ASSERT(false); + } + +#if Q3DStudio_MEMORY_HEAPTRACKING + void *theAllocatedPtr = CMemory::Malloc()(static_cast<const size_t>(inSize)); + if (s_MemoryReport.GetCount() < s_MemoryReport.GetCapacity()) { + SReportEntry theEntry = { theAllocatedPtr, inSize, inDescription, inFile, inLine }; + s_MemoryReport.Push(theEntry); + } else { + static BOOL s_FullWarning = false; + if (!s_FullWarning) { + qCWarning (qt3ds::TRACE_INFO) << "HeapTracker full. " + << "Please increase Q3DStudio_MEMORY_HEAPTRACKINGSIZE(" + << Q3DStudio_MEMORY_HEAPTRACKINGSIZE << ") " + << "to track all allocation and tune your pools to avoid " + << "hitting the heap."; + s_FullWarning = true; + } + } + return theAllocatedPtr; +#else + Q3DStudio_UNREFERENCED_PARAMETER(inLine); + Q3DStudio_UNREFERENCED_PARAMETER(inFile); + Q3DStudio_UNREFERENCED_PARAMETER(inDescription); + + return CMemory::Malloc()(static_cast<const size_t>(inSize)); +#endif // Q3DStudio_MEMORY_HEAPTRACKING +} + +//============================================================================== +/** + * Free a block of memory allocated using CMemoryHeap::Allocate + * @param inPointer pointer given in a previous allocation + * @param inSize size of given memory block, in bytes + */ +void CMemoryHeap::Free(void *inPointer, INT32 inSize) +{ + // No-Op on NULL + if (!inPointer) + return; + +#if Q3DStudio_MEMORY_HEAPTRACKING + RemoveReport(inPointer); +#endif // Q3DStudio_MEMORY_HEAPTRACKING + + s_Probe.Free(inSize); + return CMemory::Free()(inPointer); +} + +//============================================================================== +/** + * Re-allocate an existing chunk of memory and potentially track it. + * @param inPointer pointer given in a previous allocation + * @param inOldSize size of current memory block, in bytes + * @param inNewSize size of requested memory block, in bytes + * @param inNewDescription allocation description such as class name or pool name + * @param inFile file name + * @param inFunction method name + * @param inLine line number + * @return void* a pointer to a memory block large enough to hold inSize bytes + */ +void *CMemoryHeap::Reallocate(void *inPointer, const INT32 inOldSize, const INT32 inNewSize, + const CHAR *inNewDescription, const CHAR *inFile, const INT32 inLine) +{ + // Make sure this isn't a new malloc + if (!inPointer) + return Allocate(inNewSize, inNewDescription, inFile, inLine); + + // Always track stats and record new high if it's a record + s_Probe.Allocate(inNewSize); + s_Probe.Free(inOldSize); + + // Check if we are exceeding the max memory limit + Q3DStudio_ASSERT(Q3DStudio_MEMORY_LIMIT == 0 + ? true + : s_Probe.GetBytes(Q3DStudio::MEMSCOPE_GLOBAL, Q3DStudio::MEMVALUE_CURRENT) + < Q3DStudio_MEMORY_LIMIT); + +#if Q3DStudio_MEMORY_HEAPTRACKING + RemoveReport(inPointer); + + void *theReallocatedPtr = CMemory::Realloc()(inPointer, static_cast<const size_t>(inNewSize)); + + SReportEntry theEntry = { theReallocatedPtr, inNewSize, inNewDescription, inFile, inLine }; + s_MemoryReport.Push(theEntry); + + return theReallocatedPtr; +#else + return CMemory::Realloc()(inPointer, static_cast<const size_t>(inNewSize)); +#endif // Q3DStudio_MEMORY_HEAPTRACKING +} + +//============================================================================== +/** + * Retrieves memory info about a particular allocation + * @param inPointer allocated memory + * @return SMemoryHeapReportEntry* memory report + */ +CMemoryHeap::SReportEntry *CMemoryHeap::FindReport(void *inPointer) +{ + Q3DStudio_UNREFERENCED_PARAMETER(inPointer); + +#if Q3DStudio_MEMORY_HEAPTRACKING + INT32 theEnd = s_MemoryReport.GetCount(); + for (INT32 theIndex = 0; theIndex < theEnd; ++theIndex) + if (s_MemoryReport[theIndex].m_AllocatedPointer == inPointer) + return &s_MemoryReport[theIndex]; + + Q3DStudio_ASSERT(false); +#endif // Q3DStudio_MEMORY_HEAPTRACKING + + return NULL; +} + +//============================================================================== +/** + * Removes memory info due to a deallocation. + * @param inPointer allocated memory + */ +void CMemoryHeap::RemoveReport(void *inPointer) +{ + Q3DStudio_UNREFERENCED_PARAMETER(inPointer); + +#if Q3DStudio_MEMORY_HEAPTRACKING + INT32 theEnd = s_MemoryReport.GetCount(); + for (INT32 theIndex = 0; theIndex < theEnd; ++theIndex) { + if (s_MemoryReport[theIndex].m_AllocatedPointer == inPointer) { + s_MemoryReport.Remove(theIndex); + return; + } + } +#endif // Q3DStudio_MEMORY_HEAPTRACKING +} + +//============================================================================== +/** + * The memory probe records basic heap activity + * @return reference to probe + */ +CMemoryProbe &CMemoryHeap::GetProbe() +{ + return s_Probe; +} + +//============================================================================== +/** + * The report records all heap activity + * @return pointer to report if tracking is on, or NULL + */ +CMemoryHeap::TMemoryReport *CMemoryHeap::GetReport() +{ +#if Q3DStudio_MEMORY_HEAPTRACKING + return &s_MemoryReport; +#else + return NULL; +#endif // Q3DStudio_MEMORY_HEAPTRACKING +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryHeap.h b/src/system/Qt3DSMemoryHeap.h new file mode 100644 index 0000000..ba7c130 --- /dev/null +++ b/src/system/Qt3DSMemoryHeap.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemoryProbe.h" +#include "Qt3DSFixedArray.h" +#include "Qt3DSMemorySettings.h" + +//============================================================================== +/** + * Low level entry points to the heap. + * + * Do not call these directly. Use Q3DStudio_new or Q3DStudio_allocate instead since + * those use the pools. + * @see CMemoryHeap + */ +#define Q3DStudio_heap_allocate(size, desc) \ + Q3DStudio::CMemoryHeap::Allocate(size, desc, __FILE__, __LINE__) +#define Q3DStudio_heap_reallocate(ptr, oldsize, newsize, newdesc) \ + Q3DStudio::CMemoryHeap::Reallocate(ptr, oldsize, newsize, newdesc, __FILE__, _LINE__) +#define Q3DStudio_heap_free(ptr, size) Q3DStudio::CMemoryHeap::Free(ptr, size) + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Forwards +//============================================================================== +class IStream; + +//============================================================================== +/** + * Last memory interface before calls to memory callbacks or OS malloc. + * + * First of all, don't call this class directy. Use the macros + * Q3DStudio_heap_allocate and Q3DStudio_heap_free instead since they fill out file, + * line and function parameters for the tracking system. + * + * This is the single exit point for all heap memory allocations. Change this + * code to redirect memory to your own subsystems or add more tracking code to + * measure memory usage. Note however that most memory requests during runtime + * will never reach this point since memory pools will handle those requests. + * Large memory requests and emergency scenarios will still end up here. + * + * @note This class contains the only three real memory calls in Runtime. + */ +class CMemoryHeap +{ + //============================================================================== + // Structs + //============================================================================== +public: + /// Simple memory log entry + struct SReportEntry + { + const void *m_AllocatedPointer; ///< allocated pointer + INT32 m_Size; ///< size in bytes + const CHAR *m_Description; ///< simple description + const CHAR *m_File; ///< filename + INT32 m_Line; ///< line number + }; + + //============================================================================== + // Typedefs + //============================================================================== +public: + typedef CFixedArray<SReportEntry, Q3DStudio_MEMORY_HEAPTRACKINGSIZE> TMemoryReport; + + //============================================================================== + // Fields + //============================================================================== +protected: + static CMemoryProbe s_Probe; ///< Light overall allocation statistics +#if Q3DStudio_MEMORY_HEAPTRACKING + static TMemoryReport s_MemoryReport; ///< Storage for memory logs +#endif // Q3DStudio_MEMORY_HEAPTRACKING + + //============================================================================== + // Methods + //============================================================================== +public: // Allocation/Deallocation + static void *Allocate(const INT32 inSize, const CHAR *inDescription, const CHAR *inFile, + const INT32 inLine); + static void Free(void *inPointer, INT32 inSize); + static void *Reallocate(void *inPointer, const INT32 inOldSize, const INT32 inNewSize, + const CHAR *inNewDescription, const CHAR *inFile, const INT32 inLine); + +public: // Statistics + static CMemoryProbe &GetProbe(); + static TMemoryReport *GetReport(); + +protected: // Low level memory overview + static SReportEntry *FindReport(void *inPointer); + static void RemoveReport(void *inPointer); + +public: // Report request + static void Report(IStream *inStream = NULL); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryManager.cpp b/src/system/Qt3DSMemoryManager.cpp new file mode 100644 index 0000000..a1ace59 --- /dev/null +++ b/src/system/Qt3DSMemoryManager.cpp @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemory.h" +#include "Qt3DSMemoryManager.h" +#include "Qt3DSMemoryHeap.h" +#include "Qt3DSMemoryProbe.h" +#include "Qt3DSMemoryTracker.h" +#include "Qt3DSMemoryStatistics.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Create a new empty memory pool manager. + * + * The manager must be initialized before use or it will forward all requests + * to the heap. + */ +CMemoryManager::CMemoryManager() +{ + // Set default allocations functions if they are not already set + if (NULL == CMemory::Malloc()) + CMemory::SetMemoryFunctions(&malloc, &free, &realloc); + + CMemoryStatistics::AddManager(this); + +#if Q3DStudio_MEMORY_POOLTRACKING + Q3DStudio_memset(m_Histogram, 0, sizeof(m_Histogram)); + CMemoryStatistics::Overhead() += sizeof(m_Histogram); +#endif // Q3DStudio_MEMORY_POOLTRACKING +} + +//============================================================================== +/** + * Create a new initialized memory pool manager. + * + * @param inName short description of manager used in tracker + * @param inChunkSize array of values describing the chunk size of each pool + * @param inChunkCount array of values describing the number of chunks in each pool + */ +CMemoryManager::CMemoryManager(const CHAR *inName, + const INT32 inChunkSize[Q3DStudio_MEMORY_POOLCOUNT], + const INT32 inChunkCount[Q3DStudio_MEMORY_POOLCOUNT]) +{ + // Set default allocations functions if they are not already set + if (NULL == CMemory::Malloc()) + CMemory::SetMemoryFunctions(&malloc, &free, &realloc); + + CMemoryStatistics::AddManager(this); + Initialize(inName, inChunkSize, inChunkCount); + +#if Q3DStudio_MEMORY_POOLTRACKING + Q3DStudio_memset(m_Histogram, 0, sizeof(m_Histogram)); + CMemoryStatistics::Overhead() -= sizeof(m_Histogram); +#endif // Q3DStudio_MEMORY_POOLTRACKING +} + +//============================================================================== +/** + * Release the memory manager and all owned pools. + * + * Nobody better point to memory in these pool because the it will be + * invalid after this. + */ +CMemoryManager::~CMemoryManager() +{ + CMemoryStatistics::RemoveManager(this); + Release(); +} + +//============================================================================== +/** + * Configure the pool manager into separate pools of different chunk sizes. + * + * The chunk size array has to be increasing values such as: + * inChunkSize = { 8, 16, 32, 64, 96, 128, 256, 512, 1024 } + * but count doesn't: + * inChunkCount = { 500, 200, 1000, 200, 200, 100, 250, 50, 20 } + * + * The global memory manager settings are initialized in AKMemory.h + * + * @param inName short description of manager used in tracker + * @param inChunkSize array of Q3DStudio_MEMORY_POOLCOUNT values describing the chunk size + *of each pool + * @param inChunkCount array of Q3DStudio_MEMORY_POOLCOUNT values describing the number of + *chunks in each pool + */ +void CMemoryManager::Initialize(const CHAR *inName, + const INT32 inChunkSize[Q3DStudio_MEMORY_POOLCOUNT], + const INT32 inChunkCount[Q3DStudio_MEMORY_POOLCOUNT]) +{ + // Don't initialize more than once + Q3DStudio_ASSERT(m_Pool[0].GetChunkCount() == 0); + Q3DStudio_sprintf(m_Name, sizeof(m_Name), "%s", inName); + + for (INT32 thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT; ++thePoolIndex) { + // Make sure pool are aligned to Q3DStudio_MEMORY_ALIGNMENT or smaller than + // Q3DStudio_MEMORY_ALIGNMENT + Q3DStudio_ASSERT(inChunkSize[thePoolIndex] < Q3DStudio_MEMORY_ALIGNMENT + || (inChunkSize[thePoolIndex] % Q3DStudio_MEMORY_ALIGNMENT) == 0); + m_Pool[thePoolIndex].Initialize(inName, inChunkSize[thePoolIndex], + inChunkCount[thePoolIndex]); + } +} + +//============================================================================== +/** + * Release all the memory allocated in Initialize - essentially "uninitialize". + */ +void CMemoryManager::Release() +{ + for (INT32 thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT; ++thePoolIndex) + m_Pool[thePoolIndex].Release(); +} + +//============================================================================== +// ALLOCATION AND DEALLOCATION +//============================================================================== + +//============================================================================== +/** + * Fetch a new chunk of memory from the smallest pool possible + * @param inSize size of requested memory block, in bytes + * @param inType allocation description such as class name or pool name + * @param inFile file name + * @param inFunction method name + * @param inLine line number + * @return void* a pointer to a memory block large enough to hold inSize bytes + */ +void *CMemoryManager::Allocate(INT32 inSize, const CHAR *inType, const CHAR *inFile, + const INT32 inLine) +{ + Q3DStudio_ASSERT(inSize >= 0); + +#if Q3DStudio_MEMORY_POOLTRACKING + m_Histogram[Q3DStudio_min<INT32>(inSize, 511)].Add(1); +#endif // Q3DStudio_MEMORY_POOLTRACKING + +#if Q3DStudio_MEMORY_LINETRACKING + inSize += sizeof(CMemoryTracker::SMemoryInfo); // make room for SMemoryInfo +#endif // Q3DStudio_MEMORY_LINETRACKING + + // Find the smallest pool that fits + void *thePointer = NULL; + INT32 thePoolIndex = 0; + while (thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT) { + // Does this pool fit? + if (inSize <= m_Pool[thePoolIndex].GetChunkSize()) { + thePointer = m_Pool[thePoolIndex].Allocate(); + break; + } + ++thePoolIndex; + } + + // // Record the amount of wasted bytes in this chunk + if (thePointer) { + // Basic tracking + m_ManagerData.m_Aligned.Allocate(inSize); +#if Q3DStudio_MEMORY_POOLTRACKING + m_PoolData[thePoolIndex].m_Aligned.Allocate(inSize); +#endif // Q3DStudio_MEMORY_POOLTRACKING + } + // If not, we go to the heap for now. + else { + // REFACTOR: Use the next pool size up instead? + thePointer = CMemoryHeap::Allocate(inSize, inType, inFile, inLine); + m_ManagerData.m_Overflow.Allocate(inSize); + +#if Q3DStudio_MEMORY_POOLTRACKING + if (thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT) + m_PoolData[thePoolIndex].m_Overflow.Allocate( + inSize); // Heap allocation due to full memory pool +#endif // Q3DStudio_MEMORY_POOLTRACKING + } + +#if Q3DStudio_MEMORY_LINETRACKING + CMemoryTracker::SMemoryInfo *theMemoryInfo = + reinterpret_cast<CMemoryTracker::SMemoryInfo *>(thePointer); + + theMemoryInfo->m_DogTag = CMemoryTracker::TRACKER_DOGTAG; + theMemoryInfo->m_Line = static_cast<INT16>(inLine); + theMemoryInfo->m_Size = static_cast<INT16>(inSize - sizeof(CMemoryTracker::SMemoryInfo)); + theMemoryInfo->m_File = inFile; + theMemoryInfo->m_Type = inType; + + m_LineTracker.Remember(theMemoryInfo); + thePointer = reinterpret_cast<CMemoryTracker::SMemoryInfo *>(thePointer) + 1; +#endif // Q3DStudio_MEMORY_LINETRACKING + + return thePointer; +} + +//============================================================================== +/** + * Release a chunk of memory. + * @param inPointer pointer to memory to be reused + * @param inSize size of the memory we are releasing, in bytes + */ +void CMemoryManager::Free(void *inPointer, INT32 inSize) +{ + if (!inPointer) + return; + + Q3DStudio_ASSERT(inSize >= 0); + +#if Q3DStudio_MEMORY_POOLTRACKING + m_Histogram[Q3DStudio_min<INT32>(inSize, 511)].Delete(1); +#endif // Q3DStudio_MEMORY_POOLTRACKING + +#if Q3DStudio_MEMORY_LINETRACKING + inPointer = reinterpret_cast<CMemoryTracker::SMemoryInfo *>(inPointer) - 1; + m_LineTracker.Forget(reinterpret_cast<CMemoryTracker::SMemoryInfo *>(inPointer)); + inSize += sizeof(CMemoryTracker::SMemoryInfo); +#endif // Q3DStudio_MEMORY_LINETRACKING + + // Did we get a valid pool? + INT32 thePoolIndex = FetchPoolIndex(inPointer); + if (thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT) { + m_Pool[thePoolIndex].Free(inPointer); + m_ManagerData.m_Aligned.Free(inSize); +#if Q3DStudio_MEMORY_POOLTRACKING + m_PoolData[thePoolIndex].m_Aligned.Free(inSize); +#endif // Q3DStudio_MEMORY_POOLTRACKING + } else { + CMemoryHeap::Free(inPointer, inSize); + m_ManagerData.m_Overflow.Free(inSize); + +#if Q3DStudio_MEMORY_POOLTRACKING + if (inSize <= m_Pool[Q3DStudio_MEMORY_POOLCOUNT - 1].GetChunkSize()) + for (thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT; ++thePoolIndex) + if (inSize <= m_Pool[thePoolIndex].GetChunkSize()) { + m_PoolData[thePoolIndex].m_Overflow.Free(inSize); + // This is driving me crazy -CN. + // Q3DStudio_ASSERT( m_PoolData[thePoolIndex].m_Overflow.GetCalls( + // MEMSCOPE_GLOBAL, MEMVALUE_CURRENT ) >= 0 ); + break; + } +#endif // Q3DStudio_MEMORY_POOLTRACKING + } +} + +//============================================================================== +/** + * Grow the existing memory allocated + * + * @param inOldPointer pointer given in a previous allocation + * @param inOldSize size of current memory block, in bytes + * @param inNewSize size of requested memory block, in bytes + * @param inNewType allocation description such as class name or pool name + * @param inFile file name + * @param inFunction method name + * @param inLine line number + * @return void* a pointer to a memory block large enough to hold inSize bytes + */ +void *CMemoryManager::Reallocate(void *inOldPointer, const INT32 inOldSize, const INT32 inNewSize, + const CHAR *inNewType, const CHAR *inFile, const INT32 inLine) +{ + Q3DStudio_ASSERT(inOldSize >= 0 && inNewSize >= 0); + + // It's legal to pass NULL as old pointer to realloc + if (!inOldPointer) + return Allocate(inNewSize, inNewType, inFile, inLine); + + if (inNewSize == 0) { + Free(inOldPointer, inOldSize); + return NULL; + } + + // Get a new bigger chunk and transfer old data to it + void *thePointer = Allocate(inNewSize, inNewType, inFile, inLine); + Q3DStudio_memcpy(thePointer, inOldPointer, Q3DStudio_min(inOldSize, inNewSize)); + + // Release old data + Free(inOldPointer, inOldSize); + return thePointer; +} + +//============================================================================== +// IMPLEMENTATION +//============================================================================== + +//============================================================================== +/** + * Find the pool that owns the given pointer. + * @param inPointer pointer to memory to be found + * @return INT32 index of pool or Q3DStudio_MEMORY_POOLCOUNT if the chunk can't be found + */ +INT32 CMemoryManager::FetchPoolIndex(const void *inPointer) +{ + // Find pool that owns the pointer + INT32 thePoolIndex = 0; + while (thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT) { + if (m_Pool[thePoolIndex].OwnsChunk(inPointer)) + return thePoolIndex; + ++thePoolIndex; + } + + return Q3DStudio_MEMORY_POOLCOUNT; +} + +//============================================================================== +// STATISTICS +//============================================================================== + +//============================================================================== +/** + * Return the text identifier of the manager + * @return the name, max 32 bytes long + */ +const CHAR *CMemoryManager::GetName() +{ + return m_Name; +} + +//============================================================================== +/** + * Reset all probe statistics + */ +void CMemoryManager::Reset() +{ + m_ManagerData.m_Aligned.Reset(); + m_ManagerData.m_Overflow.Reset(); + +#if Q3DStudio_MEMORY_POOLTRACKING + for (INT32 thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT; ++thePoolIndex) { + m_Pool[thePoolIndex].GetProbe().Reset(); + m_PoolData[thePoolIndex].m_Aligned.Reset(); + m_PoolData[thePoolIndex].m_Overflow.Reset(); + } +#endif // Q3DStudio_MEMORY_POOLTRACKING +} + +//============================================================================== +/** + * Retrieve a particular memory pool + * @param inPoolIndex index of the pool + * @return SPoolData& is a reference to the indicated pool data + */ +CMemoryPool &CMemoryManager::GetPool(const INT32 inPoolIndex) +{ + Q3DStudio_ASSERT(inPoolIndex < Q3DStudio_MEMORY_POOLCOUNT && inPoolIndex >= 0); + return m_Pool[inPoolIndex]; +} + +//============================================================================== +/** + * Retrieve a particular memory pool + * @param inPoolIndex index of the pool + * @return SPoolData& is a reference to the indicated pool data + */ +CMemoryManager::SPoolData *CMemoryManager::GetPoolData(const INT32 inPoolIndex) +{ + Q3DStudio_UNREFERENCED_PARAMETER(inPoolIndex); + Q3DStudio_ASSERT(inPoolIndex < Q3DStudio_MEMORY_POOLCOUNT && inPoolIndex >= 0); + +#if Q3DStudio_MEMORY_POOLTRACKING + return m_PoolData + inPoolIndex; +#else + return NULL; +#endif // Q3DStudio_MEMORY_POOLTRACKING +} + +//============================================================================== +/** + * Retrieve the number of bytes that were allocated on the heap + * @return CMemoryProbe as the heap statistics + */ +CMemoryManager::SPoolData &CMemoryManager::GetManagerData() +{ + return m_ManagerData; +} + +//============================================================================== +/** + * Sum the high level statistics of all the pools. + * @return CMemoryProbe as the statistics, calculated on the spot + */ +CMemoryProbe CMemoryManager::GetProbe() +{ + CMemoryProbe theProbe; +#if Q3DStudio_MEMORY_POOLTRACKING + for (INT32 thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT; ++thePoolIndex) + theProbe.Combine(m_Pool[thePoolIndex].GetProbe()); +#endif // Q3DStudio_MEMORY_POOLTRACKING + return theProbe; +} + +//============================================================================== +/** + * Fetch the tracker if enabled by setting Q3DStudio_MEMORY_LINETRACKING + * @return CMemoryTracker pointer or NULL + */ +CMemoryTracker *CMemoryManager::GetLineTracker() +{ +#if Q3DStudio_MEMORY_LINETRACKING + return &m_LineTracker; +#else + return NULL; +#endif // Q3DStudio_MEMORY_LINETRACKING +} + +//============================================================================== +/** + * Fetch the histogram if enabled by setting Q3DStudio_MEMORY_HISTOGRAM. + * The histogram counts all requested allocations of the specific size. + * @return UINT16 array of 512 values, or NULL + */ +const CMemoryProbe::SValue *CMemoryManager::GetHistogram() +{ +#if Q3DStudio_MEMORY_POOLTRACKING + return m_Histogram; +#else + return NULL; +#endif // Q3DStudio_MEMORY_POOLTRACKING +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryManager.h b/src/system/Qt3DSMemoryManager.h new file mode 100644 index 0000000..fa54fce --- /dev/null +++ b/src/system/Qt3DSMemoryManager.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemoryPool.h" +#include "Qt3DSMemoryProbe.h" +#include "Qt3DSMemoryTracker.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Forwards +//============================================================================== +class CMemoryTracker; + +//============================================================================== +/** + * Allocation switch-board forwarding requests to pools. + * + * This is a memory pool hub acting as a complete heap replacement. The number + * of pools is hardcoded in Q3DStudio_MEMORY_POOLCOUNT but can be changed with a + * recompile. The main manager is created in AKMemory and is preconfigured to + * be generous with memory. Tune these values to match your title since + * unused chunks are wasteful. + * + * @note A pool manager survives fine even when not initialized. In this state + * it simply forwards each request to the CMemoryHeap. This setup is intentional + * to enable the default manager to survive long enough to allow future runtime + * initialization based on complexity of the level or presentation being loaded. + */ +class CMemoryManager +{ + //============================================================================== + // Structs + //============================================================================== +public: + /// External pool usage information + struct SPoolData + { + CMemoryProbe + m_Aligned; ///< Exact sum of memory use (28byte struct in 32byte pool is still 28 here) + CMemoryProbe m_Overflow; ///< Failed memory allocation because the pool was full + }; + + //============================================================================== + // Fields + //============================================================================== +protected: + CHAR m_Name[32]; ///< Manager identifier for statistics + CMemoryPool m_Pool[Q3DStudio_MEMORY_POOLCOUNT]; ///< Actual pool memory objects + SPoolData m_ManagerData; ///< Track allocations forwarded to heap because they were too large + +#if Q3DStudio_MEMORY_POOLTRACKING + SPoolData + m_PoolData[Q3DStudio_MEMORY_POOLCOUNT]; ///< Trace pools of different sizes with their usage + CMemoryProbe::SValue + m_Histogram[512]; ///< Allocation histogram if active using Q3DStudio_MEMORY_HEAPTRACKING +#endif // Q3DStudio_MEMORY_POOLTRACKING + +#if Q3DStudio_MEMORY_LINETRACKING + CMemoryTracker + m_LineTracker; ///< Line allocation tracker if active using Q3DStudio_MEMORY_LINETRACKING +#endif // Q3DStudio_MEMORY_LINETRACKING + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + CMemoryManager(); + CMemoryManager(const CHAR *inName, const INT32 inChunkSize[Q3DStudio_MEMORY_POOLCOUNT], + const INT32 inChunkCount[Q3DStudio_MEMORY_POOLCOUNT]); + ~CMemoryManager(); + +public: // Initialization + void Initialize(const CHAR *inName, const INT32 inChunkSize[Q3DStudio_MEMORY_POOLCOUNT], + const INT32 inChunkCount[Q3DStudio_MEMORY_POOLCOUNT]); + void Release(); + +public: // Allocation and Deallocation + void *Allocate(INT32 inSize, const CHAR *inType, const CHAR *inFile, const INT32 inLine); + void Free(void *inOldPointer, INT32 inSize); + void *Reallocate(void *inOldPointer, const INT32 inOldSize, const INT32 inNewSize, + const CHAR *inNewType, const CHAR *inFile, const INT32 inLine); + +protected: // Implementation + INT32 FetchPoolIndex(const void *inPointer); + +public: // Statistics + void Reset(); + const CHAR *GetName(); + CMemoryPool &GetPool(const INT32 inPoolIndex); + SPoolData *GetPoolData(const INT32 inPoolIndex); + SPoolData &GetManagerData(); + CMemoryProbe GetProbe(); + CMemoryTracker *GetLineTracker(); + const CMemoryProbe::SValue *GetHistogram(); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryPool.cpp b/src/system/Qt3DSMemoryPool.cpp new file mode 100644 index 0000000..44545d4 --- /dev/null +++ b/src/system/Qt3DSMemoryPool.cpp @@ -0,0 +1,298 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemoryPool.h" +#include "Qt3DSMemoryHeap.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Create a new memory pool. + * + */ +CMemoryPool::CMemoryPool() + : m_ChunkSize(0) + , m_ChunkCount(0) + , m_Ceiling(NULL) + , m_Memory(NULL) + , m_Top(NULL) + , m_Hole(NULL) +{ + m_Description[0] = '\0'; +} + +//============================================================================== +/** + * Release the memory pool. + * + * Nobody better point to this pool because it's illegal after this. + * We could blast the memory in debug mode to trigger bugs early but most + * compilers already do this. + */ +CMemoryPool::~CMemoryPool() +{ + Release(); +} + +//============================================================================== +/** + * Configure the memory pool. + * + * The pool will allocate inChunkSize * inChunkCount bytes of memory from + * the heap using Q3DStudio_new, aligned on 4 byte boundaries. + * + * @param inName short description of pool - used in tracker + * @param inChunkSize size in bytes of each memory block, aka chunk + * @param inChunkCount number of chunks the pool holds + */ +void CMemoryPool::Initialize(const CHAR *inName, const INT32 inChunkSize, const INT32 inChunkCount) +{ + Q3DStudio_ASSERT(!m_Memory); + + // Round up chunk size to the next even pointer size + // It needs to be at least pointer size to store the hole linked list + INT32 theRoundedChunkSize = + static_cast<INT32>(((inChunkSize + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *)); + + // Create pool description + Q3DStudio_sprintf(m_Description, sizeof(m_Description), "POOL: %s(%dx%d)", inName, + theRoundedChunkSize, inChunkCount); + + // Reserve memory pool + m_ChunkSize = theRoundedChunkSize; + m_ChunkCount = inChunkCount; + m_Memory = reinterpret_cast<INT8 *>( + Q3DStudio_heap_allocate(m_ChunkSize * m_ChunkCount, m_Description)); + m_Top = m_Memory; + m_Ceiling = m_Memory + m_ChunkSize * m_ChunkCount; +} + +//============================================================================== +/** + * Release all the memory allocated in Initialize - essentially "uninitialize". + */ +void CMemoryPool::Release() +{ + Q3DStudio_heap_free(m_Memory, m_ChunkSize * m_ChunkCount); + + m_ChunkSize = 0, m_ChunkCount = 0; + m_Ceiling = NULL; + m_Memory = NULL; + m_Top = NULL; + m_Hole = NULL; +} + +//============================================================================== +// ALLOCATION AND DEALLOCATION +//============================================================================== + +//============================================================================== +/** + * Fetch a new chunk of memory. + * + * If there is a pool hole we use that, otherwise feed of the head. + * Every alloction is tracked in m_Statistics. + * @return a pointer to inChunkSize bytes of usable memory + */ +void *CMemoryPool::Allocate() +{ + if (m_Hole) + return PopHole(); + else + return UseTop(); +} + +//============================================================================== +/** + * Release a chunk of memory and track changes in statistics + * @param inChunk a pointer to memory to be reused + */ +void CMemoryPool::Free(void *inChunk) +{ + Q3DStudio_ASSERT(OwnsChunk(inChunk)); + PushHole(inChunk); +} + +//============================================================================== +/** + * Verify that a pointer is owned by a specific pool + * @param inChunk a pointer to be checked + * @return BOOL true if the chunk is owned by this pool + */ +BOOL CMemoryPool::OwnsChunk(const void *inChunk) const +{ +#ifdef _DEBUG + // Scan all holes to prevent double releasing memory + if (!(inChunk >= m_Ceiling || inChunk < m_Memory)) { + // No freeing anything above the top? + Q3DStudio_ASSERT(inChunk < m_Top); + + // Not freeing any holes? + void *theHoleChunk = m_Hole; + while (theHoleChunk) { + Q3DStudio_ASSERT(inChunk != theHoleChunk); + theHoleChunk = reinterpret_cast<void *>(*reinterpret_cast<size_t *>(theHoleChunk)); + } + } +#endif // DEBUG + + return !(inChunk >= m_Ceiling || inChunk < m_Memory); +} + +//============================================================================== +/** + * Quick check to see if there are chunks available + * @return BOOL true if the pool has available chunks + */ +BOOL CMemoryPool::IsFull() const +{ + return m_Hole == NULL && GetFreeTops() == 0; +} + +//============================================================================== +/** + * Get the total number of free chunks in this pool. + * @return INT32 is the nunber of free chunks + */ +INT32 CMemoryPool::GetFreeChunks() const +{ + return GetFreeTops() + GetFreeHoles(); +} + +//============================================================================== +/** + * Get the number of holes in this pool. + * @return INT32 is the nunber of holes + */ +INT32 CMemoryPool::GetFreeHoles() const +{ + INT32 theHoleCounter = 0; + void *theHoleChunk = m_Hole; + + // Walk the hole list until there are no more holes + while (theHoleChunk) { + theHoleChunk = reinterpret_cast<void *>(*reinterpret_cast<size_t *>(theHoleChunk)); + ++theHoleCounter; + } + + return theHoleCounter; +} + +//============================================================================== +/** + * Get the number of chunks left at the top. + * @return INT32 is the nunber of continous chunks at the top + */ +INT32 CMemoryPool::GetFreeTops() const +{ + return static_cast<INT32>((m_Ceiling - m_Top)) / m_ChunkSize; +} + +//============================================================================== +// IMPLEMENTATION +//============================================================================== + +//============================================================================== +/** + * Return a chunch from the top. + * + * The top is only used if no pool holes are available. + * @return a pointer to the chunk at the top + */ +void *CMemoryPool::UseTop() +{ + // Out of memory? + // This is not assert since it may happen during normal runtime. + if (m_Top >= m_Ceiling) + return NULL; + + void *theChunk = m_Top; + m_Top += m_ChunkSize; + +#if Q3DStudio_MEMORY_POOLTRACKING + m_Probe.Allocate(m_ChunkSize); +#endif // Q3DStudio_MEMORY_POOLTRACKING + return theChunk; +} + +//============================================================================== +/** + * Add a new hole to the pool list. + * + * The holes are used in a stack-like fashion so the chunk we push in most + * recently is the first one to be returned next New call. + * The holes are linked by using the first four bytes to point to the next + * chunk. We are hijacking them to create a linked list of free chunks. + * @param inChunk is the just deleted chunk + */ +void CMemoryPool::PushHole(void *inChunk) +{ +#if Q3DStudio_MEMORY_POOLTRACKING + m_Probe.Free(m_ChunkSize); +#endif // Q3DStudio_MEMORY_POOLTRACKING + + // Set the pushed chunk to be the new top hole after we + // link the content of the new chunk to the last top. + *reinterpret_cast<size_t *>(inChunk) = reinterpret_cast<size_t>(m_Hole); + m_Hole = inChunk; +} + +//============================================================================== +/** + * Get the topmost hole as our chunk. + * + * Return the latest hole and relink the list of holes to the top. + * @return void* is the most recently deleted chunk + */ +void *CMemoryPool::PopHole() +{ + Q3DStudio_ASSERT(m_Hole); + + // Return the old hole as our new chunk after we + // set the hole to the second hole in the list. + void *theChunk = m_Hole; + m_Hole = reinterpret_cast<void *>(*reinterpret_cast<size_t *>(m_Hole)); + +#if Q3DStudio_MEMORY_POOLTRACKING + m_Probe.Allocate(m_ChunkSize); +#endif // Q3DStudio_MEMORY_POOLTRACKING + return theChunk; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryPool.h b/src/system/Qt3DSMemoryPool.h new file mode 100644 index 0000000..01b2e41 --- /dev/null +++ b/src/system/Qt3DSMemoryPool.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemoryProbe.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Managed memory allocation using fixed-size chunks. + * + * The pool class implements a generic algorithm that favors reusing recently + * used memory chunks instead of returning memory continously. Yet, a fresh + * pool will always return chunks positioned side by side. + * + * If a chunk is freed it will be the first to be returned next time a fresh + * chunk is new'ed. This makes the cache lines happier. Deleted chunks are + * maintained by linking to each other instead of being stored in a separate + * memory consuming array. + */ +class CMemoryPool +{ + //============================================================================== + // Fields + //============================================================================== +protected: + INT32 m_ChunkSize; ///< size in bytes of each chunk + INT32 m_ChunkCount; ///< number of chunks in pool + + INT8 *m_Ceiling; ///< ceiling memory pointer + INT8 *m_Memory; ///< base memory pointer, INT8 for easy pointer arithemtic + INT8 *m_Top; ///< edge of free continous memory + void *m_Hole; ///< first dis-continous memory chunk if any + + CMemoryProbe m_Probe; ///< call and byte data on pool usage + CHAR m_Description[32]; ///< short description of this pool + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + CMemoryPool(); + ~CMemoryPool(); + +public: // Initialization + void Initialize(const CHAR *inName, const INT32 inChunkSize, const INT32 inChunkCount); + void Release(); + +public: // Allocation and Deallocation + void *Allocate(); + void Free(void *inChunk); + BOOL IsFull() const; + BOOL OwnsChunk(const void *inChunk) const; + +protected: // Implementation + void *UseTop(); + void PushHole(void *inChunk); + void *PopHole(); + +public: // Statistics and reports + INT32 GetFreeHoles() const; + INT32 GetFreeTops() const; + INT32 GetFreeChunks() const; + INT32 GetChunkSize() const { return m_ChunkSize; } + INT32 GetChunkCount() const { return m_ChunkCount; } + CMemoryProbe &GetProbe() { return m_Probe; } +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryProbe.cpp b/src/system/Qt3DSMemoryProbe.cpp new file mode 100644 index 0000000..4e977ee --- /dev/null +++ b/src/system/Qt3DSMemoryProbe.cpp @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemoryProbe.h" +#include "Qt3DSMemoryStatistics.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor - records its size with the statistics class + */ +CMemoryProbe::CMemoryProbe() +{ + CMemoryStatistics::Overhead() += sizeof(CMemoryProbe); +} + +//============================================================================== +/** + * Destructor + */ +CMemoryProbe::~CMemoryProbe() +{ + CMemoryStatistics::Overhead() -= sizeof(CMemoryProbe); +} + +//============================================================================== +/** + * Track the number related to incrementing memory. + * @param inByteAmount amount of bytes being allocated + */ +void CMemoryProbe::Allocate(const INT32 inByteAmount) +{ + if (inByteAmount > 0) { + m_Calls[MEMSCOPE_RESET].Add(1); + m_Bytes[MEMSCOPE_RESET].Add(inByteAmount); + + m_Calls[MEMSCOPE_GLOBAL].Add(1); + m_Bytes[MEMSCOPE_GLOBAL].Add(inByteAmount); + } +} + +//============================================================================== +/** + * Track the number related to incrementing memory. + * @param inByteAmount amount of bytes being deallocted + */ +void CMemoryProbe::Free(const INT32 inByteAmount) +{ + Q3DStudio_ASSERT(inByteAmount >= 0); + if (inByteAmount > 0) { + m_Calls[MEMSCOPE_RESET].Delete(1); + m_Bytes[MEMSCOPE_RESET].Delete(inByteAmount); + + m_Calls[MEMSCOPE_GLOBAL].Delete(1); + m_Bytes[MEMSCOPE_GLOBAL].Delete(inByteAmount); + } +} + +//============================================================================== +/** + * Reset all local statistics. Global values are not reset. + */ +void CMemoryProbe::Reset() +{ + m_Calls[MEMSCOPE_RESET].Reset(); + m_Bytes[MEMSCOPE_RESET].Reset(); +} + +//============================================================================== +/** + * Helper method for adding statistics used by manager to add pool usage. + * @param inProbe is the stats being added + */ +void CMemoryProbe::Combine(const CMemoryProbe &inProbe) +{ + m_Calls[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_ADDS] += + inProbe.m_Calls[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_ADDS]; + m_Calls[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_DELETES] += + inProbe.m_Calls[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_DELETES]; + m_Calls[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_PEAK] += + inProbe.m_Calls[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_PEAK]; + m_Calls[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_CURRENT] += + inProbe.m_Calls[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_CURRENT]; + + m_Bytes[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_ADDS] += + inProbe.m_Bytes[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_ADDS]; + m_Bytes[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_DELETES] += + inProbe.m_Bytes[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_DELETES]; + m_Bytes[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_PEAK] += + inProbe.m_Bytes[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_PEAK]; + m_Bytes[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_CURRENT] += + inProbe.m_Bytes[MEMSCOPE_GLOBAL].m_Value[MEMVALUE_CURRENT]; + + m_Calls[MEMSCOPE_RESET].m_Value[MEMVALUE_ADDS] += + inProbe.m_Calls[MEMSCOPE_RESET].m_Value[MEMVALUE_ADDS]; + m_Calls[MEMSCOPE_RESET].m_Value[MEMVALUE_DELETES] += + inProbe.m_Calls[MEMSCOPE_RESET].m_Value[MEMVALUE_DELETES]; + m_Calls[MEMSCOPE_RESET].m_Value[MEMVALUE_PEAK] += + inProbe.m_Calls[MEMSCOPE_RESET].m_Value[MEMVALUE_PEAK]; + m_Calls[MEMSCOPE_RESET].m_Value[MEMVALUE_CURRENT] += + inProbe.m_Calls[MEMSCOPE_RESET].m_Value[MEMVALUE_CURRENT]; + + m_Bytes[MEMSCOPE_RESET].m_Value[MEMVALUE_ADDS] += + inProbe.m_Bytes[MEMSCOPE_RESET].m_Value[MEMVALUE_ADDS]; + m_Bytes[MEMSCOPE_RESET].m_Value[MEMVALUE_DELETES] += + inProbe.m_Bytes[MEMSCOPE_RESET].m_Value[MEMVALUE_DELETES]; + m_Bytes[MEMSCOPE_RESET].m_Value[MEMVALUE_PEAK] += + inProbe.m_Bytes[MEMSCOPE_RESET].m_Value[MEMVALUE_PEAK]; + m_Bytes[MEMSCOPE_RESET].m_Value[MEMVALUE_CURRENT] += + inProbe.m_Bytes[MEMSCOPE_RESET].m_Value[MEMVALUE_CURRENT]; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryProbe.h b/src/system/Qt3DSMemoryProbe.h new file mode 100644 index 0000000..5f0844e --- /dev/null +++ b/src/system/Qt3DSMemoryProbe.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once +#include "Qt3DSMacros.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Memory Tracking Enums +//============================================================================== + +/// Track a value - remembering peak and add/del count +enum EMemoryValue { + MEMVALUE_ADDS = 0, ///< For example: allocation call count or bytes allocated + MEMVALUE_DELETES, ///< For example: free call count or bytes deallocated + MEMVALUE_PEAK, ///< Peak of the current value since the last reset + MEMVALUE_CURRENT, ///< Current count + MEMVALUECOUNT +}; + +/// Differentiate between full session (global) or since last reset (local) +enum EMemoryScope { + MEMSCOPE_RESET = 0, ///< Since last reset + MEMSCOPE_GLOBAL, ///< Since process start + MEMSCOPECOUNT +}; + +//============================================================================== +/** + * Memory allocation counter tracking bytes or calls. + * + * A probe instance can be placed to track either number of allocations + * or the bytes of each allocation. CMemoryManager and CMemoryHeap both + * record statistics using this class. 64 bytes. + */ +class CMemoryProbe +{ + //============================================================================== + // Structs + //============================================================================== +public: + //============================================================================== + /** + * Intelligent number that tracks current, peak, incr. and decr. + * + * This value remembers how the amount added, the amount deleted, the highest + * value, while keeping a current value. These are used by CMemoryProbe when + * tracking memory allocations. + */ + struct SValue + { + // Fields + INT32 m_Value[MEMVALUECOUNT]; ///< Four aspects (add,del,current,peak) we are tracking + + // Methods + SValue() { Reset(); } + void Reset() + { + m_Value[MEMVALUE_ADDS] = 0; + m_Value[MEMVALUE_DELETES] = 0; + m_Value[MEMVALUE_PEAK] = 0; + m_Value[MEMVALUE_CURRENT] = 0; + } + + void Delete(INT32 inAmount) + { + Q3DStudio_ASSERT(inAmount >= 0); + m_Value[MEMVALUE_DELETES] += inAmount; + m_Value[MEMVALUE_CURRENT] -= inAmount; + } + + void Add(INT32 inAmount) + { + Q3DStudio_ASSERT(inAmount >= 0); + m_Value[MEMVALUE_ADDS] += inAmount; + m_Value[MEMVALUE_CURRENT] += inAmount; + m_Value[MEMVALUE_PEAK] = + Q3DStudio_max(m_Value[MEMVALUE_PEAK], m_Value[MEMVALUE_CURRENT]); + } + }; + + //============================================================================== + // Fields + //============================================================================== +protected: + SValue m_Calls[MEMSCOPECOUNT]; ///< Memory call count + SValue m_Bytes[MEMSCOPECOUNT]; ///< Memory allocation amount + + //============================================================================== + // Methods + //============================================================================== +public: // Constructor + CMemoryProbe(); + ~CMemoryProbe(); + +public: // Operations + void Reset(); + void Allocate(const INT32 inByteAmount); + void Free(const INT32 inByteAmount); + void Combine(const CMemoryProbe &inProbe); + +public: // Accessors + INT32 GetCalls(const EMemoryScope inScope, const EMemoryValue inValue) const + { + return m_Calls[inScope].m_Value[inValue]; + } + INT32 GetBytes(const EMemoryScope inScope, const EMemoryValue inValue) const + { + return m_Bytes[inScope].m_Value[inValue]; + } +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemorySettings.h b/src/system/Qt3DSMemorySettings.h new file mode 100644 index 0000000..5400242 --- /dev/null +++ b/src/system/Qt3DSMemorySettings.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSTypes.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * GlobalMemoryManager constants + * NOTE THAT THESE NUMBERS BELOW SHOULD BE ADJUSTED TO FIT YOUR APPLICATION. + * + * See the Memory Management section in the documentation for guidelines + * on memory diagnostics that enable you to optimize these values: + */ + +//============================================================================== +// Memory Pool Configuration +//============================================================================== + +#ifndef Q3DStudio_MEMORY_POOLCOUNT +#define Q3DStudio_MEMORY_POOLCOUNT 12 +#endif // Q3DStudio_MEMORY_POOLCOUNT + +/// A memory pool has a chunk size that defines he size in bytes of each slot +/// and a chunk count defining how many slots there are of that size. +/// The pools below thus has 128 slots of 4 bytes, 256 slots of 8 bytes etc: +const INT32 g_ChunkSize[Q3DStudio_MEMORY_POOLCOUNT] = { 4, 8, 16, 32, 48, 64, + 96, 128, 160, 256, 384, 640 }; +const INT32 g_ChunkCount[Q3DStudio_MEMORY_POOLCOUNT] = { 128, 256, 256, 1536, 128, 128, + 256, 64, 32, 32, 32, 32 }; + +//============================================================================== +// Memory Settings +//============================================================================== + +/// Define the upper memory limit used by Runtime. +/// 0 = unlimited +#ifndef Q3DStudio_MEMORY_LIMIT +#define Q3DStudio_MEMORY_LIMIT 0 +#endif // Q3DStudio_MEMORY_LIMIT + +// Pool sizes and diagnostics are aligned to the required boundary. +#ifndef Q3DStudio_MEMORY_ALIGNMENT +#define Q3DStudio_MEMORY_ALIGNMENT 8 +#endif // Q3DStudio_MEMORY_ALIGNMENT + +//============================================================================== +// Memory Diagnostics +//============================================================================== + +/// Note that the simple report is always on. (F1 in Quarterback) + +/// CMemoryHeap usage report. (F2 in Quarterback) +/// Tracks large allocations such as pool buffers, managers and overflows. +/// Not much overhead since most allocations should be intercepted by pools. +#ifndef Q3DStudio_MEMORY_HEAPTRACKING +#define Q3DStudio_MEMORY_HEAPTRACKING 0 +#endif // Q3DStudio_MEMORY_HEAPTRACKING + +/// Max number of 20 byte SReportEntry heap entries +/// Increase this number if you get a log warning but you should really tune +/// your memory pools to avoid hitting the heap. +#ifndef Q3DStudio_MEMORY_HEAPTRACKINGSIZE +#define Q3DStudio_MEMORY_HEAPTRACKINGSIZE 4000 +#endif // Q3DStudio_MEMORY_HEAPTRACKINGSIZE + +/// Invasive allocation tracker. (F3 in Quarterback) +/// Track detailed memory usage per allocation through CMemoryManager by tracking +/// every Runtime allocation, line by line using __FILE__ and __LINE__. +/// Note that this adds a 16byte SMemoryInfo to each allocation and thus +/// changes pool usage. +/// === Do not tune pools with line tracking enabled! === +#ifndef Q3DStudio_MEMORY_LINETRACKING +#define Q3DStudio_MEMORY_LINETRACKING 0 +#endif // Q3DStudio_MEMORY_LINETRACKING + +// Hashbin size of entries pointing to SMemoryInfo allocation headers +#ifndef Q3DStudio_MEMORY_LINETRACKINGSIZE +#define Q3DStudio_MEMORY_LINETRACKINGSIZE (128 * 1024) +#endif // Q3DStudio_MEMORY_LINETRACKINGSIZE + +/// CMemoryManager pooled memory usage report. (F5-F8 in Quarterback) +/// Track most used allocation sizes to tune pool sizes and count. +/// Enabled by default since it allows tracking precise presentation +/// memory usage without much of an overhead. +/// It also includes a histogram when showing Reset data (F5,F6) +#ifndef Q3DStudio_MEMORY_POOLTRACKING +#ifdef _DEBUG +#define Q3DStudio_MEMORY_POOLTRACKING 1 +#else +#define Q3DStudio_MEMORY_POOLTRACKING 0 +#endif +#endif // Q3DStudio_MEMORY_POOLTRACKING + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryStatistics.cpp b/src/system/Qt3DSMemoryStatistics.cpp new file mode 100644 index 0000000..2f5eba0 --- /dev/null +++ b/src/system/Qt3DSMemoryStatistics.cpp @@ -0,0 +1,647 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSIStream.h" +#include "Qt3DSMemoryStatistics.h" +#include "Qt3DSMemoryTracker.h" +#include "Qt3DSMemoryHeap.h" +#include "foundation/Qt3DSLogging.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Static Fields +//============================================================================== +INT32 CMemoryStatistics::s_Overhead = 0; +CMemoryManager *CMemoryStatistics::s_PoolManagers[MANAGERCOUNT] = { NULL }; + +//============================================================================== +// REGISTRATION +//============================================================================== + +//============================================================================== +/** + * Add the manager from the static list done automatically on manager construction. + * @param inManager the manager we are beginning to track + */ +void CMemoryStatistics::AddManager(CMemoryManager *inManager) +{ + INT32 theIndex = 0; + while (s_PoolManagers[theIndex] && theIndex < MANAGERCOUNT - 1) + ++theIndex; + + if (!s_PoolManagers[theIndex]) { + s_PoolManagers[theIndex] = inManager; + } else { + qCWarning(qt3ds::TRACE_INFO) + << "Could not add memory manager tracker. Limit: " << MANAGERCOUNT; + } +} + +//============================================================================== +/** + * Remove the manager from the static list done automatically on manager deletion. + * @param inManager the manager we are ceasing to track + */ +void CMemoryStatistics::RemoveManager(CMemoryManager *inManager) +{ + INT32 theIndex = 0; + while (inManager != s_PoolManagers[theIndex] && theIndex < MANAGERCOUNT - 1) + ++theIndex; + + if (inManager == s_PoolManagers[theIndex]) + s_PoolManagers[theIndex] = NULL; +} + +//============================================================================== +/** + * Read/write access to the static tracking field that keeps tab on how + * much memory we are spending _tracking_ memory. + * @return reference to the field tracking the overhead in bytes + */ +INT32 &CMemoryStatistics::Overhead() +{ + return s_Overhead; +} + +//============================================================================== +// OPERATION +//============================================================================== + +//============================================================================== +/** + * Reset all memory probes + */ +void CMemoryStatistics::Reset() +{ + qCInfo(qt3ds::TRACE_INFO) << "Resetting Memory Statistics"; + CMemoryHeap::GetProbe().Reset(); + + for (INT32 theIndex = 0; theIndex < MANAGERCOUNT; ++theIndex) + if (s_PoolManagers[theIndex]) + s_PoolManagers[theIndex]->Reset(); +} + +//============================================================================== +// ACCESS +//============================================================================== + +//============================================================================== +/** + * Quick access to memory usage of the first memory manager. + * @param inPeak is true if you want the peak, false if you want the current state + * @return the current explict usage in bytes + */ +INT32 CMemoryStatistics::GetRequestedBytes(BOOL inPeak /*=false*/) +{ + Q3DStudio_ASSERT(s_PoolManagers[0]); + + EMemoryValue theValue = inPeak ? MEMVALUE_PEAK : MEMVALUE_CURRENT; + CMemoryManager::SPoolData &theUsageData = s_PoolManagers[0]->GetManagerData(); + + return theUsageData.m_Aligned.GetBytes(MEMSCOPE_RESET, theValue) + + theUsageData.m_Overflow.GetBytes(MEMSCOPE_RESET, theValue); +} + +//============================================================================== +/** + * Quick access to heap usage. + * @param inPeak is true if you want the peak, false if you want the current state + * @return the current heap usage in bytes + */ +INT32 CMemoryStatistics::GetHeapBytes(BOOL inPeak /*=false*/) +{ + return Q3DStudio::CMemoryHeap::GetProbe().GetBytes(MEMSCOPE_RESET, + inPeak ? MEMVALUE_PEAK : MEMVALUE_CURRENT); +} + +//============================================================================== +/** + * Fill out a SFactSheet with memory statistics. + * @param outFacts is filled out with factoids showing the system state + * @param inPeak is true if you want the peak, false if you want the current state + * @param inGlobal is true if you want values since process start, false since last reset + */ +void CMemoryStatistics::GetFacts(SFactSheet &outFacts, BOOL inPeak /*= true*/, + BOOL inGlobal /*= true*/) +{ + INT32 thePresentationBytes = 0; + Q3DStudio_UNREFERENCED_PARAMETER(thePresentationBytes); + Q3DStudio_memset(&outFacts, 0, sizeof(SFactSheet)); + + // Translate flags to enumerations + EMemoryScope theScope = inGlobal ? MEMSCOPE_GLOBAL : MEMSCOPE_RESET; + EMemoryValue theValue = inPeak ? MEMVALUE_PEAK : MEMVALUE_CURRENT; + + // Capture heap state + outFacts.m_HeapState.m_Bytes = CMemoryHeap::GetProbe().GetBytes(theScope, theValue); + outFacts.m_HeapState.m_Calls = CMemoryHeap::GetProbe().GetCalls(theScope, theValue); + +#if Q3DStudio_MEMORY_POOLTRACKING + INT32 theTotalChunks = 0; + INT32 theTotalBytes = 0; + + // Scan all registered pool managers + Q3DStudio_sprintf(outFacts.m_ManagerState.m_Name, 32, "All Managers"); + for (INT32 theManagerIndex = 0; theManagerIndex < MANAGERCOUNT; ++theManagerIndex) { + CMemoryManager *theManager = s_PoolManagers[theManagerIndex]; + SFactoid &theManagerFact = outFacts.m_Manager[theManagerIndex]; + INT32 theManagerChunks = 0; + INT32 theManagerBytes = 0; + + // Ignore empty managers + if (!theManager) + break; + + // Scan each pool in the manager + Q3DStudio_sprintf(theManagerFact.m_Name, 32, " %s", theManager->GetName()); + for (INT32 thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT; ++thePoolIndex) { + CMemoryPool &thePool = theManager->GetPool(thePoolIndex); + CMemoryManager::SPoolData *thePoolData = theManager->GetPoolData(thePoolIndex); + Q3DStudio_ASSERT(thePoolData); + + SFactoid &thePoolFact = outFacts.m_Pool[theManagerIndex][thePoolIndex]; + INT32 theUsed = thePool.GetProbe().GetCalls(theScope, theValue); + INT32 theAlign = thePoolData->m_Aligned.GetBytes(theScope, theValue); + + // Ignore empty pools + if (thePool.GetChunkCount() == 0) + break; + + // Extract all the factoids + Q3DStudio_sprintf(thePoolFact.m_Name, 32, " %d: %4db x %4d", thePoolIndex, + thePool.GetChunkSize(), thePool.GetChunkCount()); + thePoolFact.m_Bytes = thePool.GetChunkSize() * thePool.GetChunkCount(); + thePoolFact.m_Calls = thePool.GetProbe().GetCalls(theScope, theValue); + thePoolFact.m_Used = 100 * theUsed / thePool.GetChunkCount(); + + thePoolFact.m_Align = 100; + if (theUsed > 0) + thePoolFact.m_Align = 100 * theAlign / (theUsed * thePool.GetChunkSize()); + thePoolFact.m_Miss = thePoolData->m_Overflow.GetCalls(theScope, theValue); + + thePresentationBytes += theAlign + thePoolData->m_Overflow.GetBytes(theScope, theValue); + + theManagerFact.m_Bytes += thePoolFact.m_Bytes; + theManagerFact.m_Calls += thePoolFact.m_Calls; + theManagerFact.m_Used += theUsed; + theManagerFact.m_Align += theAlign; + theManagerFact.m_Miss += thePoolFact.m_Miss; + + outFacts.m_ManagerState.m_Bytes += thePoolFact.m_Bytes; + outFacts.m_ManagerState.m_Calls += thePoolFact.m_Calls; + outFacts.m_ManagerState.m_Used += theUsed; + outFacts.m_ManagerState.m_Align += theAlign; + outFacts.m_ManagerState.m_Miss += thePoolFact.m_Miss; + + theManagerChunks += thePool.GetChunkCount(); + theManagerBytes += theUsed * thePool.GetChunkSize(); + } + + thePresentationBytes += + theManager->GetManagerData().m_Overflow.GetBytes(theScope, theValue); + + // Both the manager sub-total and grand-total need to track bytes separately + // since the percentages can't just be added or averaged. Those totals + // are instead weighted and this is the tracking math that does it. + theTotalChunks += theManagerChunks; + theTotalBytes += theManagerBytes; + + theManagerFact.m_Used = 0; + if (theManagerChunks > 0) + theManagerFact.m_Used = 100 * theManagerFact.m_Used / theManagerChunks; + + theManagerFact.m_Align = 100; + if (theManagerBytes > 0) + theManagerFact.m_Align = 100 * theManagerFact.m_Align / theManagerBytes; + + CullHistogram(theManager->GetHistogram(), theValue, outFacts.m_Histogram[theManagerIndex]); + } + + // Again this is the grand-total separate percentage computation that has + // to be done in the end when all sums have been added. + outFacts.m_ManagerState.m_Used = 0; + if (theTotalChunks > 0) + outFacts.m_ManagerState.m_Used = 100 * outFacts.m_ManagerState.m_Used / theTotalChunks; + + outFacts.m_ManagerState.m_Align = 100; + if (theTotalBytes > 0) + outFacts.m_ManagerState.m_Align = 100 * outFacts.m_ManagerState.m_Align / theTotalBytes; + +#endif // Q3DStudio_MEMORY_POOLTRACKING + + // return thePresentationBytes; +} + +//============================================================================== +/** + * Find the HISTOGRAMLIMIT highest performers in the histogram. + * @param inHistogram array of CMemoryManager::HISTOGRAMCOUNT values + * each showing the number of allocation of that bytesize + * @param outResults collects the highest points of the histogram + */ +void CMemoryStatistics::CullHistogram(const CMemoryProbe::SValue *inHistogram, + const EMemoryValue inValue, + SHistogramScore outResults[HISTOGRAMCOUNT]) +{ + // Always clear even if there is no data + Q3DStudio_memset(outResults, 0, sizeof(SHistogramScore)); + + // Return quickly when no data + if (!inHistogram) + return; + + // Scan full histogram + INT32 theLowestIndex = 0; + for (UINT16 theSize = 0; theSize < 512; ++theSize) { + // Is this count higher than the lowest recorded count? + if (inHistogram[theSize].m_Value[inValue] > outResults[theLowestIndex].m_Count) { + outResults[theLowestIndex].m_Count = inHistogram[theSize].m_Value[inValue]; + outResults[theLowestIndex].m_Size = theSize; + + // Find new low in high score + theLowestIndex = 0; + for (UINT16 theResult = 1; theResult < HISTOGRAMCOUNT; ++theResult) + if (outResults[theResult].m_Count < outResults[theLowestIndex].m_Count) + theLowestIndex = theResult; + } + } + + // Sort histogram - brute force for now so don't call this all the time + ::qsort(outResults, 10, sizeof(SHistogramScore), CompareHistogram); +} + +//============================================================================== +/** + * Helper comparison function for CullHistogram + */ +int CMemoryStatistics::CompareHistogram(const void *arg1, const void *arg2) +{ + return reinterpret_cast<const SHistogramScore *>(arg2)->m_Count + - reinterpret_cast<const SHistogramScore *>(arg1)->m_Count; +} + +//============================================================================== +/** + * Helper comparison function for CMemoryStatistics::HeapReport + */ +int CMemoryStatistics::CompareHeap(const void *inEntry1, const void *inEntry2) +{ + return reinterpret_cast<const CMemoryHeap::SReportEntry *>(inEntry1)->m_Size + - reinterpret_cast<const CMemoryHeap::SReportEntry *>(inEntry2)->m_Size; +} + +//============================================================================== +// REPORTING +//============================================================================== + +//============================================================================== +/** + * Simple memory usage report covering both bytes allocated and call count. + * @param inStream the stream we are sending the report or NULL to use logger + */ +void CMemoryStatistics::SimpleReport(IStream *inStream /*=NULL*/) +{ + CHAR theReportBuffer[REPORTSIZE]; + CMemoryProbe theProbe; + + // Basic info is always available + Report(inStream, "\n --- RUNTIME SIMPLE MEMORY REPORT ---\n"); + + // Only the first manager is reported for now + Q3DStudio_ASSERT(s_PoolManagers[0]); + theProbe = s_PoolManagers[0]->GetManagerData().m_Aligned; + theProbe.Combine(s_PoolManagers[0]->GetManagerData().m_Overflow); + Report(inStream, "PRESENTATION: Current Peak Alloc Free\n"); + Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer), + "Global:%12dk(%4d)%8dk(%4d)%8dk(%4d)%8dk(%4d)\n", + theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_CURRENT) / 1024, + theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_CURRENT), + theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_PEAK) / 1024, + theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_PEAK), + theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_ADDS) / 1024, + theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_ADDS), + theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_DELETES) / 1024, + theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_DELETES)); + Report(inStream, theReportBuffer); + Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer), + "Reset: %12dk(%4d)%8dk(%4d)%8dk(%4d)%8dk(%4d)\n", + theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_CURRENT) / 1024, + theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_CURRENT), + theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_PEAK) / 1024, + theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_PEAK), + theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_ADDS) / 1024, + theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_ADDS), + theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_DELETES) / 1024, + theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_DELETES)); + Report(inStream, theReportBuffer); + + // Overflow is memory not serviced by memory pools - removed to make the simple report... + // simpler + /* theProbe = s_PoolManagers[0]->GetManagerData( ).m_Overflow; + Report( inStream, "OVERFLOW:\n" ); + Q3DStudio_sprintf( theReportBuffer, sizeof( theReportBuffer ), + "Global:%12ldk(%4ld)%8ldk(%4ld)%8ldk(%4ld)%8ldk(%4ld)\n", + theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_CURRENT )/1024, + theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_CURRENT ), + theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_PEAK )/1024, + theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_PEAK ), + theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_ADDS )/1024, + theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_ADDS ), + theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_DELETES )/1024, + theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_DELETES ) ); + Report( inStream, theReportBuffer ); + Q3DStudio_sprintf( theReportBuffer, sizeof( theReportBuffer ), "Reset: + %12ldk(%4ld)%8ldk(%4ld)%8ldk(%4ld)%8ldk(%4ld)\n", + theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_CURRENT )/1024, + theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_CURRENT ), + theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_PEAK )/1024, + theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_PEAK ), + theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_ADDS )/1024, + theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_ADDS ), + theProbe.GetBytes( MEMSCOPE_GLOBAL, MEMVALUE_DELETES )/1024, + theProbe.GetCalls( MEMSCOPE_GLOBAL, MEMVALUE_DELETES ) ); + Report( inStream, theReportBuffer );*/ + + // All managers share the same heap + theProbe = CMemoryHeap::GetProbe(); + Report(inStream, "HEAP:\n"); + Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer), + "Global:%12dk(%4d)%8dk(%4d)%8dk(%4d)%8dk(%4d)\n", + theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_CURRENT) / 1024, + theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_CURRENT), + theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_PEAK) / 1024, + theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_PEAK), + theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_ADDS) / 1024, + theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_ADDS), + theProbe.GetBytes(MEMSCOPE_GLOBAL, MEMVALUE_DELETES) / 1024, + theProbe.GetCalls(MEMSCOPE_GLOBAL, MEMVALUE_DELETES)); + Report(inStream, theReportBuffer); + Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer), + "Reset: %12dk(%4d)%8dk(%4d)%8dk(%4d)%8dk(%4d)\n", + theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_CURRENT) / 1024, + theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_CURRENT), + theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_PEAK) / 1024, + theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_PEAK), + theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_ADDS) / 1024, + theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_ADDS), + theProbe.GetBytes(MEMSCOPE_RESET, MEMVALUE_DELETES) / 1024, + theProbe.GetCalls(MEMSCOPE_RESET, MEMVALUE_DELETES)); + Report(inStream, theReportBuffer); + + Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer), "Tracking overhead: %dk\n", +#if Q3DStudio_MEMORY_HEAPTRACKING + (s_Overhead + sizeof(CMemoryHeap::TMemoryReport)) / 1024); +#else + s_Overhead / 1024); +#endif // Q3DStudio_MEMORY_HEAPTRACKING + + Report(inStream, theReportBuffer); +} + +//============================================================================== +/** + * Output the memory report log. + * + * The is always watched by a CMemoryProbe that records all activity. Most + * individual allocations will not be recorded though since they are handled + * by memory pools. + * + * A probe records three axis of information (value, scope and call/bytes). + * + * # Value (current,peak,add,del) tracks the current value along with its + * peak value, and also separately tracks adds(allocations) and deletes(frees) + * such that current = add - del. + * # Scope (local,global) tracks values since last reset or dawn of heap. + * # Call/Bytes tracks separately bytes and calls so you can distinguish between + * many small allocations and a few large. + * + * @param inStream the stream we are sending the report or NULL to use logger + */ +void CMemoryStatistics::HeapReport(IStream *inStream /*=NULL*/) +{ + Report(inStream, "\n --- RUNTIME HEAP MEMORY REPORT ---\n"); + +#if Q3DStudio_MEMORY_HEAPTRACKING + // Detailed info needs Q3DStudio_MEMORY_HEAPTRACKING defined + INT32 theCount = CMemoryHeap::GetReport()->GetCount(); + ::qsort(&CMemoryHeap::GetReport()[0], static_cast<size_t>(theCount), + sizeof(CMemoryHeap::SReportEntry), CompareHeap); + + CHAR theReportBuffer[REPORTSIZE]; + for (INT32 theIndex = 0; theIndex < theCount; ++theIndex) { + CMemoryHeap::SReportEntry &theEntry = CMemoryHeap::GetReport()->operator[](theIndex); + Q3DStudio_sprintf(theReportBuffer, sizeof(theReportBuffer), + "%3d. %8d bytes - \"%s\" - %s (%d)\n", theIndex, theEntry.m_Size, + theEntry.m_Description, theEntry.m_File, theEntry.m_Line); + Report(inStream, theReportBuffer); + } +#else + Report(inStream, " Unavailable: Q3DStudio_MEMORY_HEAPTRACKING not defined in this build\n"); +#endif +} + +/* Example output of CMemoryStatistics::Report + +=POOL= HEAP CALLS USED ALIGN MISSES +--------------------------------------------------------------- +All Managers 722k 38 72% 19% + + Global 482k + 0: 16b x 1024 16k 2182 3% 13% + 1: 32b x 2048 64k 4123 96% 9% 38 + 2: 48b x 512 24k 212 72% 21% + 3: 64b x 512 32k 454 11% 3% + . + 8: 512b x 128 64k 68 64% 22% +*/ + +//============================================================================== +/** + * Return a text buffer describing the state of the memory system. + */ +void CMemoryStatistics::PoolReport(BOOL inPeak /*= true*/, BOOL inGlobal /*= true*/, + IStream *inStream /*=NULL*/) +{ + CHAR theLine[256] = { 0 }; + SFactSheet theFacts; + + GetFacts(theFacts, inPeak, inGlobal); + + Report(inStream, "\n --- RUNTIME POOL MEMORY REPORT ---\n"); + Q3DStudio_sprintf(theLine, 256, + "Mode: %s %s\nTotal Heap: %7dk(%d)\nPresentation: %7dk\n", + inGlobal ? "GLOBAL" : "RESET", inPeak ? "PEAK" : "CURRENT", + theFacts.m_HeapState.m_Bytes / 1024, theFacts.m_HeapState.m_Calls, + GetRequestedBytes(inPeak) / 1024); + Report(inStream, theLine); + +#if Q3DStudio_MEMORY_POOLTRACKING + Report(inStream, "=POOLS= HEAP HITS USED ALIGN MISS" + "\n"); + Report(inStream, "-----------------------------------------------------------------" + "\n"); + Q3DStudio_sprintf(theLine, 256, "All Managers %7dk %8d %5d%% %5d%% %6d" + "\n\n", + theFacts.m_ManagerState.m_Bytes / 1024, theFacts.m_ManagerState.m_Calls, + theFacts.m_ManagerState.m_Used, theFacts.m_ManagerState.m_Align, + theFacts.m_ManagerState.m_Miss); + Report(inStream, theLine); + + for (INT32 theManagerIndex = 0; theManagerIndex < MANAGERCOUNT; ++theManagerIndex) { + SFactoid &theManagerFact = theFacts.m_Manager[theManagerIndex]; + if (theManagerFact.m_Bytes > 0) { + Q3DStudio_sprintf(theLine, 256, "%-20s %7dk %8d %5d%% %5d%% %6d\n", + theManagerFact.m_Name, theManagerFact.m_Bytes / 1024, + theManagerFact.m_Calls, theManagerFact.m_Used, theManagerFact.m_Align, + theManagerFact.m_Miss); + Report(inStream, theLine); + + for (INT32 thePoolIndex = 0; thePoolIndex < Q3DStudio_MEMORY_POOLCOUNT; + ++thePoolIndex) { + SFactoid &thePoolFact = theFacts.m_Pool[theManagerIndex][thePoolIndex]; + if (theManagerFact.m_Bytes > 0) { + Q3DStudio_sprintf(theLine, 256, "%-20s %7dk %8d %5d%% %5d%% %6d\n", + thePoolFact.m_Name, thePoolFact.m_Bytes / 1024, + thePoolFact.m_Calls, thePoolFact.m_Used, thePoolFact.m_Align, + thePoolFact.m_Miss); + Report(inStream, theLine); + } + } + + // Histogram only valid for Current-Reset + if (inGlobal) { + Report(inStream, " Histogram: Only available in RESET mode\n"); + } else { + Q3DStudio_sprintf( + theLine, 256, + " Histogram: 1:%3db(%3d) 2:%3db(%3d) 3:%3db(%3d) 4:%3db(%3d) 5:%3db(%3d)\n", + theFacts.m_Histogram[theManagerIndex][0].m_Size, + theFacts.m_Histogram[theManagerIndex][0].m_Count, + theFacts.m_Histogram[theManagerIndex][1].m_Size, + theFacts.m_Histogram[theManagerIndex][1].m_Count, + theFacts.m_Histogram[theManagerIndex][2].m_Size, + theFacts.m_Histogram[theManagerIndex][2].m_Count, + theFacts.m_Histogram[theManagerIndex][3].m_Size, + theFacts.m_Histogram[theManagerIndex][3].m_Count, + theFacts.m_Histogram[theManagerIndex][4].m_Size, + theFacts.m_Histogram[theManagerIndex][4].m_Count); + Report(inStream, theLine); + Q3DStudio_sprintf( + theLine, 256, + " 6:%3db(%3d) 7:%3db(%3d) 8:%3db(%3d) 9:%3db(%3d) 10:%3db(%3d)\n", + theFacts.m_Histogram[theManagerIndex][5].m_Size, + theFacts.m_Histogram[theManagerIndex][5].m_Count, + theFacts.m_Histogram[theManagerIndex][6].m_Size, + theFacts.m_Histogram[theManagerIndex][6].m_Count, + theFacts.m_Histogram[theManagerIndex][7].m_Size, + theFacts.m_Histogram[theManagerIndex][7].m_Count, + theFacts.m_Histogram[theManagerIndex][8].m_Size, + theFacts.m_Histogram[theManagerIndex][8].m_Count, + theFacts.m_Histogram[theManagerIndex][9].m_Size, + theFacts.m_Histogram[theManagerIndex][9].m_Count); + Report(inStream, theLine); + } + } + } +#else + Report(inStream, " Unavailable: Q3DStudio_MEMORY_POOLTRACKING not defined in this build\n"); +#endif +} + +//============================================================================== +/** + * Dump the low-level memory list stored in each manager's hash bin. + * + * @note Q3DStudio_MEMORY_LINETRACKING has to be set to 1 in AKMemorySettings.h or + * the compiler for this method to save out any data. + * + * @param inStream the stream we are sending the report or NULL to use logger + */ +void CMemoryStatistics::LineReport(IStream *inStream /*=NULL*/) +{ + Report(inStream, "\n--- RUNTIME LINE MEMORY REPORT ---\n"); +#if Q3DStudio_MEMORY_LINETRACKING + Report(inStream, "ADDR, SIZE, TYPE, LINE, FILE, \n"); + + INT32 theTotalBytes = 0; + for (INT32 theManagerIndex = 0; theManagerIndex < MANAGERCOUNT; ++theManagerIndex) + if (s_PoolManagers[theManagerIndex] && s_PoolManagers[theManagerIndex]->GetLineTracker()) + theTotalBytes += s_PoolManagers[theManagerIndex]->GetLineTracker()->Report(inStream); + + CHAR theTotal[64]; + theTotal[0] = '\0'; + + Q3DStudio_sprintf(theTotal, sizeof(theTotal), "TOTAL: , %8d\n", theTotalBytes); + Report(inStream, theTotal); +#else + Report(inStream, " Unavailable: Q3DStudio_MEMORY_LINETRACKING not defined in this build\n"); +#endif // Q3DStudio_MEMORY_LINETRACKING +} + +//============================================================================== +/** + * Output to log or stream if available. + * @param inMessage string to be reported + * @param inStream stream to be used or output to log if NULL + */ +void CMemoryStatistics::Report(IStream *inStream, const CHAR *inMessage) +{ + if (inStream) + inStream->WriteRaw(inMessage, (INT32)::strlen(inMessage)); + else + qCInfo(qt3ds::TRACE_INFO) << inMessage; +} + +//============================================================================== +/** + * Output full memory report to log or stream if available. + * @param inStream stream to be used or output to log if NULL + */ +void CMemoryStatistics::FullReport(IStream *inStream /*=NULL*/) +{ + SimpleReport(inStream); + HeapReport(inStream); + LineReport(inStream); + PoolReport(false, false, inStream); + PoolReport(true, false, inStream); + PoolReport(false, true, inStream); + PoolReport(true, true, inStream); +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryStatistics.h b/src/system/Qt3DSMemoryStatistics.h new file mode 100644 index 0000000..81e3043 --- /dev/null +++ b/src/system/Qt3DSMemoryStatistics.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemoryManager.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Static facade to memory statistics and allocation tracking data. + * + * Use this class to examine the memory state of the system at any point. + * Heap, managers and pools are are connected to this point by registering + * themselves on creation. Initiate the extraction of the collected data + * using this interface. + */ +class CMemoryStatistics +{ + //============================================================================== + // Constants + //============================================================================== +public: + const static INT32 REPORTSIZE = 256; ///< Max size of single report string + const static INT32 MANAGERCOUNT = 5; ///< Fixed number of managers tracked + const static INT32 HISTOGRAMCOUNT = 10; ///< Fixed number of managers tracked + + //============================================================================== + // Structs + //============================================================================== +public: + /// One row of statistics on allocation + struct SFactoid + { + CHAR m_Name[32]; ///< Ascii identifier - manager name or pool description + INT32 m_Bytes; ///< Bytes used - full pool size for example - zero if factoid unused + INT32 m_Calls; ///< Function calls, i.e number of allocations + INT32 m_Used; ///< Discrete chunk usage in percent - 10 used of 200 gives a value 5 + INT32 m_Align; ///< Packed efficiency in percent - all 24byte structs in 32byte pool give a + ///value 75 + INT32 m_Miss; ///< Allocation misses - due to full pools for example + }; + + /// Tuple describing one data point in a histogram + struct SHistogramScore + { + INT32 m_Size; ///< Allocation request in bytes + INT32 m_Count; ///< Number of allocation requests + }; + + /// Set of factoids describing a system memory state + struct SFactSheet + { + SFactoid m_HeapState; ///< Heap facts + SFactoid m_ManagerState; ///< Combined manager facts + SFactoid m_Manager[MANAGERCOUNT]; ///< Individual manager facts + SHistogramScore m_Histogram[MANAGERCOUNT][HISTOGRAMCOUNT]; ///< Top allocation requests + ///sorted by bytes, global and + ///never reset + SFactoid m_Pool[MANAGERCOUNT][Q3DStudio_MEMORY_POOLCOUNT]; ///< Individual pool facts + }; + + //============================================================================== + // Fields + //============================================================================== +protected: + static INT32 s_Overhead; ///< Memory tracking structures report in here + static CMemoryManager + *s_PoolManagers[MANAGERCOUNT]; ///< Pointers to all created memory pool managers + + //============================================================================== + // Methods + //============================================================================== +public: // Registration + static void AddManager(CMemoryManager *inManager); + static void RemoveManager(CMemoryManager *inManager); + static INT32 &Overhead(); + +public: // Access + static void Reset(); + static void GetFacts(SFactSheet &outFacts, const BOOL inPeak = false, + const BOOL inGlobal = false); + static INT32 GetRequestedBytes(const BOOL inPeak = false); + static INT32 GetHeapBytes(const BOOL inPeak = false); + +public: // Reporting + static void SimpleReport(IStream *inStream = NULL); + static void HeapReport(IStream *inStream = NULL); + static void PoolReport(const BOOL inPeak = false, const BOOL inGlobal = false, + IStream *inStream = NULL); + static void LineReport(IStream *inStream = NULL); + + static void FullReport(IStream *inStream = NULL); + static void Report(IStream *inStream, const CHAR *inString); + +protected: // Utility + static void CullHistogram(const CMemoryProbe::SValue *inHistogram, const EMemoryValue inValue, + SHistogramScore outResults[HISTOGRAMCOUNT]); + static int CompareHeap(const void *arg1, const void *arg2); + static int CompareHistogram(const void *arg1, const void *arg2); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryTracker.cpp b/src/system/Qt3DSMemoryTracker.cpp new file mode 100644 index 0000000..8aef951 --- /dev/null +++ b/src/system/Qt3DSMemoryTracker.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSMemoryTracker.h" +#include "foundation/Qt3DSLogging.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Construct and reset the tracker. + */ +CMemoryTracker::CMemoryTracker() + : m_TrackingOverhead(0) +{ + Q3DStudio_memset(&m_TrackingHashBin, 0, sizeof(m_TrackingHashBin)); + CMemoryStatistics::Overhead() += sizeof(m_TrackingHashBin); +} + +//============================================================================== +/** + * Destructor + */ +CMemoryTracker::~CMemoryTracker() +{ + CMemoryStatistics::Overhead() -= sizeof(m_TrackingHashBin); +} + +//============================================================================== +/** + * Add information about allocation + * @param inPtr contains info about a new allocation + */ +void CMemoryTracker::Remember(SMemoryInfo *inPointer) +{ + if (inPointer) { + // Update global tracking + m_TrackingOverhead += sizeof(SMemoryInfo); + + // Locate a suitable hashbin + size_t theHashBin = + (reinterpret_cast<size_t>(inPointer) >> 2) % Q3DStudio_MEMORY_LINETRACKINGSIZE; + size_t theStartHashBin = theHashBin; + + while (m_TrackingHashBin[theHashBin]) { + ++theHashBin; + if (theHashBin >= Q3DStudio_MEMORY_LINETRACKINGSIZE) + theHashBin = 0; + + if (theHashBin == theStartHashBin) { + // We've run out of room in the hashbin. + // Abort and increase the bin size. + qCCritical(qt3ds::OUT_OF_MEMORY) + << "Memory Tracker Error: Ran out of room in tracker hashbin " + << Q3DStudio_MEMORY_LINETRACKINGSIZE; + // exit( -1 ); + } + } + + // Set WatchGuard and store the pointer in the hash bin + inPointer->m_DogTag = TRACKER_DOGTAG; + m_TrackingHashBin[theHashBin] = inPointer; + } +} + +//============================================================================== +/** + * Remove information on an allocation + * @param inPtr contains info about the allocation we are releasing + */ +void CMemoryTracker::Forget(SMemoryInfo *inPointer) +{ + if (inPointer) { + // Update global tracking + m_TrackingOverhead -= sizeof(SMemoryInfo); + + // Locate the pointer in the hash bin + size_t theHashBin = Q3DStudio_max<size_t>(0, (reinterpret_cast<size_t>(inPointer) >> 2) + % Q3DStudio_MEMORY_LINETRACKINGSIZE); + size_t theStartHashBin = theHashBin; + + while (m_TrackingHashBin[theHashBin] != inPointer) { + ++theHashBin; + if (theHashBin >= Q3DStudio_MEMORY_LINETRACKINGSIZE) + theHashBin = 0; + + if (theHashBin == theStartHashBin) { + // We were unable to locate the pointer in the hash bin. + // This is really bad, but not catastrophic + qCWarning(qt3ds::OUT_OF_MEMORY) + << "Memory Tracker Warning. Can't find pointer in tracker hashbin"; + return; + } + } + + // Verify watch guard. Something is trashing memory if this call fails. + Q3DStudio_ASSERT(m_TrackingHashBin[theHashBin]->m_DogTag == TRACKER_DOGTAG); + + // Clear the pointer from the hash bin + m_TrackingHashBin[theHashBin] = NULL; + } +} + +//============================================================================== +/** + * Dump the memory list stored in the hash bin. + * @param inFileName the report filename or NULL to dump to the logger + */ +INT32 CMemoryTracker::Report(IStream *inStream /*=NULL*/) +{ + INT32 theTotalBytes = 0; + CHAR theLine[256]; + + for (INT32 theBinIndex = 0; theBinIndex < Q3DStudio_MEMORY_LINETRACKINGSIZE; ++theBinIndex) { + if (m_TrackingHashBin[theBinIndex]) { + CMemoryTracker::SMemoryInfo *theInfo = m_TrackingHashBin[theBinIndex]; + + Q3DStudio_sprintf(theLine, sizeof(theLine), "0x%p, %8d, %s, %s(%hd)\n", theInfo, + theInfo->m_Size, theInfo->m_Type, theInfo->m_File, theInfo->m_Line); + + CMemoryStatistics::Report(inStream, theLine); + theTotalBytes += theInfo->m_Size; + } + } + + return theTotalBytes; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSMemoryTracker.h b/src/system/Qt3DSMemoryTracker.h new file mode 100644 index 0000000..ee6ce69 --- /dev/null +++ b/src/system/Qt3DSMemoryTracker.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Low level memory statistics tracking each individual allocation. + * + * This class is instantiated in each CMemoryManager if tracking is enabled + * by setting ENABLE_MEMORY_LINETRACKING to 1 in AKConfig.h for the build + * configuration you want. + * + * Tracking is much more invasive than simple statistics since it records each + * individual allocation and deallocation. The overhead can be seen mostly in + * the memory load since we store a tracking hashbin of all memory allocation + * and a 16 byte SMemoryInfo structure is prepended to each allocation no matter + * how small. This mode should be used when debugging memory to track down + * individual allocations. It's turned off by default and should stay off + * most of the time. + * + * The tracking information is usually dumped to a comma delimited .csv file + * for easy viewing as a spreadsheet of data. This action is initiated by + * pressing CTRL-F1 in Quarterback on the PC but can be added to any viewer + * by calling CMemoryStatistics::TrackingDump. + */ +class CMemoryTracker +{ + //============================================================================== + // Constants + //============================================================================== +public: + const static UINT16 TRACKER_DOGTAG = 0xbead; ///< Watch guard value in SMemoryTrackInfo + + //============================================================================== + // Structs + //============================================================================== +public: + /// 16 bytes of details on each allocation when tracking is enabled + struct SMemoryInfo + { + UINT16 m_DogTag; ///< 0xbead - asserting this to track overwrites + INT16 m_Line; ///< line from which the allocation occurred + INT32 m_Size; ///< allocation size in bytes + const CHAR *m_File; ///< file from which the allocation occurred + const CHAR *m_Type; ///< type of allocation, usually class name + }; + + //============================================================================== + // Fields + //============================================================================== +protected: + INT32 m_TrackingOverhead; ///< memory used to track allocations in bytes + SMemoryInfo *m_TrackingHashBin[Q3DStudio_MEMORY_LINETRACKINGSIZE]; ///< hash table of all + ///tracked allocations + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + CMemoryTracker(); + ~CMemoryTracker(); + +public: // Tracking + void Remember(SMemoryInfo *inData); + void Forget(SMemoryInfo *inData); + +public: // Reporting + INT32 Report(IStream *inStream = NULL); +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSPlatformSpecific.h b/src/system/Qt3DSPlatformSpecific.h new file mode 100644 index 0000000..3fc3401 --- /dev/null +++ b/src/system/Qt3DSPlatformSpecific.h @@ -0,0 +1,207 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#if defined(_PCPLATFORM) + +#define Q3DStudio_memcpy(inDest, inSource, inCount) \ + memcpy(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memmove(inDest, inSource, inCount) \ + memmove(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memset(inDest, inChar, inCount) \ + memset(inDest, inChar, static_cast<size_t>(inCount)) +#define Q3DStudio_memcmp(inDest, inSource, inCount) \ + memcmp(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_sprintf _snprintf +#define Q3DStudio_stricmp(inStr1, inStr2) _stricmp(inStr1, inStr2) +#define Q3DStudio_strnicmp(inStr1, inStr2, inCount) _strnicmp(inStr1, inStr2, inCount) +#define Q3DStudio_tolower tolower +#define Q3DStudio_restrict /*__restrict*/ +#define Q3DStudio_dcbt(inOffset, inAddress) +#define Q3DStudio_strcpy(inDest, inSize, inSource) strcpy_s(inDest, inSize, inSource) +#define Q3DStudio_strcat(inDest, inSize, inSource) strcat_s(inDest, inSize, inSource) +#define Q3DStudio_fopen fopen_s +#define Q3DStudio_sleepmillisec(inMillisec) Sleep(inMillisec) +#define Q3DStudio_getpid GetCurrentProcessId + +#elif defined(_TEGRAPLATFORM) + +#define Q3DStudio_memcpy(inDest, inSource, inCount) \ + memcpy(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memmove(inDest, inSource, inCount) \ + memmove(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memset(inDest, inChar, inCount) \ + memset(inDest, inChar, static_cast<size_t>(inCount)) +#define Q3DStudio_memcmp(inDest, inSource, inCount) \ + memcmp(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_sprintf _snprintf +#define Q3DStudio_stricmp(inStr1, inStr2) _stricmp(inStr1, inStr2) +#define Q3DStudio_strnicmp(inStr1, inStr2, inCount) _strnicmp(inStr1, inStr2, inCount) +#define Q3DStudio_tolower tolower +#define Q3DStudio_restrict /*__restrict*/ +#define Q3DStudio_dcbt(inOffset, inAddress) +#define Q3DStudio_strcpy(inDest, inSize, inSource) strcpy_s(inDest, inSize, inSource) +#define Q3DStudio_strcat(inDest, inSize, inSource) strcat_s(inDest, inSize, inSource) +#define Q3DStudio_fopen(inFilePtr, inFilename, inMode) fopen_s(inFilePtr, inFilename, inMode) +#define Q3DStudio_sleepmillisec(inMillisec) Sleep(inMillisec) +#define Q3DStudio_getpid GetCurrentProcessId + +#elif defined(_XENONPLATFORM) + +#include <xtl.h> +#define Q3DStudio_memcpy(inDest, inSource, inCount) \ + memcpy(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memmove(inDest, inSource, inCount) \ + memmove(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memset(inDest, inChar, inCount) \ + memset(inDest, inChar, static_cast<size_t>(inCount)) +#define Q3DStudio_memcmp(inDest, inSource, inCount) \ + memcmp(inDest, inSource, static_cast<size_t>(inCount)) +//#define Q3DStudio_memcpy( inDest, inSource, inCount ) XMemCpy( inDest, inSource, +//static_cast<SIZE_T>( inCount ) ) +//#define Q3DStudio_memset( inDest, inChar, inCount ) XMemSet( inDest, inChar, +//static_cast<SIZE_T>( inCount ) ) +#define Q3DStudio_sprintf _snprintf +#define Q3DStudio_tolower tolower +#define Q3DStudio_restrict /*__restrict*/ +#define Q3DStudio_dcbt(inOffset, inAddress) __dcbt(inOffset, inAddress) +#define Q3DStudio_strcpy(inDest, inSize, inSource) strcpy_s(inDest, inSize, inSource) +#define Q3DStudio_strcat(inDest, inSize, inSource) strcat_s(inDest, inSize, inSource) +#define Q3DStudio_fopen(inFilePtr, inFilename, inMode) fopen_s(inFilePtr, inFilename, inMode) +#define Q3DStudio_sleepmillisec(inMillisec) Sleep(inMillisec) +#define Q3DStudio_getpid GetCurrentProcessId +#define Q3DStudio_strnicmp(inStr1, inStr2, inCount) _strnicmp(inStr1, inStr2, inCount) +#define Q3DStudio_stricmp(inStr1, inStr2) _stricmp(inStr1, inStr2) + +#elif defined(_PS3PLATFORM) + +#define Q3DStudio_memcpy(inDest, inSource, inCount) \ + memcpy(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memmove(inDest, inSource, inCount) \ + memmove(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memset(inDest, inChar, inCount) \ + memset(inDest, inChar, static_cast<size_t>(inCount)) +#define Q3DStudio_memcmp(inDest, inSource, inCount) \ + memcmp(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_sprintf snprintf +#define Q3DStudio_tolower std::tolower +#define Q3DStudio_restrict +#define Q3DStudio_dcbt(inOffset, inAddress) +#define Q3DStudio_strcpy(inDest, inSize, inSource) strcpy(inDest, inSource) +#define Q3DStudio_strcat(inDest, inSize, inSource) strcat(inDest, inSource) +#define Q3DStudio_fopen(inFilePtr, inFilename, inMode) *(inFilePtr) = fopen(inFilename, inMode) +#define Q3DStudio_sleepmillisec(inMillisec) \ + { \ + struct timespec theSleepTime = { inMillisec / 1000, (inMillisec % 1000) * 1000000 }; \ + ::nanosleep(&theSleepTime, NULL); \ + } +#define Q3DStudio_getpid getpid +#define Q3DStudio_stricmp(inStr1, inStr2) strcasecmp(inStr1, inStr2) +#define Q3DStudio_strnicmp(inStr1, inStr2, inCount) strncasecmp(inStr1, inStr2, inCount) + +#elif defined(_LINUXPLATFORM) || defined(_INTEGRITYPLATFORM) +#include <time.h> +#define Q3DStudio_memcpy(inDest, inSource, inCount) \ + memcpy(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memmove(inDest, inSource, inCount) \ + memmove(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_memset(inDest, inChar, inCount) \ + memset(inDest, inChar, static_cast<size_t>(inCount)) +#define Q3DStudio_memcmp(inDest, inSource, inCount) \ + memcmp(inDest, inSource, static_cast<size_t>(inCount)) +#define Q3DStudio_sprintf snprintf +#define Q3DStudio_stricmp(inStr1, inStr2) strcasecmp(inStr1, inStr2) +#define Q3DStudio_strnicmp(inStr1, inStr2, inCount) strncasecmp(inStr1, inStr2, inCount) +#define Q3DStudio_tolower tolower +#define Q3DStudio_restrict /*__restrict*/ +#define Q3DStudio_dcbt(inOffset, inAddress) +#define Q3DStudio_strcpy(inDest, inSize, inSource) strcpy(inDest, inSource) +#define Q3DStudio_strcat(inDest, inSize, inSource) strcat(inDest, inSource) +#define Q3DStudio_fopen(inFilePtr, inFilename, inMode) *(inFilePtr) = fopen(inFilename, inMode) +#define Q3DStudio_sleepmillisec(inMillisec) \ + { \ + struct timespec theSleepTime = { inMillisec / 1000, (inMillisec % 1000) * 1000000 }; \ + ::nanosleep(&theSleepTime, NULL); \ + } +#define Q3DStudio_getpid getpid + +#else +#error "A platform must be defined" +#endif + +//============================================================================== +/** @def Q3DStudio_dcbt( inOffset, inAddress ) + * @brief Data Cache Block Touch - Loads the block of memory containing + * the specified address into the data cache. + * + * A program uses the dcbt instruction to request a cache block fetch before + * it is actually needed by the program. This prevents stalls in the pipeline. + */ + +//============================================================================== +/** @def Q3DStudio_restrict + * @brief Cross platform macro for pointer aliasing. + * + * Performance Implications of Pointer Aliasing + * + * Doug Cook + * Silicon Graphics, Inc. + * August, 1997 + * + * Pointer aliasing can have a severe impact on program performance. + * Understanding its implications is critical to writing high-performance code. + * This document provides a brief introduction to the problem, and suggests + * several approaches to solving it through source-code restructuring, compiler + * options, and C or C++ language extensions. + * + * *Aliasing* + * + * Here's a brief overview of aliasing. Consider the following function: + * + * void process_data(float *in, float *out, float gain, int nsamps) + * { + * int i; + * for (i = 0; i < nsamps; i++) { + * out[i] = in[i] * gain; + * } + * } + * + * In C or C++, it is legal for the parameters in and out to point to + * overlapping regions in memory. When this happens, in and out are said to be + * aliases. When the compiler optimizes the function, it does not in general + * know whether in and out are aliases. It must therefore assume that any + * store through out can affect the memory pointed to by in, which severely + * limits its ability to reorder or parallelize the code (For some simple + * cases, the compiler could analyze the entire program to determine that two + * pointers cannot be aliases. But in general, it is impossible for the + * compiler to determine whether or not two pointers are aliases, so to be + * safe, it must assume that they are). + */ diff --git a/src/system/Qt3DSTimer.cpp b/src/system/Qt3DSTimer.cpp new file mode 100644 index 0000000..d9e82eb --- /dev/null +++ b/src/system/Qt3DSTimer.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSTimer.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Constructor + */ +CTimer::CTimer(ITimeProvider &inProvider) + : m_TimeProvider(inProvider) + , m_IsRunning(false) +{ + Start(); +} + +//============================================================================== +/** + * Start the timer + */ +void CTimer::Start() +{ + if (!m_IsRunning) + m_StartTime = m_TimeProvider.GetCurrentTimeMicroSeconds(); + m_IsRunning = true; +} + +//============================================================================== +/** + * Stop the timer + */ +void CTimer::Stop() +{ + if (m_IsRunning) + m_StartTime = m_TimeProvider.GetCurrentTimeMicroSeconds() - m_StartTime; + + m_IsRunning = false; +} + +//============================================================================== +/** + * Reset the timer + */ +void CTimer::Reset() +{ + if (m_IsRunning) + m_StartTime = m_TimeProvider.GetCurrentTimeMicroSeconds(); + else + m_StartTime = 0; +} + +//============================================================================== +/** + * Gets the current time in milliseconds. + * @return the current time since timer was started(in miliseconds), + * or time when it was stopped + */ +TTimeUnit CTimer::GetTimeMilliSecs() +{ + return GetTimeMicroSecs() / 1000; +} + +//============================================================================= +/** + * Get the number of usecs elapsed since start was called. + * If the timer is running then this will return the time from when start was + * called. If the timer is stopped then this will return the amount of time + * between the start and last stop. + * @return returns the elasped micro second. + */ +TMicroSeconds CTimer::GetTimeMicroSecs() +{ + if (m_IsRunning) + return m_TimeProvider.GetCurrentTimeMicroSeconds() - m_StartTime; + else + return m_StartTime; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSTimer.h b/src/system/Qt3DSTimer.h new file mode 100644 index 0000000..278bd4b --- /dev/null +++ b/src/system/Qt3DSTimer.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSITimer.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Forwards +//============================================================================== + +//============================================================================== +/** + * Time provider interface abstracting time from the usage of time. + */ +class ITimeProvider +{ +protected: + virtual ~ITimeProvider() {} +public: + virtual INT64 GetCurrentTimeMicroSeconds() = 0; +}; + +// Pause in a way that is completely transparent to the underlying system. +class CPausingTimeProvider : public ITimeProvider +{ + ITimeProvider &m_Provider; + INT64 m_PauseOffset; + INT64 m_Offset; + bool m_Paused; + +public: + CPausingTimeProvider(ITimeProvider &inProvider) + : m_Provider(inProvider) + , m_PauseOffset(0) + , m_Offset(0) + , m_Paused(false) + { + } + + INT64 GetCurrentTimeMicroSeconds() override + { + INT64 currentTime = 0; + if (m_Paused) + currentTime = m_PauseOffset; + else + currentTime = m_Provider.GetCurrentTimeMicroSeconds(); + + return currentTime - m_Offset; + } + + void Pause() + { + if (!m_Paused) { + m_Paused = true; + m_PauseOffset = m_Provider.GetCurrentTimeMicroSeconds(); + } + } + + void UnPause() + { + if (m_Paused) { + m_Paused = false; + INT64 timePaused = m_Provider.GetCurrentTimeMicroSeconds() - m_PauseOffset; + m_Offset += timePaused; + } + } + + bool IsPaused() { return m_Paused; } + + void Reset() { m_PauseOffset = m_Offset = 0; } +}; + +//============================================================================== +/** + * @class CTimer + * @brief A very simple platform optimized utility class to return lapsed time + * + * Gets current time based on the time lapsed from the point where timer is started. + */ + +class CTimer : public ITimer +{ + + //============================================================================== + // Fields + //============================================================================== +protected: + ITimeProvider &m_TimeProvider; + INT64 m_StartTime; + BOOL m_IsRunning; // Whether this timer is running or stopped + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + CTimer(ITimeProvider &inProvider); + +public: // Operation + void Start() override; + void Stop() override; + void Reset() override; + TTimeUnit GetTimeMilliSecs() override; + TMicroSeconds GetTimeMicroSecs() override; +}; + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSTypes.cpp b/src/system/Qt3DSTypes.cpp new file mode 100644 index 0000000..25d41c8 --- /dev/null +++ b/src/system/Qt3DSTypes.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +/** + * Return 2^inBitCount - 1. + * @param inBitCount number of bits available + * @param inUnsigned true if all bits are available + * @return the higest number the bits can represent + */ +INT32 Q3DStudio_maxbits(const INT32 inBitCount, const BOOL inUnsigned) +{ + Q3DStudio_ASSERT(inBitCount < 32); + if (inUnsigned) + return (1 << inBitCount) - 1; + else + return (1 << (inBitCount - 1)) - 1; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSTypes.h b/src/system/Qt3DSTypes.h new file mode 100644 index 0000000..65d57da --- /dev/null +++ b/src/system/Qt3DSTypes.h @@ -0,0 +1,121 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#include <QtCore/qglobal.h> + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Typedefs +//============================================================================== +typedef bool BOOL; ///< true or false, usually 8 bits +typedef qint8 INT8; ///< A signed 8-bit integer, not a character +typedef quint8 UINT8; ///< An unsigned 8-bit integer 0-255, not a character +typedef qint16 INT16; ///< A signed 16-bit integer +typedef quint16 UINT16; ///< An unsigned 16-bit integer +typedef qint32 INT32; ///< A signed 32-bit integer +typedef quint32 UINT32; ///< An unsigned 32-bit integer +typedef float FLOAT; ///< A 32-bit floating point number +typedef char CHAR; ///< String character, not a number +typedef qint64 INT64; +typedef quint64 UINT64; + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +//============================================================================== +// Max constants and computation +//============================================================================== +INT32 Q3DStudio_maxbits(const INT32 inBitCount, const BOOL inUnsigned); + +#define AKMAX_INT8 static_cast<INT8>(0x7F) +#define AKMAX_UINT8 static_cast<UINT8>(0xFF) +#define AKMAX_INT16 static_cast<INT16>(0x7FFF) +#define AKMAX_UINT16 static_cast<UINT16>(0xFFFF) +#define AKMAX_INT32 0x7FFFFFFFL +#define AKMAX_UINT32 0xFFFFFFFFUL + +#define Q3DStudio_INT64_C(x) x +#define Q3DStudio_UINT64_C(x) x + +typedef FILE TFile; +typedef size_t TFileSize; + +struct VECTOR4 +{ + union { + FLOAT v[4]; + UINT32 u[4]; + }; + + FLOAT &x() { return v[0]; } + FLOAT &y() { return v[1]; } + FLOAT &z() { return v[2]; } + FLOAT &w() { return v[3]; } +}; + +struct MATRIX16 +{ + union { + VECTOR4 v[4]; + FLOAT m[4][4]; + FLOAT f[16]; + }; + + FLOAT &_11() { return f[0]; } + FLOAT &_12() { return f[1]; } + FLOAT &_13() { return f[2]; } + FLOAT &_14() { return f[3]; } + FLOAT &_21() { return f[4]; } + FLOAT &_22() { return f[5]; } + FLOAT &_23() { return f[6]; } + FLOAT &_24() { return f[7]; } + FLOAT &_31() { return f[8]; } + FLOAT &_32() { return f[9]; } + FLOAT &_33() { return f[10]; } + FLOAT &_34() { return f[11]; } + FLOAT &_41() { return f[12]; } + FLOAT &_42() { return f[13]; } + FLOAT &_43() { return f[14]; } + FLOAT &_44() { return f[15]; } +}; + +typedef INT64 TMicroSeconds; ///< Time in microseconds +typedef INT64 TTimeUnit; ///< Time in milliseconds +} // namespace Q3DStudio diff --git a/src/system/Qt3DSVector3.cpp b/src/system/Qt3DSVector3.cpp new file mode 100644 index 0000000..2d790f9 --- /dev/null +++ b/src/system/Qt3DSVector3.cpp @@ -0,0 +1,466 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "SystemPrefix.h" + +//============================================================================== +// Includes +//============================================================================== +#include "Qt3DSVector3.h" +#include "Qt3DSMatrix.h" +#include "Qt3DSDataLogger.h" +#include <math.h> + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Constants +//============================================================================== +extern const float RUNTIME_EPSILON = 0.0001f; +const float RUNTIME_SQUARE_EPSILON = 0.000001f; + +//============================================================================== +/** + * Simple constructor - creates a NULL vector. + */ +RuntimeVector3::RuntimeVector3() + : m_X(0.0f) + , m_Y(0.0f) + , m_Z(0.0f) +{ +} + +//============================================================================== +/** + * Construction from three array value. + * @param inVector the source array + */ +RuntimeVector3::RuntimeVector3(const float inVector[3]) + : m_X(inVector[0]) + , m_Y(inVector[1]) + , m_Z(inVector[2]) +{ +} + +//============================================================================== +/** + * Construction from three coordinates. + * @param inX the m_X coordinate + * @param inY the m_Y coordinate + * @param inZ the m_Z coordinate + */ +RuntimeVector3::RuntimeVector3(const float inX, const float inY, const float inZ) + : m_X(inX) + , m_Y(inY) + , m_Z(inZ) +{ +} + +//============================================================================== +/** + * Copy constructor + * @param inVector the source vector + */ +RuntimeVector3::RuntimeVector3(const RuntimeVector3 &inVector) + : m_X(inVector.m_X) + , m_Y(inVector.m_Y) + , m_Z(inVector.m_Z) +{ +} + +//============================================================================== +/** + * Assignment of coordinates. + * @param inX the m_X coordinate + * @param inY the m_Y coordinate + * @param inZ the m_Z coordinate + * @return a reference to this modified vector + */ +RuntimeVector3 &RuntimeVector3::Set(const float inX, const float inY, const float inZ) +{ + m_X = inX; + m_Y = inY; + m_Z = inZ; + return *this; +} + +//============================================================================== +/** + * Assignment of coordinates using another vector. + * @param inVector the vector to be copied. + * @return a reference to this modified vector + */ +RuntimeVector3 &RuntimeVector3::Set(const RuntimeVector3 &inVector) +{ + m_X = inVector.m_X; + m_Y = inVector.m_Y; + m_Z = inVector.m_Z; + return *this; +} + +//============================================================================== +/** + * Compare this vector with another. Exact match is not needed but instead + * an error of EPSILON is allowed. + * @param inVector the vector we are compared with + * @return true if the vectors are close to identical + * @see EPSILON + */ +bool RuntimeVector3::operator==(const RuntimeVector3 &inVector) const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + + return (::fabsf(m_X - inVector.m_X) < RUNTIME_EPSILON) && (::fabsf(m_Y - inVector.m_Y) < RUNTIME_EPSILON) + && (::fabsf(m_Z - inVector.m_Z) < RUNTIME_EPSILON); +} + +//============================================================================== +/** + * Compare this vector with another. Exact match is not needed but instead + * an error of EPSILON is allowed. + * @param inVector the vector we are compared with + * @return true if the vectors are not even close to identical + * @see EPSILON + */ +bool RuntimeVector3::operator!=(const RuntimeVector3 &inVector) const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + + return (::fabsf(m_X - inVector.m_X) > RUNTIME_EPSILON) || (::fabsf(m_Y - inVector.m_Y) > RUNTIME_EPSILON) + || (::fabsf(m_Z - inVector.m_Z) > RUNTIME_EPSILON); +} + +//============================================================================== +/** + * Add this vector with another but do not modify this vector. + * @param inVector the second vector being added + * @return a new vector + */ +RuntimeVector3 RuntimeVector3::operator+(const RuntimeVector3 &inVector) const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + + return RuntimeVector3(m_X + inVector.m_X, m_Y + inVector.m_Y, m_Z + inVector.m_Z); +} + +//============================================================================== +/** + * Add two vectors but do not modify this vector. + * @param inVector vector being subtracted + * @return a new vector + */ +RuntimeVector3 RuntimeVector3::operator-(const RuntimeVector3 &inVector) const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + return RuntimeVector3(m_X - inVector.m_X, m_Y - inVector.m_Y, m_Z - inVector.m_Z); +} + +//============================================================================== +/** + * Get a scaled copy of this vector. + * @param inFactor the factor that scales each coordinate + * @return a new scaled vector + */ +RuntimeVector3 RuntimeVector3::operator*(float inFactor) const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + return RuntimeVector3(m_X * inFactor, m_Y * inFactor, m_Z * inFactor); +} + +//============================================================================== +/** + * Invert the vector. + * @return the inverted copy of this vector + */ +RuntimeVector3 RuntimeVector3::operator-() const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + return RuntimeVector3(-m_X, -m_Y, -m_Z); +} + +//============================================================================== +/** + * Simple assignment. + * @param inVector the new vector + * @return a reference to this modified vector + */ +RuntimeVector3 &RuntimeVector3::operator=(const RuntimeVector3 &inVector) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + if (&inVector != this) { + m_X = inVector.m_X; + m_Y = inVector.m_Y; + m_Z = inVector.m_Z; + } + return *this; +} + +//============================================================================== +/** + * Increment this vector. + * @param inVector has the coordinates by which this vector will be incremented + * @return a reference to this modified vector + */ +RuntimeVector3 &RuntimeVector3::operator+=(const RuntimeVector3 &inVector) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + m_X += inVector.m_X; + m_Y += inVector.m_Y; + m_Z += inVector.m_Z; + return *this; +} + +//============================================================================== +/** + * Decrement this vector. + * @param inVector has the coordinates by which this vector will be decremented + * @return a reference to this modified vector + */ +RuntimeVector3 &RuntimeVector3::operator-=(const RuntimeVector3 &inVector) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + m_X -= inVector.m_X; + m_Y -= inVector.m_Y; + m_Z -= inVector.m_Z; + return *this; +} + +//============================================================================== +/** + * Scale this vector by a factor. + * @param inFactor the scale factor + * @return a reference to this modified vector + */ +RuntimeVector3 &RuntimeVector3::operator*=(float inFactor) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + m_X *= inFactor; + m_Y *= inFactor; + m_Z *= inFactor; + return *this; +} + +//============================================================================== +/** + * Calculates the squared distance between this vector and another. + * This is often used in sorting situations where the real distance isn't needed. + * @param inVector vector to which the distance is being calculated + * @return the squared distance between vectors + */ +float RuntimeVector3::DistanceSquared(const RuntimeVector3 &inVector) const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + return (m_X - inVector.m_X) * (m_X - inVector.m_X) + (m_Y - inVector.m_Y) * (m_Y - inVector.m_Y) + + (m_Z - inVector.m_Z) * (m_Z - inVector.m_Z); +} + +//============================================================================== +/** + * Calculates the distance between this vector and another. + * @param inVector vector to which the distance is being calculated + * @return the distance between vectors + */ +float RuntimeVector3::Distance(const RuntimeVector3 &inVector) const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + return ::sqrtf((m_X - inVector.m_X) * (m_X - inVector.m_X) + + (m_Y - inVector.m_Y) * (m_Y - inVector.m_Y) + + (m_Z - inVector.m_Z) * (m_Z - inVector.m_Z)); +} + +//============================================================================== +/** + * Calculates the squared length (squared magnitude) of the current vector. + * @return the squared length of this vector + */ +float RuntimeVector3::LengthSquared() const +{ + return m_X * m_X + m_Y * m_Y + m_Z * m_Z; +} + +//============================================================================== +/** + * Calculates the length (magnitude) of the current vector. + * @return the length of this vector + */ +float RuntimeVector3::Length() const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + return ::sqrtf(m_X * m_X + m_Y * m_Y + m_Z * m_Z); +} + +//============================================================================== +/** + * Calculates the dot product of this vector and another. + * @param inVector vector measuring with + * @return the dot product + * @see operator* + */ +float RuntimeVector3::DotProduct(const RuntimeVector3 &inVector) const +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + return m_X * inVector.m_X + m_Y * inVector.m_Y + m_Z * inVector.m_Z; +} + +//============================================================================== +/** + * Calculates the cross product of this vector and another and modifies this vector + * @param inVector other vector + * @return this cross product vector + * @see operator% + * @see operator%= + */ +RuntimeVector3 &RuntimeVector3::CrossProduct(const RuntimeVector3 &inVector) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + float theX = m_Y * inVector.m_Z - m_Z * inVector.m_Y; + float theY = m_Z * inVector.m_X - m_X * inVector.m_Z; + float theZ = m_X * inVector.m_Y - m_Y * inVector.m_X; + + m_X = theX; + m_Y = theY; + m_Z = theZ; + + return *this; +} + +//============================================================================== +/** + * Normalizes the current vector making it a unit vector. + * The normalized vector is defined to be: V_norm = V / Magnitude(V). + * @return this normalized vector +*/ +RuntimeVector3 &RuntimeVector3::Normalize() +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + float theLengthSquared = LengthSquared(); + if ((theLengthSquared > RUNTIME_SQUARE_EPSILON) && ::fabsf(theLengthSquared - 1.0f) > RUNTIME_SQUARE_EPSILON) { + float theInvLength = 1.0f / ::sqrtf(theLengthSquared); + m_X *= theInvLength; + m_Y *= theInvLength; + m_Z *= theInvLength; + } + return *this; +} + +//============================================================================== +/** + * Modifies the current vector to contain elements that are the minimum between + * this vector and another. + * @param inVector vector that whose elements are tested against the + * current vector to build the minimum. + * @return this minimized vector +*/ +RuntimeVector3 &RuntimeVector3::Minimize(const RuntimeVector3 &inVector) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + m_X = Q3DStudio_min<float>(m_X, inVector.m_X); + m_Y = Q3DStudio_min<float>(m_Y, inVector.m_Y); + m_Z = Q3DStudio_min<float>(m_Z, inVector.m_Z); + return *this; +} + +//============================================================================== +/** + * Modifies the current vector to contain elements that are the maximum between + * this vector and another. + * @param inVector vector that whose elements are tested against the + * current vector to build the maximum. + * @return this maximized vector +*/ +RuntimeVector3 &RuntimeVector3::Maximize(const RuntimeVector3 &inVector) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + m_X = Q3DStudio_max<float>(m_X, inVector.m_X); + m_Y = Q3DStudio_max<float>(m_Y, inVector.m_Y); + m_Z = Q3DStudio_max<float>(m_Z, inVector.m_Z); + return *this; +} + +//============================================================================== +/** + * Modifies the current vector by performing a linear interpolation + * between the current vector and the given vector. + * + * If inFactor is 0.0 then this vector remains unchanged. If inFactor is + * 1.0 then this vector becomes inDestVector. If inFactor is between 0.0-1.0 + * then this vector becomes a vector between this old vector and inDestVector + * proportionally interpolated based in inFactor. If inFactor is less than 0 + * or more than 1 then this vector is extrapolated. + * + * @param inDestVector Second vector for the interpolation + * @param inFactor Weight for the interpolation + * @return this interpolated vector + */ +RuntimeVector3 &RuntimeVector3::InterpolateLinear(const RuntimeVector3 &inDestVector, float inFactor) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + m_X += inFactor * (inDestVector.m_X - m_X); + m_Y += inFactor * (inDestVector.m_Y - m_Y); + m_Z += inFactor * (inDestVector.m_Z - m_Z); + return *this; +} + +//============================================================================== +/** + * Transforms this vector by the given matrix. + * + * The matrix is row column of the form Matrix[row][column]: +@code + | m0 m1 m2 w | + | m4 m5 m6 w | + | m8 m9 m10 w | + | tX tY tZ w | +@endcode + * @param inMatrix transform matrix + * @return this transformed vector + */ +RuntimeVector3 &RuntimeVector3::Transform(const RuntimeMatrix &inMatrix) +{ + PerfLogMathEvent1(DATALOGGER_VECTOR); + float theX = m_X; + float theY = m_Y; + float theZ = m_Z; + + m_X = theX * inMatrix.Get(0, 0) + theY * inMatrix.Get(1, 0) + theZ * inMatrix.Get(2, 0); + m_Y = theX * inMatrix.Get(0, 1) + theY * inMatrix.Get(1, 1) + theZ * inMatrix.Get(2, 1); + m_Z = theX * inMatrix.Get(0, 2) + theY * inMatrix.Get(1, 2) + theZ * inMatrix.Get(2, 2); + + m_X += inMatrix.Get(3, 0); + m_Y += inMatrix.Get(3, 1); + m_Z += inMatrix.Get(3, 2); + + return *this; +} + +} // namespace Q3DStudio diff --git a/src/system/Qt3DSVector3.h b/src/system/Qt3DSVector3.h new file mode 100644 index 0000000..08df028 --- /dev/null +++ b/src/system/Qt3DSVector3.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#ifdef WIN32 +#pragma warning(disable : 4201) +#endif + +//============================================================================== +// Namespace +//============================================================================== +namespace Q3DStudio { + +//============================================================================== +// Forwards +//============================================================================== +class RuntimeMatrix; + +//============================================================================== +/** + * 3D vector with automatic notification on change. + * + * This implementation of a 3D vector along with all the sibling and helper + * classes in the geometry section, try to strike a balance between clean code, + * ease-of-use and speed. Fields are public and most methods are designed to + * give the impression of a very intelligent and capable structure. Heavier + * code such as intersections is encouraged to be added externally instead + * of here. + * + * The vector is a member of the geometry classes next to CMatrix and CRotation + * @see CMatrix + * @see CRotation + */ +class RuntimeVector3 +{ + //============================================================================== + // Fields + //============================================================================== +public: + union { + float m[3]; + struct + { + float m_X; + float m_Y; + float m_Z; + }; + }; + + //============================================================================== + // Methods + //============================================================================== +public: // Construction + RuntimeVector3(); + RuntimeVector3(const float inVector[3]); + RuntimeVector3(const float inX, const float inY, const float inZ); + RuntimeVector3(const RuntimeVector3 &inVector); + +public: // Initialization + RuntimeVector3 &Set(const float inX, const float inY, const float inZ); + RuntimeVector3 &Set(const RuntimeVector3 &inVector); + +public: // Functions + float DistanceSquared(const RuntimeVector3 &inVector) const; + float Distance(const RuntimeVector3 &inVector) const; + float LengthSquared() const; + float Length() const; + float DotProduct(const RuntimeVector3 &inVector) const; + RuntimeVector3 &CrossProduct(const RuntimeVector3 &inVector); + RuntimeVector3 &Normalize(); + RuntimeVector3 &Minimize(const RuntimeVector3 &inVector); + RuntimeVector3 &Maximize(const RuntimeVector3 &inVector); + RuntimeVector3 &InterpolateLinear(const RuntimeVector3 &inDestVector, float inFactor); + RuntimeVector3 &Transform(const RuntimeMatrix &inMatrix); + +public: // Operators + bool operator==(const RuntimeVector3 &inVector) const; + bool operator!=(const RuntimeVector3 &inVector) const; + RuntimeVector3 operator+(const RuntimeVector3 &inVector) const; + RuntimeVector3 operator-(const RuntimeVector3 &inVector) const; + RuntimeVector3 operator*(float inFactor) const; + RuntimeVector3 &operator=(const RuntimeVector3 &inVector); + RuntimeVector3 &operator+=(const RuntimeVector3 &inVector); + RuntimeVector3 &operator-=(const RuntimeVector3 &inVector); + RuntimeVector3 &operator*=(float inFactor); + RuntimeVector3 operator-() const; +}; + +} // namespace Q3DStudio diff --git a/src/system/SystemPrefix.h b/src/system/SystemPrefix.h new file mode 100644 index 0000000..aa1ba18 --- /dev/null +++ b/src/system/SystemPrefix.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#pragma once + +#ifdef _WIN32 +//============================================================================== +// DEFINES +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +//============================================================================== +// DISABLED WARNINGS +// +// Note that most of these warnings are tuned off by default by the compiler +// even at warning level 4. Using option /Wall turns on all warnings and makes +// even standard Microsoft include files cry. We had to turn off these or +// turn off warnings individually for each standard include file which was +// too much work. Point is that /Wall is like Warning Level 5 and this brings +// it down to about Warning level 4.5, still way above /W4. +#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union +#pragma warning(disable : 4511) // copy constructor could not be generated +#pragma warning(disable : 4512) // assignment operator could not be generated +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#pragma warning(disable : 4619) // #pragma warning : there is no warning number '4619' (in string.h) +#pragma warning(disable : 4625) // copy constructor could not be generated because a base class copy + // constructor is inaccessible +#pragma warning(disable : 4626) // assignment operator could not be generated because a base class + // assignment operator is inaccessible +#pragma warning(disable : 4826) // Conversion from 'const void *' to 'void *' is sign-extended +#pragma warning(disable : 4996) // _snprintf' was declared deprecated +#pragma warning(disable : 4711) // function selected for automatic inline expansion +#pragma warning(disable : 4710) // function not inlined +#pragma warning(disable : 4355) // 'this' : used in base member initializer list + +#pragma warning(disable : 4640) // construction of local static object is not thread-safe +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning( \ + disable : 4738) // storing 32-bit float result in memory, possible loss of performance +#endif //_WIN32 + +//============================================================================== +// STD INCLUDES - Standard includes MUST come first +#include <stdlib.h> // Standard functions +#include <stdio.h> // File and IO +#ifndef _INTEGRITYPLATFORM +#include <memory.h> // memset, memcpy +#endif +#include <string.h> // strlen +#include <math.h> // Bezier math - pow, acos, cos, sqrt +#include <ctype.h> // _tolower + +#if defined(_LINUXPLATFORM) || defined(_INTEGRITYPLATFORM) +#include <stdint.h> +#endif + +//============================================================================== +// OUR INCLUDES +#include "Qt3DSTypes.h" +#include "Qt3DSPlatformSpecific.h" +#include "Qt3DSAssert.h" +#include "Qt3DSMacros.h" +#include "Qt3DSConfig.h" +#include "Qt3DSMemorySettings.h" +#include "Qt3DSMemory.h" +#include "Qt3DSArray.h" |