summaryrefslogtreecommitdiffstats
path: root/src/foundation
diff options
context:
space:
mode:
Diffstat (limited to 'src/foundation')
-rw-r--r--src/foundation/AutoDeallocatorAllocator.h99
-rw-r--r--src/foundation/ConvertUTF.cpp661
-rw-r--r--src/foundation/ConvertUTF.h179
-rw-r--r--src/foundation/EASTL_new.cpp75
-rw-r--r--src/foundation/FastAllocator.h115
-rw-r--r--src/foundation/FileTools.cpp550
-rw-r--r--src/foundation/FileTools.h124
-rw-r--r--src/foundation/IOStreams.cpp384
-rw-r--r--src/foundation/IOStreams.h278
-rw-r--r--src/foundation/LICENCE_SOCKET.TXT20
-rw-r--r--src/foundation/LICENSE_CONVERTUTF.TXT19
-rw-r--r--src/foundation/PoolingAllocator.h177
-rw-r--r--src/foundation/PreAllocatedAllocator.h88
-rw-r--r--src/foundation/Qt3DS.h59
-rw-r--r--src/foundation/Qt3DSAllocator.h195
-rw-r--r--src/foundation/Qt3DSAllocatorCallback.h100
-rw-r--r--src/foundation/Qt3DSAssert.h62
-rw-r--r--src/foundation/Qt3DSAtomic.h63
-rw-r--r--src/foundation/Qt3DSBasicTemplates.h113
-rw-r--r--src/foundation/Qt3DSBounds3.h443
-rw-r--r--src/foundation/Qt3DSBroadcastingAllocator.h113
-rw-r--r--src/foundation/Qt3DSContainers.h129
-rw-r--r--src/foundation/Qt3DSDataRef.h162
-rw-r--r--src/foundation/Qt3DSDiscriminatedUnion.h335
-rw-r--r--src/foundation/Qt3DSFPU.h97
-rw-r--r--src/foundation/Qt3DSFastIPC.h57
-rw-r--r--src/foundation/Qt3DSFlags.h360
-rw-r--r--src/foundation/Qt3DSFoundation.cpp237
-rw-r--r--src/foundation/Qt3DSFoundation.h120
-rw-r--r--src/foundation/Qt3DSIPC.h99
-rw-r--r--src/foundation/Qt3DSIndexableLinkedList.h309
-rw-r--r--src/foundation/Qt3DSIntrinsics.h50
-rw-r--r--src/foundation/Qt3DSInvasiveLinkedList.h361
-rw-r--r--src/foundation/Qt3DSInvasiveSet.h104
-rw-r--r--src/foundation/Qt3DSLogging.cpp44
-rw-r--r--src/foundation/Qt3DSLogging.h51
-rw-r--r--src/foundation/Qt3DSMat33.h385
-rw-r--r--src/foundation/Qt3DSMat44.h497
-rw-r--r--src/foundation/Qt3DSMath.h323
-rw-r--r--src/foundation/Qt3DSMathUtils.cpp181
-rw-r--r--src/foundation/Qt3DSMathUtils.h571
-rw-r--r--src/foundation/Qt3DSMemoryBuffer.h160
-rw-r--r--src/foundation/Qt3DSMutex.h376
-rw-r--r--src/foundation/Qt3DSNoCopy.h50
-rw-r--r--src/foundation/Qt3DSOption.h104
-rw-r--r--src/foundation/Qt3DSPerfTimer.cpp163
-rw-r--r--src/foundation/Qt3DSPerfTimer.h107
-rw-r--r--src/foundation/Qt3DSPlane.h134
-rw-r--r--src/foundation/Qt3DSPool.h159
-rw-r--r--src/foundation/Qt3DSPreprocessor.h375
-rw-r--r--src/foundation/Qt3DSQuat.h381
-rw-r--r--src/foundation/Qt3DSRefCounted.h199
-rw-r--r--src/foundation/Qt3DSSemaphore.h67
-rw-r--r--src/foundation/Qt3DSSimpleTypes.h125
-rw-r--r--src/foundation/Qt3DSStringTokenizer.h108
-rw-r--r--src/foundation/Qt3DSSync.h70
-rw-r--r--src/foundation/Qt3DSSystem.cpp139
-rw-r--r--src/foundation/Qt3DSSystem.h58
-rw-r--r--src/foundation/Qt3DSThread.h205
-rw-r--r--src/foundation/Qt3DSTime.h97
-rw-r--r--src/foundation/Qt3DSTransform.h195
-rw-r--r--src/foundation/Qt3DSUnionCast.h64
-rw-r--r--src/foundation/Qt3DSUtilities.h189
-rw-r--r--src/foundation/Qt3DSVec2.h321
-rw-r--r--src/foundation/Qt3DSVec3.h377
-rw-r--r--src/foundation/Qt3DSVec4.h373
-rw-r--r--src/foundation/Qt3DSVersionNumber.h67
-rw-r--r--src/foundation/SerializationTypes.h132
-rw-r--r--src/foundation/Socket.cpp472
-rw-r--r--src/foundation/Socket.h79
-rw-r--r--src/foundation/StrConvertUTF.h213
-rw-r--r--src/foundation/StringConversion.h226
-rw-r--r--src/foundation/StringConversionImpl.h219
-rw-r--r--src/foundation/StringTable.cpp700
-rw-r--r--src/foundation/StringTable.h311
-rw-r--r--src/foundation/StringTools.h614
-rw-r--r--src/foundation/TaggedPointer.h80
-rw-r--r--src/foundation/ThreadSafeQueue.h111
-rw-r--r--src/foundation/TrackingAllocator.cpp50
-rw-r--r--src/foundation/TrackingAllocator.h252
-rw-r--r--src/foundation/Utils.h382
-rw-r--r--src/foundation/XML.cpp948
-rw-r--r--src/foundation/XML.h680
-rw-r--r--src/foundation/linux/LICENSE.TXT7
-rw-r--r--src/foundation/linux/Qt3DSLinuxAoS.h157
-rw-r--r--src/foundation/linux/Qt3DSLinuxAtomic.cpp129
-rw-r--r--src/foundation/linux/Qt3DSLinuxFPU.cpp52
-rw-r--r--src/foundation/linux/Qt3DSLinuxFile.h48
-rw-r--r--src/foundation/linux/Qt3DSLinuxInlineAoS.h2666
-rw-r--r--src/foundation/linux/Qt3DSLinuxIntrinsics.h209
-rw-r--r--src/foundation/linux/Qt3DSLinuxMutex.cpp120
-rw-r--r--src/foundation/linux/Qt3DSLinuxSemaphore.cpp146
-rw-r--r--src/foundation/linux/Qt3DSLinuxString.h202
-rw-r--r--src/foundation/linux/Qt3DSLinuxSync.cpp137
-rw-r--r--src/foundation/linux/Qt3DSLinuxThread.cpp384
-rw-r--r--src/foundation/linux/Qt3DSLinuxTime.cpp111
-rw-r--r--src/foundation/linux/Qt3DSLinuxTrigConstants.h96
-rw-r--r--src/foundation/linux/SocketImpl.h424
-rw-r--r--src/foundation/linux/qt_attribution.json10
-rw-r--r--src/foundation/macos/Qt3DSUnixAtomic.cpp89
-rw-r--r--src/foundation/macos/Qt3DSUnixFPU.cpp61
-rw-r--r--src/foundation/macos/Qt3DSUnixMutex.cpp120
-rw-r--r--src/foundation/macos/Qt3DSUnixSemaphore.cpp146
-rw-r--r--src/foundation/macos/Qt3DSUnixSync.cpp137
-rw-r--r--src/foundation/macos/Qt3DSUnixTime.cpp108
-rw-r--r--src/foundation/qt/formatdiscovery.cpp126
-rw-r--r--src/foundation/qt_attribution.json22
-rw-r--r--src/foundation/windows/LICENSE.TXT7
-rw-r--r--src/foundation/windows/Qt3DSWindowsAoS.h126
-rw-r--r--src/foundation/windows/Qt3DSWindowsAtomic.cpp93
-rw-r--r--src/foundation/windows/Qt3DSWindowsFPU.cpp61
-rw-r--r--src/foundation/windows/Qt3DSWindowsFile.h48
-rw-r--r--src/foundation/windows/Qt3DSWindowsInclude.h93
-rw-r--r--src/foundation/windows/Qt3DSWindowsInlineAoS.h2715
-rw-r--r--src/foundation/windows/Qt3DSWindowsIntrinsics.h230
-rw-r--r--src/foundation/windows/Qt3DSWindowsMutex.cpp149
-rw-r--r--src/foundation/windows/Qt3DSWindowsSemaphore.cpp72
-rw-r--r--src/foundation/windows/Qt3DSWindowsString.h147
-rw-r--r--src/foundation/windows/Qt3DSWindowsSync.cpp74
-rw-r--r--src/foundation/windows/Qt3DSWindowsThread.cpp241
-rw-r--r--src/foundation/windows/Qt3DSWindowsTime.cpp92
-rw-r--r--src/foundation/windows/Qt3DSWindowsTrigConstants.h93
-rw-r--r--src/foundation/windows/SocketImpl.h506
-rw-r--r--src/foundation/windows/qt_attribution.json10
124 files changed, 28985 insertions, 0 deletions
diff --git a/src/foundation/AutoDeallocatorAllocator.h b/src/foundation/AutoDeallocatorAllocator.h
new file mode 100644
index 0000000..5cbbc8b
--- /dev/null
+++ b/src/foundation/AutoDeallocatorAllocator.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#ifndef QT3DS_FOUNDATION_AUTO_DEALLOCATOR_ALLOCATOR_H
+#define QT3DS_FOUNDATION_AUTO_DEALLOCATOR_ALLOCATOR_H
+#pragma once
+
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSContainers.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ using eastl::make_pair;
+ using eastl::pair;
+
+ struct SSAutoDeallocatorAllocator : public NVAllocatorCallback
+ {
+ NVAllocatorCallback &m_Allocator;
+ nvhash_map<void *, size_t> m_Allocations;
+ SSAutoDeallocatorAllocator(NVFoundationBase &inFnd)
+ : m_Allocator(inFnd.getAllocator())
+ , m_Allocations(inFnd.getAllocator(), "SSAutoDeallocatorAllocator::m_Allocations")
+ {
+ }
+
+ SSAutoDeallocatorAllocator(NVAllocatorCallback &inAlloc)
+ : m_Allocator(inAlloc)
+ , m_Allocations(inAlloc, "SSAutoDeallocatorAllocator::m_Allocations")
+ {
+ }
+
+ // Automatically deallocates everything that hasn't already been deallocated.
+ ~SSAutoDeallocatorAllocator() { deallocateAllAllocations(); }
+
+ void deallocateAllAllocations()
+ {
+ for (nvhash_map<void *, size_t>::iterator iter = m_Allocations.begin(),
+ end = m_Allocations.end();
+ iter != end; ++iter)
+ m_Allocator.deallocate(iter->first);
+ m_Allocations.clear();
+ }
+
+ void *allocate(size_t size, const char *typeName, const char *filename, int line,
+ int flags = 0) override
+ {
+ void *value = m_Allocator.allocate(size, typeName, filename, line, flags);
+ m_Allocations.insert(make_pair(value, size));
+ return value;
+ }
+
+ void *allocate(size_t size, const char *typeName, const char *filename, int line,
+ size_t alignment, size_t alignmentOffset) override
+ {
+ void *value =
+ m_Allocator.allocate(size, typeName, filename, line, alignment, alignmentOffset);
+ m_Allocations.insert(make_pair(value, size));
+ return value;
+ }
+ void deallocate(void *ptr) override
+ {
+ nvhash_map<void *, size_t>::iterator iter = m_Allocations.find(ptr);
+ QT3DS_ASSERT(iter != m_Allocations.end());
+ m_Allocator.deallocate(iter->first);
+ m_Allocations.erase(iter);
+ }
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/ConvertUTF.cpp b/src/foundation/ConvertUTF.cpp
new file mode 100644
index 0000000..a71a3ae
--- /dev/null
+++ b/src/foundation/ConvertUTF.cpp
@@ -0,0 +1,661 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+/*
+* Copyright 2001-2004 Unicode, Inc.
+*
+* Disclaimer
+*
+* This source code is provided as is by Unicode, Inc. No claims are
+* made as to fitness for any particular purpose. No warranties of any
+* kind are expressed or implied. The recipient agrees to determine
+* applicability of information provided. If this file has been
+* purchased on magnetic or optical media from Unicode, Inc., the
+* sole remedy for any claim will be exchange of defective media
+* within 90 days of receipt.
+*
+* Limitations on Rights to Redistribute This Code
+*
+* Unicode, Inc. hereby grants the right to freely use the information
+* supplied in this file in the creation of products supporting the
+* Unicode Standard, and to make copies of this file in any form
+* for internal or external distribution as long as this notice
+* remains attached.
+*/
+
+/* ---------------------------------------------------------------------
+ Conversions between UTF32, UTF-16, and UTF-8. Source code file.
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Sept 2001: fixed const & error conditions per
+ mods suggested by S. Parent & A. Lillich.
+ June 2002: Tim Dodd added detection and handling of incomplete
+ source sequences, enhanced error detection, added casts
+ to eliminate compiler warnings.
+ July 2003: slight mods to back out aggressive FFFE detection.
+ Jan 2004: updated switches in from-UTF8 conversions.
+ Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
+ See the header file "ConvertUTF.h" for complete documentation.
+------------------------------------------------------------------------ */
+
+#include "foundation/ConvertUTF.h"
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4365) // warnings on conversion from unsigned int to int
+#endif
+
+#ifdef CVTUTF_DEBUG
+#include <stdio.h>
+#endif
+
+static const int halfShift = 10; /* used for shifting by 10 bits */
+
+static const UTF32 halfBase = 0x0010000UL;
+static const UTF32 halfMask = 0x3FFUL;
+
+#define UNI_SUR_HIGH_START (UTF32)0xD800
+#define UNI_SUR_HIGH_END (UTF32)0xDBFF
+#define UNI_SUR_LOW_START (UTF32)0xDC00
+#define UNI_SUR_LOW_END (UTF32)0xDFFF
+#define false 0
+#define true 1
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult Q3DSConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF32 *source = *sourceStart;
+ UTF16 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ if (target >= targetEnd) {
+ result = targetExhausted;
+ break;
+ }
+ ch = *source++;
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved
+ * values */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_LEGAL_UTF32) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ --source; /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult Q3DSConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF16 *source = *sourceStart;
+ UTF32 *target = *targetStart;
+ UTF32 ch, ch2;
+ while (source < sourceEnd) {
+ const UTF16 *oldSource =
+ source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START)
+ + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ if (target >= targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ *target++ = ch;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+#ifdef CVTUTF_DEBUG
+ if (result == sourceIllegal) {
+ fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
+ fflush(stderr);
+ }
+#endif
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Index into the table below with the first byte of a UTF-8 sequence to
+ * get the number of trailing bytes that are supposed to follow it.
+ * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
+ * left as-is for anyone who may want to do such conversion, which was
+ * allowed in earlier algorithms.
+ */
+static const char trailingBytesForUTF8[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
+};
+
+/*
+ * Magic values subtracted from a buffer value during UTF8 conversion.
+ * This table contains as many values as there might be trailing bytes
+ * in a UTF-8 sequence.
+ */
+static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
+ 0x03C82080UL, 0xFA082080UL, 0x82082080UL };
+
+/*
+ * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
+ * into the first byte, depending on how many bytes follow. There are
+ * as many entries in this table as there are UTF-8 sequence types.
+ * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
+ * for *legal* UTF-8 will be 4 or fewer bytes total.
+ */
+static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+/* --------------------------------------------------------------------- */
+
+/* The interface converts a whole buffer to avoid function-call overhead.
+ * Constants have been gathered. Loops & conditionals have been removed as
+ * much as possible for efficiency, in favor of drop-through switches.
+ * (See "Note A" at the bottom of the file for equivalent code.)
+ * If your compiler supports it, the "isLegalUTF8" call can be turned
+ * into an inline function.
+ */
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult Q3DSConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF16 *source = *sourceStart;
+ UTF8 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ const UTF16 *oldSource =
+ source; /* In case we have to back up because of target overflow. */
+ ch = *source++;
+ /* If we have a surrogate pair, convert to UTF32 first. */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
+ /* If the 16 bits following the high surrogate are in the source buffer... */
+ if (source < sourceEnd) {
+ UTF32 ch2 = *source;
+ /* If it's a low surrogate, convert to UTF32. */
+ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
+ ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START)
+ + halfBase;
+ ++source;
+ } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ } else { /* We don't have the 16 bits following the high surrogate. */
+ --source; /* return to the high surrogate */
+ result = sourceExhausted;
+ break;
+ }
+ } else if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /* Figure out how many bytes the result will require */
+ if (ch < (UTF32)0x80) {
+ bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) {
+ bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) {
+ bytesToWrite = 3;
+ } else if (ch < (UTF32)0x110000) {
+ bytesToWrite = 4;
+ } else {
+ bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ source = oldSource; /* Back up source pointer! */
+ target -= bytesToWrite;
+ result = targetExhausted;
+ break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 3:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 2:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 1:
+ *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Utility routine to tell whether a sequence of bytes is legal UTF-8.
+ * This must be called with the length pre-determined by the first byte.
+ * If not calling this from ConvertUTF8to*, then the length can be set by:
+ * length = trailingBytesForUTF8[*source]+1;
+ * and the sequence is illegal right away if there aren't that many bytes
+ * available.
+ * If presented with a length > 4, this returns false. The Unicode
+ * definition of UTF-8 goes up to 4-byte sequences.
+ */
+
+static Boolean isLegalUTF8(const UTF8 *source, int length)
+{
+ UTF8 a;
+ const UTF8 *srcptr = source + length;
+ switch (length) {
+ default:
+ return false;
+ /* Everything else falls through when "true"... */
+ case 4:
+ if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
+ return false;
+ case 3:
+ if ((a = (*--srcptr)) < 0x80 || a > 0xBF)
+ return false;
+ case 2:
+ if ((a = (*--srcptr)) > 0xBF)
+ return false;
+
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0:
+ if (a < 0xA0)
+ return false;
+ break;
+ case 0xED:
+ if (a > 0x9F)
+ return false;
+ break;
+ case 0xF0:
+ if (a < 0x90)
+ return false;
+ break;
+ case 0xF4:
+ if (a > 0x8F)
+ return false;
+ break;
+ default:
+ if (a < 0x80)
+ return false;
+ }
+
+ case 1:
+ if (*source >= 0x80 && *source < 0xC2)
+ return false;
+ }
+ if (*source > 0xF4)
+ return false;
+ return true;
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Exported function to return whether a UTF-8 sequence is legal or not.
+ * This is not used here; it's just exported.
+ */
+Boolean Q3DSIsLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
+{
+ int length = trailingBytesForUTF8[*source] + 1;
+ if (source + length > sourceEnd) {
+ return false;
+ }
+ return isLegalUTF8(source, length);
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult Q3DSConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF8 *source = *sourceStart;
+ UTF16 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted;
+ break;
+ }
+ /* Do this check whether lenient or strict */
+ if (!isLegalUTF8(source, extraBytesToRead + 1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5:
+ ch += *source++;
+ ch <<= 6; /* remember, illegal UTF-8 */
+ case 4:
+ ch += *source++;
+ ch <<= 6; /* remember, illegal UTF-8 */
+ case 3:
+ ch += *source++;
+ ch <<= 6;
+ case 2:
+ ch += *source++;
+ ch <<= 6;
+ case 1:
+ ch += *source++;
+ ch <<= 6;
+ case 0:
+ ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead + 1); /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead + 1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = (UTF16)ch; /* normal case */
+ }
+ } else if (ch > UNI_MAX_UTF16) {
+ if (flags == strictConversion) {
+ result = sourceIllegal;
+ source -= (extraBytesToRead + 1); /* return to the start */
+ break; /* Bail out; shouldn't continue */
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ /* target is a character in range 0xFFFF - 0x10FFFF. */
+ if (target + 1 >= targetEnd) {
+ source -= (extraBytesToRead + 1); /* Back up source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ ch -= halfBase;
+ *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
+ *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult Q3DSConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF32 *source = *sourceStart;
+ UTF8 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch;
+ unsigned short bytesToWrite = 0;
+ const UTF32 byteMask = 0xBF;
+ const UTF32 byteMark = 0x80;
+ ch = *source++;
+ if (flags == strictConversion) {
+ /* UTF-16 surrogate values are illegal in UTF-32 */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ --source; /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ }
+ }
+ /*
+ * Figure out how many bytes the result will require. Turn any
+ * illegally large UTF32 things (> Plane 17) into replacement chars.
+ */
+ if (ch < (UTF32)0x80) {
+ bytesToWrite = 1;
+ } else if (ch < (UTF32)0x800) {
+ bytesToWrite = 2;
+ } else if (ch < (UTF32)0x10000) {
+ bytesToWrite = 3;
+ } else if (ch <= UNI_MAX_LEGAL_UTF32) {
+ bytesToWrite = 4;
+ } else {
+ bytesToWrite = 3;
+ ch = UNI_REPLACEMENT_CHAR;
+ result = sourceIllegal;
+ }
+
+ target += bytesToWrite;
+ if (target > targetEnd) {
+ --source; /* Back up source pointer! */
+ target -= bytesToWrite;
+ result = targetExhausted;
+ break;
+ }
+ switch (bytesToWrite) { /* note: everything falls through. */
+ case 4:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 3:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 2:
+ *--target = (UTF8)((ch | byteMark) & byteMask);
+ ch >>= 6;
+ case 1:
+ *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
+ }
+ target += bytesToWrite;
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* --------------------------------------------------------------------- */
+
+ConversionResult Q3DSConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags)
+{
+ ConversionResult result = conversionOK;
+ const UTF8 *source = *sourceStart;
+ UTF32 *target = *targetStart;
+ while (source < sourceEnd) {
+ UTF32 ch = 0;
+ unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
+ if (source + extraBytesToRead >= sourceEnd) {
+ result = sourceExhausted;
+ break;
+ }
+ /* Do this check whether lenient or strict */
+ if (!isLegalUTF8(source, extraBytesToRead + 1)) {
+ result = sourceIllegal;
+ break;
+ }
+ /*
+ * The cases all fall through. See "Note A" below.
+ */
+ switch (extraBytesToRead) {
+ case 5:
+ ch += *source++;
+ ch <<= 6;
+ case 4:
+ ch += *source++;
+ ch <<= 6;
+ case 3:
+ ch += *source++;
+ ch <<= 6;
+ case 2:
+ ch += *source++;
+ ch <<= 6;
+ case 1:
+ ch += *source++;
+ ch <<= 6;
+ case 0:
+ ch += *source++;
+ }
+ ch -= offsetsFromUTF8[extraBytesToRead];
+
+ if (target >= targetEnd) {
+ source -= (extraBytesToRead + 1); /* Back up the source pointer! */
+ result = targetExhausted;
+ break;
+ }
+ if (ch <= UNI_MAX_LEGAL_UTF32) {
+ /*
+ * UTF-16 surrogate values are illegal in UTF-32, and anything
+ * over Plane 17 (> 0x10FFFF) is illegal.
+ */
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
+ if (flags == strictConversion) {
+ source -= (extraBytesToRead + 1); /* return to the illegal value itself */
+ result = sourceIllegal;
+ break;
+ } else {
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ } else {
+ *target++ = ch;
+ }
+ } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
+ result = sourceIllegal;
+ *target++ = UNI_REPLACEMENT_CHAR;
+ }
+ }
+ *sourceStart = source;
+ *targetStart = target;
+ return result;
+}
+
+/* ---------------------------------------------------------------------
+
+ Note A.
+ The fall-through switches in UTF-8 reading code save a
+ temp variable, some decrements & conditionals. The switches
+ are equivalent to the following loop:
+ {
+ int tmpBytesToRead = extraBytesToRead+1;
+ do {
+ ch += *source++;
+ --tmpBytesToRead;
+ if (tmpBytesToRead) ch <<= 6;
+ } while (tmpBytesToRead > 0);
+ }
+ In UTF-8 writing code, the switches on "bytesToWrite" are
+ similarly unrolled loops.
+
+ --------------------------------------------------------------------- */
diff --git a/src/foundation/ConvertUTF.h b/src/foundation/ConvertUTF.h
new file mode 100644
index 0000000..93614a0
--- /dev/null
+++ b/src/foundation/ConvertUTF.h
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** 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
+
+/*
+ * Copyright 2001-2004 Unicode, Inc.
+ *
+ * Disclaimer
+ *
+ * This source code is provided as is by Unicode, Inc. No claims are
+ * made as to fitness for any particular purpose. No warranties of any
+ * kind are expressed or implied. The recipient agrees to determine
+ * applicability of information provided. If this file has been
+ * purchased on magnetic or optical media from Unicode, Inc., the
+ * sole remedy for any claim will be exchange of defective media
+ * within 90 days of receipt.
+ *
+ * Limitations on Rights to Redistribute This Code
+ *
+ * Unicode, Inc. hereby grants the right to freely use the information
+ * supplied in this file in the creation of products supporting the
+ * Unicode Standard, and to make copies of this file in any form
+ * for internal or external distribution as long as this notice
+ * remains attached.
+ */
+
+/* ---------------------------------------------------------------------
+
+ Conversions between UTF32, UTF-16, and UTF-8. Header file.
+
+ Several funtions are included here, forming a complete set of
+ conversions between the three formats. UTF-7 is not included
+ here, but is handled in a separate source file.
+
+ Each of these routines takes pointers to input buffers and output
+ buffers. The input buffers are const.
+
+ Each routine converts the text between *sourceStart and sourceEnd,
+ putting the result into the buffer between *targetStart and
+ targetEnd. Note: the end pointers are *after* the last item: e.g.
+ *(sourceEnd - 1) is the last item.
+
+ The return result indicates whether the conversion was successful,
+ and if not, whether the problem was in the source or target buffers.
+ (Only the first encountered problem is indicated.)
+
+ After the conversion, *sourceStart and *targetStart are both
+ updated to point to the end of last text successfully converted in
+ the respective buffers.
+
+ Input parameters:
+ sourceStart - pointer to a pointer to the source buffer.
+ The contents of this are modified on return so that
+ it points at the next thing to be converted.
+ targetStart - similarly, pointer to pointer to the target buffer.
+ sourceEnd, targetEnd - respectively pointers to the ends of the
+ two buffers, for overflow checking only.
+
+ These conversion functions take a ConversionFlags argument. When this
+ flag is set to strict, both irregular sequences and isolated surrogates
+ will cause an error. When the flag is set to lenient, both irregular
+ sequences and isolated surrogates are converted.
+
+ Whether the flag is strict or lenient, all illegal sequences will cause
+ an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
+ or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
+ must check for illegal sequences.
+
+ When the flag is set to lenient, characters over 0x10FFFF are converted
+ to the replacement character; otherwise (when the flag is set to strict)
+ they constitute an error.
+
+ Output parameters:
+ The value "sourceIllegal" is returned from some routines if the input
+ sequence is malformed. When "sourceIllegal" is returned, the source
+ value will point to the illegal value that caused the problem. E.g.,
+ in UTF-8 when a sequence is malformed, it points to the start of the
+ malformed sequence.
+
+ Author: Mark E. Davis, 1994.
+ Rev History: Rick McGowan, fixes & updates May 2001.
+ Fixes & updates, Sept 2001.
+
+------------------------------------------------------------------------ */
+
+/* ---------------------------------------------------------------------
+ The following 4 definitions are compiler-specific.
+ The C standard does not guarantee that wchar_t has at least
+ 16 bits, so wchar_t is no less portable than unsigned short!
+ All should be unsigned values to avoid sign extension during
+ bit mask & shift operations.
+------------------------------------------------------------------------ */
+
+typedef unsigned int UTF32; /* at least 32 bits */
+typedef unsigned short UTF16; /* at least 16 bits */
+typedef unsigned char UTF8; /* typically 8 bits */
+typedef unsigned char Boolean; /* 0 or 1 */
+
+/* Some fundamental constants */
+
+#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
+#define UNI_MAX_BMP (UTF32)0x0000FFFF
+#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
+#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
+#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
+
+typedef enum {
+ conversionOK, /* conversion successful */
+ sourceExhausted, /* partial character in source, but hit end */
+ targetExhausted, /* insuff. room in target for conversion */
+ sourceIllegal /* source sequence is illegal/malformed */
+} ConversionResult;
+
+typedef enum { strictConversion = 0, lenientConversion } ConversionFlags;
+
+/* This is for C++ and does no harm in C */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ConversionResult Q3DSConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags);
+
+ConversionResult Q3DSConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd,
+ ConversionFlags flags);
+
+ConversionResult Q3DSConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags);
+
+ConversionResult Q3DSConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd,
+ ConversionFlags flags);
+
+ConversionResult Q3DSConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags);
+
+ConversionResult Q3DSConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags);
+
+Boolean Q3DSIsLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* --------------------------------------------------------------------- */
diff --git a/src/foundation/EASTL_new.cpp b/src/foundation/EASTL_new.cpp
new file mode 100644
index 0000000..61e8e0b
--- /dev/null
+++ b/src/foundation/EASTL_new.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// we have some build dependencies which forces us to include
+// this on linux to recognize malloc
+#include <stdio.h>
+#include <stdarg.h>
+
+#if !defined(_MSC_VER)
+#include <stdlib.h>
+#endif
+
+#include "EASTL/allocator.h"
+
+void *operator new[](size_t size, const char *, int, unsigned, const char *, int)
+{
+ return malloc(size);
+}
+
+void *operator new[](size_t size, size_t, size_t, const char *, int, unsigned, const char *, int)
+{
+ return malloc(size);
+}
+// EASTL also wants us to define this (see string.h line 197)
+int Vsnprintf8(char8_t *pDestination, size_t n, const char8_t *pFormat, va_list arguments)
+{
+#ifdef _MSC_VER
+ return _vsnprintf(pDestination, n, pFormat, arguments);
+#else
+ return vsnprintf(pDestination, n, pFormat, arguments);
+#endif
+}
+int Vsnprintf16(char8_t *pDestination, size_t n, const char16_t *pFormat, va_list arguments)
+{
+#ifdef _MSC_VER
+ return _vsnprintf(pDestination, n, (char *)pFormat, arguments);
+#else
+ return vsnprintf(pDestination, n, (char *)pFormat, arguments);
+#endif
+}
+int Vsnprintf32(char8_t *pDestination, size_t n, const char32_t *pFormat, va_list arguments)
+{
+#ifdef _MSC_VER
+ return _vsnprintf(pDestination, n, (char *)pFormat, arguments);
+#else
+ return vsnprintf(pDestination, n, (char *)pFormat, arguments);
+#endif
+}
diff --git a/src/foundation/FastAllocator.h b/src/foundation/FastAllocator.h
new file mode 100644
index 0000000..c296bcb
--- /dev/null
+++ b/src/foundation/FastAllocator.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "foundation/Qt3DSAllocatorCallback.h"
+#include "foundation/Qt3DSContainers.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ /**
+ * Allocator that allocates slabs of a certain size and objects then
+ * get allocated from those slabs. This allocator is designed to reset,
+ * meaning every frame you can call reset and the objects get freed but
+ * not destructed. This allocator does not call destructors!!
+ */
+ template <QT3DSU32 alignmentInBytes = 4, QT3DSU32 slabSize = 8192>
+ struct SFastAllocator : NVAllocatorCallback
+ {
+ ForwardingAllocator m_Allocator;
+ nvvector<QT3DSU8 *> m_Slabs;
+ QT3DSU32 m_Offset;
+
+ enum {
+ SlabSize = slabSize,
+ };
+
+ static size_t getSlabSize() { return slabSize; }
+
+ SFastAllocator(NVAllocatorCallback &alloc, const char *memName)
+ : m_Allocator(alloc, memName)
+ , m_Slabs(alloc, "SFastAllocator::m_Slabs")
+ , m_Offset(0)
+ {
+ }
+
+ ~SFastAllocator()
+ {
+ for (QT3DSU32 idx = 0, end = m_Slabs.size(); idx < end; ++idx)
+ m_Allocator.deallocate(m_Slabs[idx]);
+ m_Slabs.clear();
+ m_Offset = 0;
+ }
+ void *allocate(size_t inSize, const char *inFile, int inLine, int inFlags = 0)
+ {
+ (void)inFlags;
+ if (inSize > slabSize) {
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+ QT3DSU32 misalign = m_Offset % alignmentInBytes;
+ if (misalign)
+ m_Offset = m_Offset + (alignmentInBytes - misalign);
+
+ QT3DSU32 currentSlab = m_Offset / slabSize;
+ QT3DSU32 slabOffset = m_Offset % slabSize;
+ QT3DSU32 amountLeftInSlab = slabSize - slabOffset;
+ if (inSize > amountLeftInSlab) {
+ ++currentSlab;
+ slabOffset = 0;
+ m_Offset = currentSlab * slabSize;
+ }
+ while (currentSlab >= m_Slabs.size()) {
+ m_Slabs.push_back((QT3DSU8 *)m_Allocator.allocate(slabSize, inFile, inLine));
+ }
+ QT3DSU8 *data = m_Slabs[currentSlab] + slabOffset;
+ // This would indicate the underlying allocator isn't handing back aligned memory.
+ QT3DS_ASSERT(reinterpret_cast<size_t>(data) % alignmentInBytes == 0);
+ m_Offset += (QT3DSU32)inSize;
+ return data;
+ }
+ void *allocate(size_t size, const char * /*typeName*/, const char *filename, int line,
+ int flags = 0) override
+ {
+ return allocate(size, filename, line, flags);
+ }
+ void *allocate(size_t size, const char * /*typeName*/, const char *filename, int line,
+ size_t alignment, size_t /*alignmentOffset*/) override
+ {
+ QT3DS_ASSERT(alignment == alignmentInBytes);
+ if (alignment == alignmentInBytes)
+ return allocate(size, filename, line);
+ return NULL;
+ }
+ // only reset works with deallocation
+ void deallocate(void *) override {}
+ void reset() { m_Offset = 0; }
+ };
+}
+}
diff --git a/src/foundation/FileTools.cpp b/src/foundation/FileTools.cpp
new file mode 100644
index 0000000..c1733a6
--- /dev/null
+++ b/src/foundation/FileTools.cpp
@@ -0,0 +1,550 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "foundation/FileTools.h"
+#include "foundation/Utils.h"
+#include <string.h>
+#
+#ifdef EA_PLATFORM_WINDOWS
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else // posix
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#endif
+#include <QDir>
+#include <QFile>
+#include <QUrl>
+
+using namespace qt3ds::foundation;
+
+namespace {
+// State machine where you can add a character
+// and it will tell you how many characters to erase
+struct SPathStateMachine
+{
+ struct States
+ {
+ enum Enum {
+ NoState = 0, // Don't care
+ Slash, // Last char was either a forward or backward slash
+ Period, // Last char was a period
+ TwoPeriods, // Last two characters were periods
+ };
+ };
+ struct Actions
+ {
+ enum Enum {
+ NoAction = 0,
+ DeleteBack1Slash,
+ DeleteBack2Slashes,
+ };
+ };
+
+ States::Enum m_State;
+
+ SPathStateMachine()
+ : m_State(States::NoState)
+ {
+ }
+
+ Actions::Enum AnalyzeChar(char32_t inChar)
+ {
+ switch (inChar) {
+ case '\\':
+ case '/':
+ switch (m_State) {
+ case States::NoState:
+ m_State = States::Slash;
+ break;
+ case States::Period:
+ m_State = States::Slash;
+ return Actions::DeleteBack1Slash;
+
+ case States::TwoPeriods:
+ m_State = States::Slash;
+ return Actions::DeleteBack2Slashes;
+ case States::Slash:
+ return Actions::DeleteBack1Slash;
+ }
+ break;
+ case '.':
+ switch (m_State) {
+ case States::Slash:
+ case States::NoState:
+ m_State = States::Period;
+ break;
+ case States::Period:
+ m_State = States::TwoPeriods;
+ break;
+ case States::TwoPeriods:
+ break;
+ }
+ break;
+ default:
+ m_State = States::NoState;
+ break;
+ }
+ return Actions::NoAction;
+ }
+};
+
+template <typename TStrType>
+inline bool DoDeleteBack1Slash(TStr::size_type &idx, TStrType &ioPath)
+{
+ TStr::size_type slashLoc = ioPath.rfind('/', idx - 1);
+ if ((slashLoc != TStr::npos) && (slashLoc > 2)
+ // and the next *two* characters aren't both dots.
+ && ((ioPath[slashLoc - 1] != '.') || (ioPath[slashLoc - 2] != '.'))) {
+
+ ioPath.erase(ioPath.begin() + slashLoc, ioPath.begin() + idx);
+ idx = slashLoc;
+ return true;
+ }
+ return false;
+}
+
+template <typename TStrType>
+void NormalizePathT(TStrType &ioPath)
+{
+ TStr::size_type pathLen = ioPath.size();
+ SPathStateMachine theStateMachine;
+ for (TStr::size_type idx = 0; idx < pathLen; ++idx) {
+ char8_t &currentChar = ioPath[idx];
+ if (currentChar == '\\')
+ currentChar = '/';
+ SPathStateMachine::Actions::Enum action = theStateMachine.AnalyzeChar(currentChar);
+ switch (action) {
+ case SPathStateMachine::Actions::DeleteBack2Slashes:
+ if (DoDeleteBack1Slash(idx, ioPath))
+ DoDeleteBack1Slash(idx, ioPath);
+ pathLen = ioPath.size();
+ break;
+
+ case SPathStateMachine::Actions::DeleteBack1Slash:
+ DoDeleteBack1Slash(idx, ioPath);
+ pathLen = ioPath.size();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+bool IsAbsolute(const char8_t *inPath, size_t inLen)
+{
+ if (inLen > 2 && inPath[1] == ':')
+ return true;
+ else if (inLen > 1 && (inPath[0] == '\\' || inPath[0] == '/'))
+ return true;
+ return false;
+}
+
+template <typename TStrType>
+void CombineBaseAndRelativeT(const char8_t *inBase, const char8_t *inRelative, TStrType &outString)
+{
+ if (IsAbsolute(inRelative, StrLen(inRelative))) {
+ outString.assign(nonNull(inRelative));
+ } else {
+ if (inRelative && *inRelative) {
+ if (inRelative[0] == '#')
+ outString.assign(inRelative);
+ else {
+ if (IsAbsolute(inRelative, strlen(inRelative))) {
+ outString.assign(inRelative);
+ } else {
+ outString = inBase ? inBase : "";
+ if (outString.size())
+ outString.append("/");
+ outString.append(inRelative ? inRelative : (const char8_t *)L"");
+ }
+ NormalizePathT(outString);
+ }
+ }
+ }
+}
+
+template <typename TStrType>
+void GetRelativeFromBaseT(TStrType &inBaseStr, TStrType &inRelativeStr, TStrType &outString)
+{
+ outString.clear();
+ NormalizePathT(inBaseStr);
+ NormalizePathT(inRelativeStr);
+ if (inBaseStr.size() == 0) {
+ outString.assign(inRelativeStr.c_str());
+ return;
+ }
+ if (inRelativeStr.size() == 0) {
+ outString.clear();
+ return;
+ }
+ // find longest common string
+ const char8_t *inBase = inBaseStr.c_str();
+ const char8_t *baseEnd = inBaseStr.c_str() + inBaseStr.size();
+ const char8_t *inRelative = inRelativeStr.c_str();
+ size_t relativeLen = inRelativeStr.size();
+ const char8_t *relativeEnd = inRelative + relativeLen;
+
+ for (; inRelative < relativeEnd && inBase < baseEnd && *inRelative == *inBase;
+ ++inRelative, ++inBase)
+ ;
+
+ // They had nothing in common.
+ if (inBase == inBaseStr.c_str()) {
+ outString.assign(inRelativeStr.c_str());
+ return;
+ }
+
+ if (inRelative && (*inRelative == '\\' || *inRelative == '/'))
+ ++inRelative;
+
+ const char *common = inBase;
+ if (common == NULL || *common == 0) {
+ outString.assign("./");
+ outString.append(inRelative);
+ NormalizePathT(outString);
+ return;
+ }
+ // Backtrack to the nearest slash.
+ while (*common && *common != '\\' && *common != '/')
+ --common;
+
+ bool foundNonSlash = false;
+ for (; common != baseEnd; ++common) {
+ if (*common != '\\' && *common != '/') {
+ if (foundNonSlash == false)
+ outString.append("..\\");
+ foundNonSlash = true;
+ } else
+ foundNonSlash = false;
+ }
+ if (inRelative < relativeEnd) {
+ if (outString.size() == 0)
+ outString.assign("./");
+ outString.append(inRelative);
+ }
+ NormalizePathT(outString);
+}
+}
+
+void CFileTools::NormalizePath(TStr &ioPath)
+{
+ NormalizePathT(ioPath);
+}
+
+void CFileTools::NormalizePath(eastl::string &ioPath)
+{
+ NormalizePathT(ioPath);
+}
+
+QString CFileTools::NormalizePathForQtUsage(const QString &path)
+{
+ // path can be a file path or a qrc URL string.
+
+ QString filePath = QDir::cleanPath(path);
+
+ filePath.replace(QLatin1Char('\\'), QLatin1Char('/'));
+
+ if (filePath.startsWith(QLatin1String("./")))
+ return filePath.mid(2);
+
+ if (filePath.startsWith(QLatin1String("qrc:/")))
+ return filePath.mid(3);
+ else
+ return filePath;
+}
+
+void CFileTools::CombineBaseAndRelative(const char8_t *inBase, const char8_t *inRelative,
+ TStr &outString)
+{
+ CombineBaseAndRelativeT(inBase, inRelative, outString);
+}
+
+void CFileTools::CombineBaseAndRelative(const char8_t *inBase, const char8_t *inRelative,
+ eastl::string &outString)
+{
+ CombineBaseAndRelativeT(inBase, inRelative, outString);
+}
+
+void CFileTools::GetRelativeFromBase(TStr &inBaseStr, TStr &inRelativeStr, TStr &outString)
+{
+ GetRelativeFromBaseT(inBaseStr, inRelativeStr, outString);
+}
+
+void CFileTools::GetRelativeFromBase(eastl::string &inBaseStr, eastl::string &inRelativeStr,
+ eastl::string &outString)
+{
+ GetRelativeFromBaseT(inBaseStr, inRelativeStr, outString);
+}
+
+bool CFileTools::RequiresCombineBaseAndRelative(const char8_t *inPath)
+{
+ if (inPath && *inPath)
+ return inPath[0] == '.';
+ return false;
+}
+
+template <typename TStrType>
+void ToPlatformPathT(TStrType &outString)
+{
+#ifndef EA_PLATFORM_WINDOWS
+ for (TStr::size_type pos = outString.find('\\'); pos != TStr::npos;
+ pos = outString.find('\\', pos + 1))
+ outString.replace(outString.begin() + pos, outString.begin() + pos + 1, "/");
+#else
+ (void)outString;
+#endif
+}
+
+void CFileTools::ToPlatformPath(TStr &outString)
+{
+ ToPlatformPathT(outString);
+}
+
+void CFileTools::ToPlatformPath(eastl::string &outString)
+{
+ ToPlatformPathT(outString);
+}
+
+CRegisteredString CFileTools::RemapPathToBinaryFormat(TStr &inPath, TStr &inPresentationDir,
+ TStr &ioWorkspaceStr,
+ IStringTable &inStringTable)
+{
+ GetRelativeFromBase(inPresentationDir, inPath, ioWorkspaceStr);
+ CRegisteredString theNewStr = inStringTable.RegisterStr(ioWorkspaceStr.c_str());
+ theNewStr.Remap(inStringTable.GetRemapMap());
+ return theNewStr;
+}
+
+CRegisteredString CFileTools::RemapPathFromBinaryFormat(CRegisteredString inPath,
+ const char8_t *inPresDir,
+ TStr &ioWorkspaceStr,
+ const CStrTableOrDataRef &inRef,
+ IStringTable &inStringTable)
+{
+ inPath.Remap(inRef);
+ if (RequiresCombineBaseAndRelative(inPath.c_str())) {
+ CombineBaseAndRelative(inPresDir, inPath, ioWorkspaceStr);
+ return inStringTable.RegisterStr(ioWorkspaceStr.c_str());
+ }
+ return inPath;
+}
+
+void CFileTools::GetDirectory(eastl::string &ioPath)
+{
+ eastl::string::size_type theSlashPos = ioPath.find_last_of("\\/");
+ if (theSlashPos == eastl::string::npos) {
+ ioPath.clear();
+ return;
+ }
+ ioPath.resize(theSlashPos);
+}
+
+bool CFileTools::DirectoryExists(const char8_t *inPath)
+{
+#ifdef EA_PLATFORM_WINDOWS
+ DWORD theAtts = GetFileAttributesA(inPath);
+ return theAtts != INVALID_FILE_ATTRIBUTES && (theAtts & FILE_ATTRIBUTE_DIRECTORY);
+#else // Posix style check for directory
+ int status;
+ struct stat st_buf;
+ status = stat(inPath, &st_buf);
+ if (status == 0 && S_ISDIR(st_buf.st_mode))
+ return true;
+ return false;
+#endif
+}
+
+bool CFileTools::FileExists(const char8_t *inPath)
+{
+#ifdef EA_PLATFORM_WINDOWS
+ DWORD theAtts = GetFileAttributesA(inPath);
+ return theAtts != INVALID_FILE_ATTRIBUTES;
+#else // Posix style check for directory
+ int status;
+ struct stat st_buf;
+ status = stat(inPath, &st_buf);
+ if (status == 0)
+ return true;
+ return false;
+#endif
+}
+
+eastl::string CFileTools::GetFileOrAssetPath(const char8_t *inPath)
+{
+ QFile tmp(inPath);
+ if (tmp.exists())
+ return inPath;
+ return eastl::string("assets:/") + inPath;
+}
+
+void CFileTools::SetStreamPosition(QIODevice& device, qint64 inOffset,
+ qt3ds::foundation::SeekPosition::Enum inEnum)
+{
+ if (inEnum == qt3ds::foundation::SeekPosition::Begin)
+ device.seek(inOffset);
+ else if (inEnum == qt3ds::foundation::SeekPosition::Current)
+ device.seek(device.pos() + inOffset);
+ else if (inEnum == qt3ds::foundation::SeekPosition::End)
+ device.seek(device.size() + inOffset);
+}
+
+void CFileTools::GetExtension(const char8_t *inPath, eastl::string &outExt)
+{
+ outExt.assign(nonNull(inPath));
+ size_t dotPos = outExt.find_last_of('.');
+ if (dotPos != eastl::string::npos)
+ outExt.erase(outExt.begin(), outExt.begin() + dotPos + 1);
+}
+
+void CFileTools::Split(const char8_t *inPath, eastl::string &outDir, eastl::string &outFileStem,
+ eastl::string &outExtension)
+{
+ outDir.assign(nonNull(inPath));
+ NormalizePath(outDir);
+ outFileStem = outDir;
+ GetDirectory(outDir);
+ size_t lenDiff = outFileStem.size() - outDir.size();
+ if (lenDiff > 0) {
+ if (outDir.size())
+ outFileStem = outFileStem.substr(outDir.size() + 1);
+
+ eastl::string::size_type lastDot = outFileStem.find_last_of('.');
+ if (lastDot != eastl::string::npos) {
+ outExtension = outFileStem.substr(lastDot + 1);
+ outFileStem.resize(lastDot);
+ }
+ }
+}
+
+#ifdef EA_PLATFORM_WINDOWS
+void CFileTools::GetDirectoryEntries(const eastl::string &inPath,
+ eastl::vector<eastl::string> &outFiles)
+{
+ if (inPath.size() == 0)
+ return;
+ eastl::string tempPath(inPath);
+ NormalizePath(tempPath);
+ for (eastl::string::size_type pos = tempPath.find_first_of('/'); pos != eastl::string::npos;
+ pos = tempPath.find_first_of('/', pos + 1))
+ tempPath[pos] = '\\';
+ if (tempPath.back() != '\\')
+ tempPath.append("\\");
+ tempPath.append(1, '*');
+ WIN32_FIND_DATAA ffd;
+ HANDLE hFind = FindFirstFileA(tempPath.c_str(), &ffd);
+ outFiles.clear();
+ if (INVALID_HANDLE_VALUE == hFind)
+ return;
+
+ do {
+ if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0)
+ continue;
+ outFiles.push_back(eastl::string(ffd.cFileName));
+ } while (FindNextFileA(hFind, &ffd) != 0);
+}
+#else
+void CFileTools::GetDirectoryEntries(const eastl::string &inPath,
+ eastl::vector<eastl::string> &outFiles)
+{
+ if (inPath.size() == 0)
+ return;
+ eastl::string tempPath(inPath);
+ NormalizePath(tempPath);
+ struct dirent *dent;
+ DIR *srcdir = opendir(tempPath.c_str());
+ if (srcdir) {
+ while ((dent = readdir(srcdir)) != NULL) {
+ if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
+ continue;
+ outFiles.push_back(eastl::string(dent->d_name));
+ }
+ closedir(srcdir);
+ }
+}
+#endif
+
+bool CFileTools::CreateDir(const eastl::string &inPath, bool inRecurse)
+{
+ if (DirectoryExists(inPath.c_str()))
+ return true;
+
+ eastl::string temp(inPath);
+ GetDirectory(temp);
+ if (temp.size() && !DirectoryExists(temp.c_str())) {
+ if (inRecurse)
+ CreateDir(temp, inRecurse);
+ else
+ return false;
+ }
+
+#ifdef EA_PLATFORM_WINDOWS
+ BOOL result = CreateDirectoryA(inPath.c_str(), NULL);
+ return result != 0;
+#else
+ int result = mkdir(inPath.c_str(), 0777);
+ return result == 0;
+#endif
+}
+
+void CFileTools::AppendDirectoryInPathToFile(eastl::string &ioPath, const char8_t *dirName)
+{
+ eastl::string::size_type lastSlash = ioPath.find_last_of("\\/");
+ if (lastSlash != eastl::string::npos) {
+ if (dirName == NULL)
+ dirName = ""; // avoid crashes on null strings
+ ioPath.insert(lastSlash + 1, "/");
+ ioPath.insert(lastSlash + 1, dirName);
+ } else {
+ ioPath.insert(0, "/");
+ ioPath.insert(0, dirName);
+ }
+}
+
+void CFileTools::RemoveLastDirectoryInPathToFile(eastl::string &ioPath)
+{
+ eastl::string::size_type lastSlash = ioPath.find_last_of("\\/");
+ if (lastSlash != eastl::string::npos) {
+ eastl::string::size_type secondToLastSlash = ioPath.find_last_of("\\/", lastSlash - 1);
+ if (secondToLastSlash != eastl::string::npos)
+ ioPath = ioPath.erase(secondToLastSlash, lastSlash - secondToLastSlash);
+ }
+}
+
+void CFileTools::SetExtension(eastl::string &ioPath, const char8_t *inExt)
+{
+ eastl::string::size_type thePos = ioPath.find_last_of(".");
+ if (thePos != eastl::string::npos) {
+ ++thePos;
+ ioPath = ioPath.replace(thePos, ioPath.size() - thePos, inExt);
+ }
+}
diff --git a/src/foundation/FileTools.h b/src/foundation/FileTools.h
new file mode 100644
index 0000000..5745525
--- /dev/null
+++ b/src/foundation/FileTools.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_FOUNDATION_FILE_TOOLS_H
+#define QT3DS_FOUNDATION_FILE_TOOLS_H
+
+#include "EASTL/string.h"
+#include "EASTL/vector.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/StringTable.h"
+#include "foundation/IOStreams.h"
+#include <QtGlobal>
+
+QT_FORWARD_DECLARE_CLASS(QIODevice)
+
+namespace qt3ds {
+namespace foundation {
+
+ typedef eastl::basic_string<char8_t, ForwardingAllocator> TStr;
+
+ class CFileTools
+ {
+ public:
+ // Normalizes all slashes to be windows-like
+ static void NormalizePath(TStr &ioPath);
+ static void NormalizePath(eastl::string &ioPath);
+
+ // This is kind of the opposite of the 'NormalizePath' methods above in
+ // that it forces usage of unix style directory separators rather than
+ // windows separators. In addition, the path here can be a file path or
+ // a qrc URL string. This function will eventually be refactored away
+ // when we've converted to using Qt's file system abstraction throughout
+ // the code base and use QUrl's throughout instead of raw strings to
+ // represent resources.
+ static QString NormalizePathForQtUsage(const QString &path);
+
+ static void CombineBaseAndRelative(const char8_t *inBase, const char8_t *inRelative,
+ TStr &outString);
+ static void CombineBaseAndRelative(const char8_t *inBase, const char8_t *inRelative,
+ eastl::string &outString);
+
+ // inBase and inRelative will get normalized
+ // This algorithm changes based on the platform. On windows it is not case sensitive, on
+ // not-windows it is.
+ static void GetRelativeFromBase(TStr &inBase, TStr &inRelative, TStr &outString);
+ static void GetRelativeFromBase(eastl::string &inBase, eastl::string &inRelative,
+ eastl::string &outString);
+
+ // A remapped path is a file path that starts with a '.' or a '/'. GetRelativeFromBase
+ // *always*
+ // places a '.' or a '/' at the front of the path, so if you *know* the path came from
+ // GetRelativeFromBase then you also know this function returns true of GetRelativeFromBase
+ // actually generated a path that needs CombineBaseAndRelative.
+ static bool RequiresCombineBaseAndRelative(const char8_t *inPath);
+
+ // Search/replace so that all slashes are unix-like but only on non-windows platforms
+ // Assumes the incoming path has been normalized
+ static void ToPlatformPath(TStr &ioPath);
+ static void ToPlatformPath(eastl::string &ioPath);
+
+ static CRegisteredString RemapPathToBinaryFormat(TStr &inPath, TStr &inPresentationDir,
+ TStr &ioWorkspaceStr,
+ IStringTable &inStringTable);
+ static CRegisteredString RemapPathFromBinaryFormat(CRegisteredString inPath,
+ const char8_t *inPresDir,
+ TStr &ioWorkspaceStr,
+ const CStrTableOrDataRef &inRef,
+ IStringTable &inStringTable);
+ // I
+ static void GetDirectory(eastl::string &ioPath);
+ static bool DirectoryExists(const char8_t *inPath);
+ static void GetExtension(const char8_t *inPath, eastl::string &outExt);
+ static void Split(const char8_t *inPath, eastl::string &outDir, eastl::string &outFileStem,
+ eastl::string &outExtension);
+
+ // Only implemented for windows. Does not return '.' and '..' special entries
+ // inPath is mangled in a platform specific way
+ static void GetDirectoryEntries(const eastl::string &inPath,
+ eastl::vector<eastl::string> &outFiles);
+
+ static bool CreateDir(const eastl::string &inPath, bool inRecurse = true);
+
+ // Given a/b.txt, we will end up with a/dirName/b.txt
+ static void AppendDirectoryInPathToFile(eastl::string &ioPath, const char8_t *dirName);
+ static void RemoveLastDirectoryInPathToFile(eastl::string &ioPath);
+
+ static void SetExtension(eastl::string &ioPath, const char8_t *inExt);
+
+ static bool FileExists(const char8_t *inPath);
+ static eastl::string GetFileOrAssetPath(const char8_t *inPath);
+ static void SetStreamPosition(QIODevice& device, qint64 inOffset,
+ qt3ds::foundation::SeekPosition::Enum inEnum);
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/IOStreams.cpp b/src/foundation/IOStreams.cpp
new file mode 100644
index 0000000..f1adfbc
--- /dev/null
+++ b/src/foundation/IOStreams.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** 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 "foundation/IOStreams.h"
+#include "foundation/FileTools.h"
+#include "foundation/StrConvertUTF.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSSync.h"
+#include "foundation/Qt3DSThread.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSMemoryBuffer.h"
+
+using namespace qt3ds::foundation;
+
+#ifndef _WIN32
+
+inline int _fseeki64(FILE *inFile, int64_t pos, int seekFlags)
+{
+ return fseek(inFile, (int32_t)pos, seekFlags);
+}
+
+inline int64_t _ftelli64(FILE *inFile)
+{
+ return ftell(inFile);
+}
+
+#endif
+
+CFileSeekableIOStream::CFileSeekableIOStream(const char *inFileName, FileOpenFlags inFlags)
+{
+ openFile(QString(inFileName), inFlags);
+}
+
+#ifdef WIDE_IS_DIFFERENT_TYPE_THAN_CHAR16_T
+
+CFileSeekableIOStream::CFileSeekableIOStream(const wchar_t *inFileName, FileOpenFlags inFlags)
+{
+ openFile(QString::fromWCharArray(inFileName), inFlags);
+}
+
+#endif
+
+CFileSeekableIOStream::CFileSeekableIOStream(const char16_t *inWideName, FileOpenFlags inFlags)
+{
+ openFile(QString::fromUtf16(inWideName), inFlags);
+}
+
+CFileSeekableIOStream::CFileSeekableIOStream(const QString &inFIle, FileOpenFlags inFlags)
+{
+ openFile(inFIle, inFlags);
+}
+
+void CFileSeekableIOStream::openFile(const QString &path, FileOpenFlags inFlags)
+{
+ if (path.isEmpty())
+ return;
+
+ QIODevice::OpenMode fileFlags = QIODevice::ReadOnly;
+ if (inFlags & FileOpenFlagValues::Write)
+ fileFlags = QIODevice::ReadWrite;
+ if (inFlags & FileOpenFlagValues::Truncate)
+ fileFlags |= QIODevice::Truncate;
+
+ m_File.setFileName(CFileTools::NormalizePathForQtUsage(path));
+ if (!m_File.open(fileFlags)) {
+ qCCritical(INTERNAL_ERROR) << "failed to open file"
+ << path << "with error" << m_File.errorString();
+ QT3DS_ASSERT(false);
+ }
+}
+
+CFileSeekableIOStream::~CFileSeekableIOStream()
+{
+ m_File.close();
+}
+
+bool CFileSeekableIOStream::IsOpen()
+{
+ return m_File.isOpen();
+}
+
+void CFileSeekableIOStream::SetPosition(QT3DSI64 inOffset, SeekPosition::Enum inEnum)
+{
+ if (inOffset > QT3DS_MAX_I32 || inOffset < QT3DS_MIN_I32) {
+ qCCritical(INVALID_OPERATION, "Attempt to seek further than platform allows");
+ QT3DS_ASSERT(false);
+ return;
+ } else {
+ CFileTools::SetStreamPosition(m_File, inOffset, inEnum);
+ }
+}
+
+QT3DSI64 CFileSeekableIOStream::GetPosition() const
+{
+ return m_File.pos();
+}
+
+QT3DSU32 CFileSeekableIOStream::Read(NVDataRef<QT3DSU8> data)
+{
+ return m_File.read((char *)data.begin(), data.size());
+}
+
+bool CFileSeekableIOStream::Write(NVConstDataRef<QT3DSU8> data)
+{
+ if (!m_File.isOpen()) {
+ QT3DS_ASSERT(false);
+ return 0;
+ }
+ qint64 numBytes = m_File.write((char*)data.begin(), data.size());
+ return numBytes == data.size();
+}
+
+CMemorySeekableIOStream::CMemorySeekableIOStream(NVAllocatorCallback &inAlloc,
+ const char *inAllocName)
+ : m_Allocator(inAlloc)
+ , m_AllocationName(inAllocName)
+ , m_Data(NULL)
+ , m_Size(0)
+ , m_Offset(0)
+ , m_Capacity(0)
+{
+}
+
+CMemorySeekableIOStream::~CMemorySeekableIOStream()
+{
+ if (m_Data)
+ m_Allocator.deallocate(m_Data);
+ m_Data = NULL;
+ m_Size = 0;
+ m_Capacity = 0;
+ m_Offset = 0;
+}
+
+void CMemorySeekableIOStream::SetPosition(QT3DSI64 inOffset, SeekPosition::Enum inEnum)
+{
+ QT3DSI64 startPos = 0;
+
+ switch (inEnum) {
+ case SeekPosition::Begin:
+ startPos = 0;
+ break;
+ case SeekPosition::Current:
+ startPos = m_Offset;
+ break;
+ case SeekPosition::End:
+ startPos = m_Size;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+
+ startPos += inOffset;
+ if (m_Size == 0 && inOffset != 0) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (startPos < 0) {
+ QT3DS_ASSERT(false);
+ startPos = 0;
+ }
+ if (startPos >= m_Size && startPos != 0) {
+ QT3DS_ASSERT(false);
+ startPos = m_Size - 1;
+ }
+ m_Offset = static_cast<QT3DSU32>(startPos);
+}
+
+QT3DSU32 CMemorySeekableIOStream::Read(NVDataRef<QT3DSU8> data)
+{
+ if (m_Data == NULL)
+ return 0;
+ QT3DSU32 amountLeft = m_Size - m_Offset;
+ QT3DSU32 numBytes = NVMin(amountLeft, data.size());
+ intrinsics::memCopy(data.begin(), m_Data + m_Offset, numBytes);
+ m_Offset += numBytes;
+ return numBytes;
+}
+
+bool CMemorySeekableIOStream::Write(NVConstDataRef<QT3DSU8> data)
+{
+ reserve(data.size() + m_Offset);
+ intrinsics::memCopy(m_Data + m_Offset, data.begin(), data.size());
+ m_Offset += data.size();
+ m_Size = NVMax(m_Size, m_Offset);
+ return true;
+}
+
+void CMemorySeekableIOStream::reserve(QT3DSU32 inNewSize)
+{
+ if (inNewSize > m_Capacity) {
+ if (inNewSize < 100000)
+ inNewSize *= 2;
+ QT3DSU8 *newData =
+ (QT3DSU8 *)m_Allocator.allocate(inNewSize, m_AllocationName, __FILE__, __LINE__);
+ if (m_Size) {
+ intrinsics::memCopy(newData, m_Data, m_Size);
+ m_Allocator.deallocate(m_Data);
+ }
+ m_Data = newData;
+ m_Capacity = inNewSize;
+ }
+}
+
+namespace {
+
+struct WriteBufferedStreamImpl;
+struct WriteBufferThread : public Thread
+{
+ // When a buffer is available
+ WriteBufferedStreamImpl &m_Impl;
+ WriteBufferThread(NVFoundationBase &fnd, WriteBufferedStreamImpl &i)
+ : Thread(fnd)
+ , m_Impl(i)
+ {
+ setName("WriteBufferThread");
+ }
+ void execute() override;
+};
+
+#ifdef _WIN32
+#pragma warning(disable : 4355)
+#endif
+/* Double buffered stream implementation with a sending thread constantly
+ * pulling data from the main thread and writing it out to socket.
+ */
+struct WriteBufferedStreamImpl : public WriteBufferedOutStream
+{
+ NVFoundationBase &m_Foundation;
+ IOutStream &m_Stream;
+ MemoryBuffer<> m_Buf1;
+ MemoryBuffer<> m_Buf2;
+ MemoryBuffer<> *m_CurrentBuffer;
+ MemoryBuffer<> *m_WriteBuffer;
+ QT3DSU32 m_BufferSize;
+ volatile bool m_StreamValid;
+ Mutex m_BufferLock;
+ Sync m_DataAvailable;
+ Sync m_WriteFinished;
+ WriteBufferThread m_Thread;
+ QT3DSI32 mRefCount;
+
+ WriteBufferedStreamImpl(NVFoundationBase &fnd, QT3DSU32 totalBufSize, IOutStream &s)
+ : m_Foundation(fnd)
+ , m_Stream(s)
+ , m_Buf1(ForwardingAllocator(fnd.getAllocator(), "WriteBufferedStreamImpl::buffer"))
+ , m_Buf2(ForwardingAllocator(fnd.getAllocator(), "WriteBufferedStreamImpl::buffer"))
+ , m_CurrentBuffer(&m_Buf1)
+ , m_WriteBuffer(NULL)
+ , m_BufferSize(totalBufSize / 2)
+ , m_StreamValid(true)
+ , m_BufferLock(fnd.getAllocator())
+ , m_DataAvailable(fnd.getAllocator())
+ , m_WriteFinished(fnd.getAllocator())
+ , m_Thread(fnd, *this)
+ , mRefCount(0)
+ {
+ m_Buf1.reserve(m_BufferSize);
+ m_Buf2.reserve(m_BufferSize);
+ }
+ ~WriteBufferedStreamImpl()
+ {
+ m_Thread.signalQuit();
+ m_DataAvailable.set();
+ m_Thread.waitForQuit();
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Foundation.getAllocator())
+
+ bool Write(NVConstDataRef<QT3DSU8> data) override
+ {
+ while (data.size() && m_StreamValid) {
+ QT3DSU32 currentBufferSize;
+ QT3DSU32 amountCanWrite;
+ {
+ Mutex::ScopedLock locker(m_BufferLock);
+ currentBufferSize = m_CurrentBuffer->size();
+ amountCanWrite = NVMin(data.size(), m_BufferSize - currentBufferSize);
+ m_CurrentBuffer->write(data.begin(), amountCanWrite);
+ currentBufferSize += amountCanWrite;
+ }
+ m_DataAvailable.set();
+ if (currentBufferSize == m_BufferSize) {
+ m_WriteFinished.wait();
+ m_WriteFinished.reset();
+ // Blocking call if we are already sending data.
+ data = NVConstDataRef<QT3DSU8>(data.begin() + amountCanWrite,
+ data.size() - amountCanWrite);
+ }
+ }
+ return m_StreamValid;
+ }
+
+ IOutStream &wrappedStream() override { return m_Stream; }
+
+ QT3DSU32 getTotalBufferSize()
+ {
+ Mutex::ScopedLock locker(m_BufferLock);
+ QT3DSU32 retval = m_CurrentBuffer->size();
+ if (m_WriteBuffer)
+ retval += m_WriteBuffer->size();
+ return retval;
+ }
+
+ QT3DSU32 getWriteBufferSize()
+ {
+ Mutex::ScopedLock locker(m_BufferLock);
+ if (m_WriteBuffer)
+ return m_WriteBuffer->size();
+ return 0;
+ }
+
+ void flush() override
+ {
+ while (getTotalBufferSize()) {
+ m_WriteFinished.wait();
+ m_WriteFinished.reset();
+ }
+ }
+};
+
+void WriteBufferThread::execute()
+{
+ while (!quitIsSignalled()) {
+ m_Impl.m_DataAvailable.wait();
+
+ if (!quitIsSignalled() && m_Impl.m_StreamValid) {
+ m_Impl.m_DataAvailable.reset();
+ {
+ Mutex::ScopedLock locker(m_Impl.m_BufferLock);
+ m_Impl.m_WriteBuffer = m_Impl.m_CurrentBuffer;
+ m_Impl.m_CurrentBuffer =
+ m_Impl.m_CurrentBuffer == &m_Impl.m_Buf1 ? &m_Impl.m_Buf2 : &m_Impl.m_Buf1;
+ QT3DS_ASSERT(m_Impl.m_WriteBuffer != m_Impl.m_CurrentBuffer);
+ }
+ NVConstDataRef<QT3DSU8> dataBuffer(*m_Impl.m_WriteBuffer);
+ if (dataBuffer.size()) {
+ m_Impl.m_StreamValid = m_Impl.m_Stream.Write(dataBuffer);
+ {
+ Mutex::ScopedLock locker(m_Impl.m_BufferLock);
+ m_Impl.m_WriteBuffer->clear();
+ m_Impl.m_WriteBuffer = NULL;
+ }
+ }
+ m_Impl.m_WriteFinished.set();
+ }
+ }
+ quit();
+}
+}
+
+NVScopedRefCounted<WriteBufferedOutStream>
+WriteBufferedOutStreamCreate(NVFoundationBase &fnd, IOutStream &stream, QT3DSU32 totalBufferSize)
+{
+ return QT3DS_NEW(fnd.getAllocator(), WriteBufferedStreamImpl)(fnd, totalBufferSize, stream);
+}
diff --git a/src/foundation/IOStreams.h b/src/foundation/IOStreams.h
new file mode 100644
index 0000000..855e520
--- /dev/null
+++ b/src/foundation/IOStreams.h
@@ -0,0 +1,278 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_FOUNDATION_IO_STREAMS_H
+#define QT3DS_FOUNDATION_IO_STREAMS_H
+
+#include "EABase/eabase.h"
+#include "foundation/Qt3DSDataRef.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSIntrinsics.h"
+#include "foundation/TrackingAllocator.h"
+#include "foundation/Qt3DSMath.h"
+#include "foundation/Qt3DSFlags.h"
+#include "foundation/Utils.h"
+#include "foundation/Qt3DSRefCounted.h"
+
+#include <QFile>
+#include <QString>
+
+namespace qt3ds {
+class NVFoundationBase;
+
+namespace foundation {
+
+ class IOutStream
+ {
+ protected:
+ virtual ~IOutStream() {}
+ public:
+ virtual bool Write(NVConstDataRef<QT3DSU8> data) = 0;
+ void WriteWithLen(NVConstDataRef<QT3DSU8> data)
+ {
+ Write(data.size());
+ Write(data);
+ }
+ template <typename TDataType>
+ void Write(const TDataType &type)
+ {
+ Write(toU8ConstDataRef(type));
+ }
+ template <typename TDataType>
+ void Write(const TDataType *data, QT3DSU32 numItems)
+ {
+ Write(toU8ConstDataRef(data, numItems));
+ }
+ void Write(const wchar_t *data)
+ {
+ if (data == NULL)
+ data = L"";
+ // Write the null character at the end of the string.
+ // This just makes reading and debugging a lot less error prone.
+ // at the expense of 2 bytes.
+ Write(data, (QT3DSU32)StrLen(data) + 1);
+ }
+ template <typename TDataType>
+ void WriteWithLen(const TDataType *data, QT3DSU32 numItems)
+ {
+ WriteWithLen(toU8ConstDataRef(data, numItems));
+ }
+ };
+
+ class IInStream
+ {
+ protected:
+ virtual ~IInStream() {}
+ public:
+ // Semantics are precisely that you return the amount read
+ virtual QT3DSU32 Read(NVDataRef<QT3DSU8> data) = 0;
+
+ QT3DSU32 SafeRead(NVDataRef<QT3DSU8> data)
+ {
+ QT3DSU32 amountRead = Read(data);
+ QT3DS_ASSERT(amountRead == data.size());
+ if (amountRead < data.size())
+ intrinsics::memZero(data.begin() + amountRead, data.size() - amountRead);
+ return amountRead;
+ }
+ QT3DSU32 ReadWithLen(NVDataRef<QT3DSU8> data)
+ {
+ QT3DSU32 len = 0;
+ Read(len);
+ return SafeRead(toDataRef(data.begin(), len));
+ }
+ template <typename TDataType>
+ QT3DSU32 Read(TDataType &type)
+ {
+ return SafeRead(toU8DataRef(type));
+ }
+ template <typename TDataType>
+ QT3DSU32 Read(TDataType *data, QT3DSU32 numItems)
+ {
+ return SafeRead(toU8DataRef(data, numItems));
+ }
+ };
+
+ struct SeekPosition
+ {
+ enum Enum {
+ Unknown,
+ Begin,
+ Current,
+ End,
+ };
+ };
+
+ class ISeekable
+ {
+ protected:
+ virtual ~ISeekable() {}
+ public:
+ virtual void SetPosition(QT3DSI64 inOffset, SeekPosition::Enum inEnum) = 0;
+ virtual QT3DSI64 GetPosition() const = 0;
+ virtual QT3DSI64 GetLength() const
+ {
+ ISeekable &seekable(const_cast<ISeekable &>(*this));
+ QT3DSI64 currentPos(GetPosition());
+ seekable.SetPosition(0, SeekPosition::End);
+ QT3DSI64 retval(GetPosition());
+ seekable.SetPosition(currentPos, SeekPosition::Begin);
+ return retval;
+ }
+ };
+
+ class ISeekableIOStream : public IInStream, public IOutStream, public ISeekable
+ {
+ };
+
+ struct FileOpenFlagValues
+ {
+ enum Enum {
+ Open = 1, // Without this flag, function fails if file exists
+ Truncate = 1 << 1, // Truncate the file so an immediate close will empty it.
+ Create = 1 << 2,
+ Write = 1 << 3,
+ };
+ };
+
+ typedef NVFlags<FileOpenFlagValues::Enum, int> FileOpenFlags;
+
+ static inline FileOpenFlags FileReadFlags() { return FileOpenFlags(FileOpenFlagValues::Open); }
+
+ static inline FileOpenFlags FileWriteFlags()
+ {
+ return FileOpenFlags(FileOpenFlagValues::Create | FileOpenFlagValues::Open
+ | FileOpenFlagValues::Write | FileOpenFlagValues::Truncate);
+ }
+ static inline FileOpenFlags FileAppendFlags()
+ {
+ return FileOpenFlags(FileOpenFlagValues::Create | FileOpenFlagValues::Open
+ | FileOpenFlagValues::Write);
+ }
+
+ class CFileSeekableIOStream : public ISeekableIOStream
+ {
+ protected:
+ QFile m_File;
+
+ public:
+ // Enabling append also enables reading from the file while being able to
+ // write to it.
+ CFileSeekableIOStream(const char *inFile, FileOpenFlags inFlags);
+#ifdef WIDE_IS_DIFFERENT_TYPE_THAN_CHAR16_T
+ CFileSeekableIOStream(const wchar_t *inFile, FileOpenFlags inFlags);
+#endif
+
+ CFileSeekableIOStream(const char16_t *inFile, FileOpenFlags inFlags);
+ CFileSeekableIOStream(const QString &inFIle, FileOpenFlags inFlags);
+ virtual ~CFileSeekableIOStream();
+ virtual bool IsOpen();
+ void SetPosition(QT3DSI64 inOffset, SeekPosition::Enum inEnum) override;
+ QT3DSI64 GetPosition() const override;
+ QT3DSU32 Read(NVDataRef<QT3DSU8> data) override;
+ bool Write(NVConstDataRef<QT3DSU8> data) override;
+
+ private:
+ void openFile(const QString &path, FileOpenFlags inFlags);
+ };
+
+ class CMemorySeekableIOStream : public ISeekableIOStream
+ {
+ protected:
+ NVAllocatorCallback &m_Allocator;
+ const char *m_AllocationName;
+ QT3DSU8 *m_Data;
+ QT3DSU32 m_Size;
+ QT3DSU32 m_Offset;
+ QT3DSU32 m_Capacity;
+
+ public:
+ CMemorySeekableIOStream(NVAllocatorCallback &inAlloc, const char *inAllocName);
+ virtual ~CMemorySeekableIOStream();
+ void SetPosition(QT3DSI64 inOffset, SeekPosition::Enum inEnum) override;
+ QT3DSI64 GetPosition() const override { return m_Offset; }
+ QT3DSI64 GetLength() const override { return m_Size; }
+ QT3DSU32 Read(NVDataRef<QT3DSU8> data) override;
+ bool Write(NVConstDataRef<QT3DSU8> data) override;
+
+ // Add in the standard container functions
+ QT3DSU8 *begin() { return m_Data; }
+ QT3DSU8 *end() { return m_Data + m_Size; }
+ const QT3DSU8 *begin() const { return m_Data; }
+ const QT3DSU8 *end() const { return m_Data + m_Size; }
+ void clear()
+ {
+ m_Offset = 0;
+ m_Size = 0;
+ }
+ QT3DSU32 size() const { return m_Size; }
+ void reserve(QT3DSU32 inNewSize);
+ void resize(QT3DSU32 inNewSize)
+ {
+ reserve(inNewSize);
+ m_Size = inNewSize;
+ }
+ };
+
+ // Simple, one way input stream.
+ struct SMemoryInStream : public IInStream
+ {
+ const QT3DSU8 *m_Begin;
+ const QT3DSU8 *m_End;
+ SMemoryInStream(const QT3DSU8 *b, const QT3DSU8 *e)
+ : m_Begin(b)
+ , m_End(e)
+ {
+ }
+
+ QT3DSU32 Read(NVDataRef<QT3DSU8> data) override
+ {
+ size_t available = m_End - m_Begin;
+ size_t requested = data.size();
+ size_t amount = NVMin(available, requested);
+ qt3ds::intrinsics::memCopy(data.mData, m_Begin, (QT3DSU32)amount);
+ m_Begin += amount;
+ return (QT3DSU32)amount;
+ }
+ };
+
+ class WriteBufferedOutStream : public IOutStream, public NVRefCounted
+ {
+ public:
+ virtual IOutStream &wrappedStream() = 0;
+ virtual void flush() = 0;
+
+ static NVScopedRefCounted<WriteBufferedOutStream>
+ Create(NVFoundationBase &fnd, IOutStream &stream, QT3DSU32 totalBufferSize = 128 * 1024);
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/LICENCE_SOCKET.TXT b/src/foundation/LICENCE_SOCKET.TXT
new file mode 100644
index 0000000..9b9ab80
--- /dev/null
+++ b/src/foundation/LICENCE_SOCKET.TXT
@@ -0,0 +1,20 @@
+LuaSocket 3.0 license
+Copyright (C) 2004-2013 Diego Nehab
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/src/foundation/LICENSE_CONVERTUTF.TXT b/src/foundation/LICENSE_CONVERTUTF.TXT
new file mode 100644
index 0000000..254acdf
--- /dev/null
+++ b/src/foundation/LICENSE_CONVERTUTF.TXT
@@ -0,0 +1,19 @@
+Copyright 2001-2004 Unicode, Inc.
+
+Disclaimer
+
+This source code is provided as is by Unicode, Inc. No claims are
+made as to fitness for any particular purpose. No warranties of any
+kind are expressed or implied. The recipient agrees to determine
+applicability of information provided. If this file has been
+purchased on magnetic or optical media from Unicode, Inc., the
+sole remedy for any claim will be exchange of defective media
+within 90 days of receipt.
+
+Limitations on Rights to Redistribute This Code
+
+Unicode, Inc. hereby grants the right to freely use the information
+supplied in this file in the creation of products supporting the
+Unicode Standard, and to make copies of this file in any form
+for internal or external distribution as long as this notice
+remains attached.
diff --git a/src/foundation/PoolingAllocator.h b/src/foundation/PoolingAllocator.h
new file mode 100644
index 0000000..9d939fd
--- /dev/null
+++ b/src/foundation/PoolingAllocator.h
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#ifndef QT3DS_FOUNDATION_POOLING_ALLOCATOR_H
+#define QT3DS_FOUNDATION_POOLING_ALLOCATOR_H
+#pragma once
+
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSContainers.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "foundation/Qt3DSPool.h"
+#include "foundation/AutoDeallocatorAllocator.h"
+#include "foundation/Qt3DSMutex.h"
+
+// Pooling allocator. Not designed for small allocations
+// starting at 64 bytes and up to 4 K, allocator uses pools.
+// Above that, uses default allocator. THis object is absolutely not threadsafe.
+// This addes 8 bytes to each allocation in order to safely track the allocation size.
+// There is no strict requirement to deallocate; this allocator automatically deallocates
+// anything allocated through it.
+namespace qt3ds {
+namespace foundation {
+ struct SPoolingAllocator : public NVAllocatorCallback
+ {
+ typedef Mutex TMutexType;
+ typedef Mutex::ScopedLock TLockType;
+
+ NVAllocatorCallback &m_Allocator;
+ TMutexType m_Mutex;
+
+ struct SAllocationTag
+ {
+ QT3DSU32 m_Tag;
+ size_t m_Size;
+ SAllocationTag(size_t inSize = 0)
+ : m_Tag(0xAB5534CD)
+ , m_Size(inSize)
+ {
+ }
+ };
+
+ template <size_t TObjSize>
+ struct SPoolObj
+ {
+ QT3DSU32 m_Buffer[TObjSize / 4];
+ SPoolObj() {}
+ };
+#define ITERATE_POOLING_ALLOCATOR_POOL_SIZES \
+ HANDLE_POOLING_ALLOCATOR_POOL_SIZE(64) \
+ HANDLE_POOLING_ALLOCATOR_POOL_SIZE(128) \
+ HANDLE_POOLING_ALLOCATOR_POOL_SIZE(256) \
+ HANDLE_POOLING_ALLOCATOR_POOL_SIZE(512) \
+ HANDLE_POOLING_ALLOCATOR_POOL_SIZE(1024)
+
+#define HANDLE_POOLING_ALLOCATOR_POOL_SIZE(sz) \
+ Pool<SPoolObj<sz>, ForwardingAllocator, 4> m_Pool##sz;
+ ITERATE_POOLING_ALLOCATOR_POOL_SIZES
+#undef HANDLE_POOLING_ALLOCATOR_POOL_SIZE
+
+ SSAutoDeallocatorAllocator m_LargeAllocator;
+
+#define HANDLE_POOLING_ALLOCATOR_POOL_SIZE(sz) \
+ , m_Pool##sz(ForwardingAllocator(inAllocator, "PoolingAllocatorPool"))
+
+ SPoolingAllocator(NVAllocatorCallback &inAllocator)
+ : m_Allocator(inAllocator)
+ , m_Mutex(inAllocator) ITERATE_POOLING_ALLOCATOR_POOL_SIZES
+ , m_LargeAllocator(inAllocator)
+ {
+ }
+#undef HANDLE_POOLING_ALLOCATOR_POOL_SIZE
+
+ void *doAllocateFromPool(size_t size)
+ {
+ TLockType locker(m_Mutex);
+
+#define HANDLE_POOLING_ALLOCATOR_POOL_SIZE(sz) \
+ if (size <= sz) \
+ return m_Pool##sz.allocate(__FILE__, __LINE__);
+ ITERATE_POOLING_ALLOCATOR_POOL_SIZES
+#undef HANDLE_POOLING_ALLOCATOR_POOL_SIZE
+
+ return m_LargeAllocator.allocate(size, "largetype", __FILE__, __LINE__, 0);
+ }
+
+ void *doAllocate(size_t size)
+ {
+ size += sizeof(SAllocationTag);
+ SAllocationTag *tag = reinterpret_cast<SAllocationTag *>(doAllocateFromPool(size));
+ new (tag) SAllocationTag(size);
+ QT3DSU8 *data = reinterpret_cast<QT3DSU8 *>(tag);
+ return data + sizeof(SAllocationTag);
+ }
+
+ void *allocate(size_t size, const char * /*typeName*/, const char * /*filename*/,
+ int /*line*/, int /*flags*/ = 0) override
+ {
+ return doAllocate(size);
+ }
+
+ void *allocate(size_t size, const char * /*typeName*/, const char * /*filename*/,
+ int /*line*/, size_t /*alignment*/, size_t /*alignmentOffset*/) override
+ {
+ return doAllocate(size);
+ }
+
+ /**
+ \brief Frees memory previously allocated by allocate().
+
+ <b>Threading:</b> This function should be thread safe as it can be called in the context of
+ the user thread
+ and physics processing thread(s).
+
+ \param ptr Memory to free.
+ */
+ void deallocate(void *ptr) override
+ {
+ TLockType locker(m_Mutex);
+
+ // Deallocate on null is fine.
+ if (ptr == NULL)
+ return;
+
+ SAllocationTag tempTag;
+ QT3DSU8 *dataPtr = reinterpret_cast<QT3DSU8 *>(ptr);
+ SAllocationTag *theTag =
+ reinterpret_cast<SAllocationTag *>(dataPtr - sizeof(SAllocationTag));
+ if (theTag->m_Tag != tempTag.m_Tag) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ size_t size = theTag->m_Size;
+
+ // We add this offset at allocation time
+ ptr = dataPtr - sizeof(SAllocationTag);
+
+#define HANDLE_POOLING_ALLOCATOR_POOL_SIZE(sz) \
+ if (size <= sz) { \
+ m_Pool##sz.deallocate(ptr); \
+ return; \
+ }
+ ITERATE_POOLING_ALLOCATOR_POOL_SIZES
+#undef HANDLE_POOLING_ALLOCATOR_POOL_SIZE
+ m_LargeAllocator.deallocate(ptr);
+ }
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/PreAllocatedAllocator.h b/src/foundation/PreAllocatedAllocator.h
new file mode 100644
index 0000000..aea0357
--- /dev/null
+++ b/src/foundation/PreAllocatedAllocator.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_PRE_ALLOCATED_ALLOCATOR_H
+#define QT3DS_RENDER_PRE_ALLOCATED_ALLOCATOR_H
+#include "foundation/Qt3DSAllocatorCallback.h"
+#include "foundation/Qt3DSDataRef.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ // Ignores deallocate calls if they originate withing the pre-allocation block
+ struct SPreAllocatedAllocator : public NVAllocatorCallback
+ {
+ NVAllocatorCallback &m_Allocator;
+ NVDataRef<QT3DSU8> m_PreAllocatedBlock;
+ bool m_OwnsMemory; // then we attempt to deallocate on destruction
+
+ SPreAllocatedAllocator(NVAllocatorCallback &inAllocator)
+ : m_Allocator(inAllocator)
+ , m_OwnsMemory(false)
+ {
+ }
+
+ SPreAllocatedAllocator(NVAllocatorCallback &inAllocator, NVDataRef<QT3DSU8> inData,
+ bool inOwnsMemory)
+ : m_Allocator(inAllocator)
+ , m_PreAllocatedBlock(inData)
+ , m_OwnsMemory(inOwnsMemory)
+ {
+ }
+
+ virtual ~SPreAllocatedAllocator()
+ {
+ if (m_OwnsMemory)
+ m_Allocator.deallocate(m_PreAllocatedBlock.begin());
+ }
+
+ void *allocate(size_t size, const char *typeName, const char *filename, int line,
+ int flags = 0) override
+ {
+ return m_Allocator.allocate(size, typeName, filename, line, flags);
+ }
+
+ void *allocate(size_t size, const char *typeName, const char *filename, int line,
+ size_t alignment, size_t alignmentOffset) override
+ {
+ return m_Allocator.allocate(size, typeName, filename, line, alignment, alignmentOffset);
+ }
+
+ void deallocate(void *ptr) override
+ {
+ if (!ptr)
+ return;
+ if (ptr < m_PreAllocatedBlock.begin() || ptr >= m_PreAllocatedBlock.end())
+ m_Allocator.deallocate(ptr);
+ }
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/Qt3DS.h b/src/foundation/Qt3DS.h
new file mode 100644
index 0000000..041923c
--- /dev/null
+++ b/src/foundation/Qt3DS.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_H
+#define QT3DS_H
+#include "EABase/eabase.h"
+#include "foundation/Qt3DSPreprocessor.h"
+#include "foundation/Qt3DSSimpleTypes.h"
+#include "foundation/Qt3DSAssert.h"
+
+namespace eastl {
+}
+
+namespace qt3ds {
+class NVEmpty
+{
+};
+class QT3DSMat33;
+class QT3DSMat44;
+class QT3DSVec2;
+class QT3DSVec3;
+class QT3DSVec4;
+class NVTransform;
+
+#if !defined QT3DS_DONT_PRAGMA_WARNINGS && defined EA_COMPILER_MSVC
+#pragma warning(disable : 4512) // assignment operator not generated
+#endif
+
+#define QT3DS_SIGN_BITMASK 0x80000000
+}
+
+#endif
diff --git a/src/foundation/Qt3DSAllocator.h b/src/foundation/Qt3DSAllocator.h
new file mode 100644
index 0000000..cdbbe5f
--- /dev/null
+++ b/src/foundation/Qt3DSAllocator.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSALLOCATOR_H
+#define QT3DS_FOUNDATION_PSALLOCATOR_H
+
+#include "foundation/Qt3DSAllocatorCallback.h"
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAssert.h"
+
+#if (defined(QT3DS_WINDOWS) | defined(QT3DS_X360))
+#include <typeinfo.h>
+#endif
+#if (defined(QT3DS_APPLE))
+#include <typeinfo>
+#endif
+
+#include <new>
+
+// Allocation macros going through user allocator
+#define QT3DS_ALLOC(alloc, n, name) alloc.allocate(n, name, __FILE__, __LINE__)
+#define QT3DS_ALLOC_TEMP(alloc, n, name) QT3DS_ALLOC(n, name)
+#define QT3DS_FREE(alloc, x) alloc.deallocate(x)
+#define QT3DS_FREE_AND_RESET(x) \
+{ \
+ QT3DS_FREE(x); \
+ x = 0; \
+ }
+
+// The following macros support plain-old-types and classes derived from UserAllocated.
+#define QT3DS_NEW(alloc, T) new (QT3DS_ALLOC(alloc, sizeof(T), #T)) T
+#define QT3DS_NEW_TEMP(alloc, T) QT3DS_NEW(alloc, T)
+#define QT3DS_DELETE_POD(x) \
+{ \
+ QT3DS_FREE(x); \
+ x = 0; \
+ }
+
+namespace qt3ds {
+namespace foundation {
+template <typename TObjType>
+inline void NVDelete(NVAllocatorCallback &alloc, TObjType *item)
+{
+ if (item) {
+ item->~TObjType();
+ alloc.deallocate(item);
+ }
+}
+}
+}
+
+//! placement new macro to make it easy to spot bad use of 'new'
+#define QT3DS_PLACEMENT_NEW(p, T) new (p) T
+
+// Don't use inline for alloca !!!
+#ifdef QT3DS_WINDOWS
+#include <malloc.h>
+#define NVAlloca(x) _alloca(x)
+#elif defined(QT3DS_LINUX) || defined(QT3DS_ANDROID) || defined(QT3DS_QNX)
+#if defined(__INTEGRITY)
+#include <alloca.h>
+#else
+#include <malloc.h>
+#endif
+#define NVAlloca(x) alloca(x)
+#elif defined(QT3DS_PSP2)
+#include <alloca.h>
+#define NVAlloca(x) alloca(x)
+#elif defined(QT3DS_APPLE)
+#include <stdlib.h>
+#include <alloca.h>
+#define NVAlloca(x) alloca(x)
+#elif defined(QT3DS_PS3)
+#include <alloca.h>
+#define NVAlloca(x) alloca(x)
+#elif defined(QT3DS_X360)
+#include <malloc.h>
+#define NVAlloca(x) _alloca(x)
+#elif defined(QT3DS_WII)
+#include <alloca.h>
+#define NVAlloca(x) alloca(x)
+#endif
+
+namespace qt3ds {
+namespace foundation {
+/*
+ * Bootstrap allocator using malloc/free.
+ * Don't use unless your objects get allocated before foundation is initialized.
+ */
+class RawAllocator
+{
+public:
+ RawAllocator(const char * = 0) {}
+ void *allocate(size_t size, const char *, int)
+ {
+#if defined(QT3DS_APPLE)
+ // malloc returns valid pointer for size==0, no need to check
+ return malloc(size);
+#else
+ // malloc returns valid pointer for size==0, no need to check
+ return ::malloc(size);
+#endif
+ }
+ void deallocate(void *ptr)
+ {
+#if defined(QT3DS_APPLE)
+ free(ptr);
+#else
+ // free(0) is guaranteed to have no side effect, no need to check
+ ::free(ptr);
+#endif
+ }
+};
+
+struct ForwardingAllocator
+{
+ NVAllocatorCallback *mAllocator;
+ const char *mTypeName;
+ ForwardingAllocator(const char *typeName)
+ : mTypeName(typeName)
+ {
+ }
+ ForwardingAllocator(NVAllocatorCallback &alloc, const char *typeName)
+ : mAllocator(&alloc)
+ , mTypeName(typeName)
+ {
+ }
+ ForwardingAllocator(NVAllocatorCallback *alloc = NULL)
+ : mAllocator(alloc)
+ , mTypeName("__error__")
+ {
+ QT3DS_ASSERT(false);
+ }
+ ForwardingAllocator(const ForwardingAllocator &other)
+ : mAllocator(other.mAllocator)
+ , mTypeName(other.mTypeName)
+ {
+ }
+ ForwardingAllocator &operator=(const ForwardingAllocator &other)
+ {
+ mAllocator = other.mAllocator;
+ mTypeName = other.mTypeName;
+ return *this;
+ }
+ bool operator==(const ForwardingAllocator &other) const
+ {
+ return mAllocator == other.mAllocator;
+ }
+ NVAllocatorCallback &getAllocator() { return *mAllocator; }
+ // flags are unused
+ void *allocate(size_t size, const char *filename, int line, int flags = 0)
+ {
+ return getAllocator().allocate(size, mTypeName, filename, line, flags);
+ }
+ void *allocate(size_t size, const char *filename, int line, size_t alignment,
+ size_t alignmentOffset)
+ {
+ return getAllocator().allocate(size, mTypeName, filename, line, alignment,
+ alignmentOffset);
+ }
+ void deallocate(void *ptr, size_t) { getAllocator().deallocate(ptr); }
+ void deallocate(void *ptr) { getAllocator().deallocate(ptr); }
+};
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSAllocatorCallback.h b/src/foundation/Qt3DSAllocatorCallback.h
new file mode 100644
index 0000000..ebbf819
--- /dev/null
+++ b/src/foundation/Qt3DSAllocatorCallback.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_ALLOCATOR_CALLBACK_H
+#define QT3DS_FOUNDATION_QT3DS_ALLOCATOR_CALLBACK_H
+
+/** \addtogroup foundation
+@{
+*/
+
+#include "foundation/Qt3DS.h"
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+/**
+\brief Abstract base class for an application defined memory allocator that can be used by the NV
+library.
+
+\note The SDK state should not be modified from within any allocation/free function.
+
+<b>Threading:</b> All methods of this class should be thread safe as it can be called from the user
+thread
+or the physics processing thread(s).
+*/
+
+class NVAllocatorCallback
+{
+public:
+ /**
+ \brief destructor
+ */
+ virtual ~NVAllocatorCallback() {}
+
+ /**
+ \brief Allocates size bytes of memory, which must be 16-byte aligned.
+
+ This method should never return NULL. If you run out of memory, then
+ you should terminate the app or take some other appropriate action.
+
+ <b>Threading:</b> This function should be thread safe as it can be called in the context of the
+ user thread
+ and physics processing thread(s).
+
+ \param size Number of bytes to allocate.
+ \param typeName Name of the datatype that is being allocated
+ \param filename The source file which allocated the memory
+ \param line The source line which allocated the memory
+ \return The allocated block of memory.
+ */
+ virtual void *allocate(size_t size, const char *typeName, const char *filename, int line,
+ int flags = 0) = 0;
+ virtual void *allocate(size_t size, const char *typeName, const char *filename, int line,
+ size_t alignment, size_t alignmentOffset) = 0;
+
+ /**
+ \brief Frees memory previously allocated by allocate().
+
+ <b>Threading:</b> This function should be thread safe as it can be called in the context of the
+ user thread
+ and physics processing thread(s).
+
+ \param ptr Memory to free.
+ */
+ virtual void deallocate(void *ptr) = 0;
+};
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif
diff --git a/src/foundation/Qt3DSAssert.h b/src/foundation/Qt3DSAssert.h
new file mode 100644
index 0000000..a628159
--- /dev/null
+++ b/src/foundation/Qt3DSAssert.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_ASSERT_H
+#define QT3DS_ASSERT_H
+#include "foundation/Qt3DSPreprocessor.h"
+
+// Force the user to define the Qt3DSAssert function
+namespace qt3ds {
+void Qt3DSAssert(const char *exp, const char *file, int line, bool *ignore);
+}
+
+#ifdef __CUDACC__
+#define QT3DS_ASSERT(exp) ((void)0)
+#define QT3DS_ALWAYS_ASSERT_MESSAGE(exp) ((void)0)
+#else // __CUDACC__
+#ifndef NDEBUG
+#define QT3DS_ASSERT(exp) \
+ { \
+ static bool ignore = false; \
+ (void)((!!(exp)) || (qt3ds::Qt3DSAssert(#exp, __FILE__, __LINE__, &ignore), false)); \
+ }
+#else // NDEBUG
+#define QT3DS_ASSERT(exp) ((void)0)
+#endif // NDEBUG
+#define QT3DS_ALWAYS_ASSERT_MESSAGE(exp) \
+ { \
+ static bool ignore = false; \
+ (void)((qt3ds::Qt3DSAssert(exp, __FILE__, __LINE__, &ignore), false)); \
+ }
+#endif // __CUDACC__
+
+#define QT3DS_ALWAYS_ASSERT() QT3DS_ASSERT(0)
+
+#endif
diff --git a/src/foundation/Qt3DSAtomic.h b/src/foundation/Qt3DSAtomic.h
new file mode 100644
index 0000000..69c7d3b
--- /dev/null
+++ b/src/foundation/Qt3DSAtomic.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSATOMIC_H
+#define QT3DS_FOUNDATION_PSATOMIC_H
+
+#include "foundation/Qt3DS.h"
+
+namespace qt3ds {
+namespace foundation {
+ /* set *dest equal to val. Return the old value of *dest */
+ QT3DS_AUTOTEST_EXPORT QT3DSI32 atomicExchange(volatile QT3DSI32 *dest, QT3DSI32 val);
+
+ /* if *dest == comp, replace with exch. Return original value of *dest */
+ QT3DS_AUTOTEST_EXPORT QT3DSI32 atomicCompareExchange(volatile QT3DSI32 *dest, QT3DSI32 exch, QT3DSI32 comp);
+
+ /* if *dest == comp, replace with exch. Return original value of *dest */
+ QT3DS_AUTOTEST_EXPORT void *atomicCompareExchangePointer(volatile void **dest, void *exch,
+ void *comp);
+
+ /* increment the specified location. Return the incremented value */
+ QT3DS_AUTOTEST_EXPORT QT3DSI32 atomicIncrement(volatile QT3DSI32 *val);
+
+ /* decrement the specified location. Return the decremented value */
+ QT3DS_AUTOTEST_EXPORT QT3DSI32 atomicDecrement(volatile QT3DSI32 *val);
+
+ /* add delta to *val. Return the new value */
+ QT3DS_AUTOTEST_EXPORT QT3DSI32 atomicAdd(volatile QT3DSI32 *val, QT3DSI32 delta);
+
+ /* compute the maximum of dest and val. Return the new value */
+ QT3DS_AUTOTEST_EXPORT QT3DSI32 atomicMax(volatile QT3DSI32 *val, QT3DSI32 val2);
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSBasicTemplates.h b/src/foundation/Qt3DSBasicTemplates.h
new file mode 100644
index 0000000..f14c7b3
--- /dev/null
+++ b/src/foundation/Qt3DSBasicTemplates.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSBASICTEMPLATES_H
+#define QT3DS_FOUNDATION_PSBASICTEMPLATES_H
+
+#include "foundation/Qt3DS.h"
+
+namespace qt3ds {
+namespace foundation {
+ template <typename A>
+ struct Equal
+ {
+ bool operator()(const A &a, const A &b) const { return a == b; }
+ };
+
+ template <typename A>
+ struct Less
+ {
+ bool operator()(const A &a, const A &b) const { return a < b; }
+ };
+
+ template <typename A>
+ struct Greater
+ {
+ bool operator()(const A &a, const A &b) const { return a > b; }
+ };
+
+ template <class F, class S>
+ class Pair
+ {
+ public:
+ F first;
+ S second;
+ Pair()
+ : first(F())
+ , second(S())
+ {
+ }
+ Pair(const F &f, const S &s)
+ : first(f)
+ , second(s)
+ {
+ }
+ Pair(const Pair &p)
+ : first(p.first)
+ , second(p.second)
+ {
+ }
+ // CN - fix for /.../Qt3DSBasicTemplates.h(61) : warning C4512: 'nv::foundation::Pair<F,S>' :
+ // assignment operator could not be generated
+ Pair &operator=(const Pair &p)
+ {
+ first = p.first;
+ second = p.second;
+ return *this;
+ }
+ bool operator==(const Pair &p) const { return first == p.first && second == p.second; }
+ };
+
+ template <unsigned int A>
+ struct LogTwo
+ {
+ static const unsigned int value = LogTwo<(A >> 1)>::value + 1;
+ };
+ template <>
+ struct LogTwo<1>
+ {
+ static const unsigned int value = 0;
+ };
+
+ template <typename T>
+ struct UnConst
+ {
+ typedef T Type;
+ };
+ template <typename T>
+ struct UnConst<const T>
+ {
+ typedef T Type;
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSBounds3.h b/src/foundation/Qt3DSBounds3.h
new file mode 100644
index 0000000..fda4a6d
--- /dev/null
+++ b/src/foundation/Qt3DSBounds3.h
@@ -0,0 +1,443 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_BOUNDS3_H
+#define QT3DS_FOUNDATION_QT3DS_BOUNDS3_H
+
+/** \addtogroup foundation
+@{
+*/
+
+#include "foundation/Qt3DSTransform.h"
+#include "foundation/Qt3DSMat33.h"
+#include "foundation/Qt3DSMat44.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+typedef QT3DSVec3 TNVBounds2BoxPoints[8];
+
+/**
+\brief Class representing 3D range or axis aligned bounding box.
+
+Stored as minimum and maximum extent corners. Alternate representation
+would be center and dimensions.
+May be empty or nonempty. If not empty, minimum <= maximum has to hold.
+*/
+class NVBounds3
+{
+public:
+ /**
+ \brief Default constructor, not performing any initialization for performance reason.
+ \remark Use empty() function below to construct empty bounds.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3() {}
+
+ /**
+ \brief Construct from two bounding points
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3(const QT3DSVec3 &minimum, const QT3DSVec3 &maximum);
+
+ /**
+ \brief Return empty bounds.
+ */
+ static QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 empty();
+
+ /**
+ \brief returns the AABB containing v0 and v1.
+ \param v0 first point included in the AABB.
+ \param v1 second point included in the AABB.
+ */
+ static QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 boundsOfPoints(const QT3DSVec3 &v0,
+ const QT3DSVec3 &v1);
+
+ /**
+ \brief returns the AABB from center and extents vectors.
+ \param center Center vector
+ \param extent Extents vector
+ */
+ static QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 centerExtents(const QT3DSVec3 &center,
+ const QT3DSVec3 &extent);
+
+ /**
+ \brief Construct from center, extent, and (not necessarily orthogonal) basis
+ */
+ static QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 basisExtent(const QT3DSVec3 &center,
+ const QT3DSMat33 &basis,
+ const QT3DSVec3 &extent);
+
+ /**
+ \brief Construct from pose and extent
+ */
+ static QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 poseExtent(const NVTransform &pose,
+ const QT3DSVec3 &extent);
+
+ /**
+ \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB).
+ \param[in] matrix Transform to apply, can contain scaling as well
+ \param[in] bounds The bounds to transform.
+ */
+ static QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 transform(const QT3DSMat33 &matrix,
+ const NVBounds3 &bounds);
+
+ /**
+ \brief gets the transformed bounds of the passed AABB (resulting in a bigger AABB).
+ \param[in] transform Transform to apply, can contain scaling as well
+ \param[in] bounds The bounds to transform.
+ */
+ static QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 transform(const NVTransform &transform,
+ const NVBounds3 &bounds);
+
+ /**
+ \brief Sets empty to true
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void setEmpty();
+
+ /**
+ \brief Sets infinite bounds
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void setInfinite();
+
+ /**
+ \brief expands the volume to include v
+ \param v Point to expand to.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void include(const QT3DSVec3 &v);
+
+ /**
+ \brief expands the volume to include b.
+ \param b Bounds to perform union with.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void include(const NVBounds3 &b);
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isEmpty() const;
+
+ /**
+ \brief indicates whether the intersection of this and b is empty or not.
+ \param b Bounds to test for intersection.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool intersects(const NVBounds3 &b) const;
+
+ /**
+ \brief computes the 1D-intersection between two AABBs, on a given axis.
+ \param a the other AABB
+ \param axis the axis (0, 1, 2)
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool intersects1D(const NVBounds3 &a, QT3DSU32 axis) const;
+
+ /**
+ \brief indicates if these bounds contain v.
+ \param v Point to test against bounds.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool contains(const QT3DSVec3 &v) const;
+
+ /**
+ \brief checks a box is inside another box.
+ \param box the other AABB
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isInside(const NVBounds3 &box) const;
+
+ /**
+ \brief returns the center of this axis aligned box.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getCenter() const;
+
+ /**
+ \brief get component of the box's center along a given axis
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float getCenter(QT3DSU32 axis) const;
+
+ /**
+ \brief get component of the box's extents along a given axis
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float getExtents(QT3DSU32 axis) const;
+
+ /**
+ \brief returns the dimensions (width/height/depth) of this axis aligned box.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getDimensions() const;
+
+ /**
+ \brief returns the extents, which are half of the width/height/depth.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getExtents() const;
+
+ /**
+ \brief scales the AABB.
+ \param scale Factor to scale AABB by.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void scale(QT3DSF32 scale);
+
+ /**
+ fattens the AABB in all 3 dimensions by the given distance.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void fatten(NVReal distance);
+
+ /**
+ checks that the AABB values are not NaN
+ */
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isFinite() const;
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void expand(TNVBounds2BoxPoints &outPoints) const;
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void transform(const QT3DSMat44 &inMatrix);
+
+ QT3DSVec3 minimum, maximum;
+};
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3::NVBounds3(const QT3DSVec3 &minimum, const QT3DSVec3 &maximum)
+ : minimum(minimum)
+ , maximum(maximum)
+{
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 NVBounds3::empty()
+{
+ return NVBounds3(QT3DSVec3(QT3DS_MAX_REAL), QT3DSVec3(-QT3DS_MAX_REAL));
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::isFinite() const
+{
+ return minimum.isFinite() && maximum.isFinite();
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 NVBounds3::boundsOfPoints(const QT3DSVec3 &v0,
+ const QT3DSVec3 &v1)
+{
+ return NVBounds3(v0.minimum(v1), v0.maximum(v1));
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVBounds3 NVBounds3::centerExtents(const QT3DSVec3 &center,
+ const QT3DSVec3 &extent)
+{
+ return NVBounds3(center - extent, center + extent);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 NVBounds3::basisExtent(const QT3DSVec3 &center,
+ const QT3DSMat33 &basis,
+ const QT3DSVec3 &extent)
+{
+ // extended basis vectors
+ QT3DSVec3 c0 = basis.column0 * extent.x;
+ QT3DSVec3 c1 = basis.column1 * extent.y;
+ QT3DSVec3 c2 = basis.column2 * extent.z;
+
+ QT3DSVec3 w;
+ // find combination of base vectors that produces max. distance for each component = sum of
+ // abs()
+ w.x = NVAbs(c0.x) + NVAbs(c1.x) + NVAbs(c2.x);
+ w.y = NVAbs(c0.y) + NVAbs(c1.y) + NVAbs(c2.y);
+ w.z = NVAbs(c0.z) + NVAbs(c1.z) + NVAbs(c2.z);
+
+ return NVBounds3(center - w, center + w);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 NVBounds3::poseExtent(const NVTransform &pose,
+ const QT3DSVec3 &extent)
+{
+ return basisExtent(pose.p, QT3DSMat33(pose.q), extent);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::setEmpty()
+{
+ minimum = QT3DSVec3(QT3DS_MAX_REAL);
+ maximum = QT3DSVec3(-QT3DS_MAX_REAL);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::setInfinite()
+{
+ minimum = QT3DSVec3(-QT3DS_MAX_REAL);
+ maximum = QT3DSVec3(QT3DS_MAX_REAL);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::include(const QT3DSVec3 &v)
+{
+ QT3DS_ASSERT(isFinite());
+ minimum = minimum.minimum(v);
+ maximum = maximum.maximum(v);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::include(const NVBounds3 &b)
+{
+ QT3DS_ASSERT(isFinite());
+ minimum = minimum.minimum(b.minimum);
+ maximum = maximum.maximum(b.maximum);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::isEmpty() const
+{
+ QT3DS_ASSERT(isFinite());
+ // Consistency condition for (Min, Max) boxes: minimum < maximum
+ return minimum.x > maximum.x || minimum.y > maximum.y || minimum.z > maximum.z;
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::intersects(const NVBounds3 &b) const
+{
+ QT3DS_ASSERT(isFinite() && b.isFinite());
+ return !(b.minimum.x > maximum.x || minimum.x > b.maximum.x || b.minimum.y > maximum.y
+ || minimum.y > b.maximum.y || b.minimum.z > maximum.z || minimum.z > b.maximum.z);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::intersects1D(const NVBounds3 &a, QT3DSU32 axis) const
+{
+ QT3DS_ASSERT(isFinite() && a.isFinite());
+ return maximum[axis] >= a.minimum[axis] && a.maximum[axis] >= minimum[axis];
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::contains(const QT3DSVec3 &v) const
+{
+ QT3DS_ASSERT(isFinite());
+
+ return !(v.x < minimum.x || v.x > maximum.x || v.y < minimum.y || v.y > maximum.y
+ || v.z < minimum.z || v.z > maximum.z);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVBounds3::isInside(const NVBounds3 &box) const
+{
+ QT3DS_ASSERT(isFinite() && box.isFinite());
+ if (box.minimum.x > minimum.x)
+ return false;
+ if (box.minimum.y > minimum.y)
+ return false;
+ if (box.minimum.z > minimum.z)
+ return false;
+ if (box.maximum.x < maximum.x)
+ return false;
+ if (box.maximum.y < maximum.y)
+ return false;
+ if (box.maximum.z < maximum.z)
+ return false;
+ return true;
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 NVBounds3::getCenter() const
+{
+ QT3DS_ASSERT(isFinite());
+ return (minimum + maximum) * NVReal(0.5);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float NVBounds3::getCenter(QT3DSU32 axis) const
+{
+ QT3DS_ASSERT(isFinite());
+ return (minimum[axis] + maximum[axis]) * NVReal(0.5);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float NVBounds3::getExtents(QT3DSU32 axis) const
+{
+ QT3DS_ASSERT(isFinite());
+ return (maximum[axis] - minimum[axis]) * NVReal(0.5);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 NVBounds3::getDimensions() const
+{
+ QT3DS_ASSERT(isFinite());
+ return maximum - minimum;
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 NVBounds3::getExtents() const
+{
+ QT3DS_ASSERT(isFinite());
+ return getDimensions() * NVReal(0.5);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::scale(QT3DSF32 scale)
+{
+ QT3DS_ASSERT(isFinite());
+ *this = centerExtents(getCenter(), getExtents() * scale);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::fatten(NVReal distance)
+{
+ QT3DS_ASSERT(isFinite());
+ minimum.x -= distance;
+ minimum.y -= distance;
+ minimum.z -= distance;
+
+ maximum.x += distance;
+ maximum.y += distance;
+ maximum.z += distance;
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 NVBounds3::transform(const QT3DSMat33 &matrix,
+ const NVBounds3 &bounds)
+{
+ QT3DS_ASSERT(bounds.isFinite());
+ return bounds.isEmpty() ? bounds : NVBounds3::basisExtent(matrix * bounds.getCenter(), matrix,
+ bounds.getExtents());
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_INLINE NVBounds3 NVBounds3::transform(const NVTransform &transform,
+ const NVBounds3 &bounds)
+{
+ QT3DS_ASSERT(bounds.isFinite());
+ return bounds.isEmpty() ? bounds
+ : NVBounds3::basisExtent(transform.transform(bounds.getCenter()),
+ QT3DSMat33(transform.q), bounds.getExtents());
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::expand(TNVBounds2BoxPoints &outPoints) const
+{
+ if (isEmpty()) {
+ for (QT3DSU32 idx = 0; idx < 8; ++idx)
+ outPoints[idx] = QT3DSVec3(0, 0, 0);
+ } else {
+ // Min corner of box
+ outPoints[0] = QT3DSVec3(minimum[0], minimum[1], minimum[2]);
+ outPoints[1] = QT3DSVec3(maximum[0], minimum[1], minimum[2]);
+ outPoints[2] = QT3DSVec3(minimum[0], maximum[1], minimum[2]);
+ outPoints[3] = QT3DSVec3(minimum[0], minimum[1], maximum[2]);
+
+ // Max corner of box
+ outPoints[4] = QT3DSVec3(maximum[0], maximum[1], maximum[2]);
+ outPoints[5] = QT3DSVec3(minimum[0], maximum[1], maximum[2]);
+ outPoints[6] = QT3DSVec3(maximum[0], minimum[1], maximum[2]);
+ outPoints[7] = QT3DSVec3(maximum[0], maximum[1], minimum[2]);
+ }
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void NVBounds3::transform(const QT3DSMat44 &inMatrix)
+{
+ if (!isEmpty()) {
+ TNVBounds2BoxPoints thePoints;
+ expand(thePoints);
+ setEmpty();
+ for (QT3DSU32 idx = 0; idx < 8; ++idx)
+ include(inMatrix.transform(thePoints[idx]));
+ }
+}
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_BOUNDS3_H
diff --git a/src/foundation/Qt3DSBroadcastingAllocator.h b/src/foundation/Qt3DSBroadcastingAllocator.h
new file mode 100644
index 0000000..dc6ae7b
--- /dev/null
+++ b/src/foundation/Qt3DSBroadcastingAllocator.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_BROADCASTING_ALLOCATOR_H
+#define QT3DS_FOUNDATION_QT3DS_BROADCASTING_ALLOCATOR_H
+
+#include "foundation/Qt3DSAllocatorCallback.h"
+
+/** \addtogroup foundation
+ @{
+*/
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+/**
+\brief Abstract listener class that listens to allocation and deallocation events from the
+ foundation memory system.
+
+<b>Threading:</b> All methods of this class should be thread safe as it can be called from the user
+thread
+or the physics processing thread(s).
+*/
+class NVAllocationListener
+{
+protected:
+ virtual ~NVAllocationListener() {}
+
+public:
+ /**
+ \brief callback when memory is allocated.
+ \param size Size of the allocation in bytes.
+ \param typeName Type this data is being allocated for.
+ \param filename File the allocation came from.
+ \param line the allocation came from.
+ \param allocatedMemory memory that will be returned from the allocation.
+ */
+ virtual void onAllocation(size_t size, const char *typeName, const char *filename, int line,
+ void *allocatedMemory) = 0;
+
+ /**
+ /brief callback when memory is deallocated.
+ /param allocatedMemory memory just before allocation.
+ */
+ virtual void onDeallocation(void *allocatedMemory) = 0;
+};
+
+/**
+\brief Abstract base class for an application defined memory allocator that allows an external
+listener
+to audit the memory allocations.
+
+<b>Threading:</b> Register/deregister are *not* threadsafe!!!
+You need to be sure multiple threads are using this allocator when you are adding
+new listeners.
+*/
+class NVBroadcastingAllocator : public NVAllocatorCallback
+{
+protected:
+ virtual ~NVBroadcastingAllocator() {}
+
+public:
+ /**
+ \brief Register an allocation listener. This object will be notified whenever an
+ allocation happens.
+
+ <b>Threading:</b>Not threadsafe if you are allocating and deallocating in another
+ thread using this allocator.
+ */
+ virtual void registerAllocationListener(NVAllocationListener &inListener) = 0;
+ /**
+ \brief Deregister an allocation listener. This object will no longer receive
+ notifications upon allocation.
+
+ <b>Threading:</b>Not threadsafe if you are allocating and deallocating in another
+ thread using this allocator.
+ */
+ virtual void deregisterAllocationListener(NVAllocationListener &inListener) = 0;
+};
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_BROADCASTING_ALLOCATOR_H
diff --git a/src/foundation/Qt3DSContainers.h b/src/foundation/Qt3DSContainers.h
new file mode 100644
index 0000000..de86d85
--- /dev/null
+++ b/src/foundation/Qt3DSContainers.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_CONTAINERS_H
+#define QT3DS_CONTAINERS_H
+#include "foundation/Qt3DS.h"
+#include "EASTL/vector.h"
+#include "EASTL/hash_map.h"
+#include "EASTL/hash_set.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSDataRef.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ template <typename T>
+ class nvvector : public eastl::vector<T, ForwardingAllocator>
+ {
+ typedef eastl::vector<T, ForwardingAllocator> base_type;
+
+ public:
+ using base_type::data;
+ using base_type::size;
+
+ nvvector(NVAllocatorCallback &inAllocator, const char *inTypeName)
+ : eastl::vector<T, ForwardingAllocator>(ForwardingAllocator(inAllocator, inTypeName))
+ {
+ }
+ nvvector(const nvvector<T> &inOther)
+ : eastl::vector<T, ForwardingAllocator>(inOther)
+ {
+ }
+ nvvector<T> &operator=(const nvvector<T> &inOther)
+ {
+ eastl::vector<T, ForwardingAllocator>::operator=(inOther);
+ return *this;
+ }
+ operator NVConstDataRef<T>() const { return NVConstDataRef<T>(data(), size()); }
+ operator NVDataRef<T>() { return NVDataRef<T>(data(), size()); }
+ };
+
+ template <typename TKey, typename TValue, typename THash = eastl::hash<TKey>,
+ typename TPredicate = eastl::equal_to<TKey>>
+ class nvhash_map : public eastl::hash_map<TKey, TValue, THash, TPredicate, ForwardingAllocator>
+ {
+ typedef eastl::hash_map<TKey, TValue, THash, TPredicate, ForwardingAllocator> base_type;
+
+ public:
+ using base_type::find;
+ using base_type::end;
+
+ nvhash_map(NVAllocatorCallback &inAllocator, const char *inTypeName)
+ : eastl::hash_map<TKey, TValue, THash, TPredicate, ForwardingAllocator>(
+ ForwardingAllocator(inAllocator, inTypeName))
+ {
+ }
+ nvhash_map(const nvhash_map<TKey, TValue, THash, TPredicate> &inOther)
+ : eastl::hash_map<TKey, TValue, THash, TPredicate, ForwardingAllocator>(inOther)
+ {
+ }
+ nvhash_map<TKey, TValue, THash, TPredicate> &
+ operator=(const nvhash_map<TKey, TValue, THash, TPredicate> &inOther)
+ {
+ eastl::hash_map<TKey, TValue, THash, TPredicate, ForwardingAllocator>::operator=(
+ inOther);
+ return *this;
+ }
+ bool contains(const TKey &inKey) const { return find(inKey) != end(); }
+ };
+
+ template <typename TKey, typename THash = eastl::hash<TKey>,
+ typename TPredicate = eastl::equal_to<TKey>>
+ class nvhash_set : public eastl::hash_set<TKey, THash, TPredicate, ForwardingAllocator>
+ {
+ typedef eastl::hash_set<TKey, THash, TPredicate, ForwardingAllocator> base_type;
+
+ public:
+ using base_type::find;
+ using base_type::end;
+
+ nvhash_set(NVAllocatorCallback &inAllocator, const char *inTypeName)
+ : eastl::hash_set<TKey, THash, TPredicate, ForwardingAllocator>(
+ ForwardingAllocator(inAllocator, inTypeName))
+ {
+ }
+ nvhash_set(const nvhash_map<TKey, THash, TPredicate> &inOther)
+ : eastl::hash_set<TKey, THash, TPredicate, ForwardingAllocator>(inOther)
+ {
+ }
+ nvhash_set<TKey, THash, TPredicate> &
+ operator=(const nvhash_set<TKey, THash, TPredicate> &inOther)
+ {
+ eastl::hash_set<TKey, THash, TPredicate, ForwardingAllocator>::operator=(inOther);
+ return *this;
+ }
+ bool contains(const TKey &inKey) const { return find(inKey) != end(); }
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/Qt3DSDataRef.h b/src/foundation/Qt3DSDataRef.h
new file mode 100644
index 0000000..ad860ce
--- /dev/null
+++ b/src/foundation/Qt3DSDataRef.h
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_DATA_REF_H
+#define QT3DS_FOUNDATION_DATA_REF_H
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAssert.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ template <typename TDataType>
+ struct NVConstDataRef
+ {
+ const TDataType *mData;
+ QT3DSU32 mSize;
+
+ NVConstDataRef(const TDataType *inData, QT3DSU32 inSize)
+ : mData(inData)
+ , mSize(inSize)
+ {
+ }
+ NVConstDataRef()
+ : mData(0)
+ , mSize(0)
+ {
+ }
+
+ QT3DSU32 size() const { return mSize; }
+
+ const TDataType *begin() const { return mData; }
+ const TDataType *end() const { return mData + mSize; }
+
+ const TDataType &operator[](QT3DSU32 index) const
+ {
+ QT3DS_ASSERT(index < mSize);
+ return mData[index];
+ }
+ };
+
+ template <typename TDataType>
+ inline NVConstDataRef<TDataType> toConstDataRef(const TDataType &type)
+ {
+ return NVConstDataRef<TDataType>(&type, 1);
+ }
+
+ template <typename TDataType>
+ inline NVConstDataRef<QT3DSU8> toU8ConstDataRef(const TDataType &type)
+ {
+ return NVConstDataRef<QT3DSU8>(reinterpret_cast<const QT3DSU8 *>(&type), sizeof(TDataType));
+ }
+
+ template <typename TDataType>
+ inline NVConstDataRef<TDataType> toConstDataRef(const TDataType *type, QT3DSU32 count)
+ {
+ return NVConstDataRef<TDataType>(type, count);
+ }
+
+ template <typename TDataType>
+ inline NVConstDataRef<QT3DSU8> toU8ConstDataRef(const TDataType *type, QT3DSU32 count)
+ {
+ return NVConstDataRef<QT3DSU8>(reinterpret_cast<const QT3DSU8 *>(type),
+ sizeof(TDataType) * count);
+ }
+
+ template <typename TDataType>
+ struct NVDataRef
+ {
+ TDataType *mData;
+ QT3DSU32 mSize;
+
+ NVDataRef(TDataType *inData, QT3DSU32 inSize)
+ : mData(inData)
+ , mSize(inSize)
+ {
+ }
+ NVDataRef()
+ : mData(0)
+ , mSize(0)
+ {
+ }
+ QT3DSU32 size() const { return mSize; }
+
+ TDataType *begin() { return mData; }
+ TDataType *end() { return mData + mSize; }
+
+ TDataType *begin() const { return mData; }
+ TDataType *end() const { return mData + mSize; }
+
+ TDataType &operator[](QT3DSU32 index)
+ {
+ QT3DS_ASSERT(index < mSize);
+ return mData[index];
+ }
+
+ const TDataType &operator[](QT3DSU32 index) const
+ {
+ QT3DS_ASSERT(index < mSize);
+ return mData[index];
+ }
+
+ operator NVConstDataRef<TDataType>() const
+ {
+ return NVConstDataRef<TDataType>(mData, mSize);
+ }
+ };
+
+ template <typename TDataType>
+ inline NVDataRef<TDataType> toDataRef(TDataType &type)
+ {
+ return NVDataRef<TDataType>(&type, 1);
+ }
+
+ template <typename TDataType>
+ inline NVDataRef<QT3DSU8> toU8DataRef(TDataType &type)
+ {
+ return NVDataRef<QT3DSU8>(reinterpret_cast<QT3DSU8 *>(&type), sizeof(TDataType));
+ }
+
+ template <typename TDataType>
+ inline NVDataRef<TDataType> toDataRef(TDataType *type, QT3DSU32 count)
+ {
+ return NVDataRef<TDataType>(type, count);
+ }
+
+ template <typename TDataType>
+ inline NVDataRef<QT3DSU8> toU8DataRef(TDataType *type, QT3DSU32 count)
+ {
+ return NVDataRef<QT3DSU8>(reinterpret_cast<QT3DSU8 *>(type), sizeof(TDataType) * count);
+ }
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/foundation/Qt3DSDiscriminatedUnion.h b/src/foundation/Qt3DSDiscriminatedUnion.h
new file mode 100644
index 0000000..1957eb2
--- /dev/null
+++ b/src/foundation/Qt3DSDiscriminatedUnion.h
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_DISCRIMINATED_UNION_H
+#define QT3DS_FOUNDATION_DISCRIMINATED_UNION_H
+#include "Qt3DSAssert.h"
+#include "foundation/Qt3DSSimpleTypes.h"
+#include "foundation/Qt3DSIntrinsics.h"
+#include "foundation/Qt3DSUnionCast.h"
+
+#ifdef WIN32
+#pragma warning(disable : 4100)
+#endif
+
+namespace qt3ds {
+namespace foundation {
+
+ template <typename TUnionTraits, int TBufferSize>
+ class DiscriminatedUnion
+ {
+ public:
+ typedef DiscriminatedUnion<TUnionTraits, TBufferSize> TThisType;
+ typedef TUnionTraits TTraits;
+ typedef typename TTraits::TIdType TIdType;
+
+ protected:
+ char m_Data[TBufferSize];
+ // Id type must include a no-data type.
+ TIdType m_DataType;
+
+ public:
+ DiscriminatedUnion() { TTraits::defaultConstruct(m_Data, m_DataType); }
+
+ DiscriminatedUnion(const TThisType &inOther)
+ : m_DataType(inOther.m_DataType)
+ {
+ TTraits::copyConstruct(m_Data, inOther.m_Data, m_DataType);
+ }
+
+ template <typename TDataType>
+ DiscriminatedUnion(const TDataType &inType)
+ {
+ TTraits::copyConstruct(m_Data, m_DataType, inType);
+ }
+
+ ~DiscriminatedUnion() { TTraits::destruct(m_Data, m_DataType); }
+
+ TThisType &operator=(const TThisType &inType)
+ {
+ if (this != &inType) {
+ TTraits::destruct(m_Data, m_DataType);
+ m_DataType = inType.m_DataType;
+ TTraits::copyConstruct(m_Data, inType.m_Data, inType.m_DataType);
+ }
+ return *this;
+ }
+
+ typename TTraits::TIdType getType() const { return m_DataType; }
+
+ template <typename TDataType>
+ const TDataType *getDataPtr() const
+ {
+ return TTraits::template getDataPtr<TDataType>(m_Data, m_DataType);
+ }
+
+ template <typename TDataType>
+ TDataType *getDataPtr()
+ {
+ return TTraits::template getDataPtr<TDataType>(m_Data, m_DataType);
+ }
+
+ template <typename TDataType>
+ TDataType getData() const
+ {
+ const TDataType *dataPtr = getDataPtr<TDataType>();
+ if (dataPtr)
+ return *dataPtr;
+ QT3DS_ASSERT(false);
+ return TDataType();
+ }
+
+ bool operator==(const TThisType &inOther) const
+ {
+ return m_DataType == inOther.m_DataType
+ && TTraits::areEqual(m_Data, inOther.m_Data, m_DataType);
+ }
+
+ bool operator!=(const TThisType &inOther) const
+ {
+ return m_DataType != inOther.m_DataType
+ || TTraits::areEqual(m_Data, inOther.m_Data, m_DataType) == false;
+ }
+
+ template <typename TRetType, typename TVisitorType>
+ TRetType visit(TVisitorType inVisitor)
+ {
+ return TTraits::template visit<TRetType>(m_Data, m_DataType, inVisitor);
+ }
+
+ template <typename TRetType, typename TVisitorType>
+ TRetType visit(TVisitorType inVisitor) const
+ {
+ return TTraits::template visit<TRetType>(m_Data, m_DataType, inVisitor);
+ }
+ };
+
+ // Helper system to enable quicker and correct construction of union traits types
+
+ struct CopyConstructVisitor
+ {
+ const char *m_Src;
+ CopyConstructVisitor(const char *inSrc)
+ : m_Src(inSrc)
+ {
+ }
+
+ template <typename TDataType>
+ void operator()(TDataType &inDst)
+ {
+ new (&inDst) TDataType(*NVUnionCast<const TDataType *>(m_Src));
+ }
+ void operator()() { QT3DS_ASSERT(false); }
+ };
+
+ template <typename TDataType>
+ struct DestructTraits
+ {
+ void destruct(TDataType &inType) { inType.~TDataType(); }
+ };
+
+ // Until compilers improve a bit, you need this for POD types else you get
+ // unused parameter warnings.
+ template <>
+ struct DestructTraits<QT3DSU8>
+ {
+ void destruct(QT3DSU8 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSI8>
+ {
+ void destruct(QT3DSI8 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSU16>
+ {
+ void destruct(QT3DSU16 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSI16>
+ {
+ void destruct(QT3DSI16 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSU32>
+ {
+ void destruct(QT3DSU32 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSI32>
+ {
+ void destruct(QT3DSI32 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSU64>
+ {
+ void destruct(QT3DSU64 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSI64>
+ {
+ void destruct(QT3DSI64 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSF32>
+ {
+ void destruct(QT3DSF32 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSF64>
+ {
+ void destruct(QT3DSF64 &) {}
+ };
+ template <>
+ struct DestructTraits<bool>
+ {
+ void destruct(bool &) {}
+ };
+ template <>
+ struct DestructTraits<void *>
+ {
+ void destruct(void *&) {}
+ };
+#ifdef __INTEGRITY
+ template <>
+ struct DestructTraits<QT3DSVec2>
+ {
+ void destruct(QT3DSVec2 &) {}
+ };
+ template <>
+ struct DestructTraits<QT3DSVec3>
+ {
+ void destruct(QT3DSVec3 &) {}
+ };
+#endif
+
+ struct DestructVisitor
+ {
+ template <typename TDataType>
+ void operator()(TDataType &inDst)
+ {
+ DestructTraits<TDataType>().destruct(inDst);
+ }
+ void operator()() { QT3DS_ASSERT(false); }
+ };
+
+ template <typename TDataType>
+ struct EqualVisitorTraits
+ {
+ bool operator()(const TDataType &lhs, const TDataType &rhs) { return lhs == rhs; }
+ };
+
+ struct EqualVisitor
+ {
+ const char *m_Rhs;
+ EqualVisitor(const char *rhs)
+ : m_Rhs(rhs)
+ {
+ }
+ template <typename TDataType>
+ bool operator()(const TDataType &lhs)
+ {
+ const TDataType &rhs(*NVUnionCast<const TDataType *>(m_Rhs));
+ return EqualVisitorTraits<TDataType>()(lhs, rhs);
+ }
+ bool operator()()
+ {
+ QT3DS_ASSERT(false);
+ return true;
+ }
+ };
+
+ template <typename TBase, QT3DSU32 TBufferSize>
+ struct DiscriminatedUnionGenericBase : public TBase
+ {
+ typedef typename TBase::TIdType TIdType;
+
+ static void zeroBuf(char *outDst) { qt3ds::intrinsics::memZero(outDst, TBufferSize); }
+
+ static void defaultConstruct(char *outDst, TIdType &outType)
+ {
+ zeroBuf(outDst);
+ outType = TBase::getNoDataId();
+ }
+
+ template <typename TDataType>
+ static void copyConstruct(char *outDst, TIdType &outType, const TDataType &inSrc)
+ {
+ zeroBuf(outDst);
+ StaticAssert<sizeof(TDataType) <= TBufferSize>::valid_expression();
+ outType = TBase::template getType<TDataType>();
+ new (outDst) TDataType(inSrc);
+ }
+
+ static void copyConstruct(char *inDst, const char *inSrc, TIdType inType)
+ {
+ if (inType == TBase::getNoDataId())
+ zeroBuf(inDst);
+ else
+ TBase::template visit<void>(inDst, inType, CopyConstructVisitor(inSrc));
+ }
+
+ static void destruct(char *inDst, TIdType inType)
+ {
+ if (inType != TBase::getNoDataId())
+ TBase::template visit<void>(inDst, inType, DestructVisitor());
+ zeroBuf(inDst);
+ }
+
+ template <typename TDataType>
+ static const TDataType *getDataPtr(const char *inData, const TIdType &inType)
+ {
+ if (TBase::template getType<TDataType>() == inType)
+ return NVUnionCast<const TDataType *>(inData);
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+
+ template <typename TDataType>
+ static TDataType *getDataPtr(char *inData, const TIdType &inType)
+ {
+ if (TBase::template getType<TDataType>() == inType)
+ return NVUnionCast<TDataType *>(inData);
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+
+ static bool areEqual(const char *inLhs, const char *inRhs, TIdType inType)
+ {
+ if (inType != TBase::getNoDataId())
+ return TBase::template visit<bool>(inLhs, inType, EqualVisitor(inRhs));
+ else
+ return true;
+ }
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/Qt3DSFPU.h b/src/foundation/Qt3DSFPU.h
new file mode 100644
index 0000000..e4a47f0
--- /dev/null
+++ b/src/foundation/Qt3DSFPU.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSFPU_H
+#define QT3DS_FOUNDATION_PSFPU_H
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSUnionCast.h"
+
+// unsigned integer representation of a floating-point value.
+#ifdef QT3DS_PS3
+QT3DS_FORCE_INLINE unsigned int QT3DS_IR(const float x)
+{
+ return qt3ds::NVUnionCast<unsigned int, float>(x);
+}
+#else
+#define QT3DS_IR(x) ((QT3DSU32 &)(x))
+#endif
+
+// signed integer representation of a floating-point value.
+#ifdef QT3DS_PS3
+QT3DS_FORCE_INLINE int QT3DS_SIR(const float x)
+{
+ return qt3ds::NVUnionCast<int, float>(x);
+}
+#else
+#define QT3DS_SIR(x) ((QT3DSI32 &)(x))
+#endif
+
+// Floating-point representation of a integer value.
+#ifdef QT3DS_PS3
+QT3DS_FORCE_INLINE float QT3DS_FR(const unsigned int x)
+{
+ return qt3ds::NVUnionCast<float, unsigned int>(x);
+}
+#else
+#define QT3DS_FR(x) ((QT3DSF32 &)(x))
+#endif
+
+#ifdef QT3DS_PS3
+QT3DS_FORCE_INLINE float *QT3DS_FPTR(unsigned int *x)
+{
+ return qt3ds::NVUnionCast<float *, unsigned int *>(x);
+}
+
+QT3DS_FORCE_INLINE float *QT3DS_FPTR(int *x)
+{
+ return qt3ds::NVUnionCast<float *, int *>(x);
+}
+#else
+#define QT3DS_FPTR(x) ((QT3DSF32 *)(x))
+#endif
+
+#define QT3DS_SIGN_BITMASK 0x80000000
+
+namespace qt3ds {
+namespace foundation {
+class QT3DS_FOUNDATION_API FPUGuard
+{
+public:
+ FPUGuard(); // set fpu control word for PhysX
+ ~FPUGuard(); // restore fpu control word
+private:
+ QT3DSU32 mControlWords[8];
+};
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSFastIPC.h b/src/foundation/Qt3DSFastIPC.h
new file mode 100644
index 0000000..800c3df
--- /dev/null
+++ b/src/foundation/Qt3DSFastIPC.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FAST_IPC_H
+#define QT3DS_FAST_IPC_H
+
+#include "foundation/Qt3DSSimpleTypes.h"
+#include "foundation/Qt3DSIPC.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ NVIPC *createFastIPC(
+ NVIPC::ErrorCode &errorCode, // error code return if creation fails
+ NVIPC::ConnectionType connectionType =
+ NVIPC::CT_CLIENT_OR_SERVER, // how to establish the connection
+ const char *mappingObject = "Global\\FastIPC", // Name of communications channel
+ QT3DSU32 serverRingBufferSize = 1024 * 4, // buffer size for outgoing server messages.
+ QT3DSU32 clientRingBufferSize = 1024 * 4, // buffer size for incoming client messages.
+ bool allowLongMessages = true,
+ bool bufferSends = false,
+ QT3DSU32 maxBufferSendSize = 1024 * 8); // True if we want to buffer sends, if true, then
+ // pumpSendBuffers should be called by the send thread.
+
+ void releaseFastIPC(NVIPC *f);
+
+}; // end of namespace
+}; // end of namespace
+
+#endif
diff --git a/src/foundation/Qt3DSFlags.h b/src/foundation/Qt3DSFlags.h
new file mode 100644
index 0000000..765f386
--- /dev/null
+++ b/src/foundation/Qt3DSFlags.h
@@ -0,0 +1,360 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_FLAGS_H
+#define QT3DS_FOUNDATION_QT3DS_FLAGS_H
+
+/** \addtogroup foundation
+ @{
+*/
+
+#include "foundation/Qt3DS.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+/**
+\brief Container for bitfield flag variables associated with a specific enum type.
+
+This allows for type safe manipulation for bitfields.
+
+<h3>Example</h3>
+ // enum that defines each bit...
+ struct MyEnum
+ {
+ enum Enum
+ {
+ eMAN = 1,
+ eBEAR = 2,
+ ePIG = 4,
+ };
+ };
+
+ // implements some convenient global operators.
+ QT3DS_FLAGS_OPERATORS(MyEnum::Enum, QT3DSU8);
+
+ NVFlags<MyEnum::Enum, QT3DSU8> myFlags;
+ myFlags |= MyEnum::eMAN;
+ myFlags |= MyEnum::eBEAR | MyEnum::ePIG;
+ if(myFlags & MyEnum::eBEAR)
+ {
+ doSomething();
+ }
+*/
+template <typename enumtype, typename storagetype = QT3DSU32>
+class NVFlags
+{
+public:
+ QT3DS_INLINE explicit NVFlags(const NVEmpty &) {}
+ QT3DS_INLINE NVFlags(void);
+ QT3DS_INLINE NVFlags(enumtype e);
+ QT3DS_INLINE NVFlags(const NVFlags<enumtype, storagetype> &f);
+ QT3DS_INLINE explicit NVFlags(storagetype b);
+
+ QT3DS_INLINE bool operator==(enumtype e) const;
+ QT3DS_INLINE bool operator==(const NVFlags<enumtype, storagetype> &f) const;
+ QT3DS_INLINE bool operator==(bool b) const;
+ QT3DS_INLINE bool operator!=(enumtype e) const;
+ QT3DS_INLINE bool operator!=(const NVFlags<enumtype, storagetype> &f) const;
+
+ QT3DS_INLINE NVFlags<enumtype, storagetype> &operator=(enumtype e);
+
+ QT3DS_INLINE NVFlags<enumtype, storagetype> &operator|=(enumtype e);
+ QT3DS_INLINE NVFlags<enumtype, storagetype> &operator|=(const NVFlags<enumtype, storagetype> &f);
+ QT3DS_INLINE NVFlags<enumtype, storagetype> operator|(enumtype e) const;
+ QT3DS_INLINE NVFlags<enumtype, storagetype>
+ operator|(const NVFlags<enumtype, storagetype> &f) const;
+
+ QT3DS_INLINE NVFlags<enumtype, storagetype> &operator&=(enumtype e);
+ QT3DS_INLINE NVFlags<enumtype, storagetype> &operator&=(const NVFlags<enumtype, storagetype> &f);
+ QT3DS_INLINE NVFlags<enumtype, storagetype> operator&(enumtype e) const;
+ QT3DS_INLINE NVFlags<enumtype, storagetype>
+ operator&(const NVFlags<enumtype, storagetype> &f) const;
+
+ QT3DS_INLINE NVFlags<enumtype, storagetype> &operator^=(enumtype e);
+ QT3DS_INLINE NVFlags<enumtype, storagetype> &operator^=(const NVFlags<enumtype, storagetype> &f);
+ QT3DS_INLINE NVFlags<enumtype, storagetype> operator^(enumtype e) const;
+ QT3DS_INLINE NVFlags<enumtype, storagetype>
+ operator^(const NVFlags<enumtype, storagetype> &f) const;
+
+ QT3DS_INLINE NVFlags<enumtype, storagetype> operator~(void)const;
+
+ QT3DS_INLINE operator bool(void) const;
+ QT3DS_INLINE operator QT3DSU8(void) const;
+ QT3DS_INLINE operator QT3DSU16(void) const;
+ QT3DS_INLINE operator QT3DSU32(void) const;
+
+ QT3DS_INLINE void clear(enumtype e);
+
+ QT3DS_INLINE void clearOrSet(bool value, enumtype enumVal);
+
+public:
+ friend QT3DS_INLINE NVFlags<enumtype, storagetype> operator&(enumtype a,
+ NVFlags<enumtype, storagetype> &b)
+ {
+ NVFlags<enumtype, storagetype> out;
+ out.mBits = a & b.mBits;
+ return out;
+ }
+
+private:
+ storagetype mBits;
+};
+
+#define QT3DS_FLAGS_OPERATORS(enumtype, storagetype) \
+ QT3DS_INLINE NVFlags<enumtype, storagetype> operator|(enumtype a, enumtype b) \
+{ \
+ NVFlags<enumtype, storagetype> r(a); \
+ r |= b; \
+ return r; \
+} \
+ QT3DS_INLINE NVFlags<enumtype, storagetype> operator&(enumtype a, enumtype b) \
+{ \
+ NVFlags<enumtype, storagetype> r(a); \
+ r &= b; \
+ return r; \
+} \
+ QT3DS_INLINE NVFlags<enumtype, storagetype> operator~(enumtype a) \
+{ \
+ return ~NVFlags<enumtype, storagetype>(a); \
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype>::NVFlags(void)
+{
+ mBits = 0;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype>::NVFlags(enumtype e)
+{
+ mBits = static_cast<storagetype>(e);
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype>::NVFlags(const NVFlags<enumtype, storagetype> &f)
+{
+ mBits = f.mBits;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype>::NVFlags(storagetype b)
+{
+ mBits = b;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE bool NVFlags<enumtype, storagetype>::operator==(enumtype e) const
+{
+ return mBits == static_cast<storagetype>(e);
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE bool NVFlags<enumtype, storagetype>::
+operator==(const NVFlags<enumtype, storagetype> &f) const
+{
+ return mBits == f.mBits;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE bool NVFlags<enumtype, storagetype>::operator==(bool b) const
+{
+ return ((bool)*this) == b;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE bool NVFlags<enumtype, storagetype>::operator!=(enumtype e) const
+{
+ return mBits != static_cast<storagetype>(e);
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE bool NVFlags<enumtype, storagetype>::
+operator!=(const NVFlags<enumtype, storagetype> &f) const
+{
+ return mBits != f.mBits;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> &NVFlags<enumtype, storagetype>::operator=(enumtype e)
+{
+ mBits = static_cast<storagetype>(e);
+ return *this;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> &NVFlags<enumtype, storagetype>::operator|=(enumtype e)
+{
+ mBits |= static_cast<storagetype>(e);
+ return *this;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> &NVFlags<enumtype, storagetype>::
+operator|=(const NVFlags<enumtype, storagetype> &f)
+{
+ mBits |= f.mBits;
+ return *this;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> NVFlags<enumtype, storagetype>::operator|(enumtype e) const
+{
+ NVFlags<enumtype, storagetype> out(*this);
+ out |= e;
+ return out;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> NVFlags<enumtype, storagetype>::
+operator|(const NVFlags<enumtype, storagetype> &f) const
+{
+ NVFlags<enumtype, storagetype> out(*this);
+ out |= f;
+ return out;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> &NVFlags<enumtype, storagetype>::operator&=(enumtype e)
+{
+ mBits &= static_cast<storagetype>(e);
+ return *this;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> &NVFlags<enumtype, storagetype>::
+operator&=(const NVFlags<enumtype, storagetype> &f)
+{
+ mBits &= f.mBits;
+ return *this;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> NVFlags<enumtype, storagetype>::operator&(enumtype e) const
+{
+ NVFlags<enumtype, storagetype> out = *this;
+ out.mBits &= static_cast<storagetype>(e);
+ return out;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> NVFlags<enumtype, storagetype>::
+operator&(const NVFlags<enumtype, storagetype> &f) const
+{
+ NVFlags<enumtype, storagetype> out = *this;
+ out.mBits &= f.mBits;
+ return out;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> &NVFlags<enumtype, storagetype>::operator^=(enumtype e)
+{
+ mBits ^= static_cast<storagetype>(e);
+ return *this;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> &NVFlags<enumtype, storagetype>::
+operator^=(const NVFlags<enumtype, storagetype> &f)
+{
+ mBits ^= f.mBits;
+ return *this;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> NVFlags<enumtype, storagetype>::operator^(enumtype e) const
+{
+ NVFlags<enumtype, storagetype> out = *this;
+ out.mBits ^= static_cast<storagetype>(e);
+ return out;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> NVFlags<enumtype, storagetype>::
+operator^(const NVFlags<enumtype, storagetype> &f) const
+{
+ NVFlags<enumtype, storagetype> out = *this;
+ out.mBits ^= f.mBits;
+ return out;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype> NVFlags<enumtype, storagetype>::operator~(void)const
+{
+ NVFlags<enumtype, storagetype> out;
+ out.mBits = ~mBits;
+ return out;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype>::operator bool(void) const
+{
+ return mBits ? true : false;
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype>::operator QT3DSU8(void) const
+{
+ return static_cast<QT3DSU8>(mBits);
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype>::operator QT3DSU16(void) const
+{
+ return static_cast<QT3DSU16>(mBits);
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE NVFlags<enumtype, storagetype>::operator QT3DSU32(void) const
+{
+ return static_cast<QT3DSU32>(mBits);
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE void NVFlags<enumtype, storagetype>::clear(enumtype e)
+{
+ mBits &= ~static_cast<storagetype>(e);
+}
+
+template <typename enumtype, typename storagetype>
+QT3DS_INLINE void NVFlags<enumtype, storagetype>::clearOrSet(bool value, enumtype enumVal)
+{
+ if (value)
+ this->operator|=(enumVal);
+ else
+ clear(enumVal);
+}
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // #ifndef QT3DS_FOUNDATION_QT3DS_FLAGS_H
diff --git a/src/foundation/Qt3DSFoundation.cpp b/src/foundation/Qt3DSFoundation.cpp
new file mode 100644
index 0000000..8687cd6
--- /dev/null
+++ b/src/foundation/Qt3DSFoundation.cpp
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DSFoundation.h"
+
+#include "foundation/Qt3DSQuat.h"
+#include "foundation/Qt3DSThread.h"
+#include "foundation/Qt3DSUtilities.h"
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSLogging.h"
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "EASTL/hash_map.h"
+
+#include <stdio.h>
+#ifdef _WIN32
+#pragma warning(disable : 4996) // intentionally suppressing this warning message
+#endif
+namespace qt3ds {
+namespace foundation {
+ using namespace intrinsics;
+ union TempAllocatorChunk;
+
+ class NVAllocatorListenerManager;
+
+ class QT3DS_FOUNDATION_API Foundation : public NVFoundation
+ {
+
+ Foundation(NVAllocatorCallback &alloc);
+ ~Foundation();
+
+ public:
+ void addRef() override;
+ void release() override;
+
+ // factory
+ static Foundation *createInstance(QT3DSU32 version, NVAllocatorCallback &alloc);
+
+ NVBroadcastingAllocator &getAllocator() const override { return mAllocator; }
+ NVAllocatorCallback &getAllocatorCallback() const override;
+ NVAllocatorCallback &getCheckedAllocator() { return mAllocator; }
+
+ private:
+ class AlignCheckAllocator : public NVBroadcastingAllocator
+ {
+ static const QT3DSU32 MaxListenerCount = 5;
+
+ public:
+ AlignCheckAllocator(NVAllocatorCallback &originalAllocator)
+ : mAllocator(originalAllocator)
+ , mListenerCount(0)
+ {
+ }
+
+ void deallocate(void *ptr) override
+ {
+ // So here, for performance reasons I don't grab the mutex.
+ // The listener array is very rarely changing; for most situations
+ // only at startup. So it is unlikely that using the mutex
+ // will help a lot but it could have serious perf implications.
+ QT3DSU32 theCount = mListenerCount;
+ for (QT3DSU32 idx = 0; idx < theCount; ++idx)
+ mListeners[idx]->onDeallocation(ptr);
+ mAllocator.deallocate(ptr);
+ }
+ void *allocate(size_t size, const char *typeName, const char *filename, int line,
+ int flags) override;
+ void *allocate(size_t size, const char *typeName, const char *filename, int line,
+ size_t alignment, size_t alignmentOffset) override;
+ NVAllocatorCallback &getBaseAllocator() const { return mAllocator; }
+ void registerAllocationListener(NVAllocationListener &inListener) override
+ {
+ QT3DS_ASSERT(mListenerCount < MaxListenerCount);
+ if (mListenerCount < MaxListenerCount) {
+ mListeners[mListenerCount] = &inListener;
+ ++mListenerCount;
+ }
+ }
+ void deregisterAllocationListener(NVAllocationListener &inListener) override
+ {
+ for (QT3DSU32 idx = 0; idx < mListenerCount; ++idx) {
+ if (mListeners[idx] == &inListener) {
+ mListeners[idx] = mListeners[mListenerCount - 1];
+ --mListenerCount;
+ break;
+ }
+ }
+ }
+
+ private:
+ NVAllocatorCallback &mAllocator;
+ // I am not sure about using a NVArray here.
+ // For now, this is fine.
+ NVAllocationListener *mListeners[MaxListenerCount];
+ volatile QT3DSU32 mListenerCount;
+ };
+
+ mutable AlignCheckAllocator mAllocator;
+ QT3DSU32 mRefCount;
+ Mutex mRefCountMutex;
+ };
+
+ Foundation::Foundation(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ , mRefCount(0)
+ , mRefCountMutex(alloc)
+
+ {
+ }
+
+ Foundation::~Foundation() {}
+
+ NVAllocatorCallback &Foundation::getAllocatorCallback() const
+ {
+ return mAllocator.getBaseAllocator();
+ }
+
+ Foundation *Foundation::createInstance(QT3DSU32 version, NVAllocatorCallback &alloc)
+ {
+ if (version != QT3DS_FOUNDATION_VERSION) {
+ qCCritical(INVALID_PARAMETER, "Wrong version: foundation version is %d, tried to create %d",
+ QT3DS_FOUNDATION_VERSION, version);
+ return 0;
+ }
+ Foundation *mInstance = NULL;
+
+ if (!mInstance) {
+ // if we don't assign this here, the Foundation object can't create member
+ // subobjects which require the allocator
+
+ mInstance = reinterpret_cast<Foundation *>(
+ alloc.allocate(sizeof(Foundation), "Foundation", __FILE__, __LINE__));
+
+ if (mInstance) {
+ QT3DS_PLACEMENT_NEW(mInstance, Foundation)(alloc);
+
+ QT3DS_ASSERT(mInstance->mRefCount == 0);
+
+ return mInstance;
+ } else {
+ qCCritical(INTERNAL_ERROR, "Memory allocation for foundation object failed.");
+ }
+ } else {
+ qCCritical(
+ INVALID_OPERATION,
+ "Foundation object exists already. Only one instance per process can be created.");
+ }
+
+ return 0;
+ }
+
+ void Foundation::addRef()
+ {
+ mRefCountMutex.lock();
+ ++mRefCount;
+ mRefCountMutex.unlock();
+ }
+
+ void Foundation::release()
+ {
+ mRefCountMutex.lock();
+ if (mRefCount)
+ --mRefCount;
+ QT3DSU32 refCount = mRefCount;
+ mRefCountMutex.unlock();
+ if (!refCount) {
+ NVAllocatorCallback &alloc = mAllocator.getBaseAllocator();
+ this->~Foundation();
+ alloc.deallocate(this);
+ }
+ }
+
+ void *Foundation::AlignCheckAllocator::allocate(size_t size, const char *typeName,
+ const char *filename, int line, int)
+ {
+ void *addr = mAllocator.allocate(size, typeName, filename, line);
+
+ if (!addr)
+ qFatal("User allocator returned NULL.");
+
+ if (!(reinterpret_cast<size_t>(addr) & 15)) {
+ // Same comment as before in the allocation system.
+ // We don't lock the listener array mutex because of an assumption
+ // where the listener array is rarely changing.
+ QT3DSU32 theCount = mListenerCount;
+ for (QT3DSU32 idx = 0; idx < theCount; ++idx)
+ mListeners[idx]->onAllocation(size, typeName, filename, line, addr);
+ return addr;
+ }
+
+ qFatal("Allocations for qt3ds::foundation must be 16-byte aligned.");
+ return 0;
+ }
+
+ void *Foundation::AlignCheckAllocator::allocate(size_t size, const char *typeName,
+ const char *filename, int line,
+ size_t /*alignment*/,
+ size_t /*alignmentOffset*/)
+ {
+ return allocate(size, typeName, filename, line, 0);
+ }
+
+} // namespace foundation
+} // namespace qt3ds
+
+qt3ds::NVFoundation *NVCreateFoundation(qt3ds::QT3DSU32 version, qt3ds::NVAllocatorCallback &allocator)
+{
+ return qt3ds::foundation::Foundation::createInstance(version, allocator);
+}
diff --git a/src/foundation/Qt3DSFoundation.h b/src/foundation/Qt3DSFoundation.h
new file mode 100644
index 0000000..19065d2
--- /dev/null
+++ b/src/foundation/Qt3DSFoundation.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_FOUNDATION_H
+#define QT3DS_FOUNDATION_QT3DS_FOUNDATION_H
+
+/** \addtogroup foundation
+ @{
+*/
+
+#include <stdarg.h>
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSVersionNumber.h"
+#include "foundation/Qt3DSLogging.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+class NVAllocatorCallback;
+class NVProfilingZone;
+class NVBroadcastingAllocator;
+
+class NVFoundationBase
+{
+public:
+ /**
+ retrieves the current allocator.
+ */
+ virtual NVBroadcastingAllocator &getAllocator() const = 0;
+};
+
+namespace foundation {
+template <typename TObjType>
+inline void NVDelete(NVFoundationBase &alloc, TObjType *item)
+{
+ NVDelete(alloc.getAllocator(), item);
+}
+}
+
+/**
+\brief Foundation SDK singleton class.
+
+You need to have an instance of this class to instance the higher level SDKs.
+*/
+class QT3DS_FOUNDATION_API NVFoundation : public NVFoundationBase
+{
+public:
+ virtual void addRef() = 0;
+ /**
+ \brief Destroys the instance it is called on.
+
+ The operation will fail, if there are still modules referencing the foundation object. Release
+ all dependent modules prior
+ to calling this method.
+
+ @see NVCreateFoundation()
+ */
+ virtual void release() = 0;
+
+ /**
+ Retrieves the allocator this object was created with.
+ */
+ virtual NVAllocatorCallback &getAllocatorCallback() const = 0;
+
+protected:
+ virtual ~NVFoundation() {}
+};
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/**
+\brief Creates an instance of the foundation class
+
+\param version Version number we are expecting (should be QT3DS_FOUNDATION_VERSION)
+\param allocator User supplied interface for allocating memory(see #NVAllocatorCallback)
+\return Foundation instance on success, NULL if operation failed
+
+@see NVFoundation
+*/
+
+#ifdef QT3DS_FOUNDATION_NO_EXPORTS
+QT3DS_AUTOTEST_EXPORT
+#else
+QT3DS_FOUNDATION_API
+#endif
+qt3ds::NVFoundation *QT3DS_CALL_CONV NVCreateFoundation(
+ qt3ds::QT3DSU32 version, qt3ds::NVAllocatorCallback &allocator);
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_FOUNDATION_H
diff --git a/src/foundation/Qt3DSIPC.h b/src/foundation/Qt3DSIPC.h
new file mode 100644
index 0000000..9bcea1a
--- /dev/null
+++ b/src/foundation/Qt3DSIPC.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_IPC_H
+#define QT3DS_IPC_H
+
+#include "foundation/Qt3DS.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ class NVIPC
+ {
+ public:
+ enum ConnectionType {
+ CT_CLIENT, // start up as a client, will succeed even if the server has not yet been
+ // found.
+ CT_CLIENT_REQUIRE_SERVER, // start up as a client, but only if the server already
+ // exists.
+ CT_SERVER, // will start up as a server, will fail if an existing server is already
+ // open.
+ CT_CLIENT_OR_SERVER, // connect as either a client or server, don't care who is created
+ // first.
+ CT_LAST
+ };
+
+ enum ErrorCode {
+ EC_OK, // no error.
+ EC_FAIL, // generic failure.
+ EC_SERVER_ALREADY_EXISTS, // couldn't create a server, because the server already
+ // exists.
+ EC_CLIENT_ALREADY_EXISTS, // couldn't create a client, because an existing client is
+ // already registered.
+ EC_CLIENT_SERVER_ALREADY_EXISTS, // both the client and server channels are already used
+ EC_SERVER_NOT_FOUND, // client opened with a required server, which was not found.
+ EC_BUFFER_MISSMATCH, // the reserved buffers for client/server do not match up.
+ EC_MAPFILE_CREATE, // failed to create the shared memory map file.
+ EC_MAPFILE_VIEW, // failed to map the memory view of he
+ // communications errors.
+ EC_SEND_DATA_EXCEEDS_MAX_BUFFER, // trying to send more data than can even fit in the
+ // sednd buffe.
+ EC_SEND_DATA_TOO_LARGE, // the data we tried to send exceeds the available room int the
+ // output ring buffer.
+ EC_SEND_BUFFER_FULL, // the send buffer is completely full.
+ EC_SEND_FROM_WRONG_THREAD, // Tried to do a send from a different thread
+ EC_RECEIVE_FROM_WRONG_THREAD, // Tried to do a recieve from a different thread
+ EC_NO_RECEIVE_PENDING, // tried to acknowledge a receive but none was pending.
+ };
+
+ virtual bool pumpPendingSends(void) = 0; // give up a time slice to pending sends; returns
+ // true if there are still pends sending.
+ virtual ErrorCode sendData(const void *data, QT3DSU32 data_len, bool bufferIfFull) = 0;
+ virtual const void *receiveData(QT3DSU32 &data_len) = 0;
+ virtual ErrorCode receiveAcknowledge(void) = 0; // acknowledge that we have processed the
+ // incoming message and can advance the read
+ // buffer.
+
+ virtual bool isServer(void) const = 0; // returns true if we are opened as a server.
+
+ virtual bool haveConnection(void) const = 0;
+
+ virtual bool canSend(QT3DSU32 len) = 0; // return true if we can send a message of this size.
+
+ virtual void release(void) = 0;
+
+ protected:
+ virtual ~NVIPC(void){}
+ };
+}; // end of namespace
+}; // end of namespace
+
+#endif
diff --git a/src/foundation/Qt3DSIndexableLinkedList.h b/src/foundation/Qt3DSIndexableLinkedList.h
new file mode 100644
index 0000000..ff36b42
--- /dev/null
+++ b/src/foundation/Qt3DSIndexableLinkedList.h
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_INDEXABLE_LINKED_LIST_H
+#define QT3DS_FOUNDATION_INDEXABLE_LINKED_LIST_H
+#include "foundation/Qt3DSPool.h"
+
+namespace qt3ds {
+namespace foundation {
+ // Set of helper functions for manipulation of lists that are
+ // somewhat indexable but also amenable to using a pool structure.
+ template <typename TNodeType, typename TObjType, QT3DSU32 TObjCount>
+ struct IndexableLinkedList
+ {
+ typedef TNodeType SNode;
+
+ typedef Pool<SNode, ForwardingAllocator> TPoolType;
+
+ static TObjType &Create(SNode *&inInitialNode, QT3DSU32 &ioCurrentCount, TPoolType &ioPool)
+ {
+ QT3DSU32 idx = ioCurrentCount;
+ ++ioCurrentCount;
+ QT3DSU32 numGroups = (ioCurrentCount + TObjCount - 1) / TObjCount;
+ QT3DSU32 localIdx = idx % TObjCount;
+
+ SNode *theCurrentNode = inInitialNode;
+ for (QT3DSU32 idx = 0, end = numGroups; idx < end; ++idx) {
+ if (idx == 0) {
+ if (theCurrentNode == NULL)
+ inInitialNode = ioPool.construct(__FILE__, __LINE__);
+
+ theCurrentNode = inInitialNode;
+ } else {
+ if (theCurrentNode->m_NextNode == NULL)
+ theCurrentNode->m_NextNode = ioPool.construct(__FILE__, __LINE__);
+ theCurrentNode = theCurrentNode->m_NextNode;
+ }
+ }
+ return theCurrentNode->m_Data[localIdx];
+ }
+
+ static void CreateAll(SNode *&inInitialNode, QT3DSU32 inCount, TPoolType &ioPool)
+ {
+ QT3DSU32 numGroups = (inCount + TObjCount - 1) / TObjCount;
+ SNode *lastNode = NULL;
+ for (QT3DSU32 idx = 0, end = numGroups; idx < end; ++idx) {
+ SNode *nextNode = ioPool.construct(__FILE__, __LINE__);
+ if (idx == 0)
+ inInitialNode = nextNode;
+ else
+ lastNode->m_NextNode = nextNode;
+ lastNode = nextNode;
+ }
+ }
+
+ static void DeleteList(SNode *&inInitialNode, TPoolType &ioPool)
+ {
+ SNode *theNode = inInitialNode;
+ inInitialNode = NULL;
+ while (theNode) {
+ SNode *theNext = theNode->m_NextNode;
+ theNode->m_NextNode = NULL;
+ ioPool.deallocate(theNode);
+ theNode = theNext;
+ }
+ }
+
+ // Performs no checking, so you need to have already allocated what you need.
+ static const TObjType &GetObjAtIdx(const SNode *inInitialNode, QT3DSU32 inIdx)
+ {
+ QT3DSU32 groupIdx = inIdx / TObjCount;
+ QT3DSU32 localIdx = inIdx % TObjCount;
+ for (QT3DSU32 idx = 0; idx < groupIdx; ++idx)
+ inInitialNode = inInitialNode->m_NextNode;
+ return inInitialNode->m_Data[inIdx];
+ }
+
+ static TObjType &GetObjAtIdx(SNode *inInitialNode, QT3DSU32 inIdx)
+ {
+ QT3DSU32 groupIdx = inIdx / TObjCount;
+ QT3DSU32 localIdx = inIdx % TObjCount;
+ for (QT3DSU32 idx = 0; idx < groupIdx; ++idx)
+ inInitialNode = inInitialNode->m_NextNode;
+ return inInitialNode->m_Data[localIdx];
+ }
+
+ struct SIteratorType
+ {
+ QT3DSU32 m_Idx;
+ QT3DSU32 m_Count;
+ SNode *m_Node;
+
+ SIteratorType()
+ : m_Idx(0)
+ , m_Count(0)
+ , m_Node(NULL)
+ {
+ }
+ SIteratorType(const SIteratorType &iter)
+ : m_Idx(iter.m_Idx)
+ , m_Count(iter.m_Count)
+ , m_Node(iter.m_Node)
+ {
+ }
+ SIteratorType(SNode *inNode, QT3DSU32 inCount, QT3DSU32 inIdx)
+ : m_Idx(inIdx)
+ , m_Count(inCount)
+ , m_Node(inNode)
+ {
+ }
+
+ bool operator==(const SIteratorType &iter) const { return m_Idx == iter.m_Idx; }
+
+ bool operator!=(const SIteratorType &iter) const { return m_Idx != iter.m_Idx; }
+
+ TObjType &operator*()
+ {
+ QT3DSU32 localIdx = m_Idx % TObjCount;
+ return m_Node->m_Data[localIdx];
+ }
+
+ SIteratorType &operator++()
+ {
+ ++m_Idx;
+ if ((m_Idx % TObjCount) == 0)
+ m_Node = m_Node->m_NextNode;
+
+ return *this;
+ }
+ };
+
+ struct SConstIteratorType
+ {
+ QT3DSU32 m_Idx;
+ QT3DSU32 m_Count;
+ const SNode *m_Node;
+
+ SConstIteratorType()
+ : m_Idx(0)
+ , m_Count(0)
+ , m_Node(NULL)
+ {
+ }
+ SConstIteratorType(const SIteratorType &iter)
+ : m_Idx(iter.m_Idx)
+ , m_Count(iter.m_Count)
+ , m_Node(iter.m_Node)
+ {
+ }
+ SConstIteratorType(const SConstIteratorType &iter)
+ : m_Idx(iter.m_Idx)
+ , m_Count(iter.m_Count)
+ , m_Node(iter.m_Node)
+ {
+ }
+ SConstIteratorType(const SNode *inNode, QT3DSU32 inCount, QT3DSU32 inIdx)
+ : m_Idx(inIdx)
+ , m_Count(inCount)
+ , m_Node(inNode)
+ {
+ }
+
+ bool operator==(const SConstIteratorType &iter) const { return m_Idx == iter.m_Idx; }
+
+ bool operator!=(const SConstIteratorType &iter) const { return m_Idx != iter.m_Idx; }
+
+ const TObjType &operator*()
+ {
+ QT3DSU32 localIdx = m_Idx % TObjCount;
+ return m_Node->m_Data[localIdx];
+ }
+
+ SConstIteratorType &operator++()
+ {
+ ++m_Idx;
+ if ((m_Idx % TObjCount) == 0)
+ m_Node = m_Node->m_NextNode;
+
+ return *this;
+ }
+ };
+
+ typedef SIteratorType iterator;
+ typedef SConstIteratorType const_iterator;
+
+ static iterator begin(SNode *inInitialNode, QT3DSU32 inItemCount)
+ {
+ return SIteratorType(inInitialNode, inItemCount, 0);
+ }
+
+ static iterator end(SNode * /*inInitialNode*/, QT3DSU32 inItemCount)
+ {
+ return SIteratorType(NULL, inItemCount, inItemCount);
+ }
+
+ static const_iterator begin(const SNode *inInitialNode, QT3DSU32 inItemCount)
+ {
+ return SConstIteratorType(inInitialNode, inItemCount, 0);
+ }
+
+ static const_iterator end(const SNode * /*inInitialNode*/, QT3DSU32 inItemCount)
+ {
+ return SConstIteratorType(NULL, inItemCount, inItemCount);
+ }
+
+ struct SNodeIteratorType
+ {
+ SNode *m_Node;
+
+ SNodeIteratorType()
+ : m_Node(NULL)
+ {
+ }
+ SNodeIteratorType(const SNodeIteratorType &iter)
+ : m_Node(iter.m_Node)
+ {
+ }
+ SNodeIteratorType(SNode *inNode)
+ : m_Node(inNode)
+ {
+ }
+
+ bool operator==(const SNodeIteratorType &iter) const { return m_Node == iter.m_Node; }
+
+ bool operator!=(const SNodeIteratorType &iter) const { return m_Node != iter.m_Node; }
+
+ TNodeType &operator*() { return *m_Node; }
+
+ SNodeIteratorType &operator++()
+ {
+ if (m_Node)
+ m_Node = m_Node->m_NextNode;
+
+ return *this;
+ }
+ };
+
+ typedef SNodeIteratorType node_iterator;
+ static node_iterator node_begin(SNode *inFirstNode) { return node_iterator(inFirstNode); }
+ static node_iterator node_end(SNode * /*inFirstNode*/) { return node_iterator(NULL); }
+
+ // Iterates through the number of nodes required for a given count of objects
+ struct SCountIteratorType
+ {
+ QT3DSU32 m_Idx;
+ QT3DSU32 m_Count;
+
+ SCountIteratorType()
+ : m_Idx(0)
+ , m_Count(0)
+ {
+ }
+ SCountIteratorType(const SCountIteratorType &iter)
+ : m_Idx(iter.m_Idx)
+ , m_Count(iter.m_Count)
+ {
+ }
+ SCountIteratorType(QT3DSU32 idx, QT3DSU32 count)
+ : m_Idx(idx)
+ , m_Count(count)
+ {
+ }
+
+ bool operator==(const SCountIteratorType &iter) const { return m_Idx == iter.m_Idx; }
+
+ bool operator!=(const SCountIteratorType &iter) const { return m_Idx != iter.m_Idx; }
+
+ SCountIteratorType &operator++()
+ {
+ m_Idx = NVMin(m_Idx + TObjCount, m_Count);
+ return *this;
+ }
+ };
+
+ typedef SCountIteratorType count_iterator;
+ static count_iterator count_begin(QT3DSU32 count) { return SCountIteratorType(0, count); }
+ static count_iterator count_end(QT3DSU32 count) { return SCountIteratorType(count, count); }
+ };
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/foundation/Qt3DSIntrinsics.h b/src/foundation/Qt3DSIntrinsics.h
new file mode 100644
index 0000000..1d6ac7a
--- /dev/null
+++ b/src/foundation/Qt3DSIntrinsics.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_INTRINSICS_H
+#define QT3DS_FOUNDATION_QT3DS_INTRINSICS_H
+
+#include "foundation/Qt3DSPreprocessor.h"
+
+#if defined QT3DS_WINDOWS || defined QT3DS_WIN8ARM
+#include "windows/Qt3DSWindowsIntrinsics.h"
+#elif defined QT3DS_X360
+#include "xbox360/NVXbox360Intrinsics.h"
+#elif (defined QT3DS_LINUX || defined QT3DS_ANDROID || defined QT3DS_APPLE || defined QT3DS_QNX)
+#include "linux/Qt3DSLinuxIntrinsics.h"
+#elif defined QT3DS_PS3
+#include "ps3/NVPS3Intrinsics.h"
+#elif defined QT3DS_PSP2
+#include "psp2/NVPSP2Intrinsics.h"
+#else
+#error "Platform not supported!"
+#endif
+
+#endif // QT3DS_FOUNDATION_QT3DS_INTRINSICS_H
diff --git a/src/foundation/Qt3DSInvasiveLinkedList.h b/src/foundation/Qt3DSInvasiveLinkedList.h
new file mode 100644
index 0000000..da90e12
--- /dev/null
+++ b/src/foundation/Qt3DSInvasiveLinkedList.h
@@ -0,0 +1,361 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_INVASIVE_LINKED_LIST_H
+#define QT3DS_FOUNDATION_INVASIVE_LINKED_LIST_H
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+#include "foundation/Qt3DSContainers.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ // Base linked list without an included head or tail member.
+ template <typename TObjType, typename TObjHeadOp, typename TObjTailOp>
+ struct SInvasiveLinkListBase
+ {
+ TObjType *tail(TObjType *inObj)
+ {
+ if (inObj)
+ return TObjTailOp().get(inObj);
+ return NULL;
+ }
+
+ TObjType *head(TObjType *inObj)
+ {
+ if (inObj)
+ return TObjHeadOp().get(inObj);
+ return NULL;
+ }
+
+ const TObjType *tail(const TObjType *inObj)
+ {
+ if (inObj)
+ return TObjTailOp().get(inObj);
+ return NULL;
+ }
+
+ const TObjType *head(const TObjType *inObj)
+ {
+ if (inObj)
+ return TObjHeadOp().get(inObj);
+ return NULL;
+ }
+
+ void remove(TObjType &inObj)
+ {
+ TObjHeadOp theHeadOp;
+ TObjTailOp theTailOp;
+ TObjType *theHead = theHeadOp.get(inObj);
+ TObjType *theTail = theTailOp.get(inObj);
+ if (theHead)
+ theTailOp.set(*theHead, theTail);
+ if (theTail)
+ theHeadOp.set(*theTail, theHead);
+ theHeadOp.set(inObj, NULL);
+ theTailOp.set(inObj, NULL);
+ }
+
+ void insert_after(TObjType &inPosition, TObjType &inObj)
+ {
+ TObjTailOp theTailOp;
+ TObjType *theHead = &inPosition;
+ TObjType *theTail = theTailOp.get(inPosition);
+ insert(theHead, theTail, inObj);
+ }
+
+ void insert_before(TObjType &inPosition, TObjType &inObj)
+ {
+ TObjHeadOp theHeadOp;
+ TObjType *theHead = theHeadOp.get(inPosition);
+ TObjType *theTail = &inPosition;
+ insert(theHead, theTail, inObj);
+ }
+
+ void insert(TObjType *inHead, TObjType *inTail, TObjType &inObj)
+ {
+ TObjHeadOp theHeadOp;
+ TObjTailOp theTailOp;
+ if (inHead)
+ theTailOp.set(*inHead, &inObj);
+ if (inTail)
+ theHeadOp.set(*inTail, &inObj);
+ theHeadOp.set(inObj, inHead);
+ theTailOp.set(inObj, inTail);
+ }
+ };
+
+ template <typename TObjType, typename TObjTailOp>
+ struct SLinkedListIterator
+ {
+ typedef SLinkedListIterator<TObjType, TObjTailOp> TMyType;
+ TObjType *m_Obj;
+ SLinkedListIterator(TObjType *inObj = NULL)
+ : m_Obj(inObj)
+ {
+ }
+
+ bool operator!=(const TMyType &inIter) const { return m_Obj != inIter.m_Obj; }
+ bool operator==(const TMyType &inIter) const { return m_Obj == inIter.m_Obj; }
+
+ TMyType &operator++()
+ {
+ if (m_Obj)
+ m_Obj = TObjTailOp().get(*m_Obj);
+ return *this;
+ }
+
+ TMyType &operator++(int)
+ {
+ TMyType retval(*this);
+ ++(*this);
+ return retval;
+ }
+
+ TObjType &operator*() { return *m_Obj; }
+ TObjType *operator->() { return m_Obj; }
+ };
+
+ // Used for singly linked list where
+ // items have either no head or tail ptr.
+ template <typename TObjType>
+ struct SNullOp
+ {
+ void set(TObjType &, TObjType *) {}
+ TObjType *get(const TObjType &) { return NULL; }
+ };
+
+ template <typename TObjType, typename TObjTailOp>
+ struct InvasiveSingleLinkedList
+ : public SInvasiveLinkListBase<TObjType, SNullOp<TObjType>, TObjTailOp>
+ {
+ typedef InvasiveSingleLinkedList<TObjType, TObjTailOp> TMyType;
+ typedef SInvasiveLinkListBase<TObjType, SNullOp<TObjType>, TObjTailOp> TBaseType;
+ typedef SLinkedListIterator<TObjType, TObjTailOp> iterator;
+ typedef iterator const_iterator;
+ TObjType *m_Head;
+ InvasiveSingleLinkedList()
+ : m_Head(NULL)
+ {
+ }
+ InvasiveSingleLinkedList(const TMyType &inOther)
+ : m_Head(inOther.m_Head)
+ {
+ }
+ TMyType &operator=(const TMyType &inOther)
+ {
+ m_Head = inOther.m_Head;
+ return *this;
+ }
+
+ TObjType &front() const { return *m_Head; }
+
+ void push_front(TObjType &inObj)
+ {
+ if (m_Head != NULL)
+ TBaseType::insert_before(*m_Head, inObj);
+ m_Head = &inObj;
+ }
+
+ void push_back(TObjType &inObj)
+ {
+ if (m_Head == NULL)
+ m_Head = &inObj;
+ else {
+ TObjType *lastObj = NULL;
+ for (iterator iter = begin(), endIter = end(); iter != endIter; ++iter)
+ lastObj = &(*iter);
+
+ QT3DS_ASSERT(lastObj);
+ if (lastObj)
+ TObjTailOp().set(*lastObj, &inObj);
+ }
+ }
+
+ void remove(TObjType &inObj)
+ {
+ if (m_Head == &inObj)
+ m_Head = TObjTailOp().get(inObj);
+ TBaseType::remove(inObj);
+ }
+
+ bool empty() const { return m_Head == NULL; }
+
+ iterator begin() { return iterator(m_Head); }
+ iterator end() { return iterator(NULL); }
+
+ const_iterator begin() const { return iterator(m_Head); }
+ const_iterator end() const { return iterator(NULL); }
+ };
+
+ template <typename TObjType, typename TObjHeadOp, typename TObjTailOp>
+ struct InvasiveLinkedList : public SInvasiveLinkListBase<TObjType, TObjHeadOp, TObjTailOp>
+ {
+ typedef InvasiveLinkedList<TObjType, TObjHeadOp, TObjTailOp> TMyType;
+ typedef SInvasiveLinkListBase<TObjType, TObjHeadOp, TObjTailOp> TBaseType;
+ typedef SLinkedListIterator<TObjType, TObjTailOp> iterator;
+ typedef iterator const_iterator;
+ typedef SLinkedListIterator<TObjType, TObjHeadOp> reverse_iterator;
+ typedef reverse_iterator const_reverse_iterator;
+
+ TObjType *m_Head;
+ TObjType *m_Tail;
+
+ InvasiveLinkedList()
+ : m_Head(NULL)
+ , m_Tail(NULL)
+ {
+ }
+ InvasiveLinkedList(const TMyType &inOther)
+ : m_Head(inOther.m_Head)
+ , m_Tail(inOther.m_Tail)
+ {
+ }
+ TMyType &operator=(const TMyType &inOther)
+ {
+ m_Head = inOther.m_Head;
+ m_Tail = inOther.m_Tail;
+ return *this;
+ }
+
+ TObjType &front() const
+ {
+ QT3DS_ASSERT(m_Head);
+ return *m_Head;
+ }
+ TObjType &back() const
+ {
+ QT3DS_ASSERT(m_Tail);
+ return *m_Tail;
+ }
+
+ TObjType *front_ptr() const { return m_Head; }
+ TObjType *back_ptr() const { return m_Tail; }
+
+ void push_front(TObjType &inObj)
+ {
+ if (m_Head != NULL)
+ TBaseType::insert_before(*m_Head, inObj);
+ m_Head = &inObj;
+
+ if (m_Tail == NULL)
+ m_Tail = &inObj;
+ }
+
+ void push_back(TObjType &inObj)
+ {
+ if (m_Tail != NULL)
+ TBaseType::insert_after(*m_Tail, inObj);
+ m_Tail = &inObj;
+
+ if (m_Head == NULL)
+ m_Head = &inObj;
+ }
+
+ void remove(TObjType &inObj)
+ {
+ if (m_Head == &inObj)
+ m_Head = TObjTailOp().get(inObj);
+ if (m_Tail == &inObj)
+ m_Tail = TObjHeadOp().get(inObj);
+
+ TBaseType::remove(inObj);
+ }
+
+ bool empty() const { return m_Head == NULL; }
+
+ iterator begin() { return iterator(m_Head); }
+ iterator end() { return iterator(NULL); }
+
+ const_iterator begin() const { return iterator(m_Head); }
+ const_iterator end() const { return iterator(NULL); }
+
+ reverse_iterator rbegin() { return reverse_iterator(m_Tail); }
+ reverse_iterator rend() { return reverse_iterator(NULL); }
+
+ const_reverse_iterator rbegin() const { return reverse_iterator(m_Tail); }
+ const_reverse_iterator rend() const { return reverse_iterator(NULL); }
+ };
+
+// Macros to speed up the definitely of invasive linked lists.
+#define DEFINE_INVASIVE_SINGLE_LIST(type) \
+ struct S##type; \
+ struct S##type##NextOp \
+ { \
+ S##type *get(S##type &s); \
+ const S##type *get(const S##type &s) const; \
+ void set(S##type &inItem, S##type *inNext); \
+ }; \
+ typedef InvasiveSingleLinkedList<S##type, S##type##NextOp> T##type##List;
+
+#define DEFINE_INVASIVE_LIST(type) \
+ struct S##type; \
+ struct S##type##NextOp \
+ { \
+ S##type *get(S##type &s); \
+ const S##type *get(const S##type &s) const; \
+ void set(S##type &inItem, S##type *inNext); \
+ }; \
+ struct S##type##PreviousOp \
+ { \
+ S##type *get(S##type &s); \
+ const S##type *get(const S##type &s) const; \
+ void set(S##type &inItem, S##type *inNext); \
+ }; \
+ typedef InvasiveLinkedList<S##type, S##type##PreviousOp, S##type##NextOp> T##type##List;
+
+#define IMPLEMENT_INVASIVE_LIST(type, prevMember, nextMember) \
+ inline S##type *S##type##NextOp::get(S##type &s) { return s.nextMember; } \
+ inline const S##type *S##type##NextOp::get(const S##type &s) const { return s.nextMember; } \
+ inline void S##type##NextOp::set(S##type &inItem, S##type *inNext) \
+ { \
+ inItem.nextMember = inNext; \
+ } \
+ inline S##type *S##type##PreviousOp::get(S##type &s) { return s.prevMember; } \
+ inline const S##type *S##type##PreviousOp::get(const S##type &s) const \
+ { \
+ return s.prevMember; \
+ } \
+ inline void S##type##PreviousOp::set(S##type &inItem, S##type *inNext) \
+ { \
+ inItem.prevMember = inNext; \
+ }
+
+#define IMPLEMENT_INVASIVE_SINGLE_LIST(type, nextMember) \
+ inline S##type *S##type##NextOp::get(S##type &s) { return s.nextMember; } \
+ inline const S##type *S##type##NextOp::get(const S##type &s) const { return s.nextMember; } \
+ inline void S##type##NextOp::set(S##type &inItem, S##type *inNext) \
+ { \
+ inItem.nextMember = inNext; \
+ }
+}
+}
+#endif \ No newline at end of file
diff --git a/src/foundation/Qt3DSInvasiveSet.h b/src/foundation/Qt3DSInvasiveSet.h
new file mode 100644
index 0000000..772a230
--- /dev/null
+++ b/src/foundation/Qt3DSInvasiveSet.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_INVASIVE_SET_H
+#define QT3DS_FOUNDATION_INVASIVE_SET_H
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+#include "foundation/Qt3DSContainers.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ template <typename TObjectType, typename TGetSetIndexOp, typename TSetSetIndexOp>
+ class InvasiveSet
+ {
+ nvvector<TObjectType *> mSet;
+
+ InvasiveSet(const InvasiveSet &other);
+ InvasiveSet &operator=(const InvasiveSet &other);
+
+ public:
+ InvasiveSet(NVAllocatorCallback &callback, const char *allocName)
+ : mSet(callback, allocName)
+ {
+ }
+
+ bool insert(TObjectType &inObject)
+ {
+ QT3DSU32 currentIdx = TGetSetIndexOp()(inObject);
+ if (currentIdx == QT3DS_MAX_U32) {
+ TSetSetIndexOp()(inObject, mSet.size());
+ mSet.push_back(&inObject);
+ return true;
+ }
+ return false;
+ }
+
+ bool remove(TObjectType &inObject)
+ {
+ QT3DSU32 currentIdx = TGetSetIndexOp()(inObject);
+ if (currentIdx != QT3DS_MAX_U32) {
+ TObjectType *theEnd = mSet.back();
+ TObjectType *theObj = &inObject;
+ if (theEnd != theObj) {
+ TSetSetIndexOp()(*theEnd, currentIdx);
+ mSet[currentIdx] = theEnd;
+ }
+ mSet.pop_back();
+ TSetSetIndexOp()(inObject, QT3DS_MAX_U32);
+ return true;
+ }
+ return false;
+ }
+
+ bool contains(TObjectType &inObject) { return TGetSetIndexOp()(inObject) != QT3DS_MAX_U32; }
+
+ void clear()
+ {
+ for (QT3DSU32 idx = 0; idx < mSet.size(); ++idx)
+ TSetSetIndexOp()(*(mSet[idx]), QT3DS_MAX_U32);
+ mSet.clear();
+ }
+
+ TObjectType *operator[](QT3DSU32 idx) { return mSet[idx]; }
+ const TObjectType *operator[](QT3DSU32 idx) const { return mSet[idx]; }
+ QT3DSU32 size() const { return mSet.size(); }
+ TObjectType **begin() { return mSet.begin(); }
+ TObjectType **end() { return mSet.end(); }
+ const TObjectType **begin() const { return mSet.begin(); }
+ const TObjectType **end() const { return mSet.end(); }
+ const TObjectType *back() const { return mSet.back(); }
+ TObjectType *back() { return mSet.back(); }
+ };
+}
+}
+#endif \ No newline at end of file
diff --git a/src/foundation/Qt3DSLogging.cpp b/src/foundation/Qt3DSLogging.cpp
new file mode 100644
index 0000000..257b39b
--- /dev/null
+++ b/src/foundation/Qt3DSLogging.cpp
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** 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 "foundation/Qt3DSLogging.h"
+
+namespace qt3ds {
+
+Q_LOGGING_CATEGORY(GL_ERROR, "qt3ds.gl_error")
+Q_LOGGING_CATEGORY(INVALID_PARAMETER, "qt3ds.invalid_parameter")
+Q_LOGGING_CATEGORY(INVALID_OPERATION, "qt3ds.invalid_operation")
+Q_LOGGING_CATEGORY(OUT_OF_MEMORY, "qt3ds.out_of_memory")
+Q_LOGGING_CATEGORY(INTERNAL_ERROR, "qt3ds.internal_error")
+Q_LOGGING_CATEGORY(PERF_WARNING, "qt3ds.perf_warning")
+Q_LOGGING_CATEGORY(PERF_INFO, "qt3ds.perf_info")
+Q_LOGGING_CATEGORY(TRACE_INFO, "qt3ds.trace_info")
+Q_LOGGING_CATEGORY(WARNING, "qt3ds.warning")
+
+} // namespace qt3ds
diff --git a/src/foundation/Qt3DSLogging.h b/src/foundation/Qt3DSLogging.h
new file mode 100644
index 0000000..4fcb77b
--- /dev/null
+++ b/src/foundation/Qt3DSLogging.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_ERRORS_H
+#define QT3DS_FOUNDATION_QT3DS_ERRORS_H
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qloggingcategory.h>
+
+namespace qt3ds {
+
+Q_DECLARE_LOGGING_CATEGORY(GL_ERROR)
+Q_DECLARE_LOGGING_CATEGORY(INVALID_PARAMETER)
+Q_DECLARE_LOGGING_CATEGORY(INVALID_OPERATION)
+Q_DECLARE_LOGGING_CATEGORY(OUT_OF_MEMORY)
+Q_DECLARE_LOGGING_CATEGORY(INTERNAL_ERROR)
+Q_DECLARE_LOGGING_CATEGORY(PERF_WARNING)
+Q_DECLARE_LOGGING_CATEGORY(PERF_INFO)
+Q_DECLARE_LOGGING_CATEGORY(TRACE_INFO)
+Q_DECLARE_LOGGING_CATEGORY(WARNING)
+
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSMat33.h b/src/foundation/Qt3DSMat33.h
new file mode 100644
index 0000000..6fa69eb
--- /dev/null
+++ b/src/foundation/Qt3DSMat33.h
@@ -0,0 +1,385 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_MAT33_H
+#define QT3DS_FOUNDATION_QT3DS_MAT33_H
+/** \addtogroup foundation
+@{
+*/
+
+#include "foundation/Qt3DSVec3.h"
+#include "foundation/Qt3DSQuat.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+/*!
+\brief 3x3 matrix class
+
+Some clarifications, as there have been much confusion about matrix formats etc in the past.
+
+Short:
+- Matrix have base vectors in columns (vectors are column matrices, 3x1 matrices).
+- Matrix is physically stored in column major format
+- Matrices are concaternated from left
+
+Long:
+Given three base vectors a, b and c the matrix is stored as
+
+|a.x b.x c.x|
+|a.y b.y c.y|
+|a.z b.z c.z|
+
+Vectors are treated as columns, so the vector v is
+
+|x|
+|y|
+|z|
+
+And matrices are applied _before_ the vector (pre-multiplication)
+v' = M*v
+
+|x'| |a.x b.x c.x| |x| |a.x*x + b.x*y + c.x*z|
+|y'| = |a.y b.y c.y| * |y| = |a.y*x + b.y*y + c.y*z|
+|z'| |a.z b.z c.z| |z| |a.z*x + b.z*y + c.z*z|
+
+
+Physical storage and indexing:
+To be compatible with popular 3d rendering APIs (read D3d and OpenGL)
+the physical indexing is
+
+|0 3 6|
+|1 4 7|
+|2 5 8|
+
+index = column*3 + row
+
+which in C++ translates to M[column][row]
+
+The mathematical indexing is M_row,column and this is what is used for _-notation
+so _12 is 1st row, second column and operator(row, column)!
+
+@see QT3DSMat44
+
+*/
+class QT3DSMat33
+{
+public:
+ //! Default constructor
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33() {}
+
+ //! Construct from three base vectors
+ QT3DS_CUDA_CALLABLE QT3DSMat33(const QT3DSVec3 &col0, const QT3DSVec3 &col1, const QT3DSVec3 &col2)
+ : column0(col0)
+ , column1(col1)
+ , column2(col2)
+ {
+ }
+
+ //! Construct from float[9]
+ QT3DS_CUDA_CALLABLE explicit QT3DS_INLINE QT3DSMat33(NVReal values[])
+ : column0(values[0], values[1], values[2])
+ , column1(values[3], values[4], values[5])
+ , column2(values[6], values[7], values[8])
+ {
+ }
+
+ //! Construct from a quaternion
+ QT3DS_CUDA_CALLABLE explicit QT3DS_FORCE_INLINE QT3DSMat33(const QT3DSQuat &q)
+ {
+ const NVReal x = q.x;
+ const NVReal y = q.y;
+ const NVReal z = q.z;
+ const NVReal w = q.w;
+
+ const NVReal x2 = x + x;
+ const NVReal y2 = y + y;
+ const NVReal z2 = z + z;
+
+ const NVReal xx = x2 * x;
+ const NVReal yy = y2 * y;
+ const NVReal zz = z2 * z;
+
+ const NVReal xy = x2 * y;
+ const NVReal xz = x2 * z;
+ const NVReal xw = x2 * w;
+
+ const NVReal yz = y2 * z;
+ const NVReal yw = y2 * w;
+ const NVReal zw = z2 * w;
+
+ column0 = QT3DSVec3(1.0f - yy - zz, xy + zw, xz - yw);
+ column1 = QT3DSVec3(xy - zw, 1.0f - xx - zz, yz + xw);
+ column2 = QT3DSVec3(xz + yw, yz - xw, 1.0f - xx - yy);
+ }
+
+ //! Copy constructor
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33(const QT3DSMat33 &other)
+ : column0(other.column0)
+ , column1(other.column1)
+ , column2(other.column2)
+ {
+ }
+
+ //! Assignment operator
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSMat33 &operator=(const QT3DSMat33 &other)
+ {
+ column0 = other.column0;
+ column1 = other.column1;
+ column2 = other.column2;
+ return *this;
+ }
+
+ //! Set to identity matrix
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE static QT3DSMat33 createIdentity()
+ {
+ return QT3DSMat33(QT3DSVec3(1, 0, 0), QT3DSVec3(0, 1, 0), QT3DSVec3(0, 0, 1));
+ }
+
+ //! Set to zero matrix
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE static QT3DSMat33 createZero()
+ {
+ return QT3DSMat33(QT3DSVec3(0.0f), QT3DSVec3(0.0f), QT3DSVec3(0.0f));
+ }
+
+ //! Construct from diagonal, off-diagonals are zero.
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE static QT3DSMat33 createDiagonal(const QT3DSVec3 &d)
+ {
+ return QT3DSMat33(QT3DSVec3(d.x, 0.0f, 0.0f), QT3DSVec3(0.0f, d.y, 0.0f), QT3DSVec3(0.0f, 0.0f, d.z));
+ }
+
+ //! Get transposed matrix
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSMat33 getTranspose() const
+ {
+ const QT3DSVec3 v0(column0.x, column1.x, column2.x);
+ const QT3DSVec3 v1(column0.y, column1.y, column2.y);
+ const QT3DSVec3 v2(column0.z, column1.z, column2.z);
+
+ return QT3DSMat33(v0, v1, v2);
+ }
+
+ //! Get the real inverse
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 getInverse() const
+ {
+ const NVReal det = getDeterminant();
+ QT3DSMat33 inverse;
+
+ if (det != 0) {
+ const NVReal invDet = 1.0f / det;
+
+ inverse.column0[0] = invDet * (column1[1] * column2[2] - column2[1] * column1[2]);
+ inverse.column0[1] = invDet * -(column0[1] * column2[2] - column2[1] * column0[2]);
+ inverse.column0[2] = invDet * (column0[1] * column1[2] - column0[2] * column1[1]);
+
+ inverse.column1[0] = invDet * -(column1[0] * column2[2] - column1[2] * column2[0]);
+ inverse.column1[1] = invDet * (column0[0] * column2[2] - column0[2] * column2[0]);
+ inverse.column1[2] = invDet * -(column0[0] * column1[2] - column0[2] * column1[0]);
+
+ inverse.column2[0] = invDet * (column1[0] * column2[1] - column1[1] * column2[0]);
+ inverse.column2[1] = invDet * -(column0[0] * column2[1] - column0[1] * column2[0]);
+ inverse.column2[2] = invDet * (column0[0] * column1[1] - column1[0] * column0[1]);
+
+ return inverse;
+ } else {
+ return createIdentity();
+ }
+ }
+
+ //! Get determinant
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal getDeterminant() const
+ {
+ return column0.dot(column1.cross(column2));
+ }
+
+ //! Unary minus
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 operator-() const
+ {
+ return QT3DSMat33(-column0, -column1, -column2);
+ }
+
+ //! Add
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 operator+(const QT3DSMat33 &other) const
+ {
+ return QT3DSMat33(column0 + other.column0, column1 + other.column1, column2 + other.column2);
+ }
+
+ //! Subtract
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 operator-(const QT3DSMat33 &other) const
+ {
+ return QT3DSMat33(column0 - other.column0, column1 - other.column1, column2 - other.column2);
+ }
+
+ //! Scalar multiplication
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 operator*(NVReal scalar) const
+ {
+ return QT3DSMat33(column0 * scalar, column1 * scalar, column2 * scalar);
+ }
+
+ friend QT3DSMat33 operator*(NVReal, const QT3DSMat33 &);
+
+ //! Matrix vector multiplication (returns 'this->transform(vec)')
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 operator*(const QT3DSVec3 &vec) const { return transform(vec); }
+
+ //! Matrix multiplication
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSMat33 operator*(const QT3DSMat33 &other) const
+ {
+ // Rows from this <dot> columns from other
+ // column0 = transform(other.column0) etc
+ return QT3DSMat33(transform(other.column0), transform(other.column1),
+ transform(other.column2));
+ }
+
+ // a <op>= b operators
+
+ //! Equals-add
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 &operator+=(const QT3DSMat33 &other)
+ {
+ column0 += other.column0;
+ column1 += other.column1;
+ column2 += other.column2;
+ return *this;
+ }
+
+ //! Equals-sub
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 &operator-=(const QT3DSMat33 &other)
+ {
+ column0 -= other.column0;
+ column1 -= other.column1;
+ column2 -= other.column2;
+ return *this;
+ }
+
+ //! Equals scalar multiplication
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 &operator*=(NVReal scalar)
+ {
+ column0 *= scalar;
+ column1 *= scalar;
+ column2 *= scalar;
+ return *this;
+ }
+
+ //! Element access, mathematical way!
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal operator()(unsigned int row, unsigned int col) const
+ {
+ return (*this)[col][row];
+ }
+
+ //! Element access, mathematical way!
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal &operator()(unsigned int row, unsigned int col)
+ {
+ return (*this)[col][row];
+ }
+
+ // Transform etc
+
+ //! Transform vector by matrix, equal to v' = M*v
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 transform(const QT3DSVec3 &other) const
+ {
+ return column0 * other.x + column1 * other.y + column2 * other.z;
+ }
+
+ //! Transform vector by matrix transpose, v' = M^t*v
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 transformTranspose(const QT3DSVec3 &other) const
+ {
+ return QT3DSVec3(column0.dot(other), column1.dot(other), column2.dot(other));
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const NVReal *front() const { return &column0.x; }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 &operator[](int num) { return (&column0)[num]; }
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const QT3DSVec3 &operator[](int num) const
+ {
+ return (&column0)[num];
+ }
+
+ // Data, see above for format!
+
+ QT3DSVec3 column0, column1, column2; // the three base vectors
+};
+
+// implementation from Qt3DSQuat.h
+QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSQuat::QT3DSQuat(const QT3DSMat33 &m)
+{
+ NVReal tr = m(0, 0) + m(1, 1) + m(2, 2), h;
+ if (tr >= 0) {
+ h = NVSqrt(tr + 1);
+ w = NVReal(0.5) * h;
+ h = NVReal(0.5) / h;
+
+ x = (m(2, 1) - m(1, 2)) * h;
+ y = (m(0, 2) - m(2, 0)) * h;
+ z = (m(1, 0) - m(0, 1)) * h;
+ } else {
+ int i = 0;
+ if (m(1, 1) > m(0, 0))
+ i = 1;
+ if (m(2, 2) > m(i, i))
+ i = 2;
+ switch (i) {
+ case 0:
+ h = NVSqrt((m(0, 0) - (m(1, 1) + m(2, 2))) + 1);
+ x = NVReal(0.5) * h;
+ h = NVReal(0.5) / h;
+
+ y = (m(0, 1) + m(1, 0)) * h;
+ z = (m(2, 0) + m(0, 2)) * h;
+ w = (m(2, 1) - m(1, 2)) * h;
+ break;
+ case 1:
+ h = NVSqrt((m(1, 1) - (m(2, 2) + m(0, 0))) + 1);
+ y = NVReal(0.5) * h;
+ h = NVReal(0.5) / h;
+
+ z = (m(1, 2) + m(2, 1)) * h;
+ x = (m(0, 1) + m(1, 0)) * h;
+ w = (m(0, 2) - m(2, 0)) * h;
+ break;
+ case 2:
+ h = NVSqrt((m(2, 2) - (m(0, 0) + m(1, 1))) + 1);
+ z = NVReal(0.5) * h;
+ h = NVReal(0.5) / h;
+
+ x = (m(2, 0) + m(0, 2)) * h;
+ y = (m(1, 2) + m(2, 1)) * h;
+ w = (m(1, 0) - m(0, 1)) * h;
+ break;
+ default: // Make compiler happy
+ x = y = z = w = 0;
+ break;
+ }
+ }
+}
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_MAT33_H
diff --git a/src/foundation/Qt3DSMat44.h b/src/foundation/Qt3DSMat44.h
new file mode 100644
index 0000000..53a66e2
--- /dev/null
+++ b/src/foundation/Qt3DSMat44.h
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_MAT44_H
+#define QT3DS_FOUNDATION_QT3DS_MAT44_H
+/** \addtogroup foundation
+@{
+*/
+
+#include "foundation/Qt3DSQuat.h"
+#include "foundation/Qt3DSVec4.h"
+#include "foundation/Qt3DSMat33.h"
+#include "foundation/Qt3DSTransform.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+/*!
+\brief 4x4 matrix class
+
+This class is layout-compatible with D3D and OpenGL matrices. More notes on layout are given in the QT3DSMat33
+Graphics matrices always (by which I mean DX and OpenGL) have the rotation basis vectors stored contiguously
+in 0-2, 3-5, 6-8 and the the translation stored contiguously in 12-14. However, DX calls this row major and GL calls it column-major.
+http://www.mindcontrol.org/~hplus/graphics/matrix-layout.html
+
+you can blat these directly into GL (or DX)
+
+--Dilip Sequeira
+
+@see QT3DSMat33 NVTransform
+*/
+
+class QT3DSMat44
+{
+public:
+ //! Default constructor
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44() {}
+
+ //! Construct from four 4-vectors
+ QT3DS_CUDA_CALLABLE QT3DSMat44(const QT3DSVec4 &col0, const QT3DSVec4 &col1, const QT3DSVec4 &col2,
+ const QT3DSVec4 &col3)
+ : column0(col0)
+ , column1(col1)
+ , column2(col2)
+ , column3(col3)
+ {
+ }
+
+ //! Construct from three base vectors and a translation
+ QT3DS_CUDA_CALLABLE QT3DSMat44(const QT3DSVec3 &column0, const QT3DSVec3 &column1, const QT3DSVec3 &column2,
+ const QT3DSVec3 &column3)
+ : column0(column0, 0)
+ , column1(column1, 0)
+ , column2(column2, 0)
+ , column3(column3, 1)
+ {
+ }
+
+ //! Construct from float[16]
+ explicit QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44(NVReal values[])
+ : column0(values[0], values[1], values[2], values[3])
+ , column1(values[4], values[5], values[6], values[7])
+ , column2(values[8], values[9], values[10], values[11])
+ , column3(values[12], values[13], values[14], values[15])
+ {
+ }
+
+ //! Construct from a quaternion
+ explicit QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44(const QT3DSQuat &q)
+ {
+ const NVReal x = q.x;
+ const NVReal y = q.y;
+ const NVReal z = q.z;
+ const NVReal w = q.w;
+
+ const NVReal x2 = x + x;
+ const NVReal y2 = y + y;
+ const NVReal z2 = z + z;
+
+ const NVReal xx = x2 * x;
+ const NVReal yy = y2 * y;
+ const NVReal zz = z2 * z;
+
+ const NVReal xy = x2 * y;
+ const NVReal xz = x2 * z;
+ const NVReal xw = x2 * w;
+
+ const NVReal yz = y2 * z;
+ const NVReal yw = y2 * w;
+ const NVReal zw = z2 * w;
+
+ column0 = QT3DSVec4(1.0f - yy - zz, xy + zw, xz - yw, 0.0f);
+ column1 = QT3DSVec4(xy - zw, 1.0f - xx - zz, yz + xw, 0.0f);
+ column2 = QT3DSVec4(xz + yw, yz - xw, 1.0f - xx - yy, 0.0f);
+ column3 = QT3DSVec4(0.0f, 0.0f, 0.0f, 1.0f);
+ }
+
+ //! Construct from a diagonal vector
+ explicit QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44(const QT3DSVec4 &diagonal)
+ : column0(diagonal.x, 0.0f, 0.0f, 0.0f)
+ , column1(0.0f, diagonal.y, 0.0f, 0.0f)
+ , column2(0.0f, 0.0f, diagonal.z, 0.0f)
+ , column3(0.0f, 0.0f, 0.0f, diagonal.w)
+ {
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DSMat44(const QT3DSMat33 &orientation, const QT3DSVec3 &position)
+ : column0(orientation.column0, 0.0f)
+ , column1(orientation.column1, 0.0f)
+ , column2(orientation.column2, 0.0f)
+ , column3(position, 1)
+ {
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DSMat44(const NVTransform &t) { *this = QT3DSMat44(QT3DSMat33(t.q), t.p); }
+
+ //! Copy constructor
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44(const QT3DSMat44 &other)
+ : column0(other.column0)
+ , column1(other.column1)
+ , column2(other.column2)
+ , column3(other.column3)
+ {
+ }
+
+ //! Assignment operator
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE const QT3DSMat44 &operator=(const QT3DSMat44 &other)
+ {
+ column0 = other.column0;
+ column1 = other.column1;
+ column2 = other.column2;
+ column3 = other.column3;
+ return *this;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE static QT3DSMat44 createIdentity()
+ {
+ return QT3DSMat44(QT3DSVec4(1.0f, 0.0f, 0.0f, 0.0f), QT3DSVec4(0.0f, 1.0f, 0.0f, 0.0f),
+ QT3DSVec4(0.0f, 0.0f, 1.0f, 0.0f), QT3DSVec4(0.0f, 0.0f, 0.0f, 1.0f));
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE static QT3DSMat44 createZero()
+ {
+ return QT3DSMat44(QT3DSVec4(0.0f), QT3DSVec4(0.0f), QT3DSVec4(0.0f), QT3DSVec4(0.0f));
+ }
+
+ //! Get transposed matrix
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 getTranspose() const
+ {
+ return QT3DSMat44(QT3DSVec4(column0.x, column1.x, column2.x, column3.x),
+ QT3DSVec4(column0.y, column1.y, column2.y, column3.y),
+ QT3DSVec4(column0.z, column1.z, column2.z, column3.z),
+ QT3DSVec4(column0.w, column1.w, column2.w, column3.w));
+ }
+
+ //! Unary minus
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator-() const
+ {
+ return QT3DSMat44(-column0, -column1, -column2, -column3);
+ }
+
+ //! Add
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator+(const QT3DSMat44 &other) const
+ {
+ return QT3DSMat44(column0 + other.column0, column1 + other.column1, column2 + other.column2,
+ column3 + other.column3);
+ }
+
+ //! Subtract
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator-(const QT3DSMat44 &other) const
+ {
+ return QT3DSMat44(column0 - other.column0, column1 - other.column1, column2 - other.column2,
+ column3 - other.column3);
+ }
+
+ //! Scalar multiplication
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator*(NVReal scalar) const
+ {
+ return QT3DSMat44(column0 * scalar, column1 * scalar, column2 * scalar, column3 * scalar);
+ }
+
+ friend QT3DSMat44 operator*(NVReal, const QT3DSMat44 &);
+
+ //! Matrix multiplication
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 operator*(const QT3DSMat44 &other) const
+ {
+ // Rows from this <dot> columns from other
+ // column0 = transform(other.column0) etc
+ return QT3DSMat44(transform(other.column0), transform(other.column1), transform(other.column2),
+ transform(other.column3));
+ }
+
+ // a <op>= b operators
+
+ //! Equals-add
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 &operator+=(const QT3DSMat44 &other)
+ {
+ column0 += other.column0;
+ column1 += other.column1;
+ column2 += other.column2;
+ column3 += other.column3;
+ return *this;
+ }
+
+ //! Equals-sub
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 &operator-=(const QT3DSMat44 &other)
+ {
+ column0 -= other.column0;
+ column1 -= other.column1;
+ column2 -= other.column2;
+ column3 -= other.column3;
+ return *this;
+ }
+
+ //! Equals scalar multiplication
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 &operator*=(NVReal scalar)
+ {
+ column0 *= scalar;
+ column1 *= scalar;
+ column2 *= scalar;
+ column3 *= scalar;
+ return *this;
+ }
+
+ //! Element access, mathematical way!
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal operator()(unsigned int row, unsigned int col) const
+ {
+ return (*this)[col][row];
+ }
+
+ //! Element access, mathematical way!
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal &operator()(unsigned int row, unsigned int col)
+ {
+ return (*this)[col][row];
+ }
+
+ //! Transform vector by matrix, equal to v' = M*v
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 transform(const QT3DSVec4 &other) const
+ {
+ return column0 * other.x + column1 * other.y + column2 * other.z + column3 * other.w;
+ }
+
+ //! Transform vector by matrix, equal to v' = M*v
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 transform(const QT3DSVec3 &other) const
+ {
+ return transform(QT3DSVec4(other, 1)).getXYZ();
+ }
+
+ //! Rotate vector by matrix, equal to v' = M*v
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 rotate(const QT3DSVec4 &other) const
+ {
+ return column0 * other.x + column1 * other.y + column2 * other.z; // + column3*0;
+ }
+
+ //! Rotate vector by matrix, equal to v' = M*v
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 rotate(const QT3DSVec3 &other) const
+ {
+ return rotate(QT3DSVec4(other, 1)).getXYZ();
+ }
+
+ /**
+* Shamelessly pulled from gl-matrix.js
+ * Rotates a matrix by the given angle around the specified axis
+*
+* @param angle Angle (in radians) to rotate
+* @param axis vec3 representing the axis to rotate around
+*/
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool rotate(QT3DSF32 angleRadians, QT3DSVec3 axis)
+ {
+ QT3DSF32 x = axis[0], y = axis[1], z = axis[2], len = x * x + y * y + z * z, s, c, t, a00, a01,
+ a02, a03, a10, a11, a12, a13, a20, a21, a22, a23, b00, b01, b02, b10, b11, b12, b20,
+ b21, b22;
+
+ if (!len) {
+ return false;
+ }
+ if (len != 1.0f) {
+ len = 1 / (NVSqrt(len));
+ x *= len;
+ y *= len;
+ z *= len;
+ }
+
+ s = NVSin(angleRadians);
+ c = NVCos(angleRadians);
+ t = 1 - c;
+
+ QT3DSF32 *dataPtr(front());
+
+// inverse algorithm was written for row-major matrixes.
+#define mat(idx) dataPtr[idx]
+
+ a00 = mat(0);
+ a01 = mat(1);
+ a02 = mat(2);
+ a03 = mat(3);
+ a10 = mat(4);
+ a11 = mat(5);
+ a12 = mat(6);
+ a13 = mat(7);
+ a20 = mat(8);
+ a21 = mat(9);
+ a22 = mat(10);
+ a23 = mat(11);
+#undef mat
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c;
+ b01 = y * x * t + z * s;
+ b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s;
+ b11 = y * y * t + c;
+ b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s;
+ b21 = y * z * t - x * s;
+ b22 = z * z * t + c;
+
+// Perform rotation-specific matrix multiplication
+
+#define dest(idx) dataPtr[idx]
+
+ dest(0) = a00 * b00 + a10 * b01 + a20 * b02;
+ dest(1) = a01 * b00 + a11 * b01 + a21 * b02;
+ dest(2) = a02 * b00 + a12 * b01 + a22 * b02;
+ dest(3) = a03 * b00 + a13 * b01 + a23 * b02;
+
+ dest(4) = a00 * b10 + a10 * b11 + a20 * b12;
+ dest(5) = a01 * b10 + a11 * b11 + a21 * b12;
+ dest(6) = a02 * b10 + a12 * b11 + a22 * b12;
+ dest(7) = a03 * b10 + a13 * b11 + a23 * b12;
+
+ dest(8) = a00 * b20 + a10 * b21 + a20 * b22;
+ dest(9) = a01 * b20 + a11 * b21 + a21 * b22;
+ dest(10) = a02 * b20 + a12 * b21 + a22 * b22;
+ dest(11) = a03 * b20 + a13 * b21 + a23 * b22;
+
+#undef dest
+
+ return true;
+ };
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 getBasis(int num) const
+ {
+ QT3DS_ASSERT(num >= 0 && num < 3);
+ return (&column0)[num].getXYZ();
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 getPosition() const { return column3.getXYZ(); }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE void setPosition(const QT3DSVec3 &position)
+ {
+ column3.x = position.x;
+ column3.y = position.y;
+ column3.z = position.z;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal *front() { return &column0.x; }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const NVReal *front() const { return &column0.x; }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec4 &operator[](int num) { return (&column0)[num]; }
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const QT3DSVec4 &operator[](int num) const
+ {
+ return (&column0)[num];
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE void scale(const QT3DSVec4 &p)
+ {
+ column0 *= p.x;
+ column1 *= p.y;
+ column2 *= p.z;
+ column3 *= p.w;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 inverseRT(void) const
+ {
+ QT3DSVec3 r0(column0.x, column1.x, column2.x), r1(column0.y, column1.y, column2.y),
+ r2(column0.z, column1.z, column2.z);
+
+ return QT3DSMat44(r0, r1, r2, -(r0 * column3.x + r1 * column3.y + r2 * column3.z));
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat44 getInverse(void) const
+ {
+ // inverse algorithm was written for row-major matrixes.
+ const QT3DSF32 *myPtr(front());
+#define mat(idx) myPtr[idx]
+
+ QT3DSF32 a00 = mat(0), a01 = mat(1), a02 = mat(2), a03 = mat(3), a10 = mat(4), a11 = mat(5),
+ a12 = mat(6), a13 = mat(7), a20 = mat(8), a21 = mat(9), a22 = mat(10), a23 = mat(11),
+ a30 = mat(12), a31 = mat(13), a32 = mat(14), a33 = mat(15),
+#undef mat
+
+ b00 = a00 * a11 - a01 * a10, b01 = a00 * a12 - a02 * a10, b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11, b04 = a01 * a13 - a03 * a11, b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30, b07 = a20 * a32 - a22 * a30, b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31, b10 = a21 * a33 - a23 * a31, b11 = a22 * a33 - a23 * a32,
+
+ d = (b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06), invDet;
+
+ // Calculate the determinant
+ if (!d) {
+ QT3DS_ASSERT(false);
+ return QT3DSMat44::createIdentity();
+ }
+ invDet = 1 / d;
+
+ QT3DSMat44 retval;
+ QT3DSF32 *destPtr = retval.front();
+
+#define dest(idx) destPtr[idx]
+ dest(0) = (a11 * b11 - a12 * b10 + a13 * b09) * invDet;
+ dest(1) = (-a01 * b11 + a02 * b10 - a03 * b09) * invDet;
+ dest(2) = (a31 * b05 - a32 * b04 + a33 * b03) * invDet;
+ dest(3) = (-a21 * b05 + a22 * b04 - a23 * b03) * invDet;
+ dest(4) = (-a10 * b11 + a12 * b08 - a13 * b07) * invDet;
+ dest(5) = (a00 * b11 - a02 * b08 + a03 * b07) * invDet;
+ dest(6) = (-a30 * b05 + a32 * b02 - a33 * b01) * invDet;
+ dest(7) = (a20 * b05 - a22 * b02 + a23 * b01) * invDet;
+ dest(8) = (a10 * b10 - a11 * b08 + a13 * b06) * invDet;
+ dest(9) = (-a00 * b10 + a01 * b08 - a03 * b06) * invDet;
+ dest(10) = (a30 * b04 - a31 * b02 + a33 * b00) * invDet;
+ dest(11) = (-a20 * b04 + a21 * b02 - a23 * b00) * invDet;
+ dest(12) = (-a10 * b09 + a11 * b07 - a12 * b06) * invDet;
+ dest(13) = (a00 * b09 - a01 * b07 + a02 * b06) * invDet;
+ dest(14) = (-a30 * b03 + a31 * b01 - a32 * b00) * invDet;
+ dest(15) = (a20 * b03 - a21 * b01 + a22 * b00) * invDet;
+#undef dest
+
+ return retval;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool isFinite() const
+ {
+ return column0.isFinite() && column1.isFinite() && column2.isFinite() && column3.isFinite();
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 getUpper3x3() const
+ {
+ return QT3DSMat33(column0.getXYZ(), column1.getXYZ(), column2.getXYZ());
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSMat33 getUpper3x3InverseTranspose() const
+ {
+ return getUpper3x3().getInverse().getTranspose();
+ }
+
+ // Data, see above for format!
+
+ QT3DSVec4 column0, column1, column2, column3; // the four base vectors
+};
+
+// implementation from Qt3DSTransform.h
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVTransform::NVTransform(const QT3DSMat44 &m)
+{
+ QT3DSVec3 column0 = QT3DSVec3(m.column0.x, m.column0.y, m.column0.z);
+ QT3DSVec3 column1 = QT3DSVec3(m.column1.x, m.column1.y, m.column1.z);
+ QT3DSVec3 column2 = QT3DSVec3(m.column2.x, m.column2.y, m.column2.z);
+
+ q = QT3DSQuat(QT3DSMat33(column0, column1, column2));
+ p = QT3DSVec3(m.column3.x, m.column3.y, m.column3.z);
+}
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_MAT44_H
diff --git a/src/foundation/Qt3DSMath.h b/src/foundation/Qt3DSMath.h
new file mode 100644
index 0000000..931852e
--- /dev/null
+++ b/src/foundation/Qt3DSMath.h
@@ -0,0 +1,323 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_MATH_H
+#define QT3DS_FOUNDATION_QT3DS_MATH_H
+
+/** \addtogroup foundation
+@{
+*/
+
+#include <math.h>
+#include <float.h>
+#include <stdlib.h>
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSIntrinsics.h"
+#include "foundation/Qt3DSAssert.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+// constants
+static const NVReal NVPi = NVReal(3.141592653589793);
+static const NVReal NVHalfPi = NVReal(1.57079632679489661923);
+static const NVReal NVTwoPi = NVReal(6.28318530717958647692);
+static const NVReal NVInvPi = NVReal(0.31830988618379067154);
+
+/**
+\brief The return value is the greater of the two specified values.
+*/
+template <class T>
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE T NVMax(T a, T b)
+{
+ return a < b ? b : a;
+}
+
+//! overload for float to use fsel on xbox
+template <>
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float NVMax(float a, float b)
+{
+ return intrinsics::selectMax(a, b);
+}
+
+/**
+\brief The return value is the lesser of the two specified values.
+*/
+template <class T>
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE T NVMin(T a, T b)
+{
+ return a < b ? a : b;
+}
+
+template <>
+//! overload for float to use fsel on xbox
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float NVMin(float a, float b)
+{
+ return intrinsics::selectMin(a, b);
+}
+
+/*
+Many of these are just implemented as QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE calls to the C lib right now,
+but later we could replace some of them with some approximations or more
+clever stuff.
+*/
+
+/**
+\brief abs returns the absolute value of its argument.
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVAbs(QT3DSF32 a)
+{
+ return intrinsics::abs(a);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVEquals(QT3DSF32 a, QT3DSF32 b, QT3DSF32 epsilon)
+{
+ return (NVAbs(a - b) < epsilon);
+}
+
+/**
+\brief abs returns the absolute value of its argument.
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVAbs(QT3DSF64 a)
+{
+ return ::fabs(a);
+}
+
+/**
+\brief abs returns the absolute value of its argument.
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSI32 NVAbs(QT3DSI32 a)
+{
+ return ::abs(a);
+}
+
+/**
+\brief Clamps v to the range [hi,lo]
+*/
+template <class T>
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE T NVClamp(T v, T lo, T hi)
+{
+ QT3DS_ASSERT(lo <= hi);
+ return NVMin(hi, NVMax(lo, v));
+}
+
+//! \brief Square root.
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVSqrt(QT3DSF32 a)
+{
+ return intrinsics::sqrt(a);
+}
+
+//! \brief Square root.
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVSqrt(QT3DSF64 a)
+{
+ return ::sqrt(a);
+}
+
+//! \brief reciprocal square root.
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVRecipSqrt(QT3DSF32 a)
+{
+ return intrinsics::recipSqrt(a);
+}
+
+//! \brief reciprocal square root.
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVRecipSqrt(QT3DSF64 a)
+{
+ return 1 / ::sqrt(a);
+}
+
+//!trigonometry -- all angles are in radians.
+
+//! \brief Sine of an angle ( <b>Unit:</b> Radians )
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVSin(QT3DSF32 a)
+{
+ return intrinsics::sin(a);
+}
+
+//! \brief Sine of an angle ( <b>Unit:</b> Radians )
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVSin(QT3DSF64 a)
+{
+ return ::sin(a);
+}
+
+//! \brief Cosine of an angle (<b>Unit:</b> Radians)
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVCos(QT3DSF32 a)
+{
+ return intrinsics::cos(a);
+}
+
+//! \brief Cosine of an angle (<b>Unit:</b> Radians)
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVCos(QT3DSF64 a)
+{
+ return ::cos(a);
+}
+
+/**
+\brief Tangent of an angle.
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVTan(QT3DSF32 a)
+{
+ return QT3DSF32(::tan(a));
+}
+
+/**
+\brief Tangent of an angle.
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVTan(QT3DSF64 a)
+{
+ return ::tan(a);
+}
+
+/**
+\brief Arcsine.
+Returns angle between -PI/2 and PI/2 in radians
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVAsin(QT3DSF32 f)
+{
+ return QT3DSF32(::asin(NVClamp(f, -1.0f, 1.0f)));
+}
+
+/**
+\brief Arcsine.
+Returns angle between -PI/2 and PI/2 in radians
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVAsin(QT3DSF64 f)
+{
+ return ::asin(NVClamp(f, -1.0, 1.0));
+}
+
+/**
+\brief Arccosine.
+Returns angle between 0 and PI in radians
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVAcos(QT3DSF32 f)
+{
+ return QT3DSF32(::acos(NVClamp(f, -1.0f, 1.0f)));
+}
+
+/**
+\brief Arccosine.
+Returns angle between 0 and PI in radians
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVAcos(QT3DSF64 f)
+{
+ return ::acos(NVClamp(f, -1.0, 1.0));
+}
+
+/**
+\brief ArcTangent.
+Returns angle between -PI/2 and PI/2 in radians
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVAtan(QT3DSF32 a)
+{
+ return QT3DSF32(::atan(a));
+}
+
+/**
+\brief ArcTangent.
+Returns angle between -PI/2 and PI/2 in radians
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVAtan(QT3DSF64 a)
+{
+ return ::atan(a);
+}
+
+/**
+\brief Arctangent of (x/y) with correct sign.
+Returns angle between -PI and PI in radians
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVAtan2(QT3DSF32 x, QT3DSF32 y)
+{
+ return QT3DSF32(::atan2(x, y));
+}
+
+/**
+\brief Arctangent of (x/y) with correct sign.
+Returns angle between -PI and PI in radians
+<b>Unit:</b> Radians
+*/
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 NVAtan2(QT3DSF64 x, QT3DSF64 y)
+{
+ return ::atan2(x, y);
+}
+
+//! \brief returns true if the passed number is a finite floating point number as opposed to INF, NAN, etc.
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVIsFinite(QT3DSF32 f)
+{
+ return intrinsics::isFinite(f);
+}
+
+//! \brief returns true if the passed number is a finite floating point number as opposed to INF, NAN, etc.
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool NVIsFinite(QT3DSF64 f)
+{
+ return intrinsics::isFinite(f);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVFloor(QT3DSF32 a)
+{
+ return ::floorf(a);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVExp(QT3DSF32 a)
+{
+ return ::expf(a);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVCeil(QT3DSF32 a)
+{
+ return ::ceilf(a);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVSign(QT3DSF32 a)
+{
+ return qt3ds::intrinsics::sign(a);
+}
+
+QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 NVPow(QT3DSF32 x, QT3DSF32 y)
+{
+ return ::powf(x, y);
+};
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_MATH_H
diff --git a/src/foundation/Qt3DSMathUtils.cpp b/src/foundation/Qt3DSMathUtils.cpp
new file mode 100644
index 0000000..7eee740
--- /dev/null
+++ b/src/foundation/Qt3DSMathUtils.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DSMathUtils.h"
+#include "foundation/Qt3DSUtilities.h"
+#include "foundation/Qt3DSMat33.h"
+
+using namespace qt3ds;
+using namespace qt3ds::foundation;
+using namespace qt3ds::intrinsics;
+
+QT3DSQuat qt3ds::foundation::computeQuatFromNormal(const QT3DSVec3 &n)
+{
+ // parallel or anti-parallel
+ if (n.x > 0.9999f) {
+ // parallel
+ return QT3DSQuat::createIdentity();
+ } else if (n.x < -0.9999f) {
+ // anti-parallel
+ // contactQuaternion.fromAngleAxisFast(PXD_PI, Vector3(0.0f, 1.0f, 0.0f));
+ return QT3DSQuat(0.0f, 1.0f, 0.0f, 0.0f);
+ } else {
+ QT3DSVec3 rotVec(0.0f, -n.z, n.y);
+
+ // Convert to quat
+ NVReal angle = rotVec.magnitude();
+ rotVec *= 1.0f / angle;
+ // if(angle > 1.0f) angle = 1.0f;
+ angle = selectMin(angle, 1.0f);
+
+ // djs: injudiciously imbecilic use of trig functions, good thing Adam is going to trample
+ // this path like a
+ // frustrated rhinoceros in mating season
+
+ angle = NVAsin(angle);
+
+ // if(n.x < 0)
+ // angle = NVPi - angle;
+ angle = fsel(n.x, angle, NVPi - angle);
+
+ return QT3DSQuat(angle, rotVec);
+ }
+}
+
+/**
+\brief computes a oriented bounding box around the scaled basis.
+\param basis Input = skewed basis, Output = (normalized) orthogonal basis.
+\return Bounding box extent.
+*/
+QT3DSVec3 qt3ds::foundation::optimizeBoundingBox(QT3DSMat33 &basis)
+{
+ QT3DSVec3 *QT3DS_RESTRICT vec = &basis[0]; // PT: don't copy vectors if not needed...
+
+ // PT: since we store the magnitudes to memory, we can avoid the FCMNV afterwards
+ QT3DSVec3 magnitude(vec[0].magnitudeSquared(), vec[1].magnitudeSquared(),
+ vec[2].magnitudeSquared());
+
+// find indices sorted by magnitude
+#ifdef QT3DS_X360
+ int i = (QT3DSU32 &)(magnitude[1]) > (QT3DSU32 &)(magnitude[0]) ? 1 : 0;
+ int j = (QT3DSU32 &)(magnitude[2]) > (QT3DSU32 &)(magnitude[1 - i]) ? 2 : 1 - i;
+#else
+ int i = magnitude[1] > magnitude[0] ? 1 : 0;
+ int j = magnitude[2] > magnitude[1 - i] ? 2 : 1 - i;
+#endif
+ const int k = 3 - i - j;
+#ifdef QT3DS_X360
+ if ((QT3DSU32 &)(magnitude[i]) < (QT3DSU32 &)(magnitude[j]))
+#else
+ if (magnitude[i] < magnitude[j])
+#endif
+ swap(i, j);
+
+ // ortho-normalize basis
+
+ NVReal invSqrt = NVRecipSqrt(magnitude[i]);
+ magnitude[i] *= invSqrt;
+ vec[i] *= invSqrt; // normalize the first axis
+ NVReal dotij = vec[i].dot(vec[j]);
+ NVReal dotik = vec[i].dot(vec[k]);
+ magnitude[i] += NVAbs(dotij) + NVAbs(dotik); // elongate the axis by projection of the other two
+ vec[j] -= vec[i] * dotij; // orthogonize the two remaining axii relative to vec[i]
+ vec[k] -= vec[i] * dotik;
+
+ magnitude[j] = vec[j].normalize();
+ NVReal dotjk = vec[j].dot(vec[k]);
+ magnitude[j] += NVAbs(dotjk); // elongate the axis by projection of the other one
+ vec[k] -= vec[j] * dotjk; // orthogonize vec[k] relative to vec[j]
+
+ magnitude[k] = vec[k].normalize();
+
+ return magnitude;
+}
+
+QT3DSQuat qt3ds::foundation::slerp(const NVReal t, const QT3DSQuat &left, const QT3DSQuat &right)
+{
+ const NVReal quatEpsilon = (NVReal(1.0e-8f));
+
+ NVReal cosine = left.dot(right);
+ NVReal sign = NVReal(1);
+ if (cosine < 0) {
+ cosine = -cosine;
+ sign = NVReal(-1);
+ }
+
+ NVReal sine = NVReal(1) - cosine * cosine;
+
+ if (sine >= quatEpsilon * quatEpsilon) {
+ sine = NVSqrt(sine);
+ const NVReal angle = NVAtan2(sine, cosine);
+ const NVReal i_sin_angle = NVReal(1) / sine;
+
+ const NVReal leftw = NVSin(angle * (NVReal(1) - t)) * i_sin_angle;
+ const NVReal rightw = NVSin(angle * t) * i_sin_angle * sign;
+
+ return left * leftw + right * rightw;
+ }
+
+ return left;
+}
+
+void qt3ds::foundation::integrateTransform(const NVTransform &curTrans, const QT3DSVec3 &linvel,
+ const QT3DSVec3 &angvel, NVReal timeStep, NVTransform &result)
+{
+ result.p = curTrans.p + linvel * timeStep;
+
+ // from void NVsDynamicsContext::integrateAtomPose(NVsRigidBody* atom, Cm::BitMap
+ // &shapeChangedMap) const:
+ // Integrate the rotation using closed form quaternion integrator
+ NVReal w = angvel.magnitudeSquared();
+
+ if (w != 0.0f) {
+ w = NVSqrt(w);
+ if (w != 0.0f) {
+ const NVReal v = timeStep * w * 0.5f;
+ const NVReal q = NVCos(v);
+ const NVReal s = NVSin(v) / w;
+
+ const QT3DSVec3 pqr = angvel * s;
+ const QT3DSQuat quatVel(pqr.x, pqr.y, pqr.z, 0);
+ QT3DSQuat out; // need to have temporary, otherwise we may overwrite input if &curTrans ==
+ // &result.
+ out = quatVel * curTrans.q;
+ out.x += curTrans.q.x * q;
+ out.y += curTrans.q.y * q;
+ out.z += curTrans.q.z * q;
+ out.w += curTrans.q.w * q;
+ result.q = out;
+ return;
+ }
+ }
+ // orientation stays the same - convert from quat to matrix:
+ result.q = curTrans.q;
+}
diff --git a/src/foundation/Qt3DSMathUtils.h b/src/foundation/Qt3DSMathUtils.h
new file mode 100644
index 0000000..6d3d0ab
--- /dev/null
+++ b/src/foundation/Qt3DSMathUtils.h
@@ -0,0 +1,571 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSMATHUTILS_H
+#define QT3DS_FOUNDATION_PSMATHUTILS_H
+
+#include "foundation/Qt3DSTransform.h"
+#include "foundation/Qt3DSMat33.h"
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSIntrinsics.h"
+#include <stdlib.h>
+
+// General guideline is: if it's an abstract math function, it belongs here.
+// If it's a math function where the inputs have specific semantics (e.g.
+// separateSwingTwist) it doesn't.
+
+namespace qt3ds {
+namespace foundation {
+ using namespace intrinsics;
+ /**
+ \brief sign returns the sign of its argument. The sign of zero is undefined.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 sign(const QT3DSF32 a) {
+ return intrinsics::sign(a);
+ }
+
+ /**
+ \brief sign returns the sign of its argument. The sign of zero is undefined.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 sign(const QT3DSF64 a) { return (a >= 0.0) ? 1.0 : -1.0; }
+
+ /**
+ \brief sign returns the sign of its argument. The sign of zero is undefined.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSI32 sign(const QT3DSI32 a) { return (a >= 0) ? 1 : -1; }
+
+ /**
+ \brief Returns true if the two numbers are within eps of each other.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool equals(const QT3DSF32 a, const QT3DSF32 b, const QT3DSF32 eps)
+ {
+ return (NVAbs(a - b) < eps);
+ }
+
+ /**
+ \brief Returns true if the two numbers are within eps of each other.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool equals(const QT3DSF64 a, const QT3DSF64 b, const QT3DSF64 eps)
+ {
+ return (NVAbs(a - b) < eps);
+ }
+
+ /**
+ \brief The floor function returns a floating-point value representing the largest integer that
+ is less than or equal to x.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 floor(const QT3DSF32 a) { return floatFloor(a); }
+
+ /**
+ \brief The floor function returns a floating-point value representing the largest integer that
+ is less than or equal to x.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 floor(const QT3DSF64 a) { return ::floor(a); }
+
+ /**
+ \brief The ceil function returns a single value representing the smallest integer that is
+ greater than or equal to x.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 ceil(const QT3DSF32 a) { return ::ceilf(a); }
+
+ /**
+ \brief The ceil function returns a double value representing the smallest integer that is
+ greater than or equal to x.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 ceil(const QT3DSF64 a) { return ::ceil(a); }
+
+ /**
+ \brief mod returns the floating-point remainder of x / y.
+
+ If the value of y is 0.0, mod returns a quiet NaN.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 mod(const QT3DSF32 x, const QT3DSF32 y)
+ {
+ return (QT3DSF32)::fmod(x, y);
+ }
+
+ /**
+ \brief mod returns the floating-point remainder of x / y.
+
+ If the value of y is 0.0, mod returns a quiet NaN.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 mod(const QT3DSF64 x, const QT3DSF64 y)
+ {
+ return ::fmod(x, y);
+ }
+
+ /**
+ \brief Square.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 sqr(const QT3DSF32 a) { return a * a; }
+
+ /**
+ \brief Square.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 sqr(const QT3DSF64 a) { return a * a; }
+
+ /**
+ \brief Calculates x raised to the power of y.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 pow(const QT3DSF32 x, const QT3DSF32 y)
+ {
+ return ::powf(x, y);
+ }
+
+ /**
+ \brief Calculates x raised to the power of y.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 pow(const QT3DSF64 x, const QT3DSF64 y) { return ::pow(x, y); }
+
+ /**
+ \brief Calculates e^n
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 exp(const QT3DSF32 a) { return QT3DSF32(::exp(a)); }
+ /**
+
+ \brief Calculates e^n
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 exp(const QT3DSF64 a) { return ::exp(a); }
+
+ /**
+ \brief Calculates logarithms.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 logE(const QT3DSF32 a) { return QT3DSF32(::log(a)); }
+
+ /**
+ \brief Calculates logarithms.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 logE(const QT3DSF64 a) { return ::log(a); }
+
+ /**
+ \brief Calculates logarithms.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 log2(const QT3DSF32 a)
+ {
+ return QT3DSF32(::log(a)) / 0.693147180559945309417f;
+ }
+
+ /**
+ \brief Calculates logarithms.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 log2(const QT3DSF64 a)
+ {
+ return ::log(a) / 0.693147180559945309417;
+ }
+
+ /**
+ \brief Calculates logarithms.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 log10(const QT3DSF32 a) { return (QT3DSF32)::log10(a); }
+
+ /**
+ \brief Calculates logarithms.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 log10(const QT3DSF64 a) { return ::log10(a); }
+
+ /**
+ \brief Converts degrees to radians.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 degToRad(const QT3DSF32 a)
+ {
+ return (QT3DSF32)0.01745329251994329547 * a;
+ }
+
+ /**
+ \brief Converts degrees to radians.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 degToRad(const QT3DSF64 a)
+ {
+ return (QT3DSF64)0.01745329251994329547 * a;
+ }
+
+ /**
+ \brief Converts radians to degrees.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 radToDeg(const QT3DSF32 a)
+ {
+ return (QT3DSF32)57.29577951308232286465 * a;
+ }
+
+ /**
+ \brief Converts radians to degrees.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF64 radToDeg(const QT3DSF64 a)
+ {
+ return (QT3DSF64)57.29577951308232286465 * a;
+ }
+
+ //! \brief compute sine and cosine at the same time. There is a 'fsincos' on PC that we probably want to use here
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void sincos(const QT3DSF32 radians, QT3DSF32 &sin, QT3DSF32 &cos)
+ {
+ /* something like:
+ _asm fld Local
+ _asm fsincos
+ _asm fstp LocalCos
+ _asm fstp LocalSin
+ */
+ sin = NVSin(radians);
+ cos = NVCos(radians);
+ }
+
+ /**
+ \brief uniform random number in [a,b]
+ */
+ QT3DS_FORCE_INLINE QT3DSI32 rand(const QT3DSI32 a, const QT3DSI32 b)
+ {
+ return a + (QT3DSI32)(::rand() % (b - a + 1));
+ }
+
+ /**
+ \brief uniform random number in [a,b]
+ */
+ QT3DS_FORCE_INLINE QT3DSF32 rand(const QT3DSF32 a, const QT3DSF32 b)
+ {
+ return a + (b - a) * ::rand() / RAND_MAX;
+ }
+
+ //! \brief return angle between two vectors in radians
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSF32 angle(const QT3DSVec3 &v0, const QT3DSVec3 &v1)
+ {
+ const QT3DSF32 cos = v0.dot(v1); // |v0|*|v1|*Cos(Angle)
+ const QT3DSF32 sin = (v0.cross(v1)).magnitude(); // |v0|*|v1|*Sin(Angle)
+ return NVAtan2(sin, cos);
+ }
+
+ //! If possible use instead fsel on the dot product /*fsel(d.dot(p),onething,anotherthing);*/
+ //! Compares orientations (more readable, user-friendly function)
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool sameDirection(const QT3DSVec3 &d, const QT3DSVec3 &p)
+ {
+ return d.dot(p) >= 0.0f;
+ }
+
+ //! Checks 2 values have different signs
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE IntBool differentSign(NVReal f0, NVReal f1)
+ {
+ union {
+ QT3DSU32 u;
+ NVReal f;
+ } u1, u2;
+ u1.f = f0;
+ u2.f = f1;
+ return (u1.u ^ u2.u) & QT3DS_SIGN_BITMASK;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSMat33 star(const QT3DSVec3 &v)
+ {
+ return QT3DSMat33(QT3DSVec3(0, v.z, -v.y), QT3DSVec3(-v.z, 0, v.x), QT3DSVec3(v.y, -v.x, 0));
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 log(const QT3DSQuat &q)
+ {
+ const NVReal s = q.getImaginaryPart().magnitude();
+ if (s < 1e-12)
+ return QT3DSVec3(0.0f);
+ // force the half-angle to have magnitude <= pi/2
+ NVReal halfAngle = q.w < 0 ? NVAtan2(-s, -q.w) : NVAtan2(s, q.w);
+ QT3DS_ASSERT(halfAngle >= -NVPi / 2 && halfAngle <= NVPi / 2);
+
+ return q.getImaginaryPart().getNormalized() * 2 * halfAngle;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSQuat exp(const QT3DSVec3 &v)
+ {
+ const NVReal m = v.magnitudeSquared();
+ return m < 1e-24 ? QT3DSQuat::createIdentity() : QT3DSQuat(NVSqrt(m), v * NVRecipSqrt(m));
+ }
+
+ // quat to rotate v0 t0 v1
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSQuat rotationArc(const QT3DSVec3 &v0, const QT3DSVec3 &v1)
+ {
+ const QT3DSVec3 cross = v0.cross(v1);
+ const NVReal d = v0.dot(v1);
+ if (d <= -0.99999f)
+ return (NVAbs(v0.x) < 0.1f ? QT3DSQuat(0.0f, v0.z, -v0.y, 0.0f)
+ : QT3DSQuat(v0.y, -v0.x, 0.0, 0.0))
+ .getNormalized();
+
+ const NVReal s = NVSqrt((1 + d) * 2), r = 1 / s;
+
+ return QT3DSQuat(cross.x * r, cross.y * r, cross.z * r, s * 0.5f).getNormalized();
+ }
+
+ //! Computes the maximum delta to another transform
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal maxComponentDelta(const NVTransform &t0,
+ const NVTransform &t1)
+ {
+ NVReal delta = NVAbs(t0.p.x - t1.p.x);
+ delta = NVMax(delta, NVAbs(t0.p.y - t1.p.y));
+ delta = NVMax(delta, NVAbs(t0.p.z - t1.p.z));
+ delta = NVMax(delta, NVAbs(t0.q.x - t1.q.x));
+ delta = NVMax(delta, NVAbs(t0.q.y - t1.q.y));
+ delta = NVMax(delta, NVAbs(t0.q.z - t1.q.z));
+ delta = NVMax(delta, NVAbs(t0.q.w - t1.q.w));
+
+ return delta;
+ }
+
+ /**
+ \brief returns largest axis
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSU32 largestAxis(const QT3DSVec3 &v)
+ {
+ QT3DSU32 m = v.y > v.x ? 1 : 0;
+ return v.z > v[m] ? 2 : m;
+ }
+
+ /**
+ \brief returns axis with smallest absolute value
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSU32 closestAxis(const QT3DSVec3 &v)
+ {
+ QT3DSU32 m = NVAbs(v.y) > NVAbs(v.x) ? 1 : 0;
+ return NVAbs(v.z) > NVAbs(v[m]) ? 2 : m;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSU32 closestAxis(const QT3DSVec3 &v, QT3DSU32 &j, QT3DSU32 &k)
+ {
+ // find largest 2D plane projection
+ const QT3DSF32 absNV = NVAbs(v.x);
+ const QT3DSF32 absNy = NVAbs(v.y);
+ const QT3DSF32 absNz = NVAbs(v.z);
+
+ QT3DSU32 m = 0; // x biggest axis
+ j = 1;
+ k = 2;
+ if (absNy > absNV && absNy > absNz) {
+ // y biggest
+ j = 2;
+ k = 0;
+ m = 1;
+ } else if (absNz > absNV) {
+ // z biggest
+ j = 0;
+ k = 1;
+ m = 2;
+ }
+ return m;
+ }
+
+ /*!
+ Extend an edge along its length by a factor
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void makeFatEdge(QT3DSVec3 &p0, QT3DSVec3 &p1, NVReal fatCoeff)
+ {
+ QT3DSVec3 delta = p1 - p0;
+
+ const NVReal m = delta.magnitude();
+ if (m > 0.0f) {
+ delta *= fatCoeff / m;
+ p0 -= delta;
+ p1 += delta;
+ }
+ }
+
+ //! Compute point as combination of barycentric coordinates
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 computeBarycentricPoint(const QT3DSVec3 &p0,
+ const QT3DSVec3 &p1,
+ const QT3DSVec3 &p2, NVReal u,
+ NVReal v)
+ {
+ // This seems to confuse the compiler...
+ // return (1.0f - u - v)*p0 + u*p1 + v*p2;
+ const QT3DSF32 w = 1.0f - u - v;
+ return QT3DSVec3(w * p0.x + u * p1.x + v * p2.x, w * p0.y + u * p1.y + v * p2.y,
+ w * p0.z + u * p1.z + v * p2.z);
+ }
+
+ // generates a pair of quaternions (swing, twist) such that in = swing * twist, with
+ // swing.x = 0
+ // twist.y = twist.z = 0, and twist is a unit quat
+ QT3DS_FORCE_INLINE void separateSwingTwist(const QT3DSQuat &q, QT3DSQuat &swing, QT3DSQuat &twist)
+ {
+ twist = q.x != 0.0f ? QT3DSQuat(q.x, 0, 0, q.w).getNormalized() : QT3DSQuat::createIdentity();
+ swing = q * twist.getConjugate();
+ }
+
+ // generate two tangent vectors to a given normal
+ QT3DS_FORCE_INLINE void normalToTangents(const QT3DSVec3 &normal, QT3DSVec3 &tangent0, QT3DSVec3 &tangent1)
+ {
+ tangent0 = NVAbs(normal.x) < 0.70710678f ? QT3DSVec3(0, -normal.z, normal.y)
+ : QT3DSVec3(-normal.y, normal.x, 0);
+ tangent0.normalize();
+ tangent1 = normal.cross(tangent0);
+ }
+
+ // todo: what is this function doing?
+ QT3DS_FOUNDATION_API QT3DSQuat computeQuatFromNormal(const QT3DSVec3 &n);
+
+ /**
+ \brief computes a oriented bounding box around the scaled basis.
+ \param basis Input = skewed basis, Output = (normalized) orthogonal basis.
+ \return Bounding box extent.
+ */
+ QT3DS_FOUNDATION_API QT3DSVec3 optimizeBoundingBox(QT3DSMat33 &basis);
+
+ QT3DS_FOUNDATION_API QT3DSQuat slerp(const NVReal t, const QT3DSQuat &left, const QT3DSQuat &right);
+
+ QT3DS_INLINE QT3DSVec3 ellipseClamp(const QT3DSVec3 &point, const QT3DSVec3 &radii)
+ {
+ // This function need to be implemented in the header file because
+ // it is included in a spu shader program.
+
+ // finds the closest point on the ellipse to a given point
+
+ // (p.y, p.z) is the input point
+ // (e.y, e.z) are the radii of the ellipse
+
+ // lagrange multiplier method with Newton/Halley hybrid root-finder.
+ // see http://www.geometrictools.com/Documentation/DistancePointToEllipse2.pdf
+ // for proof of Newton step robustness and initial estimate.
+ // Halley converges much faster but sometimes overshoots - when that happens we take
+ // a newton step instead
+
+ // converges in 1-2 iterations where D&C works well, and it's good with 4 iterations
+ // with any ellipse that isn't completely crazy
+
+ const QT3DSU32 MAX_ITERATIONS = 20;
+ const NVReal convergenceThreshold = 1e-4f;
+
+ // iteration requires first quadrant but we recover generality later
+
+ QT3DSVec3 q(0, NVAbs(point.y), NVAbs(point.z));
+ const NVReal tinyEps =
+ (NVReal)(1e-6f); // very close to minor axis is numerically problematic but trivial
+ if (radii.y >= radii.z) {
+ if (q.z < tinyEps)
+ return QT3DSVec3(0, point.y > 0 ? radii.y : -radii.y, 0);
+ } else {
+ if (q.y < tinyEps)
+ return QT3DSVec3(0, 0, point.z > 0 ? radii.z : -radii.z);
+ }
+
+ QT3DSVec3 denom, e2 = radii.multiply(radii), eq = radii.multiply(q);
+
+ // we can use any initial guess which is > maximum(-e.y^2,-e.z^2) and for which f(t) is > 0.
+ // this guess works well near the axes, but is weak along the diagonals.
+
+ NVReal t = NVMax(eq.y - e2.y, eq.z - e2.z);
+
+ for (QT3DSU32 i = 0; i < MAX_ITERATIONS; i++) {
+ denom = QT3DSVec3(0, 1 / (t + e2.y), 1 / (t + e2.z));
+ QT3DSVec3 denom2 = eq.multiply(denom);
+
+ QT3DSVec3 fv = denom2.multiply(denom2);
+ NVReal f = fv.y + fv.z - 1;
+
+ // although in exact arithmetic we are guaranteed f>0, we can get here
+ // on the first iteration via catastrophic cancellation if the point is
+ // very close to the origin. In that case we just behave as if f=0
+
+ if (f < convergenceThreshold)
+ return e2.multiply(point).multiply(denom);
+
+ NVReal df = fv.dot(denom) * -2.0f;
+ t = t - f / df;
+ }
+
+ // we didn't converge, so clamp what we have
+ QT3DSVec3 r = e2.multiply(point).multiply(denom);
+ return r * NVRecipSqrt(sqr(r.y / radii.y) + sqr(r.z / radii.z));
+ }
+
+ QT3DS_INLINE NVReal tanHalf(NVReal sin, NVReal cos) { return sin / (1 + cos); }
+
+ QT3DS_INLINE QT3DSQuat quatFromTanQVector(const QT3DSVec3 &v)
+ {
+ NVReal v2 = v.dot(v);
+ if (v2 < 1e-12f)
+ return QT3DSQuat::createIdentity();
+ NVReal d = 1 / (1 + v2);
+ return QT3DSQuat(v.x * 2, v.y * 2, v.z * 2, 1 - v2) * d;
+ }
+
+ QT3DS_FORCE_INLINE QT3DSVec3 cross100(const QT3DSVec3 &b) { return QT3DSVec3(0.0f, -b.z, b.y); }
+ QT3DS_FORCE_INLINE QT3DSVec3 cross010(const QT3DSVec3 &b) { return QT3DSVec3(b.z, 0.0f, -b.x); }
+ QT3DS_FORCE_INLINE QT3DSVec3 cross001(const QT3DSVec3 &b) { return QT3DSVec3(-b.y, b.x, 0.0f); }
+
+ QT3DS_INLINE void decomposeVector(QT3DSVec3 &normalCompo, QT3DSVec3 &tangentCompo,
+ const QT3DSVec3 &outwardDir, const QT3DSVec3 &outwardNormal)
+ {
+ normalCompo = outwardNormal * (outwardDir.dot(outwardNormal));
+ tangentCompo = outwardDir - normalCompo;
+ }
+
+ //! \brief Return (i+1)%3
+ // Avoid variable shift for XBox:
+ // QT3DS_INLINE QT3DSU32 NV::getNextIndex3(QT3DSU32 i) { return (1<<i) & 3;
+ // }
+ QT3DS_INLINE QT3DSU32 getNextIndex3(QT3DSU32 i) { return (i + 1 + (i >> 1)) & 3; }
+
+ QT3DS_INLINE QT3DSMat33 rotFrom2Vectors(const QT3DSVec3 &from, const QT3DSVec3 &to)
+ {
+ // See bottom of
+ // http://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/index.htm
+
+ // Early exit if to = from
+ if ((from - to).magnitudeSquared() < 1e-4f)
+ return QT3DSMat33::createIdentity();
+
+ // Early exit if to = -from
+ if ((from + to).magnitudeSquared() < 1e-4f)
+ return QT3DSMat33::createDiagonal(QT3DSVec3(1.0f, -1.0f, -1.0f));
+
+ QT3DSVec3 n = from.cross(to);
+
+ NVReal C = from.dot(to), S = NVSqrt(1 - C * C), CC = 1 - C;
+
+ NVReal xx = n.x * n.x, yy = n.y * n.y, zz = n.z * n.z, xy = n.x * n.y, yz = n.y * n.z,
+ xz = n.x * n.z;
+
+ QT3DSMat33 R;
+
+ R(0, 0) = 1 + CC * (xx - 1);
+ R(0, 1) = -n.z * S + CC * xy;
+ R(0, 2) = n.y * S + CC * xz;
+
+ R(1, 0) = n.z * S + CC * xy;
+ R(1, 1) = 1 + CC * (yy - 1);
+ R(1, 2) = -n.x * S + CC * yz;
+
+ R(2, 0) = -n.y * S + CC * xz;
+ R(2, 1) = n.x * S + CC * yz;
+ R(2, 2) = 1 + CC * (zz - 1);
+
+ return R;
+ }
+
+ QT3DS_FOUNDATION_API void integrateTransform(const NVTransform &curTrans, const QT3DSVec3 &linvel,
+ const QT3DSVec3 &angvel, NVReal timeStep,
+ NVTransform &result);
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSMemoryBuffer.h b/src/foundation/Qt3DSMemoryBuffer.h
new file mode 100644
index 0000000..bee2f0c
--- /dev/null
+++ b/src/foundation/Qt3DSMemoryBuffer.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_MEMORYBUFFER_H
+#define QT3DS_FOUNDATION_MEMORYBUFFER_H
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSDataRef.h"
+#include "foundation/Qt3DSIntrinsics.h"
+
+#ifdef __INTEGRITY
+#define __restrict
+#endif
+
+namespace qt3ds {
+namespace foundation {
+ using namespace intrinsics;
+
+ template <typename TAllocator = ForwardingAllocator>
+ class MemoryBuffer : public TAllocator
+ {
+ QT3DSU8 *mBegin;
+ QT3DSU8 *mEnd;
+ QT3DSU8 *mCapacityEnd;
+
+ public:
+ MemoryBuffer(const TAllocator &inAlloc = TAllocator())
+ : TAllocator(inAlloc)
+ , mBegin(0)
+ , mEnd(0)
+ , mCapacityEnd(0)
+ {
+ }
+ ~MemoryBuffer()
+ {
+ if (mBegin)
+ TAllocator::deallocate(mBegin);
+ }
+ QT3DSU32 size() const { return static_cast<QT3DSU32>(mEnd - mBegin); }
+ QT3DSU32 capacity() const { return static_cast<QT3DSU32>(mCapacityEnd - mBegin); }
+ QT3DSU8 *begin() { return mBegin; }
+ QT3DSU8 *end() { return mEnd; }
+ const QT3DSU8 *begin() const { return mBegin; }
+ const QT3DSU8 *end() const { return mEnd; }
+ void clear() { mEnd = mBegin; }
+ void write(QT3DSU8 inValue) { *growBuf(1) = inValue; }
+
+ template <typename TDataType>
+ void write(const TDataType &inValue)
+ {
+ const QT3DSU8 *__restrict readPtr = reinterpret_cast<const QT3DSU8 *>(&inValue);
+ QT3DSU8 *__restrict writePtr = growBuf(sizeof(TDataType));
+ for (QT3DSU32 idx = 0; idx < sizeof(TDataType); ++idx)
+ writePtr[idx] = readPtr[idx];
+ }
+
+ template <typename TDataType>
+ void write(const TDataType *inValue, QT3DSU32 inLength)
+ {
+ using namespace qt3ds::intrinsics;
+ if (inValue && inLength) {
+ QT3DSU32 writeSize = inLength * sizeof(TDataType);
+ memCopy(growBuf(writeSize), inValue, writeSize);
+ }
+ if (inLength && !inValue) {
+ QT3DS_ASSERT(false);
+ // You can't not write something, because that will cause
+ // the receiving end to crash.
+ QT3DSU32 writeSize = inLength * sizeof(TDataType);
+ for (QT3DSU32 idx = 0; idx < writeSize; ++idx)
+ write((QT3DSU8)0);
+ }
+ }
+
+ void writeStrided(const QT3DSU8 *__restrict inData, QT3DSU32 inItemSize, QT3DSU32 inLength,
+ QT3DSU32 inStride)
+ {
+ if (inStride == 0 || inStride == inItemSize)
+ write(inData, inLength * inItemSize);
+ else if (inData && inLength) {
+ QT3DSU32 writeSize = inLength * inItemSize;
+ QT3DSU8 *__restrict writePtr = growBuf(writeSize);
+ for (QT3DSU32 idx = 0; idx < inLength;
+ ++idx, writePtr += inItemSize, inData += inStride)
+ memCopy(writePtr, inData, inItemSize);
+ }
+ }
+ QT3DSU8 *growBuf(QT3DSU32 inAmount)
+ {
+ QT3DSU32 offset = size();
+ QT3DSU32 newSize = offset + inAmount;
+ reserve(newSize);
+ mEnd += inAmount;
+ return mBegin + offset;
+ }
+ void writeZeros(QT3DSU32 inAmount)
+ {
+ QT3DSU32 offset = size();
+ growBuf(inAmount);
+ qt3ds::foundation::memZero(begin() + offset, inAmount);
+ }
+ void align(QT3DSU32 inAmount)
+ {
+ QT3DSU32 leftover = size() % inAmount;
+ if (leftover)
+ writeZeros(inAmount - leftover);
+ }
+ void reserve(QT3DSU32 newSize)
+ {
+ using namespace qt3ds::intrinsics;
+ QT3DSU32 currentSize = size();
+ if (newSize && newSize >= capacity()) {
+ QT3DSU32 newDataSize = newSize * 2;
+ if (newDataSize > 8192)
+ newDataSize = (QT3DSU32)((QT3DSU32)newSize * 1.2f);
+ QT3DSU8 *newData =
+ static_cast<QT3DSU8 *>(TAllocator::allocate(newDataSize, __FILE__, __LINE__));
+ if (mBegin) {
+ memCopy(newData, mBegin, currentSize);
+ TAllocator::deallocate(mBegin);
+ }
+ mBegin = newData;
+ mEnd = mBegin + currentSize;
+ mCapacityEnd = mBegin + newDataSize;
+ }
+ }
+ operator NVDataRef<QT3DSU8>() { return NVDataRef<QT3DSU8>(begin(), size()); }
+ operator NVConstDataRef<QT3DSU8>() const { return NVConstDataRef<QT3DSU8>(begin(), size()); }
+ };
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/foundation/Qt3DSMutex.h b/src/foundation/Qt3DSMutex.h
new file mode 100644
index 0000000..5b717e5
--- /dev/null
+++ b/src/foundation/Qt3DSMutex.h
@@ -0,0 +1,376 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSMUTEX_H
+#define QT3DS_FOUNDATION_PSMUTEX_H
+
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSNoCopy.h"
+
+/*
+ * This <new> inclusion is a best known fix for gcc 4.4.1 error:
+ * Creating object file for apex/src/NVAllocator.cpp ...
+ * In file included from apex/include/Qt3DSFoundation.h:30,
+ * from apex/src/NVAllocator.cpp:26:
+ * apex/include/Qt3DSMutex.h: In constructor 'nv::foundation::MutexT<Alloc>::MutexT(const Alloc&)':
+ * apex/include/Qt3DSMutex.h:92: error: no matching function for call to 'operator new(unsigned int,
+ * qt3ds::foundation::MutexImpl*&)'
+ * <built-in>:0: note: candidates are: void* operator new(unsigned int)
+ */
+#include <new>
+
+namespace qt3ds {
+namespace foundation {
+#ifdef QT3DS_FOUNDATION_NO_EXPORTS
+ class QT3DS_AUTOTEST_EXPORT MutexImpl
+#else
+ class QT3DS_FOUNDATION_API MutexImpl
+#endif
+ {
+ public:
+ /**
+ The constructor for Mutex creates a mutex. It is initially unlocked.
+ */
+ MutexImpl();
+
+ /**
+ The destructor for Mutex deletes the mutex.
+ */
+ ~MutexImpl();
+
+ /**
+ Acquire (lock) the mutex. If the mutex is already locked
+ by another thread, this method blocks until the mutex is
+ unlocked.
+ */
+ bool lock();
+
+ /**
+ Acquire (lock) the mutex. If the mutex is already locked
+ by another thread, this method returns false without blocking.
+ */
+ bool trylock();
+
+ /**
+ Release (unlock) the mutex.
+ */
+ bool unlock();
+
+ /**
+ Size of this class.
+ */
+ static const QT3DSU32 size;
+ };
+
+ class Mutex
+ {
+ public:
+ class ScopedLock : private NoCopy
+ {
+ Mutex &mMutex;
+
+ public:
+ QT3DS_INLINE ScopedLock(Mutex &mutex)
+ : mMutex(mutex)
+ {
+ mMutex.lock();
+ }
+ QT3DS_INLINE ~ScopedLock() { mMutex.unlock(); }
+ };
+
+ /**
+ The constructor for Mutex creates a mutex. It is initially unlocked.
+ */
+ Mutex(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ mImpl = (MutexImpl *)QT3DS_ALLOC(alloc, MutexImpl::size, "MutexImpl");
+ QT3DS_PLACEMENT_NEW(mImpl, MutexImpl)();
+ }
+
+ /**
+ The destructor for Mutex deletes the mutex.
+ */
+ ~Mutex()
+ {
+ mImpl->~MutexImpl();
+ QT3DS_FREE(mAllocator, mImpl);
+ }
+
+ /**
+ Acquire (lock) the mutex. If the mutex is already locked
+ by another thread, this method blocks until the mutex is
+ unlocked.
+ */
+ bool lock() const { return mImpl->lock(); }
+
+ /**
+ Acquire (lock) the mutex. If the mutex is already locked
+ by another thread, this method returns false without blocking.
+ */
+ bool trylock() const { return mImpl->trylock(); }
+
+ /**
+ Release (unlock) the mutex.
+ */
+ bool unlock() const { return mImpl->unlock(); }
+
+ private:
+ NVAllocatorCallback &mAllocator;
+ MutexImpl *mImpl;
+ };
+
+ class QT3DS_FOUNDATION_API ReadWriteLock : private NoCopy
+ {
+ public:
+ ReadWriteLock(NVAllocatorCallback &alloc);
+ ~ReadWriteLock();
+
+ void lockReader();
+ void lockWriter();
+
+ void unlockReader();
+ void unlockWriter();
+
+ private:
+ class ReadWriteLockImpl *mImpl;
+ };
+
+ class ScopedReadLock : private NoCopy
+ {
+ public:
+ QT3DS_INLINE ScopedReadLock(ReadWriteLock &lock)
+ : mLock(lock)
+ {
+ mLock.lockReader();
+ }
+ QT3DS_INLINE ~ScopedReadLock() { mLock.unlockReader(); }
+
+ private:
+ ReadWriteLock &mLock;
+ };
+
+ class ScopedWriteLock : private NoCopy
+ {
+ public:
+ QT3DS_INLINE ScopedWriteLock(ReadWriteLock &lock)
+ : mLock(lock)
+ {
+ mLock.lockWriter();
+ }
+ QT3DS_INLINE ~ScopedWriteLock() { mLock.unlockWriter(); }
+
+ private:
+ ReadWriteLock &mLock;
+ };
+
+/*
+ * Use this type of lock for mutex behaviour that must operate on SPU and PPU
+ * On non-PS3 platforms, it is implemented using Mutex
+ */
+#ifndef QT3DS_PS3
+
+ class AtomicLock : private NoCopy
+ {
+ Mutex mMutex;
+
+ public:
+ AtomicLock(NVAllocatorCallback &alloc)
+ : mMutex(alloc)
+ {
+ }
+
+ bool lock() { return mMutex.lock(); }
+
+ bool trylock() { return mMutex.trylock(); }
+
+ bool unlock() { return mMutex.unlock(); }
+ };
+
+ class AtomicLockCopy
+ {
+ AtomicLock *pLock;
+
+ public:
+ AtomicLockCopy()
+ : pLock(NULL)
+ {
+ }
+
+ AtomicLockCopy &operator=(AtomicLock &lock)
+ {
+ pLock = &lock;
+ return *this;
+ }
+
+ bool lock() { return pLock->lock(); }
+
+ bool trylock() { return pLock->trylock(); }
+
+ bool unlock() { return pLock->unlock(); }
+ };
+#else
+ struct AtomicLockImpl
+ {
+ QT3DS_ALIGN(128, QT3DSU32 m_Lock);
+ QT3DSI32 m_LockId;
+ QT3DSU32 m_LockCount;
+
+ AtomicLockImpl();
+ };
+ class AtomicLock //: private NoCopy
+ {
+ friend class AtomicLockCopy;
+ AtomicLockImpl *m_pImpl;
+
+ public:
+ AtomicLock();
+
+ ~AtomicLock();
+
+ bool lock();
+
+ bool trylock();
+
+ bool unlock();
+ };
+
+ // if an AtomicLock is copied and then the copy goes out of scope, it'll delete the atomic
+ // primitive
+ // (just a 128-byte aligned int) and cause a crash when it tries to delete it again
+ // This class just uses the atomic primitive without releasing it in the end.
+
+ class AtomicLockCopy
+ {
+ AtomicLockImpl *m_pImpl;
+
+ public:
+ AtomicLockCopy()
+ : m_pImpl(NULL)
+ {
+ }
+
+ AtomicLockCopy(const AtomicLock &lock)
+ : m_pImpl(lock.m_pImpl)
+ {
+ }
+
+ ~AtomicLockCopy() {}
+
+ AtomicLockCopy &operator=(const AtomicLock &lock)
+ {
+ m_pImpl = lock.m_pImpl;
+ return *this;
+ }
+
+ bool lock();
+
+ bool trylock();
+
+ bool unlock();
+ };
+#endif
+
+#ifndef QT3DS_PS3
+
+ class AtomicRwLock : private NoCopy
+ {
+ ReadWriteLock m_Lock;
+
+ public:
+ AtomicRwLock(NVAllocatorCallback &alloc)
+ : m_Lock(alloc)
+ {
+ }
+
+ void lockReader() { m_Lock.lockReader(); }
+ void lockWriter() { m_Lock.lockWriter(); }
+
+ bool tryLockReader()
+ {
+ // Todo - implement this
+ m_Lock.lockReader();
+ return true;
+ }
+
+ void unlockReader() { m_Lock.unlockReader(); }
+ void unlockWriter() { m_Lock.unlockWriter(); }
+ };
+#else
+
+ struct AtomicRwLockImpl
+ {
+ QT3DS_ALIGN(128, volatile QT3DSU32 m_Lock);
+ QT3DS_ALIGN(128, volatile QT3DSU32 m_ReadCounter);
+ QT3DSI32 m_LockId;
+ QT3DSU32 m_LockCount;
+
+ AtomicRwLockImpl();
+ };
+
+ class AtomicRwLock : private NoCopy
+ {
+ AtomicRwLockImpl *m_pImpl;
+
+ public:
+ AtomicRwLock();
+
+ ~AtomicRwLock();
+
+ void lockReader();
+
+ bool tryLockReader();
+
+ void lockWriter();
+
+ void unlockReader();
+
+ void unlockWriter();
+ };
+
+#endif
+
+ class ScopedAtomicLock : private NoCopy
+ {
+ QT3DS_INLINE ScopedAtomicLock(AtomicLock &lock)
+ : mLock(lock)
+ {
+ mLock.lock();
+ }
+ QT3DS_INLINE ~ScopedAtomicLock() { mLock.unlock(); }
+
+ private:
+ AtomicLock &mLock;
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSNoCopy.h b/src/foundation/Qt3DSNoCopy.h
new file mode 100644
index 0000000..817f5e1
--- /dev/null
+++ b/src/foundation/Qt3DSNoCopy.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSNOCOPY_H
+#define QT3DS_FOUNDATION_PSNOCOPY_H
+
+#include "foundation/Qt3DS.h"
+
+namespace qt3ds {
+namespace foundation {
+ class NoCopy
+ {
+ NoCopy(const NoCopy &c);
+ NoCopy &operator=(const NoCopy &c);
+
+ public:
+ NoCopy() {}
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSOption.h b/src/foundation/Qt3DSOption.h
new file mode 100644
index 0000000..18d6c3b
--- /dev/null
+++ b/src/foundation/Qt3DSOption.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_OPTION_H
+#define QT3DS_FOUNDATION_OPTION_H
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAssert.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ struct Empty
+ {
+ };
+
+ template <typename TDataType>
+ class Option
+ {
+ TDataType mData;
+ bool mHasValue;
+
+ public:
+ Option(const TDataType &data)
+ : mData(data)
+ , mHasValue(true)
+ {
+ }
+ Option(const Empty &)
+ : mHasValue(false)
+ {
+ }
+ Option()
+ : mHasValue(false)
+ {
+ }
+ Option(const Option &other)
+ : mData(other.mData)
+ , mHasValue(other.mHasValue)
+ {
+ }
+ Option &operator=(const Option &other)
+ {
+ mData = other.mData;
+ mHasValue = other.mHasValue;
+ return *this;
+ }
+
+ bool isEmpty() const { return !mHasValue; }
+ void setEmpty() { mHasValue = false; }
+ bool hasValue() const { return mHasValue; }
+
+ const TDataType &getValue() const
+ {
+ QT3DS_ASSERT(mHasValue);
+ return mData;
+ }
+ TDataType &getValue()
+ {
+ QT3DS_ASSERT(mHasValue);
+ return mData;
+ }
+ TDataType &unsafeGetValue() { return mData; }
+
+ operator const TDataType &() const { return getValue(); }
+ operator TDataType &() { return getValue(); }
+
+ const TDataType *operator->() const { return &getValue(); }
+ TDataType *operator->() { return &getValue(); }
+
+ const TDataType &operator*() const { return getValue(); }
+ TDataType &operator*() { return getValue(); }
+ };
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/foundation/Qt3DSPerfTimer.cpp b/src/foundation/Qt3DSPerfTimer.cpp
new file mode 100644
index 0000000..06fb5d3
--- /dev/null
+++ b/src/foundation/Qt3DSPerfTimer.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "foundation/Qt3DSPerfTimer.h"
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "EASTL/hash_map.h"
+#include "EASTL/string.h"
+#include "EASTL/vector.h"
+#include "EASTL/sort.h"
+
+using namespace qt3ds::foundation;
+using namespace qt3ds;
+
+namespace {
+struct STimerEntry
+{
+ QT3DSU64 m_Total;
+ QT3DSU64 m_Max;
+ QT3DSU32 m_UpdateCount;
+ CRegisteredString m_Tag;
+ size_t m_Order;
+
+ STimerEntry(CRegisteredString tag, size_t order)
+ : m_Total(0)
+ , m_Max(0)
+ , m_UpdateCount(0)
+ , m_Tag(tag)
+ , m_Order(order)
+ {
+ }
+ void Update(QT3DSU64 increment)
+ {
+ m_Total += increment;
+ m_Max = increment > m_Max ? increment : m_Max;
+ ++m_UpdateCount;
+ }
+
+ void Output(NVFoundationBase &fnd, QT3DSU32 inFramesPassed)
+ {
+ Q_UNUSED(fnd)
+ if (m_Total) {
+ QT3DSU64 tensNanos = Time::sCounterFreq.toTensOfNanos(m_Total);
+ QT3DSU64 maxNanos = Time::sCounterFreq.toTensOfNanos(m_Max);
+
+ double milliseconds = tensNanos / 100000.0;
+ double maxMilliseconds = maxNanos / 100000.0;
+ if (inFramesPassed == 0)
+ qCWarning(WARNING, PERF_INFO, "%s - %fms", m_Tag.c_str(), milliseconds);
+ else {
+ milliseconds /= inFramesPassed;
+ qCWarning(WARNING, PERF_INFO, "%s - %fms/frame-total %fms-max %u hits",
+ m_Tag.c_str(), milliseconds, maxMilliseconds, m_UpdateCount);
+ }
+ }
+ }
+
+ void Reset()
+ {
+ m_Total = 0;
+ m_Max = 0;
+ m_UpdateCount = 0;
+ }
+
+ bool operator<(const STimerEntry &other) const { return m_Order < other.m_Order; }
+};
+struct SPerfTimer : public IPerfTimer
+{
+ typedef eastl::hash_map<CRegisteredString, STimerEntry> THashMapType;
+ NVFoundationBase &m_Foundation;
+ // This object needs its own string table because it is used during the binary load process with
+ // the application string table gets booted up.
+ NVScopedRefCounted<IStringTable> m_StringTable;
+ THashMapType m_Entries;
+ eastl::vector<STimerEntry> m_PrintEntries;
+ Mutex m_Mutex;
+ QT3DSI32 mRefCount;
+
+ SPerfTimer(NVFoundationBase &fnd)
+ : m_Foundation(fnd)
+ , m_StringTable(IStringTable::CreateStringTable(fnd.getAllocator()))
+ , m_Mutex(fnd.getAllocator())
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Foundation.getAllocator())
+
+ void Update(const char *inId, QT3DSU64 inAmount) override
+ {
+ Mutex::ScopedLock __locker(m_Mutex);
+ CRegisteredString theStr(m_StringTable->RegisterStr(inId));
+ THashMapType::iterator theFind =
+ m_Entries.insert(eastl::make_pair(theStr, STimerEntry(theStr, m_Entries.size()))).first;
+ theFind->second.Update(inAmount);
+ }
+
+ // Dump current summation of timer data.
+ void OutputTimerData(QT3DSU32 inFramesPassed = 0) override
+ {
+ Mutex::ScopedLock __locker(m_Mutex);
+ m_PrintEntries.clear();
+ for (THashMapType::iterator iter = m_Entries.begin(), end = m_Entries.end(); iter != end;
+ ++iter) {
+ m_PrintEntries.push_back(iter->second);
+ iter->second.Reset();
+ }
+
+ eastl::sort(m_PrintEntries.begin(), m_PrintEntries.end());
+
+ for (QT3DSU32 idx = 0, end = (QT3DSU32)m_PrintEntries.size(); idx < end; ++idx) {
+ m_PrintEntries[idx].Output(m_Foundation, inFramesPassed);
+ }
+ }
+
+ void ResetTimerData() override
+ {
+ Mutex::ScopedLock __locker(m_Mutex);
+ for (THashMapType::iterator iter = m_Entries.begin(), end = m_Entries.end(); iter != end;
+ ++iter) {
+ iter->second.Reset();
+ }
+ }
+
+ virtual void ClearPerfKeys()
+ {
+ Mutex::ScopedLock __locker(m_Mutex);
+ m_Entries.clear();
+ }
+};
+}
+
+IPerfTimer &IPerfTimer::CreatePerfTimer(NVFoundationBase &fnd)
+{
+ return *QT3DS_NEW(fnd.getAllocator(), SPerfTimer)(fnd);
+}
diff --git a/src/foundation/Qt3DSPerfTimer.h b/src/foundation/Qt3DSPerfTimer.h
new file mode 100644
index 0000000..c63091c
--- /dev/null
+++ b/src/foundation/Qt3DSPerfTimer.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PERFTIMER_H
+#define QT3DS_FOUNDATION_PERFTIMER_H
+
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSTime.h"
+#include "foundation/Qt3DSRefCounted.h"
+#include "foundation/StringTable.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ class IPerfTimer : public NVRefCounted
+ {
+ protected:
+ virtual ~IPerfTimer() {}
+ public:
+ // amount is in counter frequency units
+ virtual void Update(const char *inTag, QT3DSU64 inAmount) = 0;
+ // Dump current summation of timer data.
+ virtual void OutputTimerData(QT3DSU32 inFrameCount = 0) = 0;
+ virtual void ResetTimerData() = 0;
+
+ static IPerfTimer &CreatePerfTimer(NVFoundationBase &inFoundation);
+ };
+
+ // Specialize this struct to get the perf timer in different contexts.
+ template <typename TTimerProvider>
+ struct STimerProvider
+ {
+ static IPerfTimer &getPerfTimer(TTimerProvider &inProvider)
+ {
+ return inProvider.getPerfTimer();
+ }
+ };
+
+ template <typename TTimerProvider>
+ IPerfTimer &getPerfTimer(TTimerProvider &inProvider)
+ {
+ return STimerProvider<TTimerProvider>::getPerfTimer(inProvider);
+ }
+
+ struct SStackPerfTimer
+ {
+ IPerfTimer *m_Timer;
+ QT3DSU64 m_Start;
+ const char *m_Id;
+
+ SStackPerfTimer(IPerfTimer &destination, const char *inId)
+ : m_Timer(&destination)
+ , m_Start(Time::getCurrentCounterValue())
+ , m_Id(inId)
+ {
+ }
+
+ SStackPerfTimer(IPerfTimer *destination, const char *inId)
+ : m_Timer(destination)
+ , m_Start(Time::getCurrentCounterValue())
+ , m_Id(inId)
+ {
+ }
+
+ ~SStackPerfTimer()
+ {
+ if (m_Timer) {
+ QT3DSU64 theStop = Time::getCurrentCounterValue();
+ QT3DSU64 theAmount = theStop - m_Start;
+ m_Timer->Update(m_Id, theAmount);
+ }
+ }
+ };
+}
+}
+
+#define QT3DS_FOUNDATION_PERF_SCOPED_TIMER(context, name) \
+ SStackPerfTimer __perfTimer(getPerfTimer(context), #name);
+
+#endif \ No newline at end of file
diff --git a/src/foundation/Qt3DSPlane.h b/src/foundation/Qt3DSPlane.h
new file mode 100644
index 0000000..378c3bc
--- /dev/null
+++ b/src/foundation/Qt3DSPlane.h
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_PLANE_H
+#define QT3DS_FOUNDATION_QT3DS_PLANE_H
+
+/** \addtogroup foundation
+@{
+*/
+
+#include "foundation/Qt3DSMath.h"
+#include "foundation/Qt3DSVec3.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+/**
+\brief Representation of a plane.
+
+ Plane equation used: n.dot(v) + d = 0
+*/
+class NVPlane
+{
+public:
+ /**
+ \brief Constructor
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVPlane() {}
+
+ /**
+ \brief Constructor from a normal and a distance
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVPlane(NVReal nx, NVReal ny, NVReal nz, NVReal distance)
+ : n(nx, ny, nz)
+ , d(distance)
+ {
+ }
+
+ /**
+ \brief Constructor from a normal and a distance
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVPlane(const QT3DSVec3 &normal, NVReal distance)
+ : n(normal)
+ , d(distance)
+ {
+ }
+
+ /**
+ \brief Constructor from a point on the plane and a normal
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVPlane(const QT3DSVec3 &point, const QT3DSVec3 &normal)
+ : n(normal)
+ , d(-point.dot(n)) // p satisfies normal.dot(p) + d = 0
+ {
+ }
+
+ /**
+ \brief Constructor from three points
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVPlane(const QT3DSVec3 &p0, const QT3DSVec3 &p1, const QT3DSVec3 &p2)
+ {
+ n = (p1 - p0).cross(p2 - p0).getNormalized();
+ d = -p0.dot(n);
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal distance(const QT3DSVec3 &p) const { return p.dot(n) + d; }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool contains(const QT3DSVec3 &p) const
+ {
+ return NVAbs(distance(p)) < (1.0e-7f);
+ }
+
+ /**
+ \brief projects p into the plane
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 project(const QT3DSVec3 &p) const
+ {
+ return p - n * distance(p);
+ }
+
+ /**
+ \brief find an arbitrary point in the plane
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 pointInPlane() const { return -n * d; }
+
+ /**
+ \brief equivalent plane with unit normal
+ */
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void normalize()
+ {
+ NVReal denom = 1.0f / n.magnitude();
+ n *= denom;
+ d *= denom;
+ }
+
+ QT3DSVec3 n; //!< The normal to the plane
+ NVReal d; //!< The distance from the origin
+};
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif
diff --git a/src/foundation/Qt3DSPool.h b/src/foundation/Qt3DSPool.h
new file mode 100644
index 0000000..5bd07f8
--- /dev/null
+++ b/src/foundation/Qt3DSPool.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_POOL_H
+#define QT3DS_POOL_H
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSMath.h" //NVMax
+#include "EASTL/vector.h"
+
+namespace qt3ds {
+namespace foundation {
+ // Pool of fixed size objects.
+ template <typename TObjType, typename TAllocator = EASTLAllocatorType,
+ QT3DSU32 alignmentInBytes = 4, QT3DSU32 slabSize = 4096>
+ class Pool
+ {
+ protected:
+ TAllocator mAllocator;
+ struct Link
+ {
+ Link *mNext;
+ Link(Link *next = NULL)
+ : mNext(next)
+ {
+ }
+ };
+ eastl::vector<void *, TAllocator> mSlabs;
+ Link *mFreeList;
+
+ public:
+ Pool(const TAllocator &alloc = TAllocator())
+ : mAllocator(alloc)
+ , mSlabs(alloc)
+ , mFreeList(NULL)
+ {
+ StaticAssert<sizeof(TObjType) < slabSize>::valid_expression();
+ }
+ ~Pool()
+ {
+ for (QT3DSU32 idx = 0, end = mSlabs.size(); idx < end; ++idx)
+ mAllocator.deallocate(mSlabs[idx], slabSize);
+ mSlabs.clear();
+ mFreeList = NULL;
+ }
+ void appendToFreeList(Link *inLink)
+ {
+ inLink->mNext = mFreeList;
+ mFreeList = inLink;
+ }
+ void appendSlabToFreeList(void *slab)
+ {
+ QT3DSU8 *newMem = reinterpret_cast<QT3DSU8 *>(slab);
+ QT3DSU32 objSize = (QT3DSU32)qt3ds::NVMax(sizeof(TObjType), sizeof(Link));
+ // align the memory correctly
+ if (objSize % alignmentInBytes)
+ objSize += alignmentInBytes - (objSize % alignmentInBytes);
+
+ QT3DSU32 numObjsInSlab = slabSize / objSize;
+ for (QT3DSU32 idx = 0; idx < numObjsInSlab; ++idx) {
+ QT3DSU8 *objPtr = newMem + idx * objSize;
+ appendToFreeList(reinterpret_cast<Link *>(objPtr));
+ }
+ }
+ void allocateSlab(const char *file, int line)
+ {
+ QT3DSU32 objSize = (QT3DSU32)NVMax(sizeof(TObjType), sizeof(Link));
+ // align the memory correctly
+ if (objSize % alignmentInBytes)
+ objSize += alignmentInBytes - (objSize % alignmentInBytes);
+
+ QT3DSU8 *newMem = (QT3DSU8 *)mAllocator.allocate(slabSize, file, line);
+ if (newMem == NULL)
+ return; // out of mem, bad error
+ mSlabs.push_back(newMem);
+ appendSlabToFreeList(newMem);
+ }
+
+ void *allocate(const char *file, int line)
+ {
+ if (!mFreeList)
+ allocateSlab(file, line);
+
+ if (mFreeList) {
+ Link *retval = mFreeList;
+ mFreeList = retval->mNext;
+ return retval;
+ }
+
+ return NULL;
+ }
+
+ void deallocate(void *inPtr)
+ {
+#if _DEBUG
+ // Ensure inPtr came from a known slab.
+ bool found = false;
+ for (QT3DSU32 idx = 0, end = mSlabs.size(); idx < end && !found; ++idx) {
+ QT3DSU8 *slabMem = reinterpret_cast<QT3DSU8 *>(mSlabs[idx]);
+ QT3DSU8 *slabEnd = slabMem + slabSize;
+ QT3DSU8 *memPtr = reinterpret_cast<QT3DSU8 *>(inPtr);
+
+ if (memPtr >= mSlabs[idx] && memPtr < slabEnd)
+ found = true;
+ }
+ QT3DS_ASSERT(found);
+#endif
+ appendToFreeList(reinterpret_cast<Link *>(inPtr));
+ }
+
+ template <typename TArg1, typename TArg2>
+ TObjType *construct(const TArg1 &arg1, const TArg2 &arg2, const char *file, int line)
+ {
+ TObjType *newMem = (TObjType *)allocate(file, line);
+ return new (newMem) TObjType(arg1, arg2);
+ }
+
+ template <typename TArg1>
+ TObjType *construct(const TArg1 &arg1, const char *file, int line)
+ {
+ TObjType *newMem = (TObjType *)allocate(file, line);
+ return new (newMem) TObjType(arg1);
+ }
+
+ TObjType *construct(const char *file, int line)
+ {
+ TObjType *newMem = (TObjType *)allocate(file, line);
+ return new (newMem) TObjType();
+ }
+ };
+}
+}
+#endif
diff --git a/src/foundation/Qt3DSPreprocessor.h b/src/foundation/Qt3DSPreprocessor.h
new file mode 100644
index 0000000..371d3e6
--- /dev/null
+++ b/src/foundation/Qt3DSPreprocessor.h
@@ -0,0 +1,375 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_PREPROCESSOR_H
+#define QT3DS_FOUNDATION_QT3DS_PREPROCESSOR_H
+
+#include <stddef.h>
+/** \addtogroup foundation
+ @{
+*/
+
+/**
+List of preprocessor defines used to configure the SDK
+- NDEBUG/_DEBUG: enable asserts (exactly one needs to be defined)
+- QT3DS_CHECKED: enable run time checks, mostly unused or equiv. to _DEBUG
+- QT3DS_SUPPORT_VISUAL_DEBUGGER: ...
+- AG_PERFMON: ...
+*/
+
+/**
+Compiler define
+*/
+#ifdef _MSC_VER
+#define QT3DS_VC
+#if _MSC_VER >= 1600
+#define QT3DS_VC10
+#elif _MSC_VER >= 1500
+#define QT3DS_VC9
+#elif _MSC_VER >= 1400
+#define QT3DS_VC8
+#elif _MSC_VER >= 1300
+#define QT3DS_VC7
+#else
+#define QT3DS_VC6
+#endif
+#elif __GNUC__ || __SNC__
+#define QT3DS_GNUC
+#elif defined(__MWERKS__)
+#define QT3DS_CW
+#elif defined(__ghs__)
+#define QT3DS_GHS
+#else
+#error "Unknown compiler"
+#endif
+
+/**
+Platform define
+*/
+#ifdef QT3DS_VC
+#ifdef _M_IX86
+#define QT3DS_X86
+#define QT3DS_WINDOWS
+#elif defined(_M_X64)
+#define QT3DS_X64
+#define QT3DS_WINDOWS
+#elif defined(_M_PPC)
+#define QT3DS_PPC
+#define QT3DS_X360
+#define QT3DS_VMX
+#elif defined(_M_ARM)
+#define QT3DS_ARM
+#define QT3DS_WIN8ARM
+#define QT3DS_ARM_NEON
+#else
+#error "Unknown platform"
+#endif
+#elif defined QT3DS_GNUC
+#ifdef __CELLOS_LV2__
+#define QT3DS_PS3
+#define QT3DS_VMX
+#elif defined(__arm__)
+#define QT3DS_ARM
+#if defined(__SNC__)
+#define QT3DS_PSP2
+#endif
+#if defined(__ARM_PCS_VFP)
+#define QT3DS_ARM_HARDFP
+#else
+#define QT3DS_ARM_SOFTFP
+#endif
+#elif defined(__aarch64__)
+#define QT3DS_ARM
+#elif defined(__i386__)
+#define QT3DS_X86
+#define QT3DS_VMX
+#elif defined(__x86_64__)
+#define QT3DS_X64
+#elif defined(__ppc__)
+#define QT3DS_PPC
+#elif defined(__ppc64__)
+#define QT3DS_PPC
+#define QT3DS_PPC64
+//# elif defined(__aarch64__)
+//# define QT3DS_ARM_64
+#else
+#error "Unknown platform"
+#endif
+#if defined(ANDROID)
+#define QT3DS_ANDROID
+#elif defined(__linux__)
+#define QT3DS_LINUX
+#elif defined(__APPLE__)
+#define QT3DS_APPLE
+#if defined(__arm__)
+#define QT3DS_APPLE_IOS
+#endif
+#elif defined(__CYGWIN__)
+#define QT3DS_CYGWIN
+#define QT3DS_LINUX
+#elif defined(__QNX__)
+#define QT3DS_QNX
+#elif defined(_WIN32)
+#define QT3DS_WINDOWS
+#else
+#error "Unkown OS"
+#endif
+#elif defined QT3DS_CW
+#if defined(__PPCGEKKO__)
+#if defined(RVL)
+#define QT3DS_WII
+#else
+#define QT3DS_GC
+#endif
+#else
+#error "Unknown platform"
+#endif
+#elif defined QT3DS_GHS
+#define QT3DS_LINUX // INTEGRITY deviations flagged with __INTEGRITY
+#if defined(__arm__) || defined(__aarch64__) || defined(__ARM64__)
+#define QT3DS_ARM
+#endif
+#endif
+
+/**
+DLL export macros
+*/
+#ifndef QT3DS_C_EXPORT
+#define QT3DS_C_EXPORT extern "C"
+#endif
+
+/**
+Define API function declaration
+
+QT3DS_FOUNDATION_EXPORTS - used by the DLL library (PhysXCommon) to export the API
+QT3DS_FOUNDATION_NO_EXPORTS - exists because there are windows configurations where
+ the QT3DS_FOUNDATION_API is linked through standard
+static linking
+no definition - this will allow DLLs and libraries to use the exported API from PhysXCommon
+
+*/
+#if defined(QT3DS_WINDOWS) && !defined(__CUDACC__)
+#if defined QT3DS_FOUNDATION_EXPORTS
+#define QT3DS_FOUNDATION_API __declspec(dllexport)
+#elif defined QT3DS_FOUNDATION_NO_EXPORTS
+#define QT3DS_FOUNDATION_API
+#else
+#define QT3DS_FOUNDATION_API __declspec(dllimport)
+#endif
+#else
+#define QT3DS_FOUNDATION_API
+#endif
+
+
+#if defined(QT3DS_AUTOTESTS_ENABLED)
+#include <qglobal.h>
+#if defined(QT3DS_BUILDING_LIBRARY)
+#define QT3DS_AUTOTEST_EXPORT Q_DECL_EXPORT
+#else
+#define QT3DS_AUTOTEST_EXPORT Q_DECL_IMPORT
+#endif
+#else
+#define QT3DS_AUTOTEST_EXPORT
+#endif
+
+/**
+Calling convention
+*/
+#ifndef QT3DS_CALL_CONV
+#if defined QT3DS_WINDOWS
+#define QT3DS_CALL_CONV __cdecl
+#else
+#define QT3DS_CALL_CONV
+#endif
+#endif
+
+/**
+Pack macros - disabled on SPU because they are not supported
+*/
+#if defined(QT3DS_VC)
+#define QT3DS_PUSH_PACK_DEFAULT __pragma(pack(push, 8))
+#define QT3DS_POP_PACK __pragma(pack(pop))
+#elif defined(QT3DS_GNUC) && !defined(__SPU__)
+#define QT3DS_PUSH_PACK_DEFAULT _Pragma("pack(push, 8)")
+#define QT3DS_POP_PACK _Pragma("pack(pop)")
+#else
+#define QT3DS_PUSH_PACK_DEFAULT
+#define QT3DS_POP_PACK
+#endif
+
+/**
+Inline macro
+*/
+#if defined(QT3DS_WINDOWS) || defined(QT3DS_X360)
+#define QT3DS_INLINE inline
+#ifdef QT3DS_VC
+#pragma inline_depth(255)
+#endif
+#else
+#define QT3DS_INLINE inline
+#endif
+
+/**
+Force inline macro
+*/
+#if defined(QT3DS_VC)
+#define QT3DS_FORCE_INLINE __forceinline
+#elif defined(QT3DS_LINUX) \
+ || defined(QT3DS_QNX) // Workaround; Fedora Core 3 do not agree with force inline and NVcPool
+#define QT3DS_FORCE_INLINE inline
+#elif defined(QT3DS_GNUC)
+#define QT3DS_FORCE_INLINE inline __attribute__((always_inline))
+#else
+#define QT3DS_FORCE_INLINE inline
+#endif
+
+/**
+Noinline macro
+*/
+#if defined QT3DS_WINDOWS
+#define QT3DS_NOINLINE __declspec(noinline)
+#elif defined(QT3DS_GNUC)
+#define QT3DS_NOINLINE __attribute__((noinline))
+#else
+#define QT3DS_NOINLINE
+#endif
+
+/*! restrict macro */
+#if __CUDACC__
+#define QT3DS_RESTRICT __restrict__
+#elif defined(QT3DS_GNUC) || defined(QT3DS_VC)
+#define QT3DS_RESTRICT __restrict
+#elif defined(QT3DS_CW) && __STDC_VERSION__ >= 199901L
+#define QT3DS_RESTRICT restrict
+#else
+#define QT3DS_RESTRICT
+#endif
+
+#if defined(QT3DS_WINDOWS) || defined(QT3DS_X360)
+#define QT3DS_NOALIAS __declspec(noalias)
+#else
+#define QT3DS_NOALIAS
+#endif
+
+/**
+Alignment macros
+
+QT3DS_ALIGN_PREFIX and QT3DS_ALIGN_SUFFIX can be used for type alignment instead of aligning individual
+variables as follows:
+QT3DS_ALIGN_PREFIX(16)
+struct A {
+...
+} QT3DS_ALIGN_SUFFIX(16);
+This declaration style is parsed correctly by Visual Assist.
+
+*/
+#ifndef QT3DS_ALIGN
+#if defined(QT3DS_VC)
+#define QT3DS_ALIGN(alignment, decl) __declspec(align(alignment)) decl
+#define QT3DS_ALIGN_PREFIX(alignment) __declspec(align(alignment))
+#define QT3DS_ALIGN_SUFFIX(alignment)
+#elif defined(QT3DS_GNUC)
+#define QT3DS_ALIGN(alignment, decl) decl __attribute__((aligned(alignment)))
+#define QT3DS_ALIGN_PREFIX(alignment)
+#define QT3DS_ALIGN_SUFFIX(alignment) __attribute__((aligned(alignment)))
+#elif defined(QT3DS_CW)
+#define QT3DS_ALIGN(alignment, decl) decl __attribute__((aligned(alignment)))
+#define QT3DS_ALIGN_PREFIX(alignment)
+#define QT3DS_ALIGN_SUFFIX(alignment) __attribute__((aligned(alignment)))
+#else
+#define QT3DS_ALIGN(alignment, decl)
+#define QT3DS_ALIGN_PREFIX(alignment)
+#define QT3DS_ALIGN_SUFFIX(alignment)
+#endif
+#endif
+
+/**
+Deprecated marco
+*/
+#if 0 // set to 1 to create warnings for deprecated functions
+#define QT3DS_DEPRECATED __declspec(deprecated)
+#else
+#define QT3DS_DEPRECATED
+#endif
+
+// VC6 no '__FUNCTION__' workaround
+#if defined QT3DS_VC6 && !defined __FUNCTION__
+#define __FUNCTION__ "Undefined"
+#endif
+
+/**
+General defines
+*/
+
+// Assertion type
+template <bool b>
+struct StaticAssert
+{
+};
+// Specialisation with member function
+template <>
+struct StaticAssert<true>
+{
+public:
+ static void valid_expression(){}
+};
+
+// static assert
+#define QT3DS_COMPILE_TIME_ASSERT(exp) typedef char NVCompileTimeAssert_Dummy[(exp) ? 1 : -1]
+
+#ifdef QT3DS_GNUC
+#define QT3DS_OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
+#else
+#define QT3DS_OFFSET_OF(X, Y) offsetof(X, Y)
+#endif
+
+// avoid unreferenced parameter warning (why not just disable it?)
+// PT: or why not just omit the parameter's name from the declaration????
+#define QT3DS_FORCE_PARAMETER_REFERENCE(_P) (void)(_P);
+#define QT3DS_UNUSED(_P) QT3DS_FORCE_PARAMETER_REFERENCE(_P)
+
+// check that exactly one of NDEBUG and _DEBUG is defined
+#if !(defined NDEBUG ^ defined _DEBUG)
+#error Exactly one of NDEBUG and _DEBUG needs to be defined by preprocessor
+#endif
+
+// make sure QT3DS_CHECKED is defined in all _DEBUG configurations as well
+#if !defined(QT3DS_CHECKED) && _DEBUG
+#define QT3DS_CHECKED
+#endif
+
+#ifdef __CUDACC__
+#define QT3DS_CUDA_CALLABLE __host__ __device__
+#else
+#define QT3DS_CUDA_CALLABLE
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_PREPROCESSOR_H
diff --git a/src/foundation/Qt3DSQuat.h b/src/foundation/Qt3DSQuat.h
new file mode 100644
index 0000000..2792f97
--- /dev/null
+++ b/src/foundation/Qt3DSQuat.h
@@ -0,0 +1,381 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_QUAT_H
+#define QT3DS_FOUNDATION_QT3DS_QUAT_H
+
+/** \addtogroup foundation
+@{
+*/
+
+#include "foundation/Qt3DSVec3.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+/**
+\brief This is a quaternion class. For more information on quaternion mathematics
+consult a mathematics source on complex numbers.
+
+*/
+
+class QT3DSQuat
+{
+public:
+ /**
+ \brief Default constructor, does not do any initialization.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat() {}
+
+ /**
+ \brief Constructor. Take note of the order of the elements!
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat(NVReal nx, NVReal ny, NVReal nz, NVReal nw)
+ : x(nx)
+ , y(ny)
+ , z(nz)
+ , w(nw)
+ {
+ }
+
+ /**
+ \brief Creates from angle-axis representation.
+
+ Axis must be normalized!
+
+ Angle is in radians!
+
+ <b>Unit:</b> Radians
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSQuat(NVReal angleRadians, const QT3DSVec3 &unitAxis)
+ {
+ QT3DS_ASSERT(NVAbs(1.0f - unitAxis.magnitude()) < 1e-3f);
+ const NVReal a = angleRadians * 0.5f;
+ const NVReal s = NVSin(a);
+ w = NVCos(a);
+ x = unitAxis.x * s;
+ y = unitAxis.y * s;
+ z = unitAxis.z * s;
+ }
+
+ /**
+ \brief Copy ctor.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat(const QT3DSQuat &v)
+ : x(v.x)
+ , y(v.y)
+ , z(v.z)
+ , w(v.w)
+ {
+ }
+
+ /**
+ \brief Creates from orientation matrix.
+
+ \param[in] m Rotation matrix to extract quaternion from.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE explicit QT3DSQuat(const QT3DSMat33 &m); /* defined in Qt3DSMat33.h */
+
+ /**
+ \brief returns true if all elements are finite (not NAN or INF, etc.)
+ */
+ QT3DS_CUDA_CALLABLE bool isFinite() const
+ {
+ return NVIsFinite(x) && NVIsFinite(y) && NVIsFinite(z) && NVIsFinite(w);
+ }
+
+ /**
+ \brief returns true if finite and magnitude is close to unit
+ */
+
+ QT3DS_CUDA_CALLABLE bool isUnit() const
+ {
+ const NVReal unitTolerance = NVReal(1e-4);
+ return isFinite() && NVAbs(magnitude() - 1) < unitTolerance;
+ }
+
+ /**
+ \brief returns true if finite and magnitude is reasonably close to unit to allow for some
+ accumulation of error vs isValid
+ */
+
+ QT3DS_CUDA_CALLABLE bool isSane() const
+ {
+ const NVReal unitTolerance = NVReal(1e-2);
+ return isFinite() && NVAbs(magnitude() - 1) < unitTolerance;
+ }
+
+ /**
+ \brief converts this quaternion to angle-axis representation
+ */
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE void toRadiansAndUnitAxis(NVReal &angle, QT3DSVec3 &axis) const
+ {
+ const NVReal quatEpsilon = (NVReal(1.0e-8f));
+ const NVReal s2 = x * x + y * y + z * z;
+ if (s2 < quatEpsilon * quatEpsilon) // can't extract a sensible axis
+ {
+ angle = 0;
+ axis = QT3DSVec3(1, 0, 0);
+ } else {
+ const NVReal s = NVRecipSqrt(s2);
+ axis = QT3DSVec3(x, y, z) * s;
+ angle = w < quatEpsilon ? NVPi : NVAtan2(s2 * s, w) * 2;
+ }
+ }
+
+ /**
+ \brief Gets the angle between this quat and the identity quaternion.
+
+ <b>Unit:</b> Radians
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal getAngle() const { return NVAcos(w) * NVReal(2); }
+
+ /**
+ \brief Gets the angle between this quat and the argument
+
+ <b>Unit:</b> Radians
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal getAngle(const QT3DSQuat &q) const
+ {
+ return NVAcos(dot(q)) * NVReal(2);
+ }
+
+ /**
+ \brief This is the squared 4D vector length, should be 1 for unit quaternions.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal magnitudeSquared() const
+ {
+ return x * x + y * y + z * z + w * w;
+ }
+
+ /**
+ \brief returns the scalar product of this and other.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal dot(const QT3DSQuat &v) const
+ {
+ return x * v.x + y * v.y + z * v.z + w * v.w;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSQuat getNormalized() const
+ {
+ const NVReal s = 1.0f / magnitude();
+ return QT3DSQuat(x * s, y * s, z * s, w * s);
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE float magnitude() const { return NVSqrt(magnitudeSquared()); }
+
+ // modifiers:
+ /**
+ \brief maps to the closest unit quaternion.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal normalize() // convert this QT3DSQuat to a unit quaternion
+ {
+ const NVReal mag = magnitude();
+ if (mag) {
+ const NVReal imag = NVReal(1) / mag;
+
+ x *= imag;
+ y *= imag;
+ z *= imag;
+ w *= imag;
+ }
+ return mag;
+ }
+
+ /*
+ \brief returns the conjugate.
+
+ \note for unit quaternions, this is the inverse.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSQuat getConjugate() const { return QT3DSQuat(-x, -y, -z, w); }
+
+ /*
+ \brief returns imaginary part.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 getImaginaryPart() const { return QT3DSVec3(x, y, z); }
+
+ /** brief computes rotation of x-axis */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getBasisVector0() const
+ {
+ // return rotate(QT3DSVec3(1,0,0));
+ const QT3DSF32 x2 = x * 2.0f;
+ const QT3DSF32 w2 = w * 2.0f;
+ return QT3DSVec3((w * w2) - 1.0f + x * x2, (z * w2) + y * x2, (-y * w2) + z * x2);
+ }
+
+ /** brief computes rotation of y-axis */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getBasisVector1() const
+ {
+ // return rotate(QT3DSVec3(0,1,0));
+ const QT3DSF32 y2 = y * 2.0f;
+ const QT3DSF32 w2 = w * 2.0f;
+ return QT3DSVec3((-z * w2) + x * y2, (w * w2) - 1.0f + y * y2, (x * w2) + z * y2);
+ }
+
+ /** brief computes rotation of z-axis */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getBasisVector2() const
+ {
+ // return rotate(QT3DSVec3(0,0,1));
+ const QT3DSF32 z2 = z * 2.0f;
+ const QT3DSF32 w2 = w * 2.0f;
+ return QT3DSVec3((y * w2) + x * z2, (-x * w2) + y * z2, (w * w2) - 1.0f + z * z2);
+ }
+
+ /**
+ rotates passed vec by this (assumed unitary)
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const QT3DSVec3 rotate(const QT3DSVec3 &v) const
+ // QT3DS_CUDA_CALLABLE QT3DS_INLINE const QT3DSVec3 rotate(const QT3DSVec3& v) const
+ {
+ const QT3DSF32 vx = 2.0f * v.x;
+ const QT3DSF32 vy = 2.0f * v.y;
+ const QT3DSF32 vz = 2.0f * v.z;
+ const QT3DSF32 w2 = w * w - 0.5f;
+ const QT3DSF32 dot2 = (x * vx + y * vy + z * vz);
+ return QT3DSVec3((vx * w2 + (y * vz - z * vy) * w + x * dot2),
+ (vy * w2 + (z * vx - x * vz) * w + y * dot2),
+ (vz * w2 + (x * vy - y * vx) * w + z * dot2));
+ /*
+ const QT3DSVec3 qv(x,y,z);
+ return (v*(w*w-0.5f) + (qv.cross(v))*w + qv*(qv.dot(v)))*2;
+ */
+ }
+
+ /**
+ inverse rotates passed vec by this (assumed unitary)
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const QT3DSVec3 rotateInv(const QT3DSVec3 &v) const
+ // QT3DS_CUDA_CALLABLE QT3DS_INLINE const QT3DSVec3 rotateInv(const QT3DSVec3& v) const
+ {
+ const QT3DSF32 vx = 2.0f * v.x;
+ const QT3DSF32 vy = 2.0f * v.y;
+ const QT3DSF32 vz = 2.0f * v.z;
+ const QT3DSF32 w2 = w * w - 0.5f;
+ const QT3DSF32 dot2 = (x * vx + y * vy + z * vz);
+ return QT3DSVec3((vx * w2 - (y * vz - z * vy) * w + x * dot2),
+ (vy * w2 - (z * vx - x * vz) * w + y * dot2),
+ (vz * w2 - (x * vy - y * vx) * w + z * dot2));
+ // const QT3DSVec3 qv(x,y,z);
+ // return (v*(w*w-0.5f) - (qv.cross(v))*w + qv*(qv.dot(v)))*2;
+ }
+
+ /**
+ \brief Assignment operator
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat &operator=(const QT3DSQuat &p)
+ {
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ w = p.w;
+ return *this;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat &operator*=(const QT3DSQuat &q)
+ {
+ const NVReal tx = w * q.x + q.w * x + y * q.z - q.y * z;
+ const NVReal ty = w * q.y + q.w * y + z * q.x - q.z * x;
+ const NVReal tz = w * q.z + q.w * z + x * q.y - q.x * y;
+
+ w = w * q.w - q.x * x - y * q.y - q.z * z;
+ x = tx;
+ y = ty;
+ z = tz;
+
+ return *this;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat &operator+=(const QT3DSQuat &q)
+ {
+ x += q.x;
+ y += q.y;
+ z += q.z;
+ w += q.w;
+ return *this;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat &operator-=(const QT3DSQuat &q)
+ {
+ x -= q.x;
+ y -= q.y;
+ z -= q.z;
+ w -= q.w;
+ return *this;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat &operator*=(const NVReal s)
+ {
+ x *= s;
+ y *= s;
+ z *= s;
+ w *= s;
+ return *this;
+ }
+
+ /** quaternion multiplication */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSQuat operator*(const QT3DSQuat &q) const
+ {
+ return QT3DSQuat(w * q.x + q.w * x + y * q.z - q.y * z, w * q.y + q.w * y + z * q.x - q.z * x,
+ w * q.z + q.w * z + x * q.y - q.x * y, w * q.w - x * q.x - y * q.y - z * q.z);
+ }
+
+ /** quaternion addition */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat operator+(const QT3DSQuat &q) const
+ {
+ return QT3DSQuat(x + q.x, y + q.y, z + q.z, w + q.w);
+ }
+
+ /** quaternion subtraction */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat operator-() const { return QT3DSQuat(-x, -y, -z, -w); }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat operator-(const QT3DSQuat &q) const
+ {
+ return QT3DSQuat(x - q.x, y - q.y, z - q.z, w - q.w);
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSQuat operator*(NVReal r) const
+ {
+ return QT3DSQuat(x * r, y * r, z * r, w * r);
+ }
+
+ static QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSQuat createIdentity() { return QT3DSQuat(0, 0, 0, 1); }
+
+ /** the quaternion elements */
+ NVReal x, y, z, w;
+};
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_QUAT_H
diff --git a/src/foundation/Qt3DSRefCounted.h b/src/foundation/Qt3DSRefCounted.h
new file mode 100644
index 0000000..b500b5f
--- /dev/null
+++ b/src/foundation/Qt3DSRefCounted.h
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_REFCOUNTED_H
+#define QT3DS_FOUNDATION_QT3DS_REFCOUNTED_H
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSNoCopy.h"
+
+namespace qt3ds {
+namespace foundation {
+ /**
+ Marker class for objects that have a release method that is expected
+ to destroy or release the object.
+ */
+ class NVReleasable
+ {
+ protected:
+ virtual ~NVReleasable() {}
+ public:
+ virtual void release() = 0;
+ };
+
+ template <typename TObjType>
+ inline void NVSafeRelease(TObjType *&item)
+ {
+ if (item) {
+ item->release();
+ item = NULL;
+ }
+ }
+
+ /**Scoped pointer that releases its data
+ when it is being destroyed*/
+ template <typename TObjType>
+ struct NVScopedReleasable : public NoCopy
+ {
+ TObjType *mPtr;
+ NVScopedReleasable()
+ : mPtr(NULL)
+ {
+ }
+ NVScopedReleasable(TObjType *item)
+ : mPtr(item)
+ {
+ }
+ NVScopedReleasable(TObjType &item)
+ : mPtr(&item)
+ {
+ }
+ ~NVScopedReleasable() { NVSafeRelease(mPtr); }
+
+ NVScopedReleasable &operator=(TObjType *inItem)
+ {
+ if (inItem != mPtr) {
+ if (mPtr)
+ mPtr->release();
+ mPtr = inItem;
+ }
+ return *this;
+ }
+
+ NVScopedReleasable &operator=(const NVScopedReleasable<TObjType> inItem)
+ {
+ QT3DS_ASSERT(false);
+ // try to do the right thing.
+ mPtr = inItem.mPtr;
+ const_cast<NVScopedReleasable<TObjType> &>(inItem).mPtr = NULL;
+ return *this;
+ }
+
+ TObjType *forget_unsafe()
+ {
+ mPtr = NULL;
+ return mPtr;
+ }
+
+ TObjType *operator->() { return mPtr; }
+ const TObjType *operator->() const { return mPtr; }
+ TObjType &operator*() { return *mPtr; }
+ const TObjType &operator*() const { return *mPtr; }
+ operator TObjType *() { return mPtr; }
+ operator const TObjType *() const { return mPtr; }
+ };
+
+ // Marker class for objects that are ref counted.
+ class NVRefCounted : public NVReleasable
+ {
+ public:
+ virtual void addRef() = 0;
+ };
+
+/**Helpers to make implementing ref counted objects as concise as possible*/
+#define QT3DS_IMPLEMENT_REF_COUNT_RELEASE(alloc) \
+ QT3DSI32 value = atomicDecrement(&mRefCount); \
+ if (value <= 0) \
+ NVDelete(alloc, this);
+
+#define QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(alloc) \
+ void addRef() { atomicIncrement(&mRefCount); } \
+ void release() { QT3DS_IMPLEMENT_REF_COUNT_RELEASE(alloc); }
+
+
+#define QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(alloc) \
+ void addRef() override { atomicIncrement(&mRefCount); } \
+ void release() override { QT3DS_IMPLEMENT_REF_COUNT_RELEASE(alloc); }
+
+ /**Safe function that checks for null before addrefing the object*/
+ template <typename TObjType>
+ inline TObjType *NVSafeAddRef(TObjType *item)
+ {
+ if (item) {
+ item->addRef();
+ }
+ return item;
+ }
+
+ /**Scoped pointer that addref's its data upon acquisition and releases its data
+ when it is being destroyed*/
+ template <typename TObjType>
+ struct NVScopedRefCounted
+ {
+ TObjType *mPtr;
+ ~NVScopedRefCounted() { NVSafeRelease(mPtr); }
+ NVScopedRefCounted(TObjType *item = NULL)
+ : mPtr(item)
+ {
+ NVSafeAddRef(mPtr);
+ }
+ NVScopedRefCounted(TObjType &item)
+ : mPtr(&item)
+ {
+ NVSafeAddRef(mPtr);
+ }
+ NVScopedRefCounted(const NVScopedRefCounted<TObjType> &other)
+ : mPtr(const_cast<TObjType *>(other.mPtr))
+ {
+ NVSafeAddRef(mPtr);
+ }
+ NVScopedRefCounted<TObjType> &operator=(const NVScopedRefCounted<TObjType> &other)
+ {
+ if (other.mPtr != mPtr) {
+ NVSafeRelease(mPtr);
+ mPtr = const_cast<TObjType *>(other.mPtr);
+ NVSafeAddRef(mPtr);
+ }
+ return *this;
+ }
+ TObjType *forget_unsafe()
+ {
+ mPtr = NULL;
+ return mPtr;
+ }
+
+ TObjType *operator->() { return mPtr; }
+ const TObjType *operator->() const { return mPtr; }
+ TObjType &operator*() { return *mPtr; }
+ const TObjType &operator*() const { return *mPtr; }
+ operator TObjType *() { return mPtr; }
+ operator const TObjType *() const { return mPtr; }
+ bool operator==(NVScopedRefCounted<TObjType> &inOther) const
+ {
+ return mPtr == inOther.mPtr;
+ }
+ bool operator!=(NVScopedRefCounted<TObjType> &inOther) const
+ {
+ return mPtr != inOther.mPtr;
+ }
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/Qt3DSSemaphore.h b/src/foundation/Qt3DSSemaphore.h
new file mode 100644
index 0000000..f58bb6e
--- /dev/null
+++ b/src/foundation/Qt3DSSemaphore.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSSEMAPHORE_H
+#define QT3DS_FOUNDATION_PSSEMAPHORE_H
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+
+namespace qt3ds {
+namespace foundation {
+ class QT3DS_FOUNDATION_API Semaphore
+ {
+ public:
+ static const QT3DSU32 waitForever = 0xffffffff;
+
+ Semaphore(NVAllocatorCallback &alloc, QT3DSU32 initialCount, QT3DSU32 maxCount);
+
+ ~Semaphore();
+
+ /**Decrements (locks) the semaphore. If the semaphore's value is greater than zero,
+ * then the decrement proceeds, and the function returns, immediately. Otherwise
+ * Wait for at most the given number of ms. Returns true if the Semaphore is signaled.
+ * Semaphore::waitForever will block forever or until the semaphore is signaled.
+ */
+
+ bool wait(QT3DSU32 milliseconds = waitForever);
+
+ /** increments (unlocks) the semaphore */
+
+ void post();
+
+ private:
+ class SemaphoreImpl *mImpl;
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSSimpleTypes.h b/src/foundation/Qt3DSSimpleTypes.h
new file mode 100644
index 0000000..05ac8d9
--- /dev/null
+++ b/src/foundation/Qt3DSSimpleTypes.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_FOUNDATION_QT3DS_SIMPLE_TYPES_H
+#define QT3DS_FOUNDATION_QT3DS_SIMPLE_TYPES_H
+
+/** \addtogroup foundation
+ @{
+*/
+
+// Platform specific types:
+// Design note: Its OK to use int for general loop variables and temps.
+
+#include <QtCore/qglobal.h>
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSPreprocessor.h"
+#include "EABase/eabase.h"
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif //#ifndef QT3DS_DOXYGEN
+
+typedef quint8 QT3DSU8;
+typedef qint8 QT3DSI8;
+typedef quint16 QT3DSU16;
+typedef qint16 QT3DSI16;
+typedef quint32 QT3DSU32;
+typedef qint32 QT3DSI32;
+
+// Android's definition of GLuint64 as unsigned long (64-bits) requires this workaround
+#if Q_PROCESSOR_WORDSIZE == 8 && (defined(Q_OS_ANDROID) || defined(Q_OS_INTEGRITY))
+typedef unsigned long QT3DSU64;
+#else
+typedef quint64 QT3DSU64;
+#endif
+
+typedef qint64 QT3DSI64;
+typedef float QT3DSF32;
+typedef double QT3DSF64;
+typedef QT3DSI32 IntBool;
+
+struct QT3DSF16
+{
+ QT3DSU16 mData;
+};
+
+QT3DS_COMPILE_TIME_ASSERT(sizeof(QT3DSI8) == 1);
+QT3DS_COMPILE_TIME_ASSERT(sizeof(QT3DSU8) == 1);
+QT3DS_COMPILE_TIME_ASSERT(sizeof(QT3DSI16) == 2);
+QT3DS_COMPILE_TIME_ASSERT(sizeof(QT3DSU16) == 2);
+QT3DS_COMPILE_TIME_ASSERT(sizeof(QT3DSI32) == 4);
+QT3DS_COMPILE_TIME_ASSERT(sizeof(QT3DSU32) == 4);
+QT3DS_COMPILE_TIME_ASSERT(sizeof(QT3DSI64) == 8);
+QT3DS_COMPILE_TIME_ASSERT(sizeof(QT3DSU64) == 8);
+
+// Type ranges
+#define QT3DS_MAX_I8 127 // maximum possible sbyte value, 0x7f
+#define QT3DS_MIN_I8 (-128) // minimum possible sbyte value, 0x80
+#define QT3DS_MAX_U8 255U // maximum possible ubyte value, 0xff
+#define QT3DS_MIN_U8 0 // minimum possible ubyte value, 0x00
+#define QT3DS_MAX_I16 32767 // maximum possible sword value, 0x7fff
+#define QT3DS_MIN_I16 (-32768) // minimum possible sword value, 0x8000
+#define QT3DS_MAX_U16 65535U // maximum possible uword value, 0xffff
+#define QT3DS_MIN_U16 0 // minimum possible uword value, 0x0000
+#define QT3DS_MAX_I32 2147483647 // maximum possible sdword value, 0x7fffffff
+#define QT3DS_MIN_I32 (-2147483647 - 1) // minimum possible sdword value, 0x80000000
+#define QT3DS_MAX_U32 4294967295U // maximum possible udword value, 0xffffffff
+#define QT3DS_MIN_U32 0 // minimum possible udword value, 0x00000000
+#define QT3DS_MAX_F32 3.4028234663852885981170418348452e+38F
+// maximum possible float value
+#define QT3DS_MAX_F64 DBL_MAX // maximum possible double value
+
+#define QT3DS_ENV_F32 FLT_EPSILON // maximum relative error of float rounding
+#define QT3DS_ENV_F64 DBL_EPSILON // maximum relative error of double rounding
+
+#ifndef QT3DS_FOUNDATION_USE_F64
+
+typedef QT3DSF32 NVReal;
+
+#define QT3DS_MAX_REAL QT3DS_MAX_F32
+#define QT3DS_ENV_REAL QT3DS_ENV_F32
+#define QT3DS_NORMALIZATION_EPSILON NVReal(1e-20f)
+
+#else
+
+typedef QT3DSF64 NVReal;
+
+#define QT3DS_MAX_REAL QT3DS_MAX_F64
+#define QT3DS_ENV_REAL QT3DS_ENV_F64
+#define QT3DS_NORMALIZATION_EPSILON NVReal(1e-180)
+
+#endif
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_SIMPLE_TYPES_H
diff --git a/src/foundation/Qt3DSStringTokenizer.h b/src/foundation/Qt3DSStringTokenizer.h
new file mode 100644
index 0000000..5229bab
--- /dev/null
+++ b/src/foundation/Qt3DSStringTokenizer.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_STRING_TOKENIZER_H
+#define QT3DS_FOUNDATION_STRING_TOKENIZER_H
+
+#include "EASTL/string.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ template <typename TStrType>
+ class QT3DS_FOUNDATION_API StringTokenizer
+ {
+ typedef typename eastl::basic_string<TStrType>::size_type size_t;
+
+ public:
+ StringTokenizer(const eastl::basic_string<TStrType> &inString,
+ const eastl::basic_string<TStrType> &inToken)
+ {
+ eastl::basic_string<TStrType> mStr = inString;
+ eastl::basic_string<TStrType> theTempString = inString.substr(0, inToken.length());
+
+ while (inToken.length() && theTempString.compare(inToken) == 0) {
+ mStr = mStr.substr(inToken.length());
+ theTempString = mStr.substr(0, inToken.length());
+ }
+
+ theTempString = mStr.substr(mStr.length() - 1 - inToken.length());
+ while (theTempString.compare(inToken) == 0) {
+ mStr = mStr.substr(0, mStr.length() - inToken.length());
+ theTempString = mStr.substr(mStr.length() - 1 - inToken.length());
+ }
+
+ m_OriginalString = mStr;
+ m_Token = inToken;
+ m_Index = 0;
+ }
+
+ eastl::basic_string<TStrType> GetCurrentPartition()
+ {
+ eastl::basic_string<TStrType> theReturnString;
+ if (m_Index != eastl::basic_string<TStrType>::npos) {
+ size_t theCurrentTokenIndex = m_OriginalString.find(m_Token, m_Index);
+ if (theCurrentTokenIndex == eastl::basic_string<TStrType>::npos) {
+ theReturnString = m_OriginalString.substr(m_Index);
+ } else {
+ theReturnString =
+ m_OriginalString.substr(m_Index, theCurrentTokenIndex - m_Index);
+ }
+ }
+
+ return theReturnString;
+ }
+
+ bool HasNextPartition() { return m_Index != eastl::basic_string<TStrType>::npos; }
+
+ void operator++()
+ {
+ if (m_Index != eastl::basic_string<TStrType>::npos) {
+ size_t theCurrentTokenIndex = m_OriginalString.find(m_Token, m_Index);
+ if (theCurrentTokenIndex == eastl::basic_string<TStrType>::npos) {
+ m_Index = eastl::basic_string<TStrType>::npos;
+ } else {
+ m_Index = theCurrentTokenIndex + m_Token.length();
+ if (m_Index > m_OriginalString.length())
+ m_Index = eastl::basic_string<TStrType>::npos;
+ }
+ }
+ }
+
+ private:
+ size_t m_Index;
+ eastl::basic_string<TStrType> m_Token;
+ eastl::basic_string<TStrType> m_OriginalString;
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSSync.h b/src/foundation/Qt3DSSync.h
new file mode 100644
index 0000000..a36afae
--- /dev/null
+++ b/src/foundation/Qt3DSSync.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSSYNC_H
+#define QT3DS_FOUNDATION_PSSYNC_H
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+
+namespace qt3ds {
+namespace foundation {
+ class QT3DS_FOUNDATION_API Sync
+ {
+ public:
+ static const QT3DSU32 waitForever = 0xffffffff;
+
+ Sync(NVAllocatorCallback &alloc);
+
+ ~Sync();
+
+ /** Wait on the object for at most the given number of ms. Returns
+ * true if the object is signaled. Sync::waitForever will block forever
+ * or until the object is signaled.
+ */
+
+ bool wait(QT3DSU32 milliseconds = waitForever);
+
+ /** Signal the synchronization object, waking all threads waiting on it */
+
+ void set();
+
+ /** Reset the synchronization object */
+
+ void reset();
+
+ private:
+ class SyncImpl *mImpl;
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSSystem.cpp b/src/foundation/Qt3DSSystem.cpp
new file mode 100644
index 0000000..e87a25e
--- /dev/null
+++ b/src/foundation/Qt3DSSystem.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DSSystem.h"
+#include "foundation/Qt3DSPreprocessor.h"
+#include "EASTL/string.h"
+
+using namespace qt3ds;
+using namespace qt3ds::foundation;
+
+#if defined(QT3DS_ANDROID)
+const char *qt3ds::foundation::System::g_OS = "android";
+const char *qt3ds::foundation::System::g_DLLExtension = ".so";
+#elif defined(QT3DS_APPLE)
+const char *qt3ds::foundation::System::g_OS = "osx";
+const char *qt3ds::foundation::System::g_DLLExtension = ".dylib";
+#elif defined(QT3DS_LINUX)
+const char *qt3ds::foundation::System::g_OS = "linux";
+const char *qt3ds::foundation::System::g_DLLExtension = ".so";
+#elif defined(QT3DS_QNX)
+const char *qt3ds::foundation::System::g_OS = "qnx";
+const char *qt3ds::foundation::System::g_DLLExtension = ".so";
+#elif defined(QT3DS_WINDOWS)
+const char *qt3ds::foundation::System::g_OS = "windows";
+const char *qt3ds::foundation::System::g_DLLExtension = ".dll";
+#else
+#error "Unknown Operating System"
+#endif
+
+#if defined(QT3DS_X86)
+const char *qt3ds::foundation::System::g_Processor = "x86";
+const char *qt3ds::foundation::System::g_BitWidth = "32";
+const char *qt3ds::foundation::System::g_FloatingPointModel = "";
+#elif defined(QT3DS_X64)
+const char *qt3ds::foundation::System::g_Processor = "x64";
+const char *qt3ds::foundation::System::g_BitWidth = "64";
+const char *qt3ds::foundation::System::g_FloatingPointModel = "";
+#elif defined(QT3DS_ARM)
+#if defined(__aarch64__) || defined(__ARM64__)
+const char *qt3ds::foundation::System::g_Processor = "arm";
+const char *qt3ds::foundation::System::g_BitWidth = "64";
+const char *qt3ds::foundation::System::g_FloatingPointModel = "softfp";
+#else
+const char *qt3ds::foundation::System::g_Processor = "arm";
+const char *qt3ds::foundation::System::g_BitWidth = "32";
+#if defined(QT3DS_ARM_HARDFP)
+const char *qt3ds::foundation::System::g_FloatingPointModel = "hardfp";
+#elif defined(QT3DS_ARM_SOFTFP)
+const char *qt3ds::foundation::System::g_FloatingPointModel = "softfp";
+#else
+#error "Unknown floating point model!"
+#endif
+#endif
+#else
+#error "Unknown Platform"
+#endif
+
+#if defined(QT3DS_ARM)
+#if defined(QT3DS_GRAPHICS_API_GLES2)
+const char *qt3ds::foundation::System::g_GPUType = "gles2";
+#elif defined(QT3DS_GRAPHICS_API_GL)
+const char *qt3ds::foundation::System::g_GPUType = "gl";
+#elif defined(QT3DS_GRAPHICS_API_GLES3)
+const char *qt3ds::foundation::System::g_GPUType = "gles3";
+#else
+#error \
+ "Must define a GPU type for arm platforms (QT3DS_GRAPHICS_API_GLES2, QT3DS_GRAPHICS_API_GLES3, QT3DS_GRAPHICS_API_GL)"
+#endif
+#elif defined(QT3DS_X86)
+const char *qt3ds::foundation::System::g_GPUType = "";
+#elif defined(QT3DS_X64)
+const char *qt3ds::foundation::System::g_GPUType = "";
+#else
+#error "Must define a processor type (QT3DS_ARM or QT3DS_X86)"
+#endif
+
+namespace {
+static const unsigned SYSTEM_STR_SIZE = 100;
+void SystemAppendString(eastl::string &str, const char *delim, const char *string)
+{
+ if (string && *string) {
+ str.append(delim);
+ str.append(string);
+ }
+}
+}
+const char *System::getPlatformStr()
+{
+ static char text[SYSTEM_STR_SIZE];
+ {
+ eastl::string str(g_Processor);
+ SystemAppendString(str, "_", g_BitWidth);
+ SystemAppendString(str, "_", g_FloatingPointModel);
+ SystemAppendString(str, "_", g_OS);
+ strcpy(text, str.c_str());
+ }
+ return text;
+}
+
+const char *System::getPlatformGLStr()
+{
+ static char text[SYSTEM_STR_SIZE];
+ {
+ eastl::string str(g_Processor);
+ SystemAppendString(str, "_", g_BitWidth);
+ SystemAppendString(str, "_", g_FloatingPointModel);
+ SystemAppendString(str, "_", g_GPUType);
+ SystemAppendString(str, "_", g_OS);
+ strcpy(text, str.c_str());
+ }
+ return text;
+} \ No newline at end of file
diff --git a/src/foundation/Qt3DSSystem.h b/src/foundation/Qt3DSSystem.h
new file mode 100644
index 0000000..84ca87d
--- /dev/null
+++ b/src/foundation/Qt3DSSystem.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_FOUNDATION_SYSTEM_H
+#define QT3DS_FOUNDATION_SYSTEM_H
+
+#include "foundation/Qt3DS.h"
+
+namespace qt3ds {
+namespace foundation {
+ class QT3DS_FOUNDATION_API System
+ {
+ public:
+ static const char *g_OS;
+ static const char *g_Processor;
+ static const char *g_BitWidth;
+ static const char *g_FloatingPointModel;
+ static const char *g_GPUType;
+ static const char *g_DLLExtension;
+ static const char *getPlatformStr();
+ static const char *getPlatformGLStr();
+
+ private:
+ System();
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSThread.h b/src/foundation/Qt3DSThread.h
new file mode 100644
index 0000000..84e169d
--- /dev/null
+++ b/src/foundation/Qt3DSThread.h
@@ -0,0 +1,205 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSTHREAD_H
+#define QT3DS_FOUNDATION_PSTHREAD_H
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSFoundation.h"
+
+// dsequeira: according to existing comment here (David Black would be my guess)
+// "This is useful to reduce bus contention on tight spin locks. And it needs
+// to be a macro as the xenon compiler often ignores even __forceinline." What's not
+// clear is why a pause function needs inlining...? (TODO: check with XBox team)
+
+// todo: these need to go somewhere else
+
+#if defined(QT3DS_WINDOWS)
+#define NVSpinLockPause() __asm pause
+#elif defined(QT3DS_X360)
+#define NVSpinLockPause() __asm nop
+#elif defined(QT3DS_LINUX) || defined(QT3DS_ANDROID) || defined(QT3DS_APPLE) || defined(QT3DS_QNX)
+#define NVSpinLockPause() asm("nop")
+#elif defined(QT3DS_PS3)
+#define NVSpinLockPause() asm("nop") // don't know if it's correct yet...
+#define QT3DS_TLS_MAX_SLOTS 64
+#elif defined(QT3DS_WII)
+#define NVSpinLockPause() asm { nop } // don't know if it's correct yet...
+#endif
+
+namespace qt3ds {
+namespace foundation {
+ struct ThreadPriority // todo: put in some other header file
+ {
+ enum Enum {
+ /**
+ \brief High priority
+ */
+ eHIGH = 0,
+
+ /**
+ \brief Above Normal priority
+ */
+ eABOVE_NORMAL = 1,
+
+ /**
+ \brief Normal/default priority
+ */
+ eNORMAL = 2,
+
+ /**
+ \brief Below Normal priority
+ */
+ eBELOW_NORMAL = 3,
+
+ /**
+ \brief Low priority.
+ */
+ eLOW = 4,
+
+ eFORCE_DWORD = 0xffFFffFF
+ };
+ };
+
+ /**
+ Thread abstraction API
+ */
+
+ class QT3DS_FOUNDATION_API Thread
+ {
+ public:
+ static const QT3DSU32 DEFAULT_STACK_SIZE;
+ typedef size_t Id; // space for a pointer or an integer
+ typedef void *(*ExecuteFn)(void *);
+
+ static Id getId();
+
+ /**
+ Construct (but do not start) the thread object. Executes in the context
+ of the spawning thread
+ */
+
+ Thread(NVFoundationBase &foundation);
+
+ /**
+ Construct and start the the thread, passing the given arg to the given fn. (pthread style)
+ */
+
+ Thread(NVFoundationBase &foundation, ExecuteFn fn, void *arg);
+
+ /**
+ Deallocate all resources associated with the thread. Should be called in the
+ context of the spawning thread.
+ */
+
+ virtual ~Thread();
+
+ /**
+ start the thread running. Called in the context of the spawning thread.
+ */
+
+ void start(QT3DSU32 stackSize);
+
+ /**
+ Violently kill the current thread. Blunt instrument, not recommended since
+ it can leave all kinds of things unreleased (stack, memory, mutexes...) Should
+ be called in the context of the spawning thread.
+ */
+
+ void kill();
+
+ /**
+ The virtual execute() method is the user defined function that will
+ run in the new thread. Called in the context of the spawned thread.
+ */
+
+ virtual void execute(void);
+
+ /**
+ stop the thread. Signals the spawned thread that it should stop, so the
+ thread should check regularly
+ */
+
+ void signalQuit();
+
+ /**
+ Wait for a thread to stop. Should be called in the context of the spawning
+ thread. Returns false if the thread has not been started.
+ */
+
+ bool waitForQuit();
+
+ /**
+ check whether the thread is signalled to quit. Called in the context of the
+ spawned thread.
+ */
+
+ bool quitIsSignalled();
+
+ /**
+ Cleanly shut down this thread. Called in the context of the spawned thread.
+ */
+ void quit();
+
+ /**
+ Change the affinity mask for this thread.
+ On Xbox360, sets the hardware thread to the first non-zero bit.
+
+ Returns previous mask if successful, or zero on failure
+ */
+ virtual QT3DSU32 setAffinityMask(QT3DSU32 mask);
+
+ static ThreadPriority::Enum getPriority(Id threadId);
+
+ /** Set thread priority. */
+ void setPriority(ThreadPriority::Enum prio);
+
+ /** set the thread's name */
+ void setName(const char *name);
+
+ /** Put the current thread to sleep for the given number of milliseconds */
+ static void sleep(QT3DSU32 ms);
+
+ /** Yield the current thread's slot on the CPU */
+ static void yield();
+
+ private:
+ class ThreadImpl *mImpl;
+ };
+
+ QT3DS_FOUNDATION_API QT3DSU32 TlsAlloc();
+ QT3DS_FOUNDATION_API void TlsFree(QT3DSU32 index);
+ QT3DS_FOUNDATION_API void *TlsGet(QT3DSU32 index);
+ QT3DS_FOUNDATION_API QT3DSU32 TlsSet(QT3DSU32 index, void *value);
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSTime.h b/src/foundation/Qt3DSTime.h
new file mode 100644
index 0000000..955bd7e
--- /dev/null
+++ b/src/foundation/Qt3DSTime.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSTIME_H
+#define QT3DS_FOUNDATION_PSTIME_H
+
+#include "foundation/Qt3DS.h"
+
+#if defined(QT3DS_LINUX) || defined(QT3DS_ANDROID) || defined(QT3DS_QNX)
+#include <time.h>
+#endif
+
+namespace qt3ds {
+namespace foundation {
+
+ struct CounterFrequencyToTensOfNanos
+ {
+ QT3DSU64 mNumerator;
+ QT3DSU64 mDenominator;
+ CounterFrequencyToTensOfNanos(QT3DSU64 inNum, QT3DSU64 inDenom)
+ : mNumerator(inNum)
+ , mDenominator(inDenom)
+ {
+ }
+
+ // quite slow.
+ QT3DSU64 toTensOfNanos(QT3DSU64 inCounter) const
+ {
+ return (inCounter * mNumerator) / mDenominator;
+ }
+ };
+
+ class QT3DS_FOUNDATION_API Time
+ {
+ public:
+ typedef double Second;
+ static const QT3DSU64 sNumTensOfNanoSecondsInASecond = 100000000;
+ // This is supposedly guaranteed to not change after system boot
+ // regardless of processors, speedstep, etc.
+ static const CounterFrequencyToTensOfNanos sCounterFreq;
+
+ static CounterFrequencyToTensOfNanos getCounterFrequency();
+
+ static QT3DSU64 getCurrentCounterValue();
+
+ // SLOW!!
+ // Thar be a 64 bit divide in thar!
+ static QT3DSU64 getCurrentTimeInTensOfNanoSeconds()
+ {
+ QT3DSU64 ticks = getCurrentCounterValue();
+ return sCounterFreq.toTensOfNanos(ticks);
+ }
+
+ Time();
+ Second getElapsedSeconds();
+ Second peekElapsedSeconds();
+ Second getLastTime() const;
+
+ private:
+#if defined(QT3DS_LINUX) || defined(QT3DS_ANDROID) || defined(QT3DS_APPLE) || defined(QT3DS_PSP2) \
+ || defined(QT3DS_QNX)
+ Second mLastTime;
+#else
+ QT3DSI64 mTickCount;
+#endif
+ };
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/Qt3DSTransform.h b/src/foundation/Qt3DSTransform.h
new file mode 100644
index 0000000..0fee0a8
--- /dev/null
+++ b/src/foundation/Qt3DSTransform.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_TRANSFORM_H
+#define QT3DS_FOUNDATION_QT3DS_TRANSFORM_H
+/** \addtogroup foundation
+ @{
+*/
+
+#include "foundation/Qt3DSQuat.h"
+#include "foundation/Qt3DSPlane.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+/*!
+\brief class representing a rigid euclidean transform as a quaternion and a vector
+*/
+
+class NVTransform
+{
+public:
+ QT3DSQuat q;
+ QT3DSVec3 p;
+
+ //#define PXTRANSFORM_DEFAULT_CONSTRUCT_NAN
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVTransform()
+#ifdef PXTRANSFORM_DEFAULT_CONSTRUCT_IDENTITY
+ : q(0, 0, 0, 1)
+ , p(0, 0, 0)
+#elif defined(PXTRANSFORM_DEFAULT_CONSTRUCT_NAN)
+#define invalid NVSqrt(-1.0f)
+ : q(invalid, invalid, invalid, invalid)
+ , p(invalid, invalid, invalid)
+#undef invalid
+#endif
+ {
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE explicit NVTransform(const QT3DSVec3 &position)
+ : q(0, 0, 0, 1)
+ , p(position)
+ {
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE explicit NVTransform(const QT3DSQuat &orientation)
+ : q(orientation)
+ , p(0, 0, 0)
+ {
+ QT3DS_ASSERT(orientation.isSane());
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVTransform(const QT3DSVec3 &p0, const QT3DSQuat &q0)
+ : q(q0)
+ , p(p0)
+ {
+ QT3DS_ASSERT(q0.isSane());
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE explicit NVTransform(const QT3DSMat44 &m); // defined in Qt3DSMat44.h
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVTransform operator*(const NVTransform &x) const
+ {
+ QT3DS_ASSERT(x.isSane());
+ return transform(x);
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVTransform getInverse() const
+ {
+ QT3DS_ASSERT(isFinite());
+ return NVTransform(q.rotateInv(-p), q.getConjugate());
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 transform(const QT3DSVec3 &input) const
+ {
+ QT3DS_ASSERT(isFinite());
+ return q.rotate(input) + p;
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 transformInv(const QT3DSVec3 &input) const
+ {
+ QT3DS_ASSERT(isFinite());
+ return q.rotateInv(input - p);
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 rotate(const QT3DSVec3 &input) const
+ {
+ QT3DS_ASSERT(isFinite());
+ return q.rotate(input);
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 rotateInv(const QT3DSVec3 &input) const
+ {
+ QT3DS_ASSERT(isFinite());
+ return q.rotateInv(input);
+ }
+
+ //! Transform transform to parent (returns compound transform: first src, then *this)
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVTransform transform(const NVTransform &src) const
+ {
+ QT3DS_ASSERT(src.isSane());
+ QT3DS_ASSERT(isSane());
+ // src = [srct, srcr] -> [r*srct + t, r*srcr]
+ return NVTransform(q.rotate(src.p) + p, q * src.q);
+ }
+
+ /**
+ \brief returns true if finite and q is a unit quaternion
+ */
+
+ QT3DS_CUDA_CALLABLE bool isValid() const { return p.isFinite() && q.isFinite() && q.isUnit(); }
+
+ /**
+ \brief returns true if finite and quat magnitude is reasonably close to unit to allow for some
+ accumulation of error vs isValid
+ */
+
+ QT3DS_CUDA_CALLABLE bool isSane() const { return isFinite() && q.isSane(); }
+
+ /**
+ \brief returns true if all elems are finite (not NAN or INF, etc.)
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isFinite() const { return p.isFinite() && q.isFinite(); }
+
+ //! Transform transform from parent (returns compound transform: first src, then this->inverse)
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVTransform transformInv(const NVTransform &src) const
+ {
+ QT3DS_ASSERT(src.isSane());
+ QT3DS_ASSERT(isFinite());
+ // src = [srct, srcr] -> [r^-1*(srct-t), r^-1*srcr]
+ QT3DSQuat qinv = q.getConjugate();
+ return NVTransform(qinv.rotate(src.p - p), qinv * src.q);
+ }
+
+ QT3DS_CUDA_CALLABLE static QT3DS_FORCE_INLINE NVTransform createIdentity()
+ {
+ return NVTransform(QT3DSVec3(0));
+ }
+
+ /**
+ \brief transform plane
+ */
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVPlane transform(const NVPlane &plane) const
+ {
+ QT3DSVec3 transformedNormal = rotate(plane.n);
+ return NVPlane(transformedNormal, plane.d - p.dot(transformedNormal));
+ }
+
+ /**
+ \brief inverse-transform plane
+ */
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVPlane inverseTransform(const NVPlane &plane) const
+ {
+ QT3DSVec3 transformedNormal = rotateInv(plane.n);
+ return NVPlane(transformedNormal, plane.d + p.dot(plane.n));
+ }
+};
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_TRANSFORM_H
diff --git a/src/foundation/Qt3DSUnionCast.h b/src/foundation/Qt3DSUnionCast.h
new file mode 100644
index 0000000..a3d0355
--- /dev/null
+++ b/src/foundation/Qt3DSUnionCast.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_UNION_CAST_H
+#define QT3DS_FOUNDATION_QT3DS_UNION_CAST_H
+
+#include "foundation/Qt3DSPreprocessor.h"
+
+/** \addtogroup foundation
+@{
+*/
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+template <class A, class B>
+QT3DS_FORCE_INLINE A NVUnionCast(B b)
+{
+ union AB {
+ AB(B bb)
+ : _b(bb)
+ {
+ }
+ B _b;
+ A _a;
+ } u(b);
+ return u._a;
+}
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+
+#endif
diff --git a/src/foundation/Qt3DSUtilities.h b/src/foundation/Qt3DSUtilities.h
new file mode 100644
index 0000000..cb9ae6a
--- /dev/null
+++ b/src/foundation/Qt3DSUtilities.h
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_PSUTILITIES_H
+#define QT3DS_FOUNDATION_PSUTILITIES_H
+
+#include "foundation/Qt3DSVec3.h"
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSIntrinsics.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ // PT: checked casts
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSU16 to16(QT3DSU32 value)
+ {
+ QT3DS_ASSERT(value <= 0xffff);
+ return QT3DSU16(value);
+ }
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSU8 to8(QT3DSU16 value)
+ {
+ QT3DS_ASSERT(value <= 0xff);
+ return QT3DSU8(value);
+ }
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSU8 to8(QT3DSU32 value)
+ {
+ QT3DS_ASSERT(value <= 0xff);
+ return QT3DSU8(value);
+ }
+
+ template <class T>
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE void swap(T &x, T &y)
+ {
+// crash with optimizations enabled, ticket in Sony
+#ifdef QT3DS_PSP2
+#pragma control % push O = 0
+#endif
+ T tmp = x;
+ x = y;
+ y = tmp;
+#ifdef QT3DS_PSP2
+#pragma control % pop O
+#endif
+ }
+
+ /*!
+Get number of elements in array
+*/
+ template <typename T, size_t N>
+ char (&ArraySizeHelper(T (&array)[N]))[N];
+#define QT3DS_ARRAY_SIZE(_array) (sizeof(qt3ds::foundation::ArraySizeHelper(_array)))
+
+ /*!
+Sort two elements using operator<
+
+On return x will be the smaller of the two
+*/
+ template <class T>
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void order(T &x, T &y)
+ {
+ if (y < x)
+ swap(x, y);
+ }
+
+ // most architectures can do predication on real comparisons, and on VMX, it matters
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void order(NVReal &x, NVReal &y)
+ {
+ NVReal newX = NVMin(x, y);
+ NVReal newY = NVMax(x, y);
+ x = newX;
+ y = newY;
+ }
+
+ /*!
+ Sort two elements using operator< and also keep order
+ of any extra data
+ */
+ template <class T, class E1>
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE void order(T &x, T &y, E1 &xe1, E1 &ye1)
+ {
+ if (y < x) {
+ swap(x, y);
+ swap(xe1, ye1);
+ }
+ }
+
+ QT3DS_INLINE void debugBreak()
+ {
+#if defined(QT3DS_WINDOWS)
+ __debugbreak();
+#elif defined(QT3DS_LINUX) || defined(QT3DS_ANDROID) || defined(QT3DS_QNX)
+ asm("int $3");
+#elif defined(QT3DS_GNUC)
+ __builtin_trap();
+#else
+ QT3DS_ASSERT(false);
+#endif
+ }
+
+ bool checkValid(const float &);
+ bool checkValid(const QT3DSVec3 &);
+ bool checkValid(const QT3DSQuat &);
+ bool checkValid(const QT3DSMat33 &);
+ bool checkValid(const NVTransform &);
+ bool checkValid(const char *);
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSI32 getPadding2(size_t value, QT3DSU32 alignment)
+ {
+ const QT3DSI32 mask = alignment - 1;
+ const QT3DSI32 overhead = QT3DSI32(value) & mask;
+ return (alignment - overhead) & mask;
+ }
+
+ // PT: "After doing a dcbz128, there is a delay of about 140 cycles before writes to that cache
+ // line can proceed without stalling.
+ // This is much faster than an L2 cache miss, but for ideal performance, it is best to avoid
+ // this stall by doing the cache-line
+ // zeroing a few cache lines ahead of where you are writing."
+ QT3DS_FORCE_INLINE void invalidateCache(void *QT3DS_RESTRICT voidPtr, QT3DSI32 size)
+ {
+#ifdef QT3DS_X360
+ QT3DSU8 *QT3DS_RESTRICT ptr = reinterpret_cast<QT3DSU8 *>(voidPtr);
+ const QT3DSI32 padding = getPadding2(size_t(ptr), 128);
+ const QT3DSI32 sizeToCover = size - padding;
+ if (sizeToCover >= 128) {
+ QT3DSU8 *ptr128 = ptr + padding;
+ QT3DSU32 nb128 = sizeToCover / 128;
+ while (nb128--) {
+ // NV::memZero128(ptr128);
+ qt3ds::foundation::memZero128(ptr128);
+ ptr128 += 128;
+ }
+ }
+#else
+ (void)voidPtr;
+ (void)size;
+#endif
+ }
+
+ // equivalent to std::max_element
+ template <typename T>
+ inline const T *maxElement(const T *first, const T *last)
+ {
+ const T *m = first;
+ for (const T *it = first + 1; it < last; ++it)
+ if (*m < *it)
+ m = it;
+
+ return m;
+ }
+
+} // namespace foundation
+} // namespace qt3ds
+
+#define QT3DS_STRINGIZE_HELPER(X) #X
+#define QT3DS_STRINGIZE(X) QT3DS_STRINGIZE_HELPER(X)
+
+#define QT3DS_CONCAT_HELPER(X, Y) X##Y
+#define QT3DS_CONCAT(X, Y) QT3DS_CONCAT_HELPER(X, Y)
+
+#endif
diff --git a/src/foundation/Qt3DSVec2.h b/src/foundation/Qt3DSVec2.h
new file mode 100644
index 0000000..0d86c91
--- /dev/null
+++ b/src/foundation/Qt3DSVec2.h
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_VEC2_H
+#define QT3DS_FOUNDATION_QT3DS_VEC2_H
+
+/** \addtogroup foundation
+@{
+*/
+
+#include "foundation/Qt3DSMath.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+/**
+\brief 2 Element vector class.
+
+This is a vector class with public data members.
+This is not nice but it has become such a standard that hiding the xy data members
+makes it difficult to reuse external code that assumes that these are public in the library.
+The vector class can be made to use float or double precision by appropriately defining NVReal.
+This has been chosen as a cleaner alternative to a template class.
+*/
+class QT3DSVec2
+{
+public:
+ /**
+ \brief default constructor leaves data uninitialized.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2() {}
+
+ /**
+ \brief Assigns scalar parameter to all elements.
+
+ Useful to initialize to zero or one.
+
+ \param[in] a Value to assign to elements.
+ */
+ explicit QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2(NVReal a)
+ : x(a)
+ , y(a)
+ {
+ }
+
+ /**
+ \brief Initializes from 2 scalar parameters.
+
+ \param[in] nx Value to initialize X component.
+ \param[in] ny Value to initialize Y component.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2(NVReal nx, NVReal ny)
+ : x(nx)
+ , y(ny)
+ {
+ }
+
+ /**
+ \brief Copy ctor.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2(const QT3DSVec2 &v)
+ : x(v.x)
+ , y(v.y)
+ {
+ }
+
+ // Operators
+
+ /**
+ \brief Assignment operator
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 &operator=(const QT3DSVec2 &p)
+ {
+ x = p.x;
+ y = p.y;
+ return *this;
+ }
+
+ /**
+ \brief element access
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal &operator[](int index)
+ {
+ QT3DS_ASSERT(index >= 0 && index <= 1);
+ return (&x)[index];
+ }
+
+ /**
+ \brief element access
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const NVReal &operator[](int index) const
+ {
+ QT3DS_ASSERT(index >= 0 && index <= 1);
+ return (&x)[index];
+ }
+
+ /**
+ \brief returns true if the two vectors are exactly equal.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool operator==(const QT3DSVec2 &v) const
+ {
+ return x == v.x && y == v.y;
+ }
+
+ /**
+ \brief returns true if the two vectors are not exactly equal.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool operator!=(const QT3DSVec2 &v) const
+ {
+ return x != v.x || y != v.y;
+ }
+
+ /**
+ \brief tests for exact zero vector
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isZero() const { return x == 0.0f && y == 0.0f; }
+
+ /**
+ \brief returns true if all 2 elems of the vector are finite (not NAN or INF, etc.)
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool isFinite() const { return NVIsFinite(x) && NVIsFinite(y); }
+
+ /**
+ \brief is normalized - used by API parameter validation
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isNormalized() const
+ {
+ const float unitTolerance = NVReal(1e-4);
+ return isFinite() && NVAbs(magnitude() - 1) < unitTolerance;
+ }
+
+ /**
+ \brief returns the squared magnitude
+
+ Avoids calling NVSqrt()!
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal magnitudeSquared() const { return x * x + y * y; }
+
+ /**
+ \brief returns the magnitude
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal magnitude() const { return NVSqrt(magnitudeSquared()); }
+
+ /**
+ \brief negation
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 operator-() const { return QT3DSVec2(-x, -y); }
+
+ /**
+ \brief vector addition
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 operator+(const QT3DSVec2 &v) const
+ {
+ return QT3DSVec2(x + v.x, y + v.y);
+ }
+
+ /**
+ \brief vector difference
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 operator-(const QT3DSVec2 &v) const
+ {
+ return QT3DSVec2(x - v.x, y - v.y);
+ }
+
+ /**
+ \brief scalar post-multiplication
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 operator*(NVReal f) const
+ {
+ return QT3DSVec2(x * f, y * f);
+ }
+
+ /**
+ \brief scalar division
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 operator/(NVReal f) const
+ {
+ f = NVReal(1) / f; // PT: inconsistent notation with operator /=
+ return QT3DSVec2(x * f, y * f);
+ }
+
+ /**
+ \brief vector addition
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 &operator+=(const QT3DSVec2 &v)
+ {
+ x += v.x;
+ y += v.y;
+ return *this;
+ }
+
+ /**
+ \brief vector difference
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 &operator-=(const QT3DSVec2 &v)
+ {
+ x -= v.x;
+ y -= v.y;
+ return *this;
+ }
+
+ /**
+ \brief scalar multiplication
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 &operator*=(NVReal f)
+ {
+ x *= f;
+ y *= f;
+ return *this;
+ }
+ /**
+ \brief scalar division
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 &operator/=(NVReal f)
+ {
+ f = 1.0f / f; // PT: inconsistent notation with operator /
+ x *= f;
+ y *= f;
+ return *this;
+ }
+
+ /**
+ \brief returns the scalar product of this and other.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal dot(const QT3DSVec2 &v) const { return x * v.x + y * v.y; }
+
+ /** return a unit vector */
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 getNormalized() const
+ {
+ const NVReal m = magnitudeSquared();
+ return m > 0 ? *this * NVRecipSqrt(m) : QT3DSVec2(0, 0);
+ }
+
+ /**
+ \brief normalizes the vector in place
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal normalize()
+ {
+ const NVReal m = magnitude();
+ if (m > 0)
+ *this /= m;
+ return m;
+ }
+
+ /**
+ \brief a[i] * b[i], for all i.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 multiply(const QT3DSVec2 &a) const
+ {
+ return QT3DSVec2(x * a.x, y * a.y);
+ }
+
+ /**
+ \brief element-wise minimum
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 minimum(const QT3DSVec2 &v) const
+ {
+ return QT3DSVec2(NVMin(x, v.x), NVMin(y, v.y));
+ }
+
+ /**
+ \brief returns MIN(x, y);
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float minElement() const { return NVMin(x, y); }
+
+ /**
+ \brief element-wise maximum
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec2 maximum(const QT3DSVec2 &v) const
+ {
+ return QT3DSVec2(NVMax(x, v.x), NVMax(y, v.y));
+ }
+
+ /**
+ \brief returns MAX(x, y);
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float maxElement() const { return NVMax(x, y); }
+
+ NVReal x, y;
+};
+
+QT3DS_CUDA_CALLABLE static QT3DS_FORCE_INLINE QT3DSVec2 operator*(NVReal f, const QT3DSVec2 &v)
+{
+ return QT3DSVec2(f * v.x, f * v.y);
+}
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_VEC2_H
diff --git a/src/foundation/Qt3DSVec3.h b/src/foundation/Qt3DSVec3.h
new file mode 100644
index 0000000..24ab823
--- /dev/null
+++ b/src/foundation/Qt3DSVec3.h
@@ -0,0 +1,377 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_VEC3_H
+#define QT3DS_FOUNDATION_QT3DS_VEC3_H
+
+/** \addtogroup foundation
+@{
+*/
+
+#include "foundation/Qt3DSMath.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+/**
+\brief 3 Element vector class.
+
+This is a vector class with public data members.
+This is not nice but it has become such a standard that hiding the xyz data members
+makes it difficult to reuse external code that assumes that these are public in the library.
+The vector class can be made to use float or double precision by appropriately defining NVReal.
+This has been chosen as a cleaner alternative to a template class.
+*/
+class QT3DSVec3
+{
+public:
+ /**
+ \brief default constructor leaves data uninitialized.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3() {}
+
+ /**
+ \brief Assigns scalar parameter to all elements.
+
+ Useful to initialize to zero or one.
+
+ \param[in] a Value to assign to elements.
+ */
+ explicit QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3(NVReal a)
+ : x(a)
+ , y(a)
+ , z(a)
+ {
+ }
+
+ /**
+ \brief Initializes from 3 scalar parameters.
+
+ \param[in] nx Value to initialize X component.
+ \param[in] ny Value to initialize Y component.
+ \param[in] nz Value to initialize Z component.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3(NVReal nx, NVReal ny, NVReal nz)
+ : x(nx)
+ , y(ny)
+ , z(nz)
+ {
+ }
+
+ /**
+ \brief Copy ctor.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3(const QT3DSVec3 &v)
+ : x(v.x)
+ , y(v.y)
+ , z(v.z)
+ {
+ }
+
+ // Operators
+
+ /**
+ \brief Assignment operator
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 &operator=(const QT3DSVec3 &p)
+ {
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ return *this;
+ }
+
+ /**
+ \brief element access
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal &operator[](int index)
+ {
+ QT3DS_ASSERT(index >= 0 && index <= 2);
+ return (&x)[index];
+ }
+
+ /**
+ \brief element access
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE const NVReal &operator[](int index) const
+ {
+ QT3DS_ASSERT(index >= 0 && index <= 2);
+ return (&x)[index];
+ }
+
+ /**
+ \brief returns true if the two vectors are exactly equal.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool operator==(const QT3DSVec3 &v) const
+ {
+ return x == v.x && y == v.y && z == v.z;
+ }
+
+ /**
+ \brief returns true if the two vectors are not exactly equal.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool operator!=(const QT3DSVec3 &v) const
+ {
+ return x != v.x || y != v.y || z != v.z;
+ }
+
+ /**
+ \brief tests for exact zero vector
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isZero() const
+ {
+ return x == 0.0f && y == 0.0f && z == 0.0f;
+ }
+
+ /**
+ \brief returns true if all 3 elems of the vector are finite (not NAN or INF, etc.)
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool isFinite() const
+ {
+ return NVIsFinite(x) && NVIsFinite(y) && NVIsFinite(z);
+ }
+
+ /**
+ \brief is normalized - used by API parameter validation
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isNormalized() const
+ {
+ const float unitTolerance = NVReal(1e-4);
+ return isFinite() && NVAbs(magnitude() - 1) < unitTolerance;
+ }
+
+ /**
+ \brief returns the squared magnitude
+
+ Avoids calling NVSqrt()!
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal magnitudeSquared() const
+ {
+ return x * x + y * y + z * z;
+ }
+
+ /**
+ \brief returns the magnitude
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal magnitude() const { return NVSqrt(magnitudeSquared()); }
+
+ /**
+ \brief negation
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 operator-() const { return QT3DSVec3(-x, -y, -z); }
+
+ /**
+ \brief vector addition
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 operator+(const QT3DSVec3 &v) const
+ {
+ return QT3DSVec3(x + v.x, y + v.y, z + v.z);
+ }
+
+ /**
+ \brief vector difference
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 operator-(const QT3DSVec3 &v) const
+ {
+ return QT3DSVec3(x - v.x, y - v.y, z - v.z);
+ }
+
+ /**
+ \brief scalar post-multiplication
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 operator*(NVReal f) const
+ {
+ return QT3DSVec3(x * f, y * f, z * f);
+ }
+
+ /**
+ \brief scalar division
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 operator/(NVReal f) const
+ {
+ f = NVReal(1) / f; // PT: inconsistent notation with operator /=
+ return QT3DSVec3(x * f, y * f, z * f);
+ }
+
+ /**
+ \brief vector addition
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 &operator+=(const QT3DSVec3 &v)
+ {
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ return *this;
+ }
+
+ /**
+ \brief vector difference
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 &operator-=(const QT3DSVec3 &v)
+ {
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ return *this;
+ }
+
+ /**
+ \brief scalar multiplication
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 &operator*=(NVReal f)
+ {
+ x *= f;
+ y *= f;
+ z *= f;
+ return *this;
+ }
+ /**
+ \brief scalar division
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 &operator/=(NVReal f)
+ {
+ f = 1.0f / f; // PT: inconsistent notation with operator /
+ x *= f;
+ y *= f;
+ z *= f;
+ return *this;
+ }
+
+ /**
+ \brief returns the scalar product of this and other.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal dot(const QT3DSVec3 &v) const
+ {
+ return x * v.x + y * v.y + z * v.z;
+ }
+
+ /**
+ \brief cross product
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 cross(const QT3DSVec3 &v) const
+ {
+ return QT3DSVec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
+ }
+
+ /** return a unit vector */
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 getNormalized() const
+ {
+ const NVReal m = magnitudeSquared();
+ return m > 0 ? *this * NVRecipSqrt(m) : QT3DSVec3(0, 0, 0);
+ }
+
+ /**
+ \brief normalizes the vector in place
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal normalize()
+ {
+ const NVReal m = magnitude();
+ if (m > 0)
+ *this /= m;
+ return m;
+ }
+
+ /**
+ \brief normalizes the vector in place. Does nothing if vector magnitude is under
+ QT3DS_NORMALIZATION_EPSILON.
+ Returns vector magnitude if >= QT3DS_NORMALIZATION_EPSILON and 0.0f otherwise.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal normalizeSafe()
+ {
+ const NVReal mag = magnitude();
+ if (mag < QT3DS_NORMALIZATION_EPSILON)
+ return 0.0f;
+ *this *= NVReal(1) / mag;
+ return mag;
+ }
+
+ /**
+ \brief normalizes the vector in place. Asserts if vector magnitude is under
+ QT3DS_NORMALIZATION_EPSILON.
+ returns vector magnitude.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE NVReal normalizeFast()
+ {
+ const NVReal mag = magnitude();
+ QT3DS_ASSERT(mag >= QT3DS_NORMALIZATION_EPSILON);
+ *this *= NVReal(1) / mag;
+ return mag;
+ }
+
+ /**
+ \brief a[i] * b[i], for all i.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 multiply(const QT3DSVec3 &a) const
+ {
+ return QT3DSVec3(x * a.x, y * a.y, z * a.z);
+ }
+
+ /**
+ \brief element-wise minimum
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 minimum(const QT3DSVec3 &v) const
+ {
+ return QT3DSVec3(NVMin(x, v.x), NVMin(y, v.y), NVMin(z, v.z));
+ }
+
+ /**
+ \brief returns MIN(x, y, z);
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float minElement() const { return NVMin(x, NVMin(y, z)); }
+
+ /**
+ \brief element-wise maximum
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE QT3DSVec3 maximum(const QT3DSVec3 &v) const
+ {
+ return QT3DSVec3(NVMax(x, v.x), NVMax(y, v.y), NVMax(z, v.z));
+ }
+
+ /**
+ \brief returns MAX(x, y, z);
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float maxElement() const { return NVMax(x, NVMax(y, z)); }
+
+ NVReal x, y, z;
+};
+
+QT3DS_CUDA_CALLABLE static QT3DS_FORCE_INLINE QT3DSVec3 operator*(NVReal f, const QT3DSVec3 &v)
+{
+ return QT3DSVec3(f * v.x, f * v.y, f * v.z);
+}
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_VEC3_H
diff --git a/src/foundation/Qt3DSVec4.h b/src/foundation/Qt3DSVec4.h
new file mode 100644
index 0000000..acccd48
--- /dev/null
+++ b/src/foundation/Qt3DSVec4.h
@@ -0,0 +1,373 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_VEC4_H
+#define QT3DS_FOUNDATION_QT3DS_VEC4_H
+/** \addtogroup foundation
+@{
+*/
+#include "foundation/Qt3DSMath.h"
+#include "foundation/Qt3DSVec3.h"
+#include "foundation/Qt3DSAssert.h"
+
+/**
+\brief 4 Element vector class.
+
+This is a vector class with public data members.
+This is not nice but it has become such a standard that hiding the xyz data members
+makes it difficult to reuse external code that assumes that these are public in the library.
+The vector class can be made to use float or double precision by appropriately defining NVReal.
+This has been chosen as a cleaner alternative to a template class.
+*/
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+class QT3DSVec4
+{
+public:
+ /**
+ \brief default constructor leaves data uninitialized.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4() {}
+
+ /**
+ \brief Assigns scalar parameter to all elements.
+
+ Useful to initialize to zero or one.
+
+ \param[in] a Value to assign to elements.
+ */
+ explicit QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4(NVReal a)
+ : x(a)
+ , y(a)
+ , z(a)
+ , w(a)
+ {
+ }
+
+ /**
+ \brief Initializes from 3 scalar parameters.
+
+ \param[in] nx Value to initialize X component.
+ \param[in] ny Value to initialize Y component.
+ \param[in] nz Value to initialize Z component.
+ \param[in] nw Value to initialize W component.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4(NVReal nx, NVReal ny, NVReal nz, NVReal nw)
+ : x(nx)
+ , y(ny)
+ , z(nz)
+ , w(nw)
+ {
+ }
+
+ /**
+ \brief Initializes from 3 scalar parameters.
+
+ \param[in] v Value to initialize the X, Y, and Z components.
+ \param[in] nw Value to initialize W component.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4(const QT3DSVec3 &v, NVReal nw)
+ : x(v.x)
+ , y(v.y)
+ , z(v.z)
+ , w(nw)
+ {
+ }
+
+ /**
+ \brief Initializes from an array of scalar parameters.
+
+ \param[in] v Value to initialize with.
+ */
+ explicit QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4(const NVReal v[])
+ : x(v[0])
+ , y(v[1])
+ , z(v[2])
+ , w(v[3])
+ {
+ }
+
+ /**
+ \brief Copy ctor.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4(const QT3DSVec4 &v)
+ : x(v.x)
+ , y(v.y)
+ , z(v.z)
+ , w(v.w)
+ {
+ }
+
+ // Operators
+
+ /**
+ \brief Assignment operator
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 &operator=(const QT3DSVec4 &p)
+ {
+ x = p.x;
+ y = p.y;
+ z = p.z;
+ w = p.w;
+ return *this;
+ }
+
+ /**
+ \brief element access
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal &operator[](int index)
+ {
+ QT3DS_ASSERT(index >= 0 && index <= 3);
+ return (&x)[index];
+ }
+
+ /**
+ \brief element access
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE const NVReal &operator[](int index) const
+ {
+ QT3DS_ASSERT(index >= 0 && index <= 3);
+ return (&x)[index];
+ }
+
+ /**
+ \brief returns true if the two vectors are exactly equal.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool operator==(const QT3DSVec4 &v) const
+ {
+ return x == v.x && y == v.y && z == v.z && w == v.w;
+ }
+
+ /**
+ \brief returns true if the two vectors are not exactly equal.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool operator!=(const QT3DSVec4 &v) const
+ {
+ return x != v.x || y != v.y || z != v.z || w != v.w;
+ }
+
+ /**
+ \brief tests for exact zero vector
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool isZero() const { return x == 0 && y == 0 && z == 0 && w == 0; }
+
+ /**
+ \brief returns true if all 3 elems of the vector are finite (not NAN or INF, etc.)
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool isFinite() const
+ {
+ return NVIsFinite(x) && NVIsFinite(y) && NVIsFinite(z) && NVIsFinite(w);
+ }
+
+ /**
+ \brief is normalized - used by API parameter validation
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE bool isNormalized() const
+ {
+ const float unitTolerance = NVReal(1e-4);
+ return isFinite() && NVAbs(magnitude() - 1) < unitTolerance;
+ }
+
+ /**
+ \brief returns the squared magnitude
+
+ Avoids calling NVSqrt()!
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal magnitudeSquared() const
+ {
+ return x * x + y * y + z * z + w * w;
+ }
+
+ /**
+ \brief returns the magnitude
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal magnitude() const { return NVSqrt(magnitudeSquared()); }
+
+ /**
+ \brief negation
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 operator-() const { return QT3DSVec4(-x, -y, -z, -w); }
+
+ /**
+ \brief vector addition
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 operator+(const QT3DSVec4 &v) const
+ {
+ return QT3DSVec4(x + v.x, y + v.y, z + v.z, w + v.w);
+ }
+
+ /**
+ \brief vector difference
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 operator-(const QT3DSVec4 &v) const
+ {
+ return QT3DSVec4(x - v.x, y - v.y, z - v.z, w - v.w);
+ }
+
+ /**
+ \brief scalar post-multiplication
+ */
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 operator*(NVReal f) const
+ {
+ return QT3DSVec4(x * f, y * f, z * f, w * f);
+ }
+
+ /**
+ \brief scalar division
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 operator/(NVReal f) const
+ {
+ f = NVReal(1) / f;
+ return QT3DSVec4(x * f, y * f, z * f, w * f);
+ }
+
+ /**
+ \brief vector addition
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 &operator+=(const QT3DSVec4 &v)
+ {
+ x += v.x;
+ y += v.y;
+ z += v.z;
+ w += v.w;
+ return *this;
+ }
+
+ /**
+ \brief vector difference
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 &operator-=(const QT3DSVec4 &v)
+ {
+ x -= v.x;
+ y -= v.y;
+ z -= v.z;
+ w -= v.w;
+ return *this;
+ }
+
+ /**
+ \brief scalar multiplication
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 &operator*=(NVReal f)
+ {
+ x *= f;
+ y *= f;
+ z *= f;
+ w *= f;
+ return *this;
+ }
+ /**
+ \brief scalar division
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 &operator/=(NVReal f)
+ {
+ f = 1.0f / f;
+ x *= f;
+ y *= f;
+ z *= f;
+ w *= f;
+ return *this;
+ }
+
+ /**
+ \brief returns the scalar product of this and other.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal dot(const QT3DSVec4 &v) const
+ {
+ return x * v.x + y * v.y + z * v.z + w * v.w;
+ }
+
+ /** return a unit vector */
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 getNormalized() const
+ {
+ NVReal m = magnitudeSquared();
+ return m > 0 ? *this * NVRecipSqrt(m) : QT3DSVec4(0, 0, 0, 0);
+ }
+
+ /**
+ \brief normalizes the vector in place
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE NVReal normalize()
+ {
+ NVReal m = magnitude();
+ if (m > 0)
+ *this /= m;
+ return m;
+ }
+
+ /**
+ \brief a[i] * b[i], for all i.
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 multiply(const QT3DSVec4 &a) const
+ {
+ return QT3DSVec4(x * a.x, y * a.y, z * a.z, w * a.w);
+ }
+
+ /**
+ \brief element-wise minimum
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 minimum(const QT3DSVec4 &v) const
+ {
+ return QT3DSVec4(NVMin(x, v.x), NVMin(y, v.y), NVMin(z, v.z), NVMin(w, v.w));
+ }
+
+ /**
+ \brief element-wise maximum
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec4 maximum(const QT3DSVec4 &v) const
+ {
+ return QT3DSVec4(NVMax(x, v.x), NVMax(y, v.y), NVMax(z, v.z), NVMax(w, v.w));
+ }
+
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE QT3DSVec3 getXYZ() const { return QT3DSVec3(x, y, z); }
+
+ /**
+ \brief set vector elements to zero
+ */
+ QT3DS_CUDA_CALLABLE QT3DS_INLINE void setZero() { x = y = z = w = NVReal(0); }
+
+ NVReal x, y, z, w;
+};
+
+QT3DS_CUDA_CALLABLE static QT3DS_INLINE QT3DSVec4 operator*(NVReal f, const QT3DSVec4 &v)
+{
+ return QT3DSVec4(f * v.x, f * v.y, f * v.z, f * v.w);
+}
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+/** @} */
+#endif // QT3DS_FOUNDATION_QT3DS_VEC4_H
diff --git a/src/foundation/Qt3DSVersionNumber.h b/src/foundation/Qt3DSVersionNumber.h
new file mode 100644
index 0000000..5942ef7
--- /dev/null
+++ b/src/foundation/Qt3DSVersionNumber.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+/*
+VersionNumbers: The combination of these
+numbers uniquely identifies the API, and should
+be incremented when the SDK API changes. This may
+include changes to file formats.
+
+This header is included in the main SDK header files
+so that the entire SDK and everything that builds on it
+is completely rebuilt when this file changes. Thus,
+this file is not to include a frequently changing
+build number. See BuildNumber.h for that.
+
+Each of these three values should stay below 255 because
+sometimes they are stored in a byte.
+*/
+/** \addtogroup foundation
+ @{
+*/
+#ifndef QT3DS_FOUNDATION_QT3DS_VERSION_NUMBER_H
+#define QT3DS_FOUNDATION_QT3DS_VERSION_NUMBER_H
+
+#define QT3DS_FOUNDATION_VERSION_MAJOR 3
+#define QT3DS_FOUNDATION_VERSION_MINOR 3
+#define QT3DS_FOUNDATION_VERSION_BUGFIX 0
+
+/**
+The constant QT3DS_FOUNDATION_VERSION is used when creating certain PhysX module objects.
+This is to ensure that the application is using the same header version as the library was built
+with.
+*/
+#define QT3DS_FOUNDATION_VERSION \
+ ((QT3DS_FOUNDATION_VERSION_MAJOR << 24) + (QT3DS_FOUNDATION_VERSION_MINOR << 16) \
+ + (QT3DS_FOUNDATION_VERSION_BUGFIX << 8) + 0)
+
+#endif // QT3DS_FOUNDATION_QT3DS_VERSION_NUMBER_H
+
+/** @} */
diff --git a/src/foundation/SerializationTypes.h b/src/foundation/SerializationTypes.h
new file mode 100644
index 0000000..c7fe5ce
--- /dev/null
+++ b/src/foundation/SerializationTypes.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_RENDER_SERIALIZATION_TYPES_H
+#define QT3DS_RENDER_SERIALIZATION_TYPES_H
+#include "EASTL/hash_map.h"
+#include "foundation/Qt3DSDataRef.h"
+#include "foundation/Qt3DSMemoryBuffer.h"
+#include "foundation/Qt3DSContainers.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ struct SStrRemapMap : public nvhash_map<char8_t *, QT3DSU32>
+ {
+ typedef nvhash_map<char8_t *, QT3DSU32> TBaseType;
+ SStrRemapMap(NVAllocatorCallback &inAlloc, const char *inName)
+ : TBaseType(inAlloc, inName)
+ {
+ }
+ };
+
+ struct SPtrOffsetMap : public nvhash_map<const void *, QT3DSU32>
+ {
+ typedef nvhash_map<const void *, QT3DSU32> TBaseType;
+ SPtrOffsetMap(NVAllocatorCallback &inAlloc, const char *inName)
+ : TBaseType(inAlloc, inName)
+ {
+ }
+ };
+
+ struct SWriteBuffer : public MemoryBuffer<>
+ {
+ SWriteBuffer(NVAllocatorCallback &inAlloc, const char *inName)
+ : MemoryBuffer<>(ForwardingAllocator(inAlloc, inName))
+ {
+ }
+ };
+
+ // Simple data reader that mimics a string
+ struct SDataReader
+ {
+ QT3DSU8 *m_CurrentPtr;
+ QT3DSU8 *m_EndPtr;
+ SDataReader(QT3DSU8 *inStartPtr, QT3DSU8 *inEndPtr)
+ : m_CurrentPtr(inStartPtr)
+ , m_EndPtr(inEndPtr)
+ {
+ }
+
+ template <typename TDataType>
+ TDataType *Load()
+ {
+ if ((m_CurrentPtr + sizeof(TDataType)) > m_EndPtr) {
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+ TDataType *theType = reinterpret_cast<TDataType *>(m_CurrentPtr);
+ m_CurrentPtr += sizeof(TDataType);
+ return theType;
+ }
+
+ template <typename TDataType>
+ void MemCopy(TDataType *dt, QT3DSU32 count)
+ {
+ if (count) {
+ QT3DSU32 loadSize = count * sizeof(TDataType);
+ QT3DSU32 amountLeft = (QT3DSU32)(m_EndPtr - m_CurrentPtr);
+ QT3DSU32 amountLoaded = NVMin(loadSize, amountLeft);
+ memCopy(dt, m_CurrentPtr, amountLoaded);
+ m_CurrentPtr += amountLoaded;
+ if (amountLoaded < loadSize) {
+ QT3DS_ASSERT(false);
+ QT3DSU8 *rawPtr = (QT3DSU8 *)dt;
+ rawPtr += amountLoaded;
+ size_t leftover = loadSize - amountLoaded;
+ // zeroing things out at least is an attempt to provide ordered
+ // data that may prevent a crash in some cases.
+ memZero(rawPtr, (QT3DSU32)leftover);
+ }
+ }
+ }
+
+ // Don't make a habit of using this a lot.
+ template <typename TDataType>
+ TDataType &LoadRef()
+ {
+ TDataType *retval = Load<TDataType>();
+ if (!retval)
+ QT3DS_ASSERT(false);
+ return *retval;
+ }
+
+ void Align(size_t alignment)
+ {
+ size_t offset = (size_t)(m_CurrentPtr);
+ if (offset % alignment)
+ m_CurrentPtr += (alignment - (offset % alignment));
+ }
+
+ void Align() { Align(sizeof(void *)); }
+ };
+}
+}
+#endif \ No newline at end of file
diff --git a/src/foundation/Socket.cpp b/src/foundation/Socket.cpp
new file mode 100644
index 0000000..df00e60
--- /dev/null
+++ b/src/foundation/Socket.cpp
@@ -0,0 +1,472 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+/*
+LuaSocket 3.0 license
+Copyright � 2004-2013 Diego Nehab
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#include "foundation/Socket.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSSync.h"
+#include "foundation/Qt3DSMemoryBuffer.h"
+
+#if defined QT3DS_WINDOWS || defined QT3DS_WIN8ARM
+#include "windows/SocketImpl.h"
+#else
+#include "linux/SocketImpl.h"
+#endif
+
+using namespace qt3ds;
+using namespace qt3ds::foundation;
+using namespace qt3ds::foundation::socketimpl;
+
+namespace {
+
+#if defined QT3DS_WINDOWS || defined QT3DS_WIN8ARM
+/*-------------------------------------------------------------------------*\
+* Some systems do not provide this so that we provide our own. It's not
+* marvelously fast, but it works just fine.
+\*-------------------------------------------------------------------------*/
+int inet_aton(const char *cp, struct in_addr *inp)
+{
+ unsigned int a = 0, b = 0, c = 0, d = 0;
+ int n = 0, r;
+ unsigned long int addr = 0;
+ r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n);
+ if (r == 0 || n == 0)
+ return 0;
+ cp += n;
+ if (*cp)
+ return 0;
+ if (a > 255 || b > 255 || c > 255 || d > 255)
+ return 0;
+ if (inp) {
+ addr += a;
+ addr <<= 8;
+ addr += b;
+ addr <<= 8;
+ addr += c;
+ addr <<= 8;
+ addr += d;
+ inp->s_addr = htonl(addr);
+ }
+ return 1;
+}
+#endif
+
+/*-------------------------------------------------------------------------*\
+* Tries to connect to remote address (address, port)
+\*-------------------------------------------------------------------------*/
+int inet_tryconnect(p_socket ps, const char *address, unsigned short port, QT3DSU32 tm, SA *remoteAddr)
+{
+ struct sockaddr_in remote;
+ int err;
+ memset(&remote, 0, sizeof(remote));
+ remote.sin_family = AF_INET;
+ remote.sin_port = htons(port);
+ if (strcmp(address, "*")) {
+ if (!inet_aton(address, &remote.sin_addr)) {
+ struct hostent *hp = NULL;
+ struct in_addr **addr;
+ err = socket_gethostbyname(address, &hp);
+ if (err != IO_DONE)
+ return err;
+ addr = (struct in_addr **)hp->h_addr_list;
+ memcpy(&remote.sin_addr, *addr, sizeof(struct in_addr));
+ }
+ } else
+ remote.sin_family = AF_UNSPEC;
+ if (remoteAddr)
+ memcpy(remoteAddr, &remote, sizeof(remote));
+ err = socket_connect(ps, (SA *)&remote, sizeof(remote), tm);
+ return err;
+}
+
+/*-------------------------------------------------------------------------*\
+* Tries to bind socket to (address, port)
+\*-------------------------------------------------------------------------*/
+int inet_trybind(p_socket ps, const char *address, unsigned short port)
+{
+ struct sockaddr_in local;
+ int err;
+ memset(&local, 0, sizeof(local));
+ /* address is either wildcard or a valid ip address */
+ local.sin_addr.s_addr = htonl(INADDR_ANY);
+ local.sin_port = htons(port);
+ local.sin_family = AF_INET;
+ if (strcmp(address, "*") && !inet_aton(address, &local.sin_addr)) {
+ struct hostent *hp = NULL;
+ struct in_addr **addr;
+ err = socket_gethostbyname(address, &hp);
+ if (err != IO_DONE)
+ return err;
+ addr = (struct in_addr **)hp->h_addr_list;
+ memcpy(&local.sin_addr, *addr, sizeof(struct in_addr));
+ }
+ err = socket_bind(ps, (SA *)&local, sizeof(local));
+ if (err != IO_DONE)
+ socket_destroy(ps);
+ return err;
+}
+
+static bool is_socket_error(int errcode)
+{
+ return errcode != IO_DONE && errcode != IO_TIMEOUT;
+}
+
+const char *generalized_strerror(int err)
+{
+ if (err <= 0)
+ return io_strerror(err);
+ else
+ return socket_strerror(err);
+}
+
+struct SocketSystemCore : public NVRefCounted
+{
+ NVFoundationBase &m_Foundation;
+ QT3DSI32 mRefCount;
+ SocketSystemCore(NVFoundationBase &fnd)
+ : m_Foundation(fnd)
+ , mRefCount(0)
+ {
+ }
+ ~SocketSystemCore() { socket_close(); }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation.getAllocator())
+
+ static NVScopedRefCounted<SocketSystemCore> Create(NVFoundationBase &fnd)
+ {
+ int success = socket_open();
+ if (!success) {
+ qCCritical(INVALID_OPERATION, "Failed to initialize network subsystem");
+ return NVScopedRefCounted<SocketSystemCore>();
+ }
+ return QT3DS_NEW(fnd.getAllocator(), SocketSystemCore)(fnd);
+ }
+};
+
+struct SocketStreamImpl : public SocketStream
+{
+ NVScopedRefCounted<SocketSystemCore> m_SocketCore;
+ NVFoundationBase &m_Foundation;
+ t_socket m_Socket;
+ SA m_Destination;
+ bool m_Connected;
+ QT3DSU32 m_Timeout;
+ QT3DSI32 mRefCount;
+ SocketStreamImpl(SocketSystemCore &core, NVFoundationBase &fnd, t_socket s, SA dest)
+ : m_SocketCore(core)
+ , m_Foundation(fnd)
+ , m_Socket(s)
+ , m_Destination(dest)
+ , m_Connected(true)
+ , m_Timeout(10000)
+ , mRefCount(0)
+ {
+ // We use wait functions in order to block.
+ socket_setnonblocking(&m_Socket);
+ }
+
+ ~SocketStreamImpl()
+ {
+ shutdown();
+ socket_destroy(&m_Socket);
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Foundation.getAllocator())
+
+ void setTimeout(QT3DSU32 milliseconds) override { m_Timeout = milliseconds; }
+
+ bool Write(NVConstDataRef<QT3DSU8> data) override
+ {
+ if (m_Connected == false)
+ return false;
+
+ size_t totalSent = 0;
+ const char *writePtr(reinterpret_cast<const char *>(data.begin()));
+ size_t amountLeft = data.size();
+ do {
+
+ size_t amountSent = 0;
+ int errcode =
+ socket_send(&m_Socket, writePtr + totalSent, amountLeft, &amountSent, m_Timeout);
+
+ if (is_socket_error(errcode)) {
+ m_Connected = false;
+ qCWarning(WARNING, "Networking error during send: %s", generalized_strerror(errcode));
+ return false;
+ }
+ totalSent += amountSent;
+ amountLeft -= amountSent;
+ } while (amountLeft);
+ return true;
+ }
+
+ QT3DSU32 Read(NVDataRef<QT3DSU8> data) override
+ {
+ if (m_Connected == false)
+ return 0;
+ size_t amountReceived = 0;
+ int errcode = socket_recv(&m_Socket, reinterpret_cast<char *>(data.begin()), data.size(),
+ &amountReceived, m_Timeout);
+ if (is_socket_error(errcode)) {
+ m_Connected = false;
+ qCWarning(WARNING, "Networking error during receive: %s", generalized_strerror(errcode));
+ return false;
+ }
+ return static_cast<QT3DSU32>(amountReceived);
+ }
+
+ QT3DSU32 nonBlockingRead(NVDataRef<QT3DSU8> data) override
+ {
+ if (m_Connected == false)
+ return 0;
+ size_t amountReceived = 0;
+ int errcode = socket_recv(&m_Socket, reinterpret_cast<char *>(data.begin()), data.size(),
+ &amountReceived, 0);
+ if (is_socket_error(errcode)) {
+ m_Connected = false;
+ qCWarning(WARNING, "Networking error during receive: %s",
+ generalized_strerror(errcode));
+ return false;
+ }
+ return static_cast<QT3DSU32>(amountReceived);
+ }
+
+ bool connected() override { return m_Connected; }
+
+ void shutdown() override
+ {
+ if (m_Connected) {
+ socket_shutdown(&m_Socket, 2);
+ m_Connected = false;
+ }
+ }
+};
+
+struct FileSocketStreamImpl : public SocketStream
+{
+ NVFoundationBase &m_Foundation;
+ CFileSeekableIOStream m_Stream;
+ FileOpenFlags m_FileFlags;
+ bool m_Connected;
+ QT3DSI32 mRefCount;
+
+ FileSocketStreamImpl(NVFoundationBase &fnd, const char *fname, FileOpenFlags fileFlags)
+ : m_Foundation(fnd)
+ , m_Stream(fname, fileFlags)
+ , m_FileFlags(fileFlags)
+ , m_Connected(false)
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Foundation.getAllocator())
+
+ bool IsOpen() { return m_Connected && m_Stream.IsOpen(); }
+
+ QT3DSU32 Read(NVDataRef<QT3DSU8> data) override
+ {
+ if (IsOpen()) {
+ QT3DSU32 retval = m_Stream.Read(data);
+ if (retval < data.size())
+ m_Connected = false;
+ return retval;
+ }
+
+ return 0;
+ }
+
+ bool Write(NVConstDataRef<QT3DSU8> data) override
+ {
+ bool canWrite = m_FileFlags & FileOpenFlagValues::Write;
+ if (IsOpen() && canWrite) {
+ m_Stream.Write(data);
+ return true;
+ }
+ return false;
+ }
+
+ void setTimeout(QT3DSU32) override {}
+
+ QT3DSU32 nonBlockingRead(NVDataRef<QT3DSU8> data) override { return Read(data); }
+
+ bool connected() override { return m_Connected; }
+
+ void shutdown() override { m_Connected = false; }
+};
+
+struct SocketServerImpl : public SocketServer
+{
+ NVScopedRefCounted<SocketSystemCore> m_SocketCore;
+ NVFoundationBase &m_Foundation;
+ t_socket m_Socket;
+ int m_Port;
+ QT3DSU32 m_Timeout;
+ QT3DSI32 mRefCount;
+ SocketServerImpl(SocketSystemCore &core, NVFoundationBase &fnd, t_socket s, int port)
+ : m_SocketCore(core)
+ , m_Foundation(fnd)
+ , m_Socket(s)
+ , m_Port(port)
+ , m_Timeout(10000)
+ , mRefCount(0)
+ {
+ }
+
+ ~SocketServerImpl() { socket_destroy(&m_Socket); }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Foundation.getAllocator())
+
+ int port() override { return m_Port; }
+
+ void setTimeout(QT3DSU32 milliseconds) override { m_Timeout = milliseconds; }
+
+ NVScopedRefCounted<SocketStream> nextClient() override
+ {
+ SA daddr;
+ memset(&daddr, 0, sizeof(daddr));
+ t_socket new_socket;
+ int errcode = socket_accept(&m_Socket, &new_socket, NULL, NULL, m_Timeout);
+
+ if (is_socket_error(errcode)) {
+ return NVScopedRefCounted<SocketStream>();
+ } else if (errcode == IO_DONE) {
+ return QT3DS_NEW(m_Foundation.getAllocator(),
+ SocketStreamImpl)(*m_SocketCore, m_Foundation, new_socket, daddr);
+ }
+ return NVScopedRefCounted<SocketStream>();
+ }
+};
+
+struct SocketSystemImpl : public SocketSystem
+{
+ NVScopedRefCounted<SocketSystemCore> m_SocketCore;
+ NVFoundationBase &m_Foundation;
+ QT3DSI32 mRefCount;
+ SocketSystemImpl(SocketSystemCore &core, NVFoundationBase &fnd)
+ : m_SocketCore(core)
+ , m_Foundation(fnd)
+ , mRefCount(0)
+
+ {
+ }
+ ~SocketSystemImpl() {}
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation.getAllocator())
+
+ NVScopedRefCounted<SocketStream> createStream(const char *host, QT3DSI32 port,
+ QT3DSU32 timeoutMilliseconds) override
+ {
+ t_socket newSocket(SOCKET_INVALID);
+ int errcode = socket_create(&newSocket, PF_INET, SOCK_STREAM, 0);
+ if (is_socket_error(errcode)) {
+ qCWarning(WARNING, "Error during connect: %s", generalized_strerror(errcode));
+ return NVScopedRefCounted<SocketStream>();
+ }
+ SA remoteAddr;
+ memset(&remoteAddr, 0, sizeof(SA));
+ errcode = inet_tryconnect(&newSocket, host, (unsigned short)port, timeoutMilliseconds,
+ &remoteAddr);
+ if (is_socket_error(errcode)) {
+ qCWarning(WARNING, "Error during connect: %s", generalized_strerror(errcode));
+ return NVScopedRefCounted<SocketStream>();
+ } else if (errcode == IO_DONE) {
+ return QT3DS_NEW(m_Foundation.getAllocator(),
+ SocketStreamImpl)(*m_SocketCore, m_Foundation, newSocket, remoteAddr);
+ }
+ return NVScopedRefCounted<SocketStream>();
+ }
+
+ NVScopedRefCounted<SocketServer> createServer(QT3DSI32 port) override
+ {
+ t_socket newSocket(SOCKET_INVALID);
+ int errcode = socket_create(&newSocket, PF_INET, SOCK_STREAM, 0);
+ if (is_socket_error(errcode)) {
+ qCWarning(WARNING, "Error during create server create socket: %s",
+ generalized_strerror(errcode));
+ return NVScopedRefCounted<SocketServer>();
+ }
+ errcode = inet_trybind(&newSocket, "*", (unsigned short)port);
+ if (is_socket_error(errcode)) {
+ qCWarning(WARNING, "Error during create server bind: %s",
+ generalized_strerror(errcode));
+ return NVScopedRefCounted<SocketServer>();
+ } else if (errcode == IO_DONE) {
+ errcode = socket_listen(&newSocket, 10);
+ if (errcode == IO_DONE) {
+ return QT3DS_NEW(m_Foundation.getAllocator(),
+ SocketServerImpl)(*m_SocketCore, m_Foundation, newSocket, port);
+ } else
+ qCWarning(WARNING, "Error during create server listen: %s",
+ generalized_strerror(errcode));
+ }
+ return NVScopedRefCounted<SocketServer>();
+ }
+};
+}
+
+NVScopedRefCounted<SocketStream>
+SocketStream::CreateFileStream(NVFoundationBase &fnd, const char *fname, FileOpenFlags flags)
+{
+ return QT3DS_NEW(fnd.getAllocator(), FileSocketStreamImpl)(fnd, fname, flags);
+}
+
+NVScopedRefCounted<SocketSystem> SocketSystem::createSocketSystem(NVFoundationBase &fnd)
+{
+ NVScopedRefCounted<SocketSystemCore> theCore = SocketSystemCore::Create(fnd);
+ if (theCore) {
+ return QT3DS_NEW(fnd.getAllocator(), SocketSystemImpl)(*theCore, fnd);
+ }
+ return NVScopedRefCounted<SocketSystem>();
+}
diff --git a/src/foundation/Socket.h b/src/foundation/Socket.h
new file mode 100644
index 0000000..f561ab8
--- /dev/null
+++ b/src/foundation/Socket.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_FOUNDATION_SOCKET_H
+#define QT3DS_FOUNDATION_SOCKET_H
+#include "foundation/IOStreams.h"
+#include "foundation/Qt3DSRefCounted.h"
+#include "foundation/Qt3DSMemoryBuffer.h"
+
+namespace qt3ds {
+
+class NVFoundationBase;
+namespace foundation {
+
+ class SocketStream : public IInStream, public IOutStream, public NVRefCounted
+ {
+ public:
+ // set timeout for write and blocking read operations
+ // Setting to zero makes all operations nonblocking.
+ virtual void setTimeout(QT3DSU32 milliseconds) = 0;
+ virtual QT3DSU32 nonBlockingRead(NVDataRef<QT3DSU8> ioBuffer) = 0;
+ virtual bool connected() = 0;
+ virtual void shutdown() = 0;
+
+ // Useful to testing systems without going into the issues that a network connection can
+ // cause.
+ static NVScopedRefCounted<SocketStream>
+ CreateFileStream(NVFoundationBase &fnd, const char *fname, FileOpenFlags flags);
+ };
+
+ class SocketServer : public NVRefCounted
+ {
+ public:
+ virtual int port() = 0;
+ virtual void setTimeout(QT3DSU32 milliseconds) = 0;
+ virtual NVScopedRefCounted<SocketStream> nextClient() = 0;
+ };
+
+ class SocketSystem : public NVRefCounted
+ {
+ public:
+ // timeout of 0 means wait forever
+ virtual NVScopedRefCounted<SocketStream>
+ createStream(const char *host, QT3DSI32 port, QT3DSU32 timeoutMilliseconds = 10000) = 0;
+ virtual NVScopedRefCounted<SocketServer> createServer(QT3DSI32 port) = 0;
+
+ static NVScopedRefCounted<SocketSystem> createSocketSystem(NVFoundationBase &fnd);
+ };
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/foundation/StrConvertUTF.h b/src/foundation/StrConvertUTF.h
new file mode 100644
index 0000000..965867c
--- /dev/null
+++ b/src/foundation/StrConvertUTF.h
@@ -0,0 +1,213 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_RENDER_STR_CONVERT_UTF_H
+#define QT3DS_RENDER_STR_CONVERT_UTF_H
+#include <EASTL/string.h>
+#include "foundation/ConvertUTF.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSSimpleTypes.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ using namespace qt3ds;
+ template <typename TSrcType>
+ struct ConverterType
+ {
+ };
+ template <>
+ struct ConverterType<char8_t>
+ {
+ typedef UTF8 TConverterType;
+ };
+ template <>
+ struct ConverterType<char16_t>
+ {
+ typedef UTF16 TConverterType;
+ };
+ template <>
+ struct ConverterType<char32_t>
+ {
+ typedef UTF32 TConverterType;
+ };
+
+ template <QT3DSU32 TWCharSize>
+ struct WCharType
+ {
+ };
+
+ template <>
+ struct WCharType<2>
+ {
+ typedef char16_t TCharType;
+ };
+
+ template <>
+ struct WCharType<4>
+ {
+ typedef char32_t TCharType;
+ };
+
+ typedef WCharType<sizeof(wchar_t)> TWCharEASTLConverter;
+
+ template <typename TSrcType, typename TDestType>
+ struct UTFConversionSelector
+ {
+ };
+
+ template <>
+ struct UTFConversionSelector<char8_t, char16_t>
+ {
+ static ConversionResult Convert(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags)
+ {
+ return Q3DSConvertUTF8toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ }
+ };
+
+ template <>
+ struct UTFConversionSelector<char8_t, char32_t>
+ {
+ static ConversionResult Convert(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags)
+ {
+ return Q3DSConvertUTF8toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ }
+ };
+ template <>
+ struct UTFConversionSelector<char16_t, char8_t>
+ {
+ static ConversionResult Convert(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
+ {
+ return Q3DSConvertUTF16toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ }
+ };
+ template <>
+ struct UTFConversionSelector<char16_t, char32_t>
+ {
+ static ConversionResult Convert(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags)
+ {
+ return Q3DSConvertUTF16toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ }
+ };
+ template <>
+ struct UTFConversionSelector<char32_t, char8_t>
+ {
+ static ConversionResult Convert(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
+ {
+ return Q3DSConvertUTF32toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ }
+ };
+ template <>
+ struct UTFConversionSelector<char32_t, char16_t>
+ {
+ static ConversionResult Convert(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags)
+ {
+ return Q3DSConvertUTF32toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ }
+ };
+
+ // Convert into an EASTL string type.
+ // inSrcLen may be zero in which case we analyze the string looking for the zero element.
+ template <typename TSrcType, typename TDestType, typename TAllocType>
+ bool ConvertUTF(const TSrcType *inSrc, size_t inSrcLen,
+ eastl::basic_string<TDestType, TAllocType> &outString)
+ {
+ typedef typename ConverterType<TDestType>::TConverterType TDestUTFType;
+ typedef typename ConverterType<TSrcType>::TConverterType TSrcUTFType;
+ if (inSrc == 0 || *inSrc == 0) {
+ outString.clear();
+ return true;
+ }
+
+ if (inSrcLen == 0) {
+ // empty loop intentional.
+ for (const TSrcType *ptr = inSrc; ptr && *ptr; ++ptr, ++inSrcLen) {
+ }
+ }
+
+ typename eastl::basic_string<TDestType, TAllocType>::size_type capacity =
+ outString.capacity();
+ if (capacity == 0)
+ outString.resize((QT3DSU32)inSrcLen * 2);
+ else
+ outString.resize(capacity);
+
+ ConversionResult theConversionResult(conversionOK);
+ TDestUTFType *writePtr = NULL;
+ do {
+ writePtr = reinterpret_cast<TDestUTFType *>(const_cast<TDestType *>(outString.data()));
+ TDestUTFType *writeEnd(writePtr + outString.size());
+ const TSrcUTFType *readPtr(reinterpret_cast<const TSrcUTFType *>(inSrc));
+ const TSrcUTFType *readEnd = readPtr + inSrcLen;
+ theConversionResult = UTFConversionSelector<TSrcType, TDestType>::Convert(
+ &readPtr, readEnd, &writePtr, writeEnd, lenientConversion);
+ if (theConversionResult == targetExhausted) {
+ capacity = outString.capacity() * 2;
+ outString.resize(capacity);
+ }
+ } while (theConversionResult == targetExhausted);
+
+ if (theConversionResult == conversionOK) {
+ TDestUTFType *writeStart =
+ reinterpret_cast<TDestUTFType *>(const_cast<TDestType *>(outString.data()));
+ outString.resize((QT3DSU32)(writePtr - writeStart));
+ return true;
+ } else {
+ outString.clear();
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ }
+
+#ifdef WIDE_IS_DIFFERENT_TYPE_THAN_CHAR16_T
+
+ template <typename TDestType, typename TAllocType>
+ bool ConvertWideUTF(const wchar_t *inSrc, size_t inSrcLen,
+ eastl::basic_string<TDestType, TAllocType> &outString)
+ {
+ return ConvertUTF((const TWCharEASTLConverter::TCharType *)inSrc, inSrcLen, outString);
+ }
+
+#endif
+}
+}
+
+#endif
diff --git a/src/foundation/StringConversion.h b/src/foundation/StringConversion.h
new file mode 100644
index 0000000..a55ebb3
--- /dev/null
+++ b/src/foundation/StringConversion.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$
+**
+****************************************************************************/
+#pragma once
+#ifndef QT3DS_FOUNDATION_STRING_CONVERSION_H
+#define QT3DS_FOUNDATION_STRING_CONVERSION_H
+#include "foundation/Qt3DSSimpleTypes.h"
+#include "foundation/Qt3DSMemoryBuffer.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Utils.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ // Template base class so that we can convert items to and from char* and wchar_t*
+ // representations
+ template <typename TDataType>
+ struct StringConversion
+ {
+ bool force_compile_error;
+ };
+
+ // Write the char8_t but exlude the null terminator
+ // Meant to write data model values.
+ // Memory buffer contains a non-null-terminated
+ // char8_t string
+ struct Char8TWriter
+ {
+ MemoryBuffer<ForwardingAllocator> &m_Buffer;
+ Char8TWriter(MemoryBuffer<ForwardingAllocator> &buf)
+ : m_Buffer(buf)
+ {
+ }
+ void Write(const char8_t *value, QT3DSU32 len = 0)
+ {
+ if (isTrivial(value))
+ return;
+ if (len == 0)
+ len = (QT3DSU32)StrLen(value);
+ m_Buffer.write(value, len);
+ }
+ void Write(char8_t value) { m_Buffer.write(value); }
+ void Write(bool value) { Write(value ? "True" : "False"); }
+
+ // Takes care of long and float
+ template <typename TDataType>
+ void Write(TDataType value)
+ {
+ char8_t buf[256];
+ QT3DSU32 numWritten =
+ StringConversion<TDataType>().ToStr(value, NVDataRef<char8_t>(buf, 256));
+ if (numWritten)
+ Write((const char8_t *)buf);
+ else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ template <typename TDataType>
+ void Write(NVConstDataRef<TDataType> values, QT3DSU32 grouping = 6, QT3DSU32 tabCount = 0)
+ {
+ for (QT3DSU32 idx = 0; idx < values.size(); ++idx) {
+ if (idx) {
+ if ((idx % grouping) == 0) {
+ Write((char8_t)'\n');
+ for (QT3DSU32 tabIdx = 0; tabIdx < tabCount; ++tabIdx)
+ Write((char8_t)'\t');
+ } else
+ Write((char8_t)' ');
+ }
+ Write(values[idx]);
+ }
+ }
+
+ void Write(NVConstDataRef<char8_t> values, QT3DSU32 ignored = 6)
+ {
+ (void)ignored;
+ if (values.size() && values[0] != 0) {
+ QT3DSU32 lastItem = values.size() - 1;
+ if (values[lastItem] == 0)
+ --lastItem;
+ Write(values.begin(), lastItem + 1);
+ }
+ }
+ };
+
+ inline bool IsWhite(char8_t value)
+ {
+ return value == '\n' || value == '\r' || value == ' ' || value == '\t';
+ }
+
+ // skip until we find whitespace.
+ inline char8_t *FindNextWhitespace(char8_t *input)
+ {
+ if (input == NULL)
+ return input;
+ char8_t *marker = input;
+ // Empty loop intentional
+ for (; *marker && !IsWhite(*marker); ++marker)
+ ;
+ return marker;
+ }
+
+ // skip until we find something that isn't whitespace.
+ inline char8_t *FindNextNonWhitespace(char8_t *input)
+ {
+ if (input == NULL)
+ return input;
+ char8_t *marker = input;
+ // Empty loop intentional
+ for (; *marker && IsWhite(*marker); ++marker)
+ ;
+ return marker;
+ }
+
+ // Reading is destructive in the case of floating point lists, so we may
+ // destroy the incoming string.
+ // We are assuming the string is null-terminated at end ptr.
+ struct Char8TReader
+ {
+ char8_t *m_StartPtr;
+ // Buffer used for temp storage
+ MemoryBuffer<ForwardingAllocator> &m_Buffer;
+ Char8TReader(char8_t *sp, MemoryBuffer<ForwardingAllocator> &buf)
+ : m_StartPtr(sp)
+ , m_Buffer(buf)
+ {
+ }
+ void Read(const char8_t *&outPtr) { outPtr = m_StartPtr; }
+
+ template <typename TDataType>
+ void Read(TDataType &data)
+ {
+ bool success = StringConversion<TDataType>().StrTo(m_StartPtr, data);
+ QT3DS_ASSERT(success);
+ (void)success;
+ }
+ // Destructive operation because we can't trust
+ // strtod to do the right thing. On windows, for long strings,
+ // it calls strlen every operation thus leading to basically N^2
+ // behavior
+ template <typename TDataType>
+ void ReadRef(NVDataRef<TDataType> data)
+ {
+ QT3DSU32 idx = 0;
+ m_StartPtr = FindNextNonWhitespace(m_StartPtr);
+ for (; idx < data.size() && m_StartPtr && *m_StartPtr; ++idx) {
+ char8_t *nextPtr = FindNextWhitespace(m_StartPtr);
+ if (nextPtr && *nextPtr)
+ *nextPtr = 0;
+ else
+ nextPtr = NULL;
+ StringConversion<TDataType>().StrTo(m_StartPtr, data[idx]);
+ m_StartPtr = nextPtr;
+ if (m_StartPtr)
+ m_StartPtr = FindNextNonWhitespace(m_StartPtr + 1);
+ }
+ QT3DS_ASSERT(idx == data.size());
+ }
+
+ void ReadBuffer(NVConstDataRef<char8_t> &outBuffer)
+ {
+ if (m_StartPtr && *m_StartPtr) {
+ QT3DSU32 len = (QT3DSU32)strlen(m_StartPtr);
+ outBuffer = NVConstDataRef<char8_t>(m_StartPtr, len + 1);
+ }
+ }
+
+ // Destructive operation because we can't trust
+ // strtod to do the right thing. On windows, for long strings,
+ // it calls strlen every operation thus leading to basically N^2
+ // behavior
+ template <typename TDataType>
+ void ReadBuffer(NVConstDataRef<TDataType> &outBuffer)
+ {
+ m_Buffer.clear();
+ m_StartPtr = FindNextNonWhitespace(m_StartPtr);
+ while (m_StartPtr && *m_StartPtr) {
+ char8_t *nextPtr = FindNextWhitespace(m_StartPtr);
+ if (nextPtr && *nextPtr)
+ *nextPtr = 0;
+ else
+ nextPtr = NULL;
+ TDataType temp;
+ StringConversion<TDataType>().StrTo(m_StartPtr, temp);
+ m_Buffer.write(temp);
+ m_StartPtr = nextPtr;
+ if (m_StartPtr)
+ m_StartPtr = FindNextNonWhitespace(m_StartPtr + 1);
+ }
+ QT3DSU32 numItems = m_Buffer.size() / sizeof(TDataType);
+ if (numItems)
+ outBuffer = NVConstDataRef<TDataType>((TDataType *)m_Buffer.begin(), numItems);
+ else
+ outBuffer = NVConstDataRef<TDataType>();
+ }
+ };
+}
+}
+#endif \ No newline at end of file
diff --git a/src/foundation/StringConversionImpl.h b/src/foundation/StringConversionImpl.h
new file mode 100644
index 0000000..c5063e6
--- /dev/null
+++ b/src/foundation/StringConversionImpl.h
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_FOUNDATION_STRING_CONVERSION_IMPL_H
+#define QT3DS_FOUNDATION_STRING_CONVERSION_IMPL_H
+#include "foundation/StringConversion.h"
+#include "foundation/Qt3DSMemoryBuffer.h"
+#include "EABase/eabase.h"
+#include "foundation/StringTable.h"
+#include "foundation/Utils.h"
+#include "stdlib.h"
+#include "stdio.h" //snprintf
+#include <QLocale>
+
+#if !defined EA_PLATFORM_WINDOWS
+#define _snprintf snprintf
+#endif
+
+namespace qt3ds {
+namespace foundation {
+
+ template <>
+ struct StringConversion<bool>
+ {
+ QT3DSU32 ToStr(bool item, NVDataRef<char8_t> buffer)
+ {
+ return static_cast<QT3DSU32>(
+ _snprintf(buffer.begin(), buffer.size(), "%s", item ? "True" : "False"));
+ }
+ bool StrTo(const char8_t *buffer, bool &item)
+ {
+ if (AreEqualCaseless(buffer, "True"))
+ item = true;
+ else
+ item = false;
+ return true;
+ }
+ };
+
+ template <>
+ struct StringConversion<QT3DSU8>
+ {
+ QT3DSU32 ToStr(QT3DSU8 item, NVDataRef<char8_t> buffer)
+ {
+ return static_cast<QT3DSU32>(
+ _snprintf(buffer.begin(), buffer.size(), "%hu", static_cast<QT3DSU16>(item)));
+ }
+ bool StrTo(const char8_t *buffer, QT3DSU8 &item)
+ {
+ item = static_cast<QT3DSU8>(strtoul(buffer, NULL, 10));
+ return true;
+ }
+ };
+ template <>
+ struct StringConversion<QT3DSI8>
+ {
+ QT3DSU32 ToStr(QT3DSI8 item, NVDataRef<char8_t> buffer)
+ {
+ return static_cast<QT3DSU32>(
+ _snprintf(buffer.begin(), buffer.size(), "%hd", static_cast<QT3DSI16>(item)));
+ }
+ bool StrTo(const char8_t *buffer, QT3DSI8 &item)
+ {
+ item = static_cast<QT3DSI8>(strtol(buffer, NULL, 10));
+ return true;
+ }
+ };
+ template <>
+ struct StringConversion<QT3DSU16>
+ {
+ QT3DSU32 ToStr(QT3DSU16 item, NVDataRef<char8_t> buffer)
+ {
+ return static_cast<QT3DSU32>(_snprintf(buffer.begin(), buffer.size(), "%hu", item));
+ }
+ bool StrTo(const char8_t *buffer, QT3DSU16 &item)
+ {
+ item = static_cast<QT3DSU16>(strtoul(buffer, NULL, 10));
+ return true;
+ }
+ };
+ template <>
+ struct StringConversion<QT3DSI16>
+ {
+ QT3DSU32 ToStr(QT3DSI16 item, NVDataRef<char8_t> buffer)
+ {
+ return static_cast<QT3DSU32>(_snprintf(buffer.begin(), buffer.size(), "%hd", item));
+ }
+ bool StrTo(const char8_t *buffer, QT3DSI16 &item)
+ {
+ item = static_cast<QT3DSI16>(strtol(buffer, NULL, 10));
+ return true;
+ }
+ };
+
+ template <>
+ struct StringConversion<QT3DSU32>
+ {
+ QT3DSU32 ToStr(QT3DSU32 item, NVDataRef<char8_t> buffer)
+ {
+ // hope the buffer is big enough...
+ return static_cast<QT3DSU32>(_snprintf(buffer.begin(), buffer.size(), "%u", item));
+ }
+ bool StrTo(const char8_t *buffer, QT3DSU32 &item)
+ {
+ item = strtoul(buffer, NULL, 10);
+ return true;
+ }
+ };
+ template <>
+ struct StringConversion<QT3DSI32>
+ {
+ QT3DSU32 ToStr(QT3DSI32 item, NVDataRef<char8_t> buffer)
+ {
+ return static_cast<QT3DSU32>(_snprintf(buffer.begin(), buffer.size(), "%d", (int)item));
+ }
+ bool StrTo(const char8_t *buffer, QT3DSI32 &item)
+ {
+ item = strtol(buffer, NULL, 10);
+ return true;
+ }
+ };
+ template <>
+ struct StringConversion<QT3DSU64>
+ {
+ QT3DSU32 ToStr(QT3DSU64 item, NVDataRef<char8_t> buffer)
+ {
+#ifdef _WIN32
+ return static_cast<QT3DSU32>(_snprintf(buffer.begin(), buffer.size(), "%I64u", item));
+#else
+ return static_cast<QT3DSU32>(_snprintf(buffer.begin(), buffer.size(), "%lu", item));
+#endif
+ }
+ bool StrTo(const char8_t *buffer, QT3DSU64 &item)
+ {
+ item = strtoul(buffer, NULL, 10);
+ return true;
+ }
+ };
+ template <>
+ struct StringConversion<QT3DSI64>
+ {
+ QT3DSU32 ToStr(QT3DSI64 item, NVDataRef<char8_t> buffer)
+ {
+#ifdef _WIN32
+ return static_cast<QT3DSU32>(_snprintf(buffer.begin(), buffer.size(), "%I64d", item));
+#else
+ return static_cast<QT3DSU32>(_snprintf(buffer.begin(), buffer.size(), "%ld", item));
+#endif
+ }
+ bool StrTo(const char8_t *buffer, QT3DSI64 &item)
+ {
+ item = strtol(buffer, NULL, 10);
+ return true;
+ }
+ };
+ template <>
+ struct StringConversion<QT3DSF32>
+ {
+ QT3DSU32 ToStr(QT3DSF32 item, NVDataRef<char8_t> buffer)
+ {
+ QString s = QLocale::c().toString(item);
+ strncpy(buffer.begin(), s.toStdString().c_str(), buffer.size());
+ return s.length();
+ }
+ bool StrTo(const char8_t *buffer, QT3DSF32 &item)
+ {
+ bool ok;
+ item = QLocale::c().toFloat(buffer, &ok);
+ return ok;
+ }
+ };
+
+ template <>
+ struct StringConversion<QT3DSF64>
+ {
+ QT3DSU32 ToStr(QT3DSF64 item, NVDataRef<char8_t> buffer)
+ {
+ QString s = QLocale::c().toString(item);
+ strncpy(buffer.begin(), s.toStdString().c_str(), buffer.size());
+ return s.length();
+ }
+ bool StrTo(const char8_t *buffer, QT3DSF64 &item)
+ {
+ bool ok;
+ item = QLocale::c().toDouble(buffer, &ok);
+ return ok;
+ }
+ };
+}
+}
+
+#endif
diff --git a/src/foundation/StringTable.cpp b/src/foundation/StringTable.cpp
new file mode 100644
index 0000000..47130dc
--- /dev/null
+++ b/src/foundation/StringTable.cpp
@@ -0,0 +1,700 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "foundation/StringTable.h"
+#include "foundation/Qt3DSContainers.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Utils.h"
+#include "EASTL/string.h"
+#include "EASTL/sort.h"
+#include "foundation/StrConvertUTF.h"
+#include "foundation/PreAllocatedAllocator.h"
+#include "foundation/SerializationTypes.h"
+#include "foundation/Qt3DSMutex.h"
+
+using namespace qt3ds;
+using namespace qt3ds::foundation;
+using namespace eastl;
+
+namespace eastl {
+struct SCharAndHash
+{
+ const char8_t *m_Data;
+ size_t m_Hash;
+ // Cache the generated hash code.
+ SCharAndHash(const char8_t *inData)
+ : m_Data(inData)
+ , m_Hash(eastl::hash<const char8_t *>()(inData))
+ {
+ }
+ SCharAndHash()
+ : m_Data(nullptr)
+ , m_Hash(0)
+ {
+ }
+ operator const char *() const { return m_Data; }
+};
+template <>
+struct hash<SCharAndHash>
+{
+ size_t operator()(const SCharAndHash &inItem) const { return inItem.m_Hash; }
+};
+
+template <>
+struct equal_to<SCharAndHash>
+{
+ bool operator()(const SCharAndHash &inLhs, const SCharAndHash &inRhs) const
+ {
+ return char_equal_to()(inLhs.m_Data, inRhs.m_Data);
+ }
+};
+}
+
+void CRegisteredString::Remap(const IStringTable &inTable)
+{
+ Remap(const_cast<IStringTable &>(inTable).GetRemapMap());
+}
+
+void CRegisteredString::Remap(const SStrRemapMap &inMap)
+{
+ if (IsValid()) {
+ SStrRemapMap::const_iterator theIter = inMap.find((char8_t *)m_String);
+ if (theIter != inMap.end())
+ m_String = reinterpret_cast<const char8_t *>(theIter->second);
+ else {
+ QT3DS_ASSERT(false);
+ // Ensure a failure here doesn't *guarantee* a crash somewhere else.
+ m_String = nullptr;
+ }
+ } else {
+ // Indicates an invalid string.
+ m_String = reinterpret_cast<const char8_t *>(QT3DS_MAX_U32);
+ }
+}
+
+void CRegisteredString::Remap(NVDataRef<QT3DSU8> inDataPtr)
+{
+ size_t theOffset = reinterpret_cast<size_t>(m_String);
+ if (theOffset >= QT3DS_MAX_U32)
+ m_String = "";
+ else {
+ if (theOffset < inDataPtr.size())
+ m_String = reinterpret_cast<char8_t *>(inDataPtr.begin() + theOffset);
+ else {
+ QT3DS_ASSERT(false);
+ m_String = "";
+ }
+ }
+}
+
+namespace {
+
+const char16_t g_char16EmptyStr[] = { 0, 0, 0, 0 };
+const char32_t g_char32EmptyStr[] = { 0, 0, 0, 0 };
+
+typedef eastl::basic_string<char8_t, ForwardingAllocator> TNarrowStr;
+typedef eastl::basic_string<TWCharEASTLConverter::TCharType, ForwardingAllocator> TWideStr;
+
+inline bool isTrivialWide(const wchar_t *str)
+{
+ return str == nullptr || *str == 0;
+}
+
+QT3DSU8 *AlignPointer(QT3DSU8 *inStart, QT3DSU8 *inPtr)
+{
+ QT3DSU32 alignment = sizeof(void *);
+ size_t numBytes = (size_t)(inPtr - inStart);
+ QT3DS_ASSERT(inStart < inPtr);
+ if (numBytes % alignment)
+ inPtr += alignment - (numBytes % alignment);
+ return inPtr;
+}
+
+QT3DSU32 Align(QT3DSU32 inValue)
+{
+ QT3DSU32 alignment = sizeof(void *);
+ QT3DSU32 leftover = inValue % alignment;
+ if (leftover)
+ inValue += alignment - leftover;
+ return inValue;
+}
+
+// Structure that is written out to the file.
+// Directly after this is the string character data.
+// TWideStr& inConvertStr
+struct SStringFileData
+{
+ QT3DSU32 m_StartOffset;
+ QT3DSU32 m_StrLen;
+ QT3DSU32 m_Handle;
+ char8_t *m_Str;
+ SStringFileData(QT3DSU32 len, QT3DSU32 off, QT3DSU32 handle, char8_t *data)
+ : m_StartOffset(off)
+ , m_StrLen(len)
+ , m_Handle(handle)
+ , m_Str(data)
+ {
+ }
+ SStringFileData()
+ : m_StartOffset(0)
+ , m_StrLen(0)
+ , m_Handle(0)
+ , m_Str(nullptr)
+ {
+ }
+ void Deallocate(NVAllocatorCallback &inAlloc)
+ {
+ inAlloc.deallocate(m_Str);
+ m_Str = nullptr;
+ }
+ const char8_t *GetNarrow() { return m_Str; }
+ operator CRegisteredString() const
+ {
+ return CRegisteredString::ISwearThisHasBeenRegistered(m_Str);
+ }
+ QT3DSU32 EndOffset() const { return m_StartOffset + m_StrLen; }
+
+ // Used only for the lower bound operation to find a given object by offset.
+ bool operator<(const SStringFileData &inOther) const
+ {
+ return m_StartOffset < inOther.m_StartOffset;
+ }
+};
+
+struct SCharAndHandle
+{
+ const char8_t *m_Data;
+ QT3DSU32 m_Handle;
+ SCharAndHandle()
+ : m_Data(nullptr)
+ , m_Handle(0)
+ {
+ }
+ SCharAndHandle(const char8_t *data, QT3DSU32 hdl)
+ : m_Data(data)
+ , m_Handle(hdl)
+ {
+ }
+ operator const char *() const { return m_Data; }
+};
+
+struct SStringFileHeader
+{
+ QT3DSU32 m_NumStrings;
+ QT3DSU32 m_NextHandleValue;
+ // offset to the items of fixed size. Variable sized data is stored
+ // up front.
+ QT3DSU32 m_FixedBufferOffset;
+ SStringFileHeader()
+ : m_NumStrings(0)
+ , m_NextHandleValue(0)
+ , m_FixedBufferOffset(0)
+ {
+ }
+
+ SStringFileHeader(QT3DSU32 ns, QT3DSU32 hv, QT3DSU32 fbo)
+ : m_NumStrings(ns)
+ , m_NextHandleValue(hv)
+ , m_FixedBufferOffset(fbo)
+ {
+ }
+};
+
+// This is the core of the string table.
+struct SStringFileDataList
+{
+ typedef nvhash_map<SCharAndHash, SCharAndHandle> TMapType;
+ typedef nvhash_map<QT3DSU32, const char8_t *> THandleMapType;
+
+ mutable SPreAllocatedAllocator m_Allocator;
+
+ // When we load from a file, we get a these items
+ NVConstDataRef<SStringFileData> m_DataBlock;
+ NVConstDataRef<eastl::pair<size_t, QT3DSU32>> m_HashDataBlockOffset;
+ NVConstDataRef<eastl::pair<QT3DSU32, QT3DSU32>> m_HandleDataBlockOffset;
+
+ // When we are running normally, this items get mangled
+ nvvector<SStringFileData> m_AppendedStrings;
+
+protected:
+ // Built roughly on demand
+ SStrRemapMap m_StrRemapMap;
+ TMapType m_HashToStrMap;
+ THandleMapType m_HandleToStrMap;
+ QT3DSU32 m_NextHandleValue;
+
+public:
+ SStringFileDataList(NVAllocatorCallback &inAlloc)
+ : m_Allocator(inAlloc)
+ , m_AppendedStrings(inAlloc, "StringTable::m_AppendedStrings")
+ , m_StrRemapMap(inAlloc, "StringTable::m_StrRemapMap")
+ , m_HashToStrMap(inAlloc, "StringTable::m_HashToStrMap")
+ , m_HandleToStrMap(inAlloc, "StringTable::m_HashToStrMap")
+ , m_NextHandleValue(1)
+ {
+ }
+ ~SStringFileDataList()
+ {
+ for (QT3DSU32 idx = 0, end = m_AppendedStrings.size(); idx < end; ++idx)
+ m_AppendedStrings[idx].Deallocate(m_Allocator);
+ }
+
+ SStrRemapMap &GetRemapMap()
+ {
+ if (m_StrRemapMap.empty()) {
+ for (QT3DSU32 idx = 0, end = m_DataBlock.size(); idx < end; ++idx)
+ m_StrRemapMap.insert(
+ eastl::make_pair(m_DataBlock[idx].m_Str, m_DataBlock[idx].m_StartOffset));
+ for (QT3DSU32 idx = 0, end = m_AppendedStrings.size(); idx < end; ++idx)
+ m_StrRemapMap.insert(eastl::make_pair(m_AppendedStrings[idx].m_Str,
+ m_AppendedStrings[idx].m_StartOffset));
+ }
+ return m_StrRemapMap;
+ }
+
+ struct SHashPairComparator
+ {
+ bool operator()(const eastl::pair<size_t, QT3DSU32> &lhs,
+ const eastl::pair<size_t, QT3DSU32> &rhs) const
+ {
+ return lhs.first < rhs.first;
+ }
+ };
+
+ struct SHandlePairComparator
+ {
+ bool operator()(const eastl::pair<QT3DSU32, QT3DSU32> &lhs,
+ const eastl::pair<QT3DSU32, QT3DSU32> &rhs) const
+ {
+ return lhs.first < rhs.first;
+ }
+ };
+
+ SCharAndHandle DoFindStr(SCharAndHash hashCode)
+ {
+ if (isTrivial(hashCode.m_Data))
+ return SCharAndHandle();
+ TMapType::iterator theFind = m_HashToStrMap.find(hashCode);
+ if (theFind == m_HashToStrMap.end()) {
+ SCharAndHandle newStr = FindStrByHash(hashCode);
+ if (!newStr.m_Data)
+ newStr = Append(hashCode);
+
+ // It may not be obvious why we have to reset the data member.
+ // we have to do this so the hashtable keys don't change if the user isn't
+ // passing in a persistent string.
+ hashCode.m_Data = newStr;
+
+ theFind = m_HashToStrMap.insert(eastl::make_pair(hashCode, newStr)).first;
+ m_HandleToStrMap.insert(eastl::make_pair(theFind->second.m_Handle, newStr));
+ }
+ return theFind->second;
+ }
+
+ const CRegisteredString FindStr(SCharAndHash hashCode)
+ {
+ SCharAndHandle result = DoFindStr(hashCode);
+ if (result.m_Data)
+ return CRegisteredString::ISwearThisHasBeenRegistered(result.m_Data);
+ return CRegisteredString();
+ }
+
+ const CStringHandle FindStrHandle(SCharAndHash hashCode)
+ {
+ SCharAndHandle result = DoFindStr(hashCode);
+ return CStringHandle::ISwearThisHasBeenRegistered(result.m_Handle);
+ }
+
+ const CRegisteredString FindStrByHandle(QT3DSU32 handle)
+ {
+ if (handle == 0)
+ return CRegisteredString();
+
+ THandleMapType::iterator theFind = m_HandleToStrMap.find(handle);
+ if (theFind == m_HandleToStrMap.end()) {
+ const char8_t *newStr = FindStrByHandleData(handle);
+ if (!newStr)
+ return CRegisteredString();
+ theFind = m_HandleToStrMap.insert(eastl::make_pair(handle, newStr)).first;
+ }
+ return CRegisteredString::ISwearThisHasBeenRegistered(theFind->second);
+ }
+
+ void Save(SWriteBuffer &ioBuffer) const
+ {
+ // Buffer should be aligned before we get to it.
+ QT3DS_ASSERT(ioBuffer.size() % 4 == 0);
+
+ QT3DSU32 numStrs = Size();
+ size_t bufferBegin = ioBuffer.size();
+ SStringFileHeader theHeader;
+ ioBuffer.write(theHeader);
+ QT3DSU32 startOffset = ioBuffer.size();
+
+ eastl::vector<eastl::pair<size_t, QT3DSU32>> hashToStringIndex;
+ eastl::vector<eastl::pair<QT3DSU32, QT3DSU32>> handleToStringIndex;
+ hashToStringIndex.reserve(numStrs);
+ handleToStringIndex.reserve(numStrs);
+ WriteStringBlockData(m_DataBlock.begin(), m_DataBlock.end(), ioBuffer, hashToStringIndex,
+ handleToStringIndex);
+ WriteStringBlockData(m_AppendedStrings.data(),
+ m_AppendedStrings.data() + m_AppendedStrings.size(), ioBuffer,
+ hashToStringIndex, handleToStringIndex);
+ ioBuffer.align(4);
+
+ QT3DSU32 fixedOffset = ioBuffer.size() - startOffset;
+ WriteStringBlock(m_DataBlock.begin(), m_DataBlock.end(), ioBuffer);
+ WriteStringBlock(m_AppendedStrings.data(),
+ m_AppendedStrings.data() + m_AppendedStrings.size(), ioBuffer);
+
+ // sort by hash code so we can do binary lookups later.
+ eastl::sort(hashToStringIndex.begin(), hashToStringIndex.end(), SHashPairComparator());
+ ioBuffer.write(hashToStringIndex.data(), (QT3DSU32)hashToStringIndex.size());
+
+ eastl::sort(handleToStringIndex.begin(), handleToStringIndex.end(),
+ SHandlePairComparator());
+ ioBuffer.write(handleToStringIndex.data(), (QT3DSU32)handleToStringIndex.size());
+
+ SStringFileHeader *fixedOffsetPtr =
+ reinterpret_cast<SStringFileHeader *>(ioBuffer.begin() + bufferBegin);
+ *fixedOffsetPtr = SStringFileHeader(numStrs, m_NextHandleValue, fixedOffset);
+ }
+
+ void Load(NVDataRef<QT3DSU8> inMemory)
+ {
+ QT3DS_ASSERT(m_AppendedStrings.empty());
+ m_Allocator.m_PreAllocatedBlock = inMemory;
+ m_Allocator.m_OwnsMemory = false;
+ SDataReader theReader(inMemory.begin(), inMemory.end());
+ SStringFileHeader theHeader = theReader.LoadRef<SStringFileHeader>();
+ QT3DSU32 numStrs = theHeader.m_NumStrings;
+ m_NextHandleValue = theHeader.m_NextHandleValue;
+ QT3DSU32 fixedOffset = theHeader.m_FixedBufferOffset;
+ theReader.m_CurrentPtr += fixedOffset;
+ m_DataBlock = NVConstDataRef<SStringFileData>(
+ reinterpret_cast<const SStringFileData *>(theReader.m_CurrentPtr), numStrs);
+ theReader.m_CurrentPtr += sizeof(SStringFileData) * numStrs;
+
+ m_HashDataBlockOffset = NVConstDataRef<eastl::pair<size_t, QT3DSU32>>(
+ reinterpret_cast<const eastl::pair<size_t, QT3DSU32> *>(theReader.m_CurrentPtr), numStrs);
+ theReader.m_CurrentPtr += sizeof(eastl::pair<size_t, QT3DSU32>) * numStrs;
+
+ m_HandleDataBlockOffset = NVConstDataRef<eastl::pair<QT3DSU32, QT3DSU32>>(
+ reinterpret_cast<const eastl::pair<QT3DSU32, QT3DSU32> *>(theReader.m_CurrentPtr), numStrs);
+
+ for (QT3DSU32 idx = 0, end = m_DataBlock.size(); idx < end; ++idx) {
+ SStringFileData &theData = const_cast<SStringFileData &>(m_DataBlock[idx]);
+ theData.m_Str = reinterpret_cast<char8_t *>(inMemory.mData + theData.m_StartOffset);
+ }
+ }
+
+protected:
+ // When we load from a file, we do not put every string into the hash because building
+ // hashtables takes
+ // time. We only put them into the hash on demand; this avoids building a giant hashtable upon
+ // load.
+ // and since in general we do not need to lookup all hash values again it avoids building the
+ // hashtable
+ // in general.
+ SCharAndHandle FindStrByHash(SCharAndHash hashCode) const
+ {
+ const eastl::pair<size_t, QT3DSU32> *iter =
+ eastl::lower_bound(m_HashDataBlockOffset.begin(), m_HashDataBlockOffset.end(),
+ eastl::make_pair(hashCode.m_Hash, (QT3DSU32)0), SHashPairComparator());
+
+ for (; iter != m_HashDataBlockOffset.end() && iter->first == hashCode.m_Hash; ++iter) {
+ if (AreEqual(m_DataBlock[iter->second].m_Str, hashCode.m_Data))
+ return SCharAndHandle(m_DataBlock[iter->second].m_Str,
+ m_DataBlock[iter->second].m_Handle);
+ }
+ return SCharAndHandle();
+ }
+
+ const char8_t *FindStrByHandleData(QT3DSU32 handle) const
+ {
+ const eastl::pair<QT3DSU32, QT3DSU32> *iter =
+ eastl::lower_bound(m_HandleDataBlockOffset.begin(), m_HandleDataBlockOffset.end(),
+ eastl::make_pair(handle, (QT3DSU32)0), SHandlePairComparator());
+
+ if (iter != m_HandleDataBlockOffset.end() && iter->first == handle
+ && m_DataBlock[iter->second].m_Handle == handle)
+ return m_DataBlock[iter->second].m_Str;
+ return nullptr;
+ }
+
+ void WriteStringBlockData(const SStringFileData *begin, const SStringFileData *end,
+ SWriteBuffer &ioBuffer,
+ eastl::vector<eastl::pair<size_t, QT3DSU32>> &ioHashToStringIndex,
+ eastl::vector<eastl::pair<QT3DSU32, QT3DSU32>> &ioHandleToStringIndex) const
+ {
+ for (const SStringFileData *iter = begin; iter != end; ++iter) {
+ size_t idx = ioHashToStringIndex.size();
+ SCharAndHash theHash(iter->m_Str);
+ ioHashToStringIndex.push_back(eastl::make_pair(theHash.m_Hash, (QT3DSU32)idx));
+ ioHandleToStringIndex.push_back(eastl::make_pair(iter->m_Handle, (QT3DSU32)idx));
+ ioBuffer.write(iter->m_Str, iter->m_StrLen);
+ }
+ }
+
+ void WriteStringBlock(const SStringFileData *begin, const SStringFileData *end,
+ SWriteBuffer &ioBuffer) const
+ {
+ for (const SStringFileData *iter = begin; iter != end; ++iter)
+ ioBuffer.write(*iter);
+ }
+
+ SCharAndHandle Append(SCharAndHash inStrHash)
+ {
+ if (isTrivial(inStrHash.m_Data))
+ return SCharAndHandle();
+
+ const char8_t *inStr(inStrHash.m_Data);
+ QT3DSU32 len = (QT3DSU32)strlen(inStr) + 1;
+ char8_t *newStr = (char8_t *)m_Allocator.allocate(len, "StringData", __FILE__, __LINE__);
+ memCopy(newStr, inStr, len);
+
+ // We write the number of strings to the file just after the header.
+ QT3DSU32 theOffset = sizeof(SStringFileHeader);
+ if (Size())
+ theOffset = Back().EndOffset();
+
+ QT3DSU32 handleValue = m_NextHandleValue;
+ ++m_NextHandleValue;
+ m_AppendedStrings.push_back(SStringFileData(len, theOffset, handleValue, newStr));
+
+ // Only add to the str map if necessary because building it could be expensive.
+ if (m_StrRemapMap.empty() == false)
+ m_StrRemapMap.insert(eastl::make_pair(newStr, theOffset));
+
+ return SCharAndHandle(newStr, handleValue);
+ }
+ // precondition is that size != 0
+ const SStringFileData &Back() const
+ {
+ QT3DS_ASSERT(Size());
+
+ if (m_AppendedStrings.size()) {
+ return m_AppendedStrings.back();
+ } else {
+ return m_DataBlock[m_DataBlock.size() - 1];
+ }
+ }
+
+ QT3DSU32 Size() const { return static_cast<QT3DSU32>(m_AppendedStrings.size() + m_DataBlock.size()); }
+};
+
+struct SStringTableMutexScope
+{
+ Mutex *m_Mutex;
+ SStringTableMutexScope(Mutex *inM)
+ : m_Mutex(inM)
+ {
+ if (m_Mutex)
+ m_Mutex->lock();
+ }
+ ~SStringTableMutexScope()
+ {
+ if (m_Mutex)
+ m_Mutex->unlock();
+ }
+};
+
+#define STRING_TABLE_MULTITHREADED_METHOD SStringTableMutexScope __locker(m_MultithreadMutex)
+
+class StringTable : public IStringTable
+{
+ typedef nvhash_map<SCharAndHash, QT3DSU32> TMapType;
+ typedef nvhash_map<CRegisteredString, TWideStr> TNarrowToWideMapType;
+ SStringFileDataList m_FileData;
+ NVAllocatorCallback &m_Allocator;
+ TNarrowToWideMapType m_StrWideMap;
+ volatile QT3DSI32 mRefCount; // fnd's naming convention
+ eastl::basic_string<char8_t, ForwardingAllocator> m_ConvertBuffer;
+ TWideStr m_WideConvertBuffer;
+ Mutex m_MultithreadMutexBacker;
+ Mutex *m_MultithreadMutex;
+ // Data that will be written out to the file.
+
+public:
+ StringTable(NVAllocatorCallback &alloc)
+ : m_FileData(alloc)
+ , m_Allocator(m_FileData.m_Allocator)
+ , m_StrWideMap(alloc, "StringTable::m_StrWideMap")
+ , mRefCount(0)
+ , m_ConvertBuffer(ForwardingAllocator(alloc, "StringTable::m_ConvertBuffer"))
+ , m_WideConvertBuffer(ForwardingAllocator(alloc, "StringTable::m_WideConvertBuffer"))
+ , m_MultithreadMutexBacker(alloc)
+ , m_MultithreadMutex(nullptr)
+ {
+ }
+
+ virtual ~StringTable() override {}
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_FileData.m_Allocator.m_Allocator)
+
+ void EnableMultithreadedAccess() override
+ {
+ m_MultithreadMutex = &m_MultithreadMutexBacker;
+ }
+
+ void DisableMultithreadedAccess() override
+ {
+ m_MultithreadMutex = nullptr;
+ }
+
+ CRegisteredString RegisterStr(const QString &str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ if (str.isEmpty())
+ return CRegisteredString();
+ return RegisterStr(str.toUtf8());
+ }
+
+ CRegisteredString RegisterStr(const QByteArray &str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ if (str.isEmpty())
+ return CRegisteredString();
+ return RegisterStr(str.constData());
+ }
+
+ CRegisteredString RegisterStr(const eastl::string &string) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ return RegisterStr(string.c_str());
+ }
+
+ CRegisteredString RegisterStr(Qt3DSBCharPtr str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ if (isTrivial(str))
+ return CRegisteredString();
+ return m_FileData.FindStr(str);
+ }
+
+ // utf-16->utf-8
+ CRegisteredString RegisterStr(const char16_t *str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ qt3ds::foundation::ConvertUTF(str, 0, m_ConvertBuffer);
+ return RegisterStr(m_ConvertBuffer.c_str());
+ }
+ // utf-32->utf-8
+ CRegisteredString RegisterStr(const char32_t *str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ qt3ds::foundation::ConvertUTF(str, 0, m_ConvertBuffer);
+ return RegisterStr(m_ConvertBuffer.c_str());
+ }
+
+ CRegisteredString RegisterStr(const wchar_t *str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ if (isTrivialWide(str))
+ return CRegisteredString();
+ qt3ds::foundation::ConvertUTF(
+ reinterpret_cast<const TWCharEASTLConverter::TCharType *>(str), 0,
+ m_ConvertBuffer);
+ return RegisterStr(m_ConvertBuffer.c_str());
+ }
+
+ CStringHandle GetHandle(Qt3DSBCharPtr str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ return m_FileData.FindStrHandle(str);
+ }
+
+ CRegisteredString HandleToStr(QT3DSU32 strHandle) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ return m_FileData.FindStrByHandle(strHandle);
+ }
+
+ const wchar_t *GetWideStr(CRegisteredString theStr)
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ eastl::pair<TNarrowToWideMapType::iterator, bool> pair_iter = m_StrWideMap.insert(
+ eastl::make_pair(theStr, TWideStr(ForwardingAllocator(m_Allocator, "WideString"))));
+ if (pair_iter.second)
+ qt3ds::foundation::ConvertUTF(theStr.c_str(), 0, pair_iter.first->second);
+ return reinterpret_cast<const wchar_t *>(pair_iter.first->second.c_str());
+ }
+
+ const wchar_t *GetWideStr(Qt3DSBCharPtr src) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ if (isTrivial(src))
+ return L"";
+ return GetWideStr(RegisterStr(src));
+ }
+
+ const wchar_t *GetWideStr(const wchar_t *str) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ if (isTrivialWide(str))
+ return L"";
+ qt3ds::foundation::ConvertUTF(
+ reinterpret_cast<const TWCharEASTLConverter::TCharType *>(str), 0,
+ m_ConvertBuffer);
+ return GetWideStr(RegisterStr(m_ConvertBuffer.c_str()));
+ }
+
+ const SStrRemapMap &GetRemapMap() override { return m_FileData.GetRemapMap(); }
+
+ NVAllocatorCallback &GetAllocator() override { return m_FileData.m_Allocator.m_Allocator; }
+
+ // Save to a block of memory. It is up the callers to deallocate using allocator
+ // from GetAllocator(). Returns a remap map that takes existing strings and changes their
+ // address such that they are offsets into the block of memory where this object
+ // started saving. Returns a map that converts registered strings into offsets of the
+ // written buffer.
+ void Save(SWriteBuffer &ioBuffer) const override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ m_FileData.Save(ioBuffer);
+ }
+
+ // Load all the strings from inMemory. inMemory is not freed by this object
+ // Finally, you will need to take inMemory and call remap on all strings
+ // from offsets back into their correct address into inMemory.
+ void Load(qt3ds::foundation::NVDataRef<QT3DSU8> inMemory) override
+ {
+ STRING_TABLE_MULTITHREADED_METHOD;
+ m_FileData.Load(inMemory);
+ }
+};
+}
+
+const char16_t *char16EmptyStr = g_char16EmptyStr;
+const char32_t *char32EmptyStr = g_char32EmptyStr;
+
+IStringTable &IStringTable::CreateStringTable(NVAllocatorCallback &alloc)
+{
+ return *QT3DS_NEW(alloc, StringTable)(alloc);
+}
diff --git a/src/foundation/StringTable.h b/src/foundation/StringTable.h
new file mode 100644
index 0000000..d46c111
--- /dev/null
+++ b/src/foundation/StringTable.h
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_RENDER_STRING_TABLE_H
+#define QT3DS_RENDER_STRING_TABLE_H
+
+#if defined(_WIN32) || defined(__QNXNTO__)
+#include <wchar.h>
+#ifndef WIDE_IS_DIFFERENT_TYPE_THAN_CHAR16_T
+#define WIDE_IS_DIFFERENT_TYPE_THAN_CHAR16_T
+#endif
+#endif
+
+#include <QtCore/qstring.h>
+#include <QtCore/qbytearray.h>
+
+#include "foundation/Qt3DSRefCounted.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "EASTL/string.h"
+#include "EASTL/functional.h"
+#include "EABase/eabase.h" //char16_t definition
+#include "foundation/Qt3DSDataRef.h"
+#include "foundation/Qt3DSOption.h"
+
+#include <QtCore/qstring.h>
+#include <QtCore/qhashfunctions.h>
+
+namespace qt3ds {
+namespace foundation {
+ typedef char8_t Qt3DSBChar;
+ typedef const char8_t *Qt3DSBCharPtr;
+ class IStringTable;
+
+ // Serialization types, NVRenderSerializationTypes.h
+ struct SStrRemapMap;
+ struct SWriteBuffer;
+
+ class CRegisteredString;
+
+ // Discriminated union of either data ref or str table
+ // used so clients can test serialization without actually saving
+ // the string table out and rebooting the entire system.
+ class CStrTableOrDataRef
+ {
+ Option<NVDataRef<QT3DSU8>> m_DataRef;
+ IStringTable *m_StrTable;
+
+ public:
+ CStrTableOrDataRef()
+ : m_StrTable(nullptr)
+ {
+ }
+ CStrTableOrDataRef(NVDataRef<QT3DSU8> inData)
+ : m_DataRef(inData)
+ {
+ }
+ CStrTableOrDataRef(IStringTable &inStrTable)
+ : m_StrTable(&inStrTable)
+ {
+ }
+ CStrTableOrDataRef(const CStrTableOrDataRef &inOther)
+ : m_DataRef(inOther.m_DataRef)
+ , m_StrTable(inOther.m_StrTable)
+ {
+ }
+ CStrTableOrDataRef &operator=(const CStrTableOrDataRef &inOther)
+ {
+ m_DataRef = inOther.m_DataRef;
+ m_StrTable = inOther.m_StrTable;
+ return *this;
+ }
+ bool HasStrTable() const { return m_StrTable != nullptr; }
+ bool HasDataRef() const { return m_DataRef.hasValue(); }
+ NVDataRef<QT3DSU8> GetDataRef() const { return *m_DataRef; }
+ IStringTable *GetStringTable() const
+ {
+ QT3DS_ASSERT(m_StrTable);
+ return m_StrTable;
+ }
+ };
+
+ // String that can only be constructed from strings in the string table.
+ // These strings are valid utf-8 strings
+ class CRegisteredString
+ {
+ Qt3DSBCharPtr m_String;
+
+ public:
+ CRegisteredString()
+ : m_String("")
+ {
+ }
+ CRegisteredString(const CRegisteredString &inOther)
+ : m_String(inOther.m_String)
+ {
+ }
+ CRegisteredString &operator=(const CRegisteredString &inOther)
+ {
+ m_String = inOther.m_String;
+ return *this;
+ }
+
+ bool operator==(const CRegisteredString &inStr) const { return m_String == inStr.m_String; }
+ // If you use this in a real map then you will get them sorted roughly by the correct
+ // order.
+ bool operator<(const char *inStr) const
+ {
+ // Ensure non-null strings to strcmp.
+ const char *myStr = m_String ? m_String : "";
+ inStr = inStr ? inStr : "";
+ int answer;
+ while (*myStr && *inStr) {
+ answer = *inStr - *myStr;
+ if (answer)
+ return answer < 0;
+ ++myStr;
+ ++inStr;
+ }
+ answer = *inStr - *myStr;
+ return answer < 0;
+ }
+ size_t hash() const { return eastl::hash<size_t>()(reinterpret_cast<size_t>(m_String)); }
+ operator Qt3DSBCharPtr() const { return c_str(); }
+ Qt3DSBCharPtr c_str() const { return m_String ? m_String : ""; }
+ bool IsValid() const { return m_String && *m_String; }
+
+ // If this string is in the map, changes it to the map value.
+ void Remap(const SStrRemapMap &inMap);
+
+ void Remap(const IStringTable &inTable);
+
+ // Using m_String as an offset, if possible remap into
+ // inDataPtr's block of memory
+ void Remap(NVDataRef<QT3DSU8> inDataPtr);
+
+ void Remap(const CStrTableOrDataRef &inRef)
+ {
+ if (inRef.HasDataRef())
+ Remap(inRef.GetDataRef());
+ else if (inRef.HasStrTable())
+ Remap(*inRef.GetStringTable());
+ else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ static CRegisteredString ISwearThisHasBeenRegistered(Qt3DSBCharPtr str)
+ {
+ CRegisteredString retval;
+ retval.m_String = str;
+ return retval;
+ }
+ };
+
+ inline uint qHash(const CRegisteredString &rString)
+ {
+ // Note that we are intentionally hashing a pointer to the string rather than its content,
+ // as CRegisteredString strings reside in the string table, which guarantees two instances
+ // with same string point to same string table string.
+ return QT_PREPEND_NAMESPACE(qHash(rString.c_str()));
+ }
+
+ class IStringTable;
+
+ class CStringHandle
+ {
+ QT3DSU32 m_Data;
+
+ CStringHandle(QT3DSU32 hdl)
+ : m_Data(hdl)
+ {
+ }
+
+ public:
+ CStringHandle()
+ : m_Data(0)
+ {
+ }
+ CStringHandle(const CStringHandle &other)
+ : m_Data(other.m_Data)
+ {
+ }
+ CStringHandle &operator=(const CStringHandle &other)
+ {
+ m_Data = other.m_Data;
+ return *this;
+ }
+ bool IsValid() const { return m_Data != 0; }
+ QT3DSU32 handle() const { return m_Data; }
+ inline const char8_t *c_str(IStringTable &strTable) const;
+ operator QT3DSU32() const { return m_Data; }
+ static CStringHandle ISwearThisHasBeenRegistered(QT3DSU32 strHandle)
+ {
+ return CStringHandle(strHandle);
+ }
+ };
+
+ // String table stores strings in utf-8 format and does valid utf-16,utf-32 -> utf-8
+ // also converts utf8 -> either utf-32 or utf-16, depending on sizeof( wchar_t ) if
+ // requested.
+ // UICStrConvertUTF.h
+ // Also generates offsets that are consistent so clients can convert their strings
+ // to offsets during save and convert from offset to string during load regardless
+ // of if they load before or after this table.
+ class QT3DS_AUTOTEST_EXPORT IStringTable : public NVRefCounted
+ {
+ public:
+ // default state is for multithreaded access to be disabled.
+ // remember to implement in CNullStringManager in UICTestPresentation.hxx
+ virtual void EnableMultithreadedAccess() = 0;
+ virtual void DisableMultithreadedAccess() = 0;
+
+ virtual CRegisteredString RegisterStr(const QByteArray &str) = 0;
+ virtual CRegisteredString RegisterStr(const QString &str) = 0;
+ virtual CRegisteredString RegisterStr(const eastl::string &string) = 0;
+
+ virtual CRegisteredString RegisterStr(Qt3DSBCharPtr str) = 0;
+ // utf-16->utf-8
+ virtual CRegisteredString RegisterStr(const char16_t *str) = 0;
+ // utf-32->utf-8
+ virtual CRegisteredString RegisterStr(const char32_t *str) = 0;
+
+ virtual CStringHandle GetHandle(Qt3DSBCharPtr str) = 0;
+ virtual CRegisteredString HandleToStr(QT3DSU32 strHandle) = 0;
+
+ virtual CRegisteredString RegisterStr(const wchar_t *str) = 0;
+
+ virtual const wchar_t *GetWideStr(Qt3DSBCharPtr src) = 0;
+ virtual const wchar_t *GetWideStr(const wchar_t *str) = 0;
+
+ Qt3DSBCharPtr GetNarrowStr(const wchar_t *src) { return RegisterStr(src); }
+ Qt3DSBCharPtr GetNarrowStr(Qt3DSBCharPtr src) { return RegisterStr(src); }
+
+ // The string table maintains a map that will tell clients where their strings will be
+ // in terms of offsets into the data that the string table writes.
+ // This map will change each time a new string is added to the string table.
+ // Conversion from string -> data offset.
+ virtual const SStrRemapMap &GetRemapMap() = 0;
+
+ virtual NVAllocatorCallback &GetAllocator() = 0;
+
+ // Save to a block of memory. It is up the callers to deallocate using allocator
+ // from GetAllocator(). Returns a remap map that takes existing strings and changes their
+ // address such that they are offsets into the block of memory where this object
+ // started saving. Returns a map that converts registered strings into offsets of the
+ // written buffer.
+ virtual void Save(SWriteBuffer &ioBuffer) const = 0;
+
+ // Load all the strings from inMemory. inMemory is not freed by this object
+ // Finally, you will need to take inMemory and call remap on all strings
+ // from offsets back into their correct address into inMemory.
+ virtual void Load(qt3ds::foundation::NVDataRef<QT3DSU8> inMemory) = 0;
+
+ static IStringTable &CreateStringTable(NVAllocatorCallback &alloc);
+ };
+
+ inline const char8_t *CStringHandle::c_str(IStringTable &strTable) const
+ {
+ return strTable.HandleToStr(m_Data);
+ }
+}
+}
+
+// eastl extensions to allow easy hashtable creation using string table strings.
+namespace eastl {
+
+template <>
+struct hash<qt3ds::foundation::CRegisteredString>
+{
+ size_t operator()(const qt3ds::foundation::CRegisteredString &str) const { return str.hash(); }
+};
+
+template <>
+struct equal_to<qt3ds::foundation::CRegisteredString>
+{
+ bool operator()(const qt3ds::foundation::CRegisteredString &lhs,
+ const qt3ds::foundation::CRegisteredString &rhs) const
+ {
+ return lhs == rhs;
+ }
+};
+}
+
+#endif
diff --git a/src/foundation/StringTools.h b/src/foundation/StringTools.h
new file mode 100644
index 0000000..43324b4
--- /dev/null
+++ b/src/foundation/StringTools.h
@@ -0,0 +1,614 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_RENDER_STRING_H
+#define QT3DS_RENDER_STRING_H
+#include <QtCore/qstring.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qhash.h>
+#include <string>
+
+#include "Qt3DSRender.h"
+#include "EASTL/string.h"
+
+namespace qt3ds {
+namespace foundation {
+
+class Qt3DSStringUtils {
+public:
+ static inline QString ConvertUTFtoQString(const char16_t *string)
+ {
+ return QString::fromUtf16(string);
+ }
+
+ static inline QString ConvertUTFtoQString(const char32_t *string)
+ {
+ return QString::fromUcs4(string);
+ }
+
+ static inline QString ConvertUTFtoQString(const wchar_t *string)
+ {
+ return QString::fromWCharArray(string);
+ }
+
+ static inline QString &append(QString &target, QString::iterator begin,
+ QString::iterator end)
+ {
+ for (QString::iterator iter = begin;iter != end;++iter)
+ target.append(*iter);
+ return target;
+ }
+
+ static inline QString &append(QString &target, QString::const_iterator begin,
+ QString::const_iterator end)
+ {
+ for (QString::const_iterator iter = begin;iter != end;++iter)
+ target.append(*iter);
+ return target;
+ }
+
+ /**
+ * @brief replace Replaces specified portion of a string.
+ * @param source Source text that will be used. Note: This is const and will
+ * not be directly modified.
+ * @param first First character in the range that will be replaced.
+ * @param last Last character in the range that will be replaced.
+ * @param replaceText Pointer to the character string to use for replacement.
+ * @param len Length of the replacement character string.
+ * @return Returns a new QString containing the modified result.
+ */
+ static inline QString replace(const QString &source,
+ QString::const_iterator first,
+ QString::const_iterator last,
+ const char *replaceText, int len)
+ {
+ return replace(source, first, last, QString::fromUtf8(replaceText, len));
+ }
+
+ /**
+ * @brief replace Replaces specified portion of a string.
+ * @param source Source text that will be used. Note: This is const and will
+ * not be directly modified.
+ * @param first First character in the range that will be replaced.
+ * @param last Last character in the range that will be replaced.
+ * @param replaceText String to use for replacement.
+ * @return Returns a new QString containing the modified result.
+ */
+ static inline QString replace(const QString &source,
+ QString::const_iterator first,
+ QString::const_iterator last,
+ const QString &replaceText)
+ {
+ QString newStr;
+ for (QString::const_iterator iter = source.constBegin(); iter != first;
+ iter++)
+ newStr.append(*iter);
+
+ newStr.append(replaceText);
+
+ for (QString::const_iterator iter = last; iter != source.constEnd();
+ iter++)
+ newStr.append(*iter);
+ return newStr;
+ }
+
+ /**
+ * @brief replace Replaces specified portion of a string.
+ * @param source Source text that will be used. Note: This is const and
+ * will not be directly modified.
+ * @param first First character in the range that will be replaced.
+ * @param last Last character in the range that will be replaced.
+ * @param replaceText Pointer to the character string to use for replacement.
+ * @param len Length of the replacement character string.
+ * @return Returns a temporary object allocated on the stack containing
+ * the modified result.
+ */
+ static inline QString &replace(QString &target,
+ QString::iterator first,
+ QString::iterator last,
+ const char *replaceText, int len)
+ {
+ return replace(target, first, last, QString::fromUtf8(replaceText, len));
+ }
+
+ /**
+ * @brief replace Replaces specified portion of a string.
+ * @param target Target QString that will be modified.
+ * @param first First character in the range that will be replaced.
+ * @param last Last character in the range that will be replaced.
+ * @param replaceText String to use for replacement.
+ * @return Returns the string given in target, containing the modified result.
+ */
+ static inline QString &replace(QString &target,
+ QString::iterator first,
+ QString::iterator last,
+ const QString &replaceText)
+ {
+ QString newStr;
+ for (QString::iterator iter = target.begin(); iter != first; iter++)
+ newStr.append(*iter);
+
+ newStr.append(replaceText);
+
+ for (QString::iterator iter = last; iter != target.end(); iter++)
+ newStr.append(*iter);
+
+ target = newStr;
+ return target;
+ }
+};
+
+class Qt3DSString {
+public:
+ inline Qt3DSString() {}
+
+ Qt3DSString(QChar c) : m_string(QString(c)) {}
+
+ Qt3DSString(int size, QChar c) : m_string(size, c) {}
+
+ inline Qt3DSString(QLatin1String latin1)
+ : m_string(latin1) {}
+
+ explicit Qt3DSString(const QChar *unicode, int size = -1)
+ : m_string(unicode,size) {}
+
+ inline Qt3DSString(const QString &str) Q_DECL_NOTHROW
+ : m_string(str) {}
+
+ inline Qt3DSString(const Qt3DSString &str) Q_DECL_NOTHROW
+ : m_string(str.m_string) {}
+
+ ~Qt3DSString() {}
+
+ inline operator QString() const
+ {
+ return m_string;
+ }
+
+ inline void operator=(const Qt3DSString &text)
+ {
+ m_string = text.m_string;
+ m_isDirty = true;
+ }
+
+ inline void operator=(const QString &text)
+ {
+ m_string = text;
+ m_isDirty = true;
+ }
+
+ // QString method wrappers
+ static inline Qt3DSString fromUtf8(const char *str, int size = -1)
+ {
+ return Qt3DSString(QString::fromUtf8(str, size));
+ }
+
+ typedef int size_type;
+ typedef qptrdiff difference_type;
+ typedef const QChar & const_reference;
+ typedef QChar & reference;
+ typedef QChar *pointer;
+ typedef const QChar *const_pointer;
+ typedef QChar value_type;
+ typedef QChar *iterator;
+ typedef const QChar *const_iterator;
+ typedef iterator Iterator;
+ typedef const_iterator ConstIterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ inline iterator begin() { return m_string.begin(); }
+ inline const_iterator begin() const { return m_string.begin(); }
+ inline const_iterator cbegin() const { return m_string.cbegin(); }
+ inline const_iterator constBegin() const { return m_string.constBegin(); }
+ inline iterator end() { return m_string.end(); }
+ inline const_iterator end() const { return m_string.end(); }
+ inline const_iterator cend() const { return m_string.cend(); }
+ inline const_iterator constEnd() const { return m_string.constEnd(); }
+ reverse_iterator rbegin() { return reverse_iterator(end()); }
+ reverse_iterator rend() { return reverse_iterator(begin()); }
+ const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
+ const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
+ const_reverse_iterator crbegin() const { return const_reverse_iterator(end()); }
+ const_reverse_iterator crend() const { return const_reverse_iterator(begin()); }
+
+ inline void push_back(QChar c)
+ {
+ m_string.push_back(c);
+ m_isDirty = true;
+ }
+
+ inline void push_back(const QString &s)
+ {
+ m_string.push_back(s);
+ m_isDirty = true;
+ }
+
+ inline void push_front(QChar c)
+ {
+ m_string.push_front(c);
+ m_isDirty = true;
+ }
+
+ inline void push_front(const QString &s)
+ {
+ m_string.push_front(s);
+ m_isDirty = true;
+ }
+
+ inline bool operator==(const QString &rhs)
+ {
+ return rhs == m_string;
+ }
+
+ inline bool operator<(const QString &rhs)
+ {
+ return m_string < rhs;
+ }
+
+ inline bool operator!=(const QString &rhs)
+ {
+ return !(*this == rhs);
+ }
+
+ inline bool operator>(const QString& rhs)
+ {
+ return (rhs < m_string);
+ }
+
+ inline bool operator<=(const QString& rhs)
+ {
+ return !operator> (rhs);
+ }
+
+ inline bool operator>=(const QString& rhs)
+ {
+ return !operator< (rhs);
+ }
+
+ inline Qt3DSString& operator+=(const QString &rhs)
+ {
+ m_string += rhs;
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString& operator+=(const char *s)
+ {
+ m_string += s;
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline bool isEmpty() const
+ {
+ return m_string.isEmpty();
+ }
+
+ int indexOf(const QString &str, int from = 0,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.indexOf(str, from, cs);
+ }
+
+ int indexOf(QChar ch, int from = 0,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.indexOf(ch, from, cs);
+ }
+
+ int indexOf(QLatin1String str, int from = 0,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.indexOf(str, from, cs);
+ }
+
+ int indexOf(const QStringRef &str, int from = 0,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.indexOf(str, from, cs);
+ }
+
+ int lastIndexOf(const QString &str, int from = -1,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.lastIndexOf(str, from, cs);
+ }
+
+ int lastIndexOf(QChar ch, int from = -1,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.lastIndexOf(ch, from, cs);
+ }
+
+ int lastIndexOf(QLatin1String str, int from = -1,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.lastIndexOf(str, from, cs);
+ }
+
+ int lastIndexOf(const QStringRef &str, int from = -1,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.lastIndexOf(str, from, cs);
+ }
+
+ inline void clear()
+ {
+ m_string.clear();
+ m_isDirty = true;
+ }
+
+ inline Qt3DSString &insert(int i, QChar c)
+ {
+ m_string.insert(i,c);
+ m_isDirty = true;
+ return *this;
+ }
+ inline Qt3DSString &insert(int i, const QChar *uc, int len)
+ {
+ m_string.insert(i,uc, len);
+ m_isDirty = true;
+ return *this;
+ }
+ inline Qt3DSString &insert(int i, const QString &s)
+ {
+ m_string.insert(i,s);
+ m_isDirty = true;
+ return *this;
+ }
+ inline Qt3DSString &insert(int i, const QStringRef &s)
+ {
+ m_string.insert(i,s);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &insert(int i, QLatin1String s)
+ {
+ m_string.insert(i,s);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline int size() const
+ {
+ return m_string.size();
+ }
+
+ inline int length() const {
+ return m_string.length();
+ }
+
+ inline Qt3DSString &append(QChar c)
+ {
+ m_string.append(c);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &append(const QChar *uc, int len)
+ {
+ m_string.append(uc, len);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &append(const QString &s)
+ {
+ m_string.append(s);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &append(const QStringRef &s)
+ {
+ m_string.append(s);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &append(QLatin1String s)
+ {
+ m_string.append(s);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline int compare(const QString &s,
+ Qt::CaseSensitivity cs = Qt::CaseSensitive) const
+ {
+ return m_string.compare(s, cs);
+ }
+
+ // Compatibility wrappers for std::basic_string and eastl::basic_string
+ // Required for now for the Qt 3D Studio's template classes.
+ static const int npos = -1;
+
+ inline char operator[](int idx) const
+ {
+ return m_string[idx].toLatin1();
+ }
+
+ inline void assign(const char *text)
+ {
+ m_string = QString::fromUtf8(text);
+ m_isDirty = true;
+ }
+
+ inline void assign(const char16_t *text)
+ {
+ m_string = QString::fromUtf16(text);
+ m_isDirty = true;
+ }
+
+ inline void assign(const char32_t *text)
+ {
+ m_string = QString::fromUcs4(text);
+ m_isDirty = true;
+ }
+
+ inline void assign(const wchar_t *text)
+ {
+ m_string = QString::fromWCharArray(text);
+ m_isDirty = true;
+ }
+
+ inline void assign(const eastl::string &text)
+ {
+ m_string = QString::fromUtf8(text.c_str());
+ m_isDirty = true;
+ }
+
+ inline void operator=(const char *text)
+ {
+ assign(text);
+ }
+
+ inline void operator=(const char16_t *text)
+ {
+ assign(text);
+ }
+
+ inline void operator=(const char32_t *text)
+ {
+ assign(text);
+ }
+
+ inline void operator=(const wchar_t *text)
+ {
+ assign(text);
+ }
+
+ inline void operator=(const eastl::string &text)
+ {
+ assign(text);
+ }
+
+ inline void operator=(const eastl::basic_string<char*> &text)
+ {
+ assign(*text.c_str());
+ }
+
+ inline Qt3DSString &append(QString::iterator first,
+ QString::iterator last)
+ {
+ Qt3DSStringUtils::append(m_string, first, last);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &append(QString::const_iterator first,
+ QString::const_iterator last)
+ {
+ Qt3DSStringUtils::append(m_string, first, last);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &append(const char *text, int size)
+ {
+ m_string.append(QString::fromUtf8(text, size));
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &append(const char *text)
+ {
+ m_string.append(QString::fromUtf8(text));
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &replace(QString::iterator replaceBegin,
+ QString::iterator replaceEnd,
+ const char *replaceText, int len)
+ {
+ return replace(replaceBegin, replaceEnd,
+ QString::fromUtf8(replaceText, len));
+ }
+
+ inline Qt3DSString &replace(QString::iterator replaceBegin,
+ QString::iterator replaceEnd,
+ const QString &replaceText)
+ {
+ m_string = Qt3DSStringUtils::replace(this->m_string,
+ replaceBegin, replaceEnd,
+ replaceText);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline Qt3DSString &replace(QString::const_iterator replaceBegin,
+ QString::const_iterator replaceEnd,
+ const QString &replaceText)
+ {
+ m_string = Qt3DSStringUtils::replace(this->m_string,
+ replaceBegin, replaceEnd,
+ replaceText);
+ m_isDirty = true;
+ return *this;
+ }
+
+ inline QByteArray toUtf8() const
+ {
+ updateCache();
+ return m_array;
+ }
+
+ inline const char *c_str() const
+ {
+ updateCache();
+ return m_array.constData();
+ }
+
+ inline const char *c_str()
+ {
+ updateCache();
+ return m_array.constData();
+ }
+
+private:
+ inline void updateCache() const
+ {
+ if (m_isDirty) {
+ m_array = m_string.toUtf8();
+ m_isDirty = false;
+ }
+ }
+
+ QString m_string;
+ mutable bool m_isDirty = true;
+ mutable QByteArray m_array;
+};
+
+}
+}
+
+#endif
diff --git a/src/foundation/TaggedPointer.h b/src/foundation/TaggedPointer.h
new file mode 100644
index 0000000..aa22725
--- /dev/null
+++ b/src/foundation/TaggedPointer.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_FOUNDATION_TAGGED_POINTER_H
+#define QT3DS_FOUNDATION_TAGGED_POINTER_H
+#include "foundation/StringTable.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ template <typename TDataType>
+ struct SPointerTag
+ {
+ /* Expected API for runtime RTTI
+ static CRegisteredString GetTag() { return g_dtype_specific_string; }
+ */
+ };
+
+ // A pointer tagged with an identifier so we can have generic
+ // user data that is still somewhat typesafe.
+ struct STaggedPointer
+ {
+ void *m_UserData;
+ CRegisteredString m_Tag;
+ STaggedPointer()
+ : m_UserData(NULL)
+ {
+ }
+
+ STaggedPointer(void *inUserData, CRegisteredString inTag)
+ : m_UserData(inUserData)
+ , m_Tag(inTag)
+ {
+ }
+
+ template <typename TDataType>
+ STaggedPointer(TDataType *inType)
+ : m_UserData(reinterpret_cast<void *>(inType))
+ , m_Tag(SPointerTag<TDataType>::GetTag())
+ {
+ }
+
+ template <typename TDataType>
+ TDataType *DynamicCast() const
+ {
+ if (m_Tag == SPointerTag<TDataType>::GetTag())
+ return reinterpret_cast<TDataType *>(m_UserData);
+ return NULL;
+ }
+ };
+}
+}
+#endif \ No newline at end of file
diff --git a/src/foundation/ThreadSafeQueue.h b/src/foundation/ThreadSafeQueue.h
new file mode 100644
index 0000000..462b6d4
--- /dev/null
+++ b/src/foundation/ThreadSafeQueue.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#ifndef QT3DS_FOUNDATION_THREAD_SAFE_QUEUE_H
+#define QT3DS_FOUNDATION_THREAD_SAFE_QUEUE_H
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSSemaphore.h"
+#include "EASTL/vector.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ template <typename TObjType, typename TAllocator = EASTLAllocatorType>
+ class ThreadSafeQueue
+ {
+ public:
+ static const QT3DSU32 MaxQueue = 0xffffffff;
+
+ protected:
+ eastl::vector<TObjType, TAllocator> mQueue;
+ Semaphore mGetSemaphore;
+ Semaphore mPutSemaphore;
+ Mutex mMutex;
+ const QT3DSU32 mMaxCount;
+
+ public:
+ ThreadSafeQueue(NVAllocatorCallback &alloc, QT3DSU32 maxCount = MaxQueue)
+ : mMutex(alloc)
+ , mGetSemaphore(alloc, 0, maxCount)
+ , mPutSemaphore(alloc, maxCount, maxCount)
+ , mMaxCount(maxCount)
+ {
+ mQueue.clear();
+ }
+
+ bool push(const TObjType &obj, QT3DSU32 milliseconds = MaxQueue)
+ {
+ if (mPutSemaphore.wait(milliseconds)) {
+ Mutex::ScopedLock __locker(mMutex);
+ mQueue.push_back(obj);
+ mGetSemaphore.post();
+ return true;
+ }
+ return false;
+ }
+
+ bool pop(TObjType &obj, QT3DSU32 milliseconds = 0)
+ {
+ if (mGetSemaphore.wait(milliseconds)) {
+ Mutex::ScopedLock __locker(mMutex);
+ obj = mQueue.back();
+ mQueue.pop_back();
+ mPutSemaphore.post();
+ return true;
+ }
+ return false;
+ }
+
+ bool isFull()
+ {
+ Mutex::ScopedLock __locker(mMutex);
+ return mQueue.size() >= mMaxCount;
+ }
+
+ bool isEmpty()
+ {
+ Mutex::ScopedLock __locker(mMutex);
+ return mQueue.size() == 0;
+ }
+
+ void clear()
+ {
+ Mutex::ScopedLock __locker(mMutex);
+ while (!mQueue.empty()) {
+ if (mGetSemaphore.wait(MaxQueue)) {
+ mQueue.pop_back();
+ mPutSemaphore.post();
+ }
+ }
+ }
+ };
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/foundation/TrackingAllocator.cpp b/src/foundation/TrackingAllocator.cpp
new file mode 100644
index 0000000..242b0ac
--- /dev/null
+++ b/src/foundation/TrackingAllocator.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/TrackingAllocator.h"
+
+namespace qt3ds {
+namespace foundation {
+
+CAllocator::~CAllocator()
+{
+ QT3DS_ASSERT(mAllocations.size() == 0);
+ MemInfo info;
+ for (PtrToInfoMap::iterator iter = mAllocations.begin(), end = mAllocations.end();
+ iter != end; ++iter) {
+ info = iter->second;
+ qCCritical(INTERNAL_ERROR, "!!Outstanding allocation of %lu bytes from %s::%d, %s",
+ info.size, info.file, info.line, info.name ? info.name : "");
+ }
+ QT3DS_UNUSED(info);
+}
+
+}
+}
diff --git a/src/foundation/TrackingAllocator.h b/src/foundation/TrackingAllocator.h
new file mode 100644
index 0000000..4fd5806
--- /dev/null
+++ b/src/foundation/TrackingAllocator.h
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#ifndef QT3DS_RENDER_ALLOCATOR_H
+#define QT3DS_RENDER_ALLOCATOR_H
+#include "foundation/Qt3DSAllocatorCallback.h"
+#include "foundation/Qt3DSMutex.h"
+#include "EASTL/hash_map.h"
+#include "foundation/Qt3DSContainers.h"
+#include "foundation/Qt3DSLogging.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ // The simplest allocator. Performs no alignment nor memory checking.
+ struct MallocAllocator : public NVAllocatorCallback
+ {
+ void *allocate(size_t size, const char *, const char *, int, int = 0) override
+ {
+ return malloc(size);
+ }
+ void *allocate(size_t size, const char *, const char *, int, size_t, size_t) override
+ {
+ return malloc(size);
+ }
+ void deallocate(void *ptr) override { free(ptr); }
+ };
+
+ struct MemInfo
+ {
+ size_t size;
+ void *originalAddress;
+ const char *name;
+ const char *file;
+ int line;
+ MemInfo(size_t _size = 0, void *addr = 0, const char *_name = "", const char *_file = "",
+ int _line = 0)
+ : size(_size)
+ , originalAddress(addr)
+ , name(_name)
+ , file(_file)
+ , line(_line)
+ {
+ }
+ };
+
+ struct FileAndLine
+ {
+ const char *mFile;
+ QT3DSU32 mLine;
+ FileAndLine(const char *f, QT3DSU32 l)
+ : mFile(f)
+ , mLine(l)
+ {
+ }
+ };
+} // namespace foundation
+} // namespace qt3ds
+
+namespace eastl {
+template <>
+struct hash<qt3ds::foundation::FileAndLine>
+{
+ size_t operator()(const qt3ds::foundation::FileAndLine &fl) const
+ {
+ return hash<const void *>()((const void *)fl.mFile) ^ hash<int>()(fl.mLine);
+ }
+};
+
+template <>
+struct equal_to<qt3ds::foundation::FileAndLine>
+{
+ bool operator()(const qt3ds::foundation::FileAndLine &fl1,
+ const qt3ds::foundation::FileAndLine &fl2) const
+ {
+ size_t fl1File(reinterpret_cast<size_t>(fl1.mFile));
+ size_t fl2File(reinterpret_cast<size_t>(fl2.mFile));
+
+ return fl1File == fl2File && fl1.mLine == fl2.mLine;
+ }
+};
+}
+
+namespace qt3ds {
+namespace foundation {
+
+ struct MemInfoAndCount : MemInfo
+ {
+ QT3DSU32 mCount;
+ QT3DSU64 mTotalBytes;
+ MemInfoAndCount(const MemInfo &info)
+ : MemInfo(info)
+ , mCount(1)
+ , mTotalBytes(info.size)
+ {
+ }
+ void increment(const MemInfo &otherInfo)
+ {
+ ++mCount;
+ mTotalBytes += otherInfo.size;
+ }
+ };
+
+ typedef nvhash_map<FileAndLine, MemInfoAndCount> TFileAndLineMemHash;
+
+ class AllocationCheckPrinter
+ {
+ protected:
+ virtual ~AllocationCheckPrinter() {}
+ public:
+ virtual void printMissing(const MemInfoAndCount &item) = 0;
+ virtual void printIncorrectCount(const MemInfoAndCount &later,
+ const MemInfoAndCount &earlier) = 0;
+ };
+
+ // All allocations are 16 byte aligned.
+ // Prints out unallocated memory at destruction.
+ class QT3DS_AUTOTEST_EXPORT CAllocator : public NVAllocatorCallback
+ {
+ public:
+ typedef Mutex TMutexType;
+ typedef Mutex::ScopedLock TLockType;
+ typedef nvhash_map<void *, MemInfo> PtrToInfoMap;
+
+ private:
+ MallocAllocator mAlloc;
+ PtrToInfoMap mAllocations;
+ PtrToInfoMap mStoredAllocations;
+ TMutexType mMutex;
+
+ public:
+ CAllocator()
+ : mAllocations(mAlloc, "MemInfo")
+ , mStoredAllocations(mAlloc, "MemInfo")
+ , mMutex(mAlloc)
+ {
+ }
+ virtual ~CAllocator();
+
+ void *allocate(size_t size, const char *tn, const char *fl, int ln, int flags) override
+ {
+ QT3DS_ASSERT(size);
+ if (size) {
+ size += 15;
+ TLockType locker(mMutex);
+ void *original = mAlloc.allocate(size, tn, fl, ln, flags);
+ size_t temp = (size_t)original;
+ temp = (temp + 15) & (~15);
+ void *retval = (void *)temp;
+ mAllocations.insert(eastl::make_pair(retval, MemInfo(size, original, tn, fl, ln)));
+ return retval;
+ }
+ return NULL;
+ }
+ void *allocate(size_t size, const char *tn, const char *fl, int ln, size_t, size_t) override
+ {
+ return allocate(size, tn, fl, ln, 0);
+ }
+ void deallocate(void *ptr) override
+ {
+ if (ptr) {
+ TLockType locker(mMutex);
+ PtrToInfoMap::iterator entry(mAllocations.find(ptr));
+ if (entry != mAllocations.end()) {
+ mAlloc.deallocate(entry->second.originalAddress);
+ mAllocations.erase(ptr);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+ const PtrToInfoMap &getOutstandingAllocations() const { return mAllocations; }
+ static void convert(const CAllocator::PtrToInfoMap &map, TFileAndLineMemHash &fl)
+ {
+ for (CAllocator::PtrToInfoMap::const_iterator iter = map.begin(), end = map.end();
+ iter != end; ++iter) {
+ const MemInfo &info(iter->second);
+ FileAndLine flKey(info.file, info.line);
+ TFileAndLineMemHash::const_iterator find(fl.find(flKey));
+ if (find == fl.end())
+ fl.insert(eastl::make_pair(flKey, MemInfoAndCount(info)));
+ else
+ const_cast<MemInfoAndCount &>(find->second).increment(info);
+ }
+ }
+ static void copyMap(const CAllocator::PtrToInfoMap &map1, CAllocator::PtrToInfoMap &map2)
+ {
+ for (CAllocator::PtrToInfoMap::const_iterator iter = map1.begin(), end = map1.end();
+ iter != end; ++iter) {
+ map2.insert(eastl::make_pair(iter->first, iter->second));
+ }
+ }
+
+ static void printDiffs(const TFileAndLineMemHash &fl1, const TFileAndLineMemHash &fl2,
+ AllocationCheckPrinter &printer)
+ {
+ using namespace std;
+ for (TFileAndLineMemHash::const_iterator iter = fl1.begin(), end = fl1.end();
+ iter != end; ++iter) {
+ TFileAndLineMemHash::const_iterator entry = fl2.find(iter->first);
+ if (entry != fl2.end()) {
+ printer.printMissing(iter->second);
+ } else if (iter->second.mCount > entry->second.mCount) {
+ printer.printIncorrectCount(iter->second, entry->second);
+ }
+ }
+ }
+
+ void printAllocationDiff(AllocationCheckPrinter &printer)
+ {
+ TFileAndLineMemHash map1fl(mAlloc, "printAllocationDiff");
+ TFileAndLineMemHash map2fl(mAlloc, "printAllocationDiff");
+ convert(mStoredAllocations, map1fl);
+ convert(mAllocations, map2fl);
+ printDiffs(map2fl, map1fl, printer);
+ }
+ void storeAllocations()
+ {
+ mStoredAllocations.clear();
+ copyMap(mAllocations, mStoredAllocations);
+ }
+ bool hasStoredAllocations() { return mStoredAllocations.size() > 0; }
+ };
+}
+}
+#endif
diff --git a/src/foundation/Utils.h b/src/foundation/Utils.h
new file mode 100644
index 0000000..33c2400
--- /dev/null
+++ b/src/foundation/Utils.h
@@ -0,0 +1,382 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_RENDER_UTILS_H
+#define QT3DS_RENDER_UTILS_H
+#include "EASTL/hash_map.h"
+#include "EASTL/hash_set.h"
+#include "EASTL/vector.h"
+#include "foundation/Qt3DSIntrinsics.h"
+#include "foundation/Qt3DSDataRef.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSContainers.h"
+#include "foundation/Qt3DSMath.h"
+#include <ctype.h>
+
+namespace qt3ds {
+namespace foundation {
+
+ // Defined in IStringTable.cpp
+ extern const char16_t *char16EmptyStr;
+ extern const char32_t *char32EmptyStr;
+
+ inline const char *nonNull(const char *src) { return src == NULL ? "" : src; }
+ inline bool isTrivial(const char *str) { return str == NULL || *str == 0; }
+ inline const char16_t *nonNull(const char16_t *src)
+ {
+ return src == NULL ? char16EmptyStr : src;
+ }
+ inline bool isTrivial(const char16_t *str) { return str == NULL || *str == 0; }
+ inline const char32_t *nonNull(const char32_t *src)
+ {
+ return src == NULL ? char32EmptyStr : src;
+ }
+ inline bool isTrivial(const char32_t *str) { return str == NULL || *str == 0; }
+
+ // Note this is safe to call on null strings.
+ template <typename TCharType>
+ inline QT3DSU32 StrLen(const TCharType *inType)
+ {
+ QT3DSU32 retval = 0;
+ while (inType && *inType) {
+ ++retval;
+ ++inType;
+ }
+ return retval;
+ }
+
+ template <typename TCharType>
+ inline QT3DSI32 Compare(const TCharType *inLhs, const TCharType *inRhs)
+ {
+ inLhs = nonNull(inLhs);
+ inRhs = nonNull(inRhs);
+ while (*inLhs && *inRhs) {
+ QT3DSI32 diff = *inLhs - *inRhs;
+ if (diff)
+ return diff;
+ ++inLhs;
+ ++inRhs;
+ }
+ return *inLhs - *inRhs;
+ }
+
+ template <typename TCharType>
+ inline QT3DSI32 CompareCaseless(const TCharType *inLhs, const TCharType *inRhs)
+ {
+ inLhs = nonNull(inLhs);
+ inRhs = nonNull(inRhs);
+ while (*inLhs && *inRhs) {
+ QT3DSI32 diff = tolower(*inLhs) - tolower(*inRhs);
+ if (diff)
+ return diff;
+ ++inLhs;
+ ++inRhs;
+ }
+ return *inLhs - *inRhs;
+ }
+
+ template <typename TCharType>
+ inline QT3DSI32 CompareNChars(const TCharType *inLhs, const TCharType *inRhs, QT3DSU32 inNumChars)
+ {
+ inLhs = nonNull(inLhs);
+ inRhs = nonNull(inRhs);
+ while (*inLhs && *inRhs && inNumChars) {
+ QT3DSI32 diff = *inLhs - *inRhs;
+ if (diff)
+ return diff;
+ ++inLhs;
+ ++inRhs;
+ --inNumChars;
+ }
+ if (inNumChars)
+ return *inLhs - *inRhs;
+ return 0;
+ }
+
+ template <typename TCharType>
+ bool AreEqual(const TCharType *inLhs, const TCharType *inRhs)
+ {
+ return Compare(inLhs, inRhs) == 0;
+ }
+
+ template <typename TCharType>
+ bool AreEqualCaseless(const TCharType *inLhs, const TCharType *inRhs)
+ {
+ return CompareCaseless(inLhs, inRhs) == 0;
+ }
+
+ inline QT3DSU32 IsBitSetInBitmap(NVConstDataRef<QT3DSU32> bitmap, QT3DSU32 entryIndex)
+ {
+ QT3DSU32 bitMapIndex = entryIndex / 32;
+ QT3DSU32 bitIndex = entryIndex % 32;
+ QT3DSU32 shouldApply = 0;
+ if (bitMapIndex < bitmap.mSize)
+ shouldApply = (1 << bitIndex) & bitmap[bitMapIndex];
+ return shouldApply;
+ }
+
+ inline void SetBitInBitmap(nvvector<QT3DSU32> &bitmap, QT3DSU32 entryIndex)
+ {
+ QT3DSU32 bitMapIndex = entryIndex / 32;
+ QT3DSU32 bitIndex = entryIndex % 32;
+ while (bitmap.size() <= bitMapIndex)
+ bitmap.push_back(0);
+ bitmap[bitMapIndex] |= (QT3DSU32)(1 << bitIndex);
+ }
+ inline void UnsetBitInBitmap(nvvector<QT3DSU32> &bitmap, QT3DSU32 entryIndex)
+ {
+ QT3DSU32 bitMapIndex = entryIndex / 32;
+ QT3DSU32 bitIndex = entryIndex % 32;
+ if (bitMapIndex < bitmap.size())
+ bitmap[bitMapIndex] &= ~((QT3DSU32)(1 << bitIndex));
+ }
+
+#define CHECK_CONDITION_AND_RETURN_FALSE(cond, errorType, message) \
+ if (cond) { \
+ m_Foundation.error(errorType, message); \
+ QT3DS_ASSERT(false); \
+ return false; \
+ }
+// Returns false if the property type doesn't match the incoming type.
+#define CHECK_CONDITION_AND_RETURN(cond, errorType, message) \
+ if (cond) { \
+ m_Foundation.error(errorType, message); \
+ QT3DS_ASSERT(false); \
+ }
+
+#define QT3DS_FOREACH(varname, stop) for (QT3DSU32 varname = 0, end = stop; varname < end; ++varname)
+
+ template <typename TKeyType, typename TValueType, typename THashType, typename TPredicate,
+ typename TBufType, typename TOperator>
+ QT3DSU32 GetMapKeysOp(const eastl::hash_map<TKeyType, TValueType, THashType, TPredicate,
+ ForwardingAllocator> &map,
+ TBufType *buffer, QT3DSU32 bufSize, QT3DSU32 startIdx, TOperator op)
+ {
+ QT3DSU32 numItems = static_cast<QT3DSU32>(map.size());
+ if (numItems == 0 || bufSize == 0)
+ return 0;
+
+ startIdx = NVMin(numItems - 1, startIdx);
+ QT3DSU32 retval = 0;
+ for (typename eastl::hash_map<TKeyType, TValueType, THashType, TPredicate,
+ ForwardingAllocator>::const_iterator iter = map.begin(),
+ end = map.end();
+ iter != end && bufSize; ++iter) {
+ if (startIdx)
+ --startIdx;
+ else {
+ buffer[retval] = op(iter->first);
+ --bufSize;
+ ++retval;
+ }
+ }
+ return retval;
+ }
+
+ struct IdOp
+ {
+ template <typename TDataType>
+ TDataType operator()(const TDataType &item)
+ {
+ return item;
+ }
+ };
+
+ template <typename TKeyType, typename TValueType, typename THashType, typename TPredicateType>
+ QT3DSU32
+ GetMapKeys(const eastl::hash_map<TKeyType, TValueType, THashType, ForwardingAllocator> &map,
+ TKeyType *buffer, QT3DSU32 bufSize, QT3DSU32 startIdx)
+ {
+ return GetMapKeysOp(map, buffer, bufSize, startIdx, IdOp());
+ }
+
+ struct DerefOp
+ {
+ template <typename TDataType>
+ TDataType operator()(const TDataType *item)
+ {
+ return *item;
+ }
+ };
+
+ template <typename TKeyType, typename TValueType, typename THashType, typename TPredicateType,
+ typename TAllocatorType, typename TBufType, typename TOp>
+ QT3DSU32 GetMapValues(
+ const eastl::hash_map<TKeyType, TValueType, THashType, TPredicateType, TAllocatorType> &map,
+ TBufType *buffer, QT3DSU32 bufSize, QT3DSU32 startIdx, TOp op)
+ {
+ QT3DSU32 numItems = static_cast<QT3DSU32>(map.size());
+ if (numItems == 0 || bufSize == 0)
+ return 0;
+
+ startIdx = NVMin(numItems - 1, startIdx);
+ QT3DSU32 retval = 0;
+ for (typename eastl::hash_map<TKeyType, TValueType, THashType, TPredicateType,
+ TAllocatorType>::const_iterator iter = map.begin(),
+ end = map.end();
+ iter != end && bufSize; ++iter) {
+ if (startIdx)
+ --startIdx;
+ else {
+ buffer[retval] = op(iter->second);
+ --bufSize;
+ ++retval;
+ }
+ }
+ return retval;
+ }
+
+ template <typename TValueType, typename TBufType>
+ QT3DSU32 GetArrayEntries(const nvvector<TValueType> &data, TBufType *buffer, QT3DSU32 bufSize,
+ QT3DSU32 startIdx)
+ {
+ QT3DSU32 numItems = static_cast<QT3DSU32>(data.size());
+ if (numItems == 0 || bufSize == 0)
+ return 0;
+
+ startIdx = NVMin(numItems - 1, startIdx);
+ QT3DSU32 available = NVMin(numItems - startIdx, bufSize);
+ QT3DS_FOREACH(idx, available)
+ buffer[idx] = data[idx + startIdx];
+ return available;
+ }
+
+ template <typename TValueType, typename TBufType>
+ QT3DSU32 GetDataRefEntries(const NVDataRef<TValueType> &data, TBufType *buffer, QT3DSU32 bufSize,
+ QT3DSU32 startIdx)
+ {
+ QT3DSU32 numItems = static_cast<QT3DSU32>(data.size());
+ if (numItems == 0 || bufSize == 0)
+ return 0;
+
+ startIdx = NVMin(numItems - 1, startIdx);
+ QT3DSU32 available = NVMin(numItems - startIdx, bufSize);
+ QT3DS_FOREACH(idx, available)
+ buffer[idx] = data.mData[idx + startIdx];
+ return available;
+ }
+
+ template <typename TValueType, typename TBufType>
+ QT3DSU32 GetDataRefEntries(const NVConstDataRef<TValueType> &data, TBufType *buffer, QT3DSU32 bufSize,
+ QT3DSU32 startIdx)
+ {
+ QT3DSU32 numItems = static_cast<QT3DSU32>(data.size());
+ if (numItems == 0 || bufSize == 0)
+ return 0;
+
+ startIdx = NVMin(numItems - 1, startIdx);
+ QT3DSU32 available = NVMin(numItems - startIdx, bufSize);
+ QT3DS_FOREACH(idx, available)
+ buffer[idx] = data.mData[idx + startIdx];
+ return available;
+ }
+
+ template <typename TKeyType, typename THashType, typename TPredicate, typename TAllocator>
+ QT3DSU32 GetHashSetEntries(eastl::hash_set<TKeyType, THashType, TPredicate, TAllocator> &data,
+ TKeyType *buffer, QT3DSU32 bufSize, QT3DSU32 startIdx)
+ {
+ QT3DSU32 numItems = static_cast<QT3DSU32>(data.size());
+ if (numItems == 0 || bufSize == 0)
+ return 0;
+ startIdx = NVMin(numItems - 1, startIdx);
+ QT3DSU32 available = NVMin(numItems - startIdx, bufSize);
+ QT3DSU32 idx = 0;
+ for (typename eastl::hash_set<TKeyType, THashType, TPredicate, TAllocator>::const_iterator
+ iter = data.begin(),
+ end = data.end();
+ iter != end && idx < available; ++iter, ++idx) {
+ if (startIdx) {
+ --startIdx;
+ continue;
+ }
+ buffer[idx] = *iter;
+ }
+ return available;
+ }
+
+ template <typename TDataType>
+ void memCopyT(TDataType *dest, const TDataType *src, QT3DSU32 size)
+ {
+ memCopy(dest, src, size * sizeof(TDataType));
+ }
+
+ template <typename TDataType>
+ NVDataRef<TDataType> PtrAtOffset(QT3DSU8 *baseData, QT3DSU32 offset, QT3DSU32 byteSize)
+ {
+ return NVDataRef<TDataType>(byteSize ? (TDataType *)(baseData + offset) : NULL,
+ byteSize / sizeof(TDataType));
+ }
+
+ struct char_hasher
+ {
+ size_t operator()(const char *item) const { return eastl::hash<const char8_t *>()(item); }
+ };
+
+ struct char_equal_to
+ {
+ bool operator()(const char *lhs, const char *rhs) const
+ {
+ if (lhs == NULL)
+ lhs = "";
+ if (rhs == NULL)
+ rhs = "";
+ return strcmp(lhs, rhs) == 0;
+ }
+ };
+
+ struct wide_char_hasher
+ {
+ size_t operator()(const char16_t *item) const
+ {
+ return eastl::hash<const char16_t *>()(item);
+ }
+ };
+
+ struct wide_char_equal_to
+ {
+ bool operator()(const char16_t *lhs, const char16_t *rhs) const
+ {
+ if (lhs == NULL)
+ lhs = reinterpret_cast<const char16_t *>(L"");
+ if (rhs == NULL)
+ rhs = reinterpret_cast<const char16_t *>(L"");
+ while (*lhs && *rhs) {
+ int answer = *lhs - *rhs;
+ if (answer)
+ return false;
+ ++lhs;
+ ++rhs;
+ }
+ return *lhs == *rhs;
+ }
+ };
+}
+}
+#endif
diff --git a/src/foundation/XML.cpp b/src/foundation/XML.cpp
new file mode 100644
index 0000000..bd12dfa
--- /dev/null
+++ b/src/foundation/XML.cpp
@@ -0,0 +1,948 @@
+/****************************************************************************
+**
+** 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 "foundation/XML.h"
+#include "foundation/Qt3DSPool.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSRefCounted.h"
+#include "foundation/StringTable.h"
+#include "foundation/IOStreams.h"
+#include "foundation/StringConversionImpl.h"
+#include "foundation/StrConvertUTF.h"
+#include "foundation/StringTable.h"
+#include "foundation/Utils.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "EASTL/hash_map.h"
+
+#ifdef QT3DS_VC
+#include <windows.h> //output debug string
+#endif
+
+#include <QtCore/qxmlstream.h>
+
+using namespace qt3ds;
+using namespace qt3ds::foundation;
+using namespace qt3ds::intrinsics;
+
+typedef char XML_Char;
+
+namespace {
+
+const QT3DSU16 g_BOMMarker = (QT3DSU16)0xFEFF;
+
+// Some DOM parsing operations are destructive. If you need
+// them to not be destructive, then we need to modify
+// the reader. Specifically parsing lists of floats, due
+// to a bug in strtod, is destructive.
+struct SDOMReader : public IDOMReader
+{
+ SReaderScope m_TopElement;
+ eastl::vector<SReaderScope> m_ScopeStack;
+ NVScopedRefCounted<IDOMFactory> m_Factory;
+ volatile QT3DSI32 mRefCount;
+
+ SDOMReader(NVAllocatorCallback &inAlloc, SDOMElement &te, NVScopedRefCounted<IStringTable> s,
+ NVScopedRefCounted<IDOMFactory> inFactory)
+ : IDOMReader(inAlloc, s)
+ , m_TopElement(&te)
+ , m_Factory(inFactory)
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Factory->GetAllocator())
+
+ SDOMElement *Current() const { return m_TopElement.m_Element; }
+
+ void PushScope() override { m_ScopeStack.push_back(SReaderScope(m_TopElement)); }
+
+ void PopScope() override
+ {
+ if (m_ScopeStack.size()) {
+ m_TopElement = m_ScopeStack.back();
+ m_ScopeStack.pop_back();
+ } else
+ m_TopElement = SReaderScope();
+ }
+
+ SReaderScope GetScope() override { return m_TopElement; }
+
+ void SetScope(SReaderScope inScope) override { m_TopElement = inScope; }
+
+ SDOMElement *GetElement() const override { return m_TopElement.m_Element; }
+
+ Option<CRegisteredString> RegisterNS(TXMLCharPtr ns)
+ {
+ if (ns) {
+ return m_StringTable->RegisterStr(ns);
+ }
+ return Empty();
+ }
+
+ bool UnregisteredAtt(TXMLCharPtr name, TXMLCharPtr &outValue, TXMLCharPtr ns = NULL) override
+ {
+ outValue = "";
+ SDOMElement *current(Current());
+ if (current) {
+ return current->AttValue(m_StringTable->RegisterStr(name), RegisterNS(ns), outValue);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ return false;
+ }
+
+ bool Att(TXMLCharPtr name, CRegisteredString &outValue, TXMLCharPtr ns = NULL) override
+ {
+ const char8_t *unregValue = NULL;
+ if (UnregisteredAtt(name, unregValue, ns)) {
+ outValue = m_StringTable->RegisterStr(unregValue);
+ return true;
+ }
+ return false;
+ }
+
+ QT3DSU32 CountChildren(TXMLCharPtr childName = NULL, TXMLCharPtr ns = NULL) override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return 0;
+ }
+ return elem->GetNumChildren(m_StringTable->RegisterStr(childName), RegisterNS(ns));
+ }
+
+ SDOMAttribute *CurrentAtt()
+ {
+ if (m_TopElement.m_Attribute)
+ return m_TopElement.m_Attribute;
+ return NULL;
+ }
+
+ SDOMAttribute *GetFirstAttribute() override
+ {
+ if (m_TopElement.m_Element)
+ m_TopElement.m_Attribute = m_TopElement.m_Element->m_Attributes.m_Head;
+ return m_TopElement.m_Attribute;
+ }
+
+ SDOMAttribute *GetNextAttribute() override
+ {
+ if (m_TopElement.m_Attribute)
+ m_TopElement.m_Attribute = m_TopElement.m_Attribute->m_NextAttribute;
+ return CurrentAtt();
+ }
+
+ bool MoveToFirstChild(TXMLCharPtr childName = NULL, TXMLCharPtr ns = NULL) override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ SDOMElement *child = elem->FindChild(m_StringTable->RegisterStr(childName), RegisterNS(ns));
+ if (child != NULL) {
+ m_TopElement = child;
+ return true;
+ }
+ return false;
+ }
+
+ bool MoveToNextSibling(TXMLCharPtr childName = NULL, TXMLCharPtr ns = NULL) override
+ {
+ SDOMElement *elem = Current();
+ if (elem == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ SDOMElement *nextSibling =
+ elem->FindSibling(m_StringTable->RegisterStr(childName), RegisterNS(ns));
+ if (nextSibling) {
+ m_TopElement = nextSibling;
+ return true;
+ }
+ return false;
+ }
+ // Leave element means go to its parent.
+ void Leave() override
+ {
+ QT3DS_ASSERT(m_TopElement.m_Element);
+ if (m_TopElement.m_Element)
+ m_TopElement = m_TopElement.m_Element->m_Parent;
+ }
+
+ bool Value(TXMLCharPtr &outValue) override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ outValue = current->m_Value;
+ return true;
+ }
+
+ SDOMElement *GetTopElement() override
+ {
+ SDOMElement *current(Current());
+ while (current && current->m_Parent)
+ current = current->m_Parent;
+ return current;
+ }
+
+ virtual NVScopedRefCounted<IDOMFactory> GetFactory() { return m_Factory; }
+};
+
+struct SDOMWriter : public IDOMWriter, public SDOMReader
+{
+ NVScopedRefCounted<IDOMFactory> m_FactoryPtr;
+ IDOMFactory &m_Factory;
+
+ SDOMWriter(NVScopedRefCounted<IDOMFactory> inDOMFactory,
+ NVScopedRefCounted<IStringTable> inStringTable, SDOMElement &inTopElem)
+ : SDOMReader(inDOMFactory->GetAllocator(), inTopElem, inStringTable, *inDOMFactory)
+ , m_FactoryPtr(inDOMFactory)
+ , m_Factory(*inDOMFactory)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Factory.GetAllocator())
+
+ void Begin(TXMLCharPtr inElemName, TXMLCharPtr inNamespace = NULL, int inLine = 0) override
+ {
+ if (!m_TopElement.m_Element) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SDOMElement *current(Current());
+ SDOMElement *newElement(m_Factory.NextElement(m_StringTable->RegisterStr(inElemName),
+ m_StringTable->RegisterStr(inNamespace),
+ inLine));
+ current->AppendChild(*newElement);
+ m_TopElement = newElement;
+ }
+
+ void Att(TXMLCharPtr name, TXMLCharPtr value, TXMLCharPtr ns, int inLine) override
+ {
+ if (!m_TopElement.m_Element) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ m_TopElement.m_Element->SetAttributeValue(m_StringTable->RegisterStr(name), RegisterNS(ns),
+ value, m_Factory, inLine);
+ }
+
+ void Value(TXMLCharPtr value) override
+ {
+ if (!m_TopElement.m_Element) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (value == NULL)
+ value = "";
+ size_t len = strlen(value);
+ m_Factory.AppendStrBuf(value, (QT3DSU32)len);
+ m_TopElement.m_Element->m_Value = m_Factory.FinalizeStrBuf();
+ }
+
+ void End() override
+ {
+ if (!m_TopElement.m_Element) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ Leave();
+ }
+ void RemoveCurrent() override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ if (current->m_Parent) {
+ m_TopElement = current->m_Parent;
+ m_TopElement.m_Element->RemoveChild(*current);
+ }
+ }
+ void RemoveAttribute(TXMLCharPtr inItem, TXMLCharPtr inNamespace) override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ current->RemoveAttribute(m_StringTable->RegisterStr(inItem), RegisterNS(inNamespace));
+ }
+
+ void MoveBefore(TXMLCharPtr inItem, TXMLCharPtr inSibling, TXMLCharPtr inNs = NULL) override
+ {
+ SDOMElement *current(Current());
+ if (!current) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ SDOMElement *theItem =
+ current->FindChild(m_StringTable->RegisterStr(inItem), RegisterNS(inNs));
+ SDOMElement *theSibling =
+ current->FindChild(m_StringTable->RegisterStr(inSibling), RegisterNS(inNs));
+ QT3DS_ASSERT(theItem && theSibling);
+ if (theItem && theSibling)
+ current->PrependChild(*theItem, theSibling);
+ }
+
+ // If current has no parent, then we are at the top
+ // of the tree and we should return 0. Or if there is no
+ // current.
+ // If there is one parent, we should return 1.
+ QT3DSU32 GetTabs() override
+ {
+ QT3DSU32 retval = 0;
+ SDOMElement *current(Current());
+ do {
+ if (current)
+ current = current->m_Parent;
+ if (current)
+ ++retval;
+ } while (current);
+ return retval;
+ }
+
+ SDOMElement *GetTopElement() override { return SDOMReader::GetTopElement(); }
+
+ NVScopedRefCounted<IDOMFactory> GetFactory() override { return m_FactoryPtr; }
+
+ NVAllocatorCallback &GetAllocator() override { return m_Factory.GetAllocator(); }
+};
+
+struct SimpleXmlWriter
+{
+
+ struct SNameNS
+ {
+ TXMLCharPtr name;
+ TXMLCharPtr ns;
+ SNameNS(TXMLCharPtr _name = NULL, TXMLCharPtr _ns = NULL)
+ : name(_name)
+ , ns(_ns)
+ {
+ }
+ };
+ IOutStream &m_Stream;
+ eastl::vector<eastl::pair<SNameNS, bool>> m_OpenElements;
+ bool m_ElementOpen;
+ char8_t m_PrintBuf[256];
+ QT3DSU32 m_Tabs;
+ eastl::basic_string<char8_t, ForwardingAllocator> m_Buffer;
+
+ SimpleXmlWriter(NVAllocatorCallback &inAlloc, IOutStream &stream, QT3DSU32 inTabs = 0)
+ : m_Stream(stream)
+ , m_ElementOpen(false)
+ , m_Tabs(inTabs)
+ , m_Buffer(ForwardingAllocator(inAlloc, "SimpleXMLWriter::m_Buffer"))
+ {
+ }
+
+ void Write(const SNameNS &data)
+ {
+ if (data.ns && *data.ns) {
+ Write(data.ns);
+ Write(':');
+ }
+ Write(data.name);
+ }
+
+ void Write(const char8_t *data, QT3DSU32 inLen = 0)
+ {
+ if (!isTrivial(data)) {
+ if (inLen == 0)
+ inLen = StrLen(data);
+ m_Stream.Write(data, inLen);
+ }
+ }
+ void BeginWrite() { m_Buffer.clear(); }
+ void WriteTemp(char8_t data) { m_Buffer.append(1, data); }
+ void WriteTemp(const char8_t *data) { m_Buffer.append(data); }
+ void EndWrite() { Write(reinterpret_cast<const char8_t *>(m_Buffer.c_str()), m_Buffer.size()); }
+ void Write(char8_t data) { m_Stream.Write(data); }
+ void Tabs()
+ {
+ QT3DS_FOREACH(idx, (m_OpenElements.size() + m_Tabs))
+ Write('\t');
+ }
+ void Close(bool newline)
+ {
+ if (m_ElementOpen) {
+ Write(">");
+ if (newline)
+ Write('\n');
+ }
+ m_ElementOpen = false;
+ }
+ void Begin(TXMLCharPtr name, TXMLCharPtr ns)
+ {
+ Close(true);
+ Tabs();
+ Write('<');
+ SNameNS theName(name, ns);
+ Write(theName);
+ m_OpenElements.push_back(eastl::pair<SNameNS, bool>(theName, false));
+ m_ElementOpen = true;
+ }
+ TXMLCharPtr ToStr(char8_t val)
+ {
+ m_PrintBuf[0] = val;
+ m_PrintBuf[1] = 0;
+ return m_PrintBuf;
+ }
+ template <typename TDataType>
+ TXMLCharPtr ToStr(TDataType val)
+ {
+ StringConversion<TDataType>().ToStr(val, NVDataRef<char8_t>(m_PrintBuf, 256));
+ return m_PrintBuf;
+ }
+ void Att(TXMLCharPtr name, TXMLCharPtr ns, TXMLCharPtr value)
+ {
+ QT3DS_ASSERT(m_ElementOpen);
+ Write(' ');
+ Write(SNameNS(name, ns));
+
+ Write("=\"");
+
+ QString str = QString::fromUtf8(nonNull(value)).toHtmlEscaped();
+ Write(str.toUtf8().constData());
+ Write("\"");
+ }
+ template <typename TData>
+ void Att(TXMLCharPtr name, TXMLCharPtr ns, TData value)
+ {
+ Att(name, ns, ToStr(value));
+ }
+
+ void Value(TXMLCharPtr value)
+ {
+ if (!isTrivial(value)) {
+ Close(false);
+
+ QString str = QString::fromUtf8(nonNull(value)).toHtmlEscaped();
+ Write(str.toUtf8().constData());
+ m_OpenElements.back().second = true;
+ }
+ }
+ void ChildValue(TXMLCharPtr name, TXMLCharPtr ns, TXMLCharPtr value)
+ {
+ Begin(name, ns);
+ Value(value);
+ End();
+ }
+ void End(bool newlineAfterClose = true)
+ {
+ QT3DS_ASSERT(m_OpenElements.size());
+ eastl::pair<SNameNS, bool> topElem = m_OpenElements.back();
+ m_OpenElements.pop_back();
+ if (m_ElementOpen)
+ Write("/>");
+ else {
+ if (topElem.second == false)
+ Tabs();
+ Write("</");
+ Write(topElem.first);
+ Write(">");
+ }
+ m_ElementOpen = false;
+ if (newlineAfterClose == true)
+ Write('\n');
+ }
+};
+
+struct DOMParser
+{
+ IDOMFactory &m_Factory;
+ SDOMElement *m_TopElement;
+ SDOMElement *m_FirstElement;
+ char8_t m_nsSeparator;
+ typedef eastl::basic_string<char8_t, ForwardingAllocator> TStrType;
+ TStrType m_NSBuffer;
+ TStrType m_NameBuffer;
+ CRegisteredString m_RegName;
+ CRegisteredString m_RegNS;
+ SNamespacePairNode *m_FirstPair;
+ SNamespacePairNode *m_LastPair;
+ QXmlStreamReader *m_XMLParser;
+
+ DOMParser(IDOMFactory &factory, QXmlStreamReader &parser, char8_t nsSeparator)
+ : m_Factory(factory)
+ , m_FirstElement(NULL)
+ , m_nsSeparator(nsSeparator)
+ , m_NSBuffer(ForwardingAllocator(factory.GetAllocator(), "DOMParser::m_NSBuffer"))
+ , m_NameBuffer(ForwardingAllocator(factory.GetAllocator(), "DOMParser::m_NameBuffer"))
+ , m_FirstPair(NULL)
+ , m_LastPair(NULL)
+ , m_XMLParser(&parser)
+ {
+ }
+
+ void ParseName(const XML_Char *name)
+ {
+ m_NSBuffer.assign(name);
+ eastl::string::size_type pos = m_NSBuffer.find(m_nsSeparator);
+ if (pos != TStrType::npos) {
+ m_NameBuffer.assign(m_NSBuffer.c_str() + pos + 1);
+ m_NSBuffer.resize(pos);
+ } else {
+ m_NameBuffer = m_NSBuffer;
+ m_NSBuffer.clear();
+ // Find the namespace with no abbreviation.
+ for (SNamespacePairNode *theNode = m_FirstPair; theNode;
+ theNode = theNode->m_NextNode) {
+ if (theNode->m_Abbreviation.IsValid() == false)
+ m_NSBuffer.assign(theNode->m_Namespace.c_str());
+ }
+ }
+ m_RegName = m_Factory.GetStringTable()->RegisterStr(m_NameBuffer.c_str());
+ m_RegNS = m_Factory.GetStringTable()->RegisterStr(m_NSBuffer.c_str());
+ }
+
+ struct SimpleXmlErrorHandler : public CXmlErrorHandler
+ {
+ void OnXmlError(TXMLCharPtr errorName, int line, int column) override
+ {
+ char8_t buffer[1024];
+ _snprintf(buffer, 1024, "%s(%d): Xml Error %s on line %d, column %d", __FILE__,
+ __LINE__, errorName, line, column);
+#ifdef QT3DS_VC
+ OutputDebugStringA(buffer);
+#endif
+ printf("%s\n", buffer);
+ }
+ };
+
+ template <QT3DSU32 THeaderLen>
+ struct SHeaderInStream : public IInStream
+ {
+ QT3DSU8 m_Header[THeaderLen];
+ IInStream &m_InStream;
+ QT3DSU32 m_BytesRead;
+
+ SHeaderInStream(IInStream &inStream)
+ : m_InStream(inStream)
+ , m_BytesRead(0)
+ {
+ }
+ bool readHeader()
+ {
+ QT3DSU32 amountRead = m_InStream.Read(NVDataRef<QT3DSU8>(m_Header, THeaderLen));
+ return amountRead == THeaderLen;
+ }
+ QT3DSU32 Read(NVDataRef<QT3DSU8> data) override
+ {
+ if (data.size() == 0)
+ return 0;
+ QT3DSU8 *writePtr(data.begin());
+ QT3DSU32 amountToRead(data.size());
+ QT3DSU32 amountRead = 0;
+ if (m_BytesRead < THeaderLen) {
+ QT3DSU32 headerLeft = NVMin(THeaderLen - m_BytesRead, amountToRead);
+ memCopy(writePtr, m_Header + m_BytesRead, headerLeft);
+ writePtr += headerLeft;
+ amountToRead -= headerLeft;
+ amountRead += headerLeft;
+ }
+ if (amountToRead)
+ amountRead += m_InStream.Read(NVDataRef<QT3DSU8>(writePtr, amountToRead));
+ m_BytesRead += amountRead;
+ return amountRead;
+ }
+ };
+
+ static eastl::pair<SNamespacePairNode *, SDOMElement *>
+ ParseXMLFile(IDOMFactory &factory, IInStream &inStream, CXmlErrorHandler *handler = NULL)
+ {
+ SimpleXmlErrorHandler simpleHandler;
+ if (handler == NULL)
+ handler = &simpleHandler;
+
+ // look for BOM (Byte-Order-Marker) in the file
+ // if found, pass in UTF-16 as the format. else
+ // pass in UTF-8 as the format.
+ SHeaderInStream<sizeof(g_BOMMarker)> theInStream(inStream);
+ if (theInStream.readHeader() == false) {
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+ QT3DSU16 theHeaderData;
+ memCopy(&theHeaderData, theInStream.m_Header, sizeof(g_BOMMarker));
+
+ char8_t nsSeparator = '$';
+
+ if (theHeaderData == g_BOMMarker)
+ qFatal("UTF-16 files not supported");
+
+ QXmlStreamReader sreader;
+ DOMParser domParser(factory, sreader, nsSeparator);
+ QT3DSU8 dataBuf[2048];
+ QT3DSU32 amountRead = 0;
+ do {
+ amountRead = theInStream.Read(toDataRef(dataBuf, 2048));
+ if (amountRead) {
+ QByteArray tmp = QByteArray::fromRawData((char*)dataBuf,amountRead);
+ sreader.addData(tmp);
+ }
+ } while (amountRead > 0);
+ while (!sreader.atEnd()) {
+ QXmlStreamReader::TokenType token = sreader.readNext();
+ if (token == QXmlStreamReader::StartElement) {
+ domParser.m_Factory.IgnoreStrBuf();
+ domParser.ParseName((TXMLCharPtr)sreader.name().toUtf8().data());
+ int line = sreader.lineNumber();
+ SDOMElement *newElem =
+ domParser.m_Factory.NextElement(domParser.m_RegName, domParser.m_RegNS, line);
+ if (domParser.m_FirstElement == NULL) {
+ domParser.m_FirstElement = newElem;
+ domParser.m_TopElement = newElem;
+ } else {
+ domParser.m_TopElement->AppendChild(*newElem);
+ domParser.m_TopElement = newElem;
+ }
+ const QXmlStreamAttributes& attributes = sreader.attributes();
+ for (auto attrib : attributes) {
+ domParser.ParseName((TXMLCharPtr)attrib.name().toUtf8().data());
+ SDOMAttribute *att =
+ domParser.m_Factory.NextAttribute(domParser.m_RegName,
+ (TXMLCharPtr)attrib.value()
+ .toUtf8().data(),
+ domParser.m_RegNS, line);
+ newElem->m_Attributes.push_back(*att);
+ }
+ } else if (token == QXmlStreamReader::Characters) {
+ QByteArray text = sreader.text().toUtf8();
+ domParser.m_Factory.AppendStrBuf(text.data(), text.length());
+ } else if (token == QXmlStreamReader::EndElement) {
+ domParser.m_TopElement->m_Value = domParser.m_Factory.FinalizeStrBuf();
+ domParser.m_TopElement = domParser.m_TopElement->m_Parent;
+ }
+
+ if (sreader.hasError()) {
+ TXMLCharPtr error = (TXMLCharPtr)sreader.errorString().toUtf8().data();
+ handler->OnXmlError(error, sreader.lineNumber(), sreader.columnNumber());
+ return nullptr;
+ }
+
+ }
+ return eastl::make_pair(domParser.m_FirstPair, domParser.m_FirstElement);
+ }
+};
+
+class SimpleDomFactory : public IDOMFactory
+{
+ typedef eastl::basic_string<char8_t, ForwardingAllocator> TNarrowStr;
+ NVAllocatorCallback &m_Allocator;
+ Pool<SDOMElement> m_ElementPool;
+ Pool<SDOMAttribute> m_AttributePool;
+ Pool<SNamespacePairNode> m_NamespaceNodePool;
+ eastl::vector<char8_t *> m_BigStrings;
+ NVScopedRefCounted<IStringTable> m_StringTable;
+ TNarrowStr m_StringBuilder;
+ volatile QT3DSI32 mRefCount;
+
+public:
+ SimpleDomFactory(NVAllocatorCallback &alloc, NVScopedRefCounted<IStringTable> strt)
+ : m_Allocator(alloc)
+ , m_StringTable(strt)
+ , m_StringBuilder(ForwardingAllocator(alloc, "SimpleDomFactory::m_StringBuilder"))
+ , mRefCount(0)
+ {
+ }
+
+ ~SimpleDomFactory()
+ {
+ QT3DS_FOREACH(idx, m_BigStrings.size())
+ m_Allocator.deallocate(m_BigStrings[idx]);
+ m_BigStrings.clear();
+ }
+
+ NVAllocatorCallback &GetAllocator() override { return m_Allocator; }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Allocator)
+
+ TXMLCharPtr RegisterStr(TXMLCharPtr str)
+ {
+ if (str == NULL || *str == 0)
+ return "";
+ return m_StringTable->RegisterStr(str);
+ }
+
+ virtual void Release() { delete this; }
+ void AppendStrBuf(TXMLCharPtr str, QT3DSU32 len) override
+ {
+ if (len && *str) {
+ m_StringBuilder.append(str, str + len);
+ }
+ }
+
+ // Null terminate what is there and return the buffer.
+ // This pointer needs to be persistent.
+ TXMLCharPtr FinalizeStrBuf() override
+ {
+ if (m_StringBuilder.size() == 0)
+ return "";
+ QT3DSU32 len = m_StringBuilder.size() + 1;
+ QT3DSU32 numBytes = len * sizeof(char8_t);
+ char8_t *newMem =
+ (char8_t *)m_Allocator.allocate(numBytes, "DOMFactory::ValueStr", __FILE__, __LINE__);
+ memCopy(newMem, m_StringBuilder.c_str(), numBytes);
+ m_BigStrings.push_back(newMem);
+ m_StringBuilder.clear();
+ return newMem;
+ }
+ void IgnoreStrBuf() override { m_StringBuilder.clear(); }
+
+ SDOMAttribute *NextAttribute(CRegisteredString name, TXMLCharPtr val,
+ CRegisteredString ns, int inLine) override
+ {
+ TXMLCharPtr v(RegisterValue(val));
+ SDOMAttribute *att = (SDOMAttribute *)m_AttributePool.allocate(__FILE__, __LINE__);
+ new (att) SDOMAttribute(name, ns, v, inLine);
+ return att;
+ }
+
+ SDOMElement *NextElement(CRegisteredString name, CRegisteredString ns, int inLine) override
+ {
+ IgnoreStrBuf();
+ SDOMElement *elem = (SDOMElement *)(m_ElementPool.allocate(__FILE__, __LINE__));
+ new (elem) SDOMElement(name, ns, inLine);
+ return elem;
+ }
+
+ SNamespacePairNode *NextNSPairNode(CRegisteredString ns, CRegisteredString abbr) override
+ {
+ return m_NamespaceNodePool.construct(SNamespacePair(ns, abbr), __FILE__, __LINE__);
+ }
+
+ NVScopedRefCounted<IStringTable> GetStringTable() override { return m_StringTable; }
+};
+}
+
+NVScopedRefCounted<IDOMReader>
+IDOMReader::CreateDOMReader(NVAllocatorCallback &inAlloc, SDOMElement &inRootElement,
+ NVScopedRefCounted<IStringTable> inStringTable,
+ NVScopedRefCounted<IDOMFactory> inFactory)
+{
+ return QT3DS_NEW(inAlloc, SDOMReader)(inAlloc, inRootElement, inStringTable, inFactory);
+}
+
+eastl::pair<NVScopedRefCounted<IDOMWriter>, NVScopedRefCounted<IDOMReader>>
+IDOMWriter::CreateDOMWriter(NVScopedRefCounted<IDOMFactory> inFactory, SDOMElement &inRootElement,
+ NVScopedRefCounted<IStringTable> inStringTable)
+{
+ NVScopedRefCounted<SDOMWriter> writer(
+ QT3DS_NEW(inFactory->GetAllocator(), SDOMWriter)(inFactory, inStringTable, inRootElement));
+ return eastl::make_pair(writer.mPtr, writer.mPtr);
+}
+
+TXMLCharPtr IDOMFactory::RegisterValue(TXMLCharPtr inValue)
+{
+ if (isTrivial(inValue))
+ return "";
+ IgnoreStrBuf();
+ AppendStrBuf(inValue, (QT3DSU32)strlen(inValue));
+ return FinalizeStrBuf();
+}
+
+NVScopedRefCounted<IDOMFactory>
+IDOMFactory::CreateDOMFactory(NVAllocatorCallback &inAlloc,
+ NVScopedRefCounted<IStringTable> inStrTable)
+{
+ return QT3DS_NEW(inAlloc, SimpleDomFactory)(inAlloc, inStrTable);
+}
+
+void CDOMSerializer::WriteXMLHeader(IOutStream &inStream)
+{
+ const char8_t *header = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
+ QT3DSU32 len = (QT3DSU32)strlen(header);
+ inStream.Write(header, len);
+}
+
+// Lexigraphically sort the attributes.
+struct SAttributeComparator
+{
+ bool operator()(const SDOMAttribute *lhs, const SDOMAttribute *rhs)
+ {
+ int nsCmp = strcmp(lhs->m_Namespace, rhs->m_Namespace);
+ if (nsCmp)
+ return nsCmp < 0;
+
+ return strcmp(lhs->m_Name, rhs->m_Name) < 0;
+ }
+};
+
+typedef eastl::vector<SDOMAttribute *, ForwardingAllocator> TAttVector;
+typedef eastl::hash_map<CRegisteredString, CRegisteredString, eastl::hash<CRegisteredString>,
+ eastl::equal_to<CRegisteredString>, ForwardingAllocator>
+ TNSMap;
+
+CRegisteredString GetOrCreateNamespaceAbbr(NVAllocatorCallback &inAlloc, CRegisteredString theNs,
+ TNSMap &inNamespace, TNSMap &inReverseNamespaces,
+ IStringTable &inStrTable, bool &outCreated)
+{
+ CRegisteredString abbr;
+ if (theNs.IsValid()) {
+ TNSMap::iterator nsIter = inNamespace.find(theNs);
+ if (nsIter != inNamespace.end()) {
+ abbr = nsIter->second;
+ outCreated = false;
+ } else {
+ eastl::basic_string<char8_t, ForwardingAllocator> theStr(
+ ForwardingAllocator(inAlloc, "nsBuilderString"));
+ theStr.assign("a");
+ eastl::basic_string<char8_t, ForwardingAllocator> theNsStr(
+ ForwardingAllocator(inAlloc, "nsBuilderString"));
+ CRegisteredString theNS = inStrTable.RegisterStr(theStr.c_str());
+ while (inReverseNamespaces.find(theNS) != inReverseNamespaces.end()) {
+ for (int idx = 0;
+ idx < 26 && inReverseNamespaces.find(theNS) == inReverseNamespaces.end();
+ ++idx) {
+ theNsStr = theStr;
+ theNsStr.append(1, (char8_t)('a' + idx));
+ theNS = inStrTable.RegisterStr(theNsStr.c_str());
+ }
+ theStr.append(1, 'a');
+ }
+ inNamespace.insert(eastl::make_pair(theNs, theNS));
+ abbr = theNS;
+ outCreated = true;
+ }
+ }
+ return abbr;
+}
+
+// Write an element with attributes sorted by name so a file diff is effective.
+void WriteElement(NVAllocatorCallback &inAlloc, SDOMElement &inElement, SimpleXmlWriter &inWriter,
+ TAttVector &inAttSorter, TNSMap &inNamespace, TNSMap &inReverseNamespaces,
+ IStringTable &inStrTable, bool inTrimEmptyElems, bool inWriteXMLNS)
+{
+ inAttSorter.clear();
+
+ // We decided that we don't want attribute sorting; the code that adds attributes needs
+ // to be consistent.
+ // This element doesn't add anything to the system in this case.
+ if (inTrimEmptyElems && inElement.m_Attributes.empty() && inElement.m_Children.empty()
+ && isTrivial(inElement.m_Value))
+ return;
+
+ for (TAttributeList::iterator iter = inElement.m_Attributes.begin(),
+ end = inElement.m_Attributes.end();
+ iter != end; ++iter)
+ inAttSorter.push_back(&(*iter));
+
+ // Find the namespace for the element
+ bool createdAbbr = false;
+ CRegisteredString abbr = GetOrCreateNamespaceAbbr(inAlloc, inElement.m_Namespace, inNamespace,
+ inReverseNamespaces, inStrTable, createdAbbr);
+
+ inWriter.Begin(inElement.m_Name, abbr);
+ eastl::basic_string<char8_t, ForwardingAllocator> theStr(
+ ForwardingAllocator(inAlloc, "nsBuilderString"));
+ if (inWriteXMLNS) {
+ for (TNSMap::iterator iter = inNamespace.begin(), end = inNamespace.end(); iter != end;
+ ++iter) {
+ theStr.assign("xmlns");
+ if (iter->second.IsValid()) {
+ theStr.append(1, ':');
+ theStr.append(iter->second.c_str());
+ }
+ inWriter.Att(theStr.c_str(), NULL, iter->first.c_str());
+ }
+ } else if (createdAbbr) {
+ theStr.assign("xmlns:");
+ theStr.append(abbr.c_str());
+ inWriter.Att(theStr.c_str(), NULL, inElement.m_Namespace.c_str());
+ }
+
+ const char8_t *theLastAttName = 0;
+ const char8_t *theLastAttNamespace = 0;
+ for (QT3DSU32 idx = 0, end = inAttSorter.size(); idx < end; ++idx) {
+ SDOMAttribute *theAtt(inAttSorter[idx]);
+ if (theAtt->m_Name != theLastAttName || theAtt->m_Namespace != theLastAttNamespace) {
+ abbr = GetOrCreateNamespaceAbbr(inAlloc, theAtt->m_Namespace, inNamespace,
+ inReverseNamespaces, inStrTable, createdAbbr);
+ if (createdAbbr) {
+ theStr.assign("xmlns:");
+ theStr.append(abbr.c_str());
+ inWriter.Att(theStr.c_str(), NULL, inElement.m_Namespace.c_str());
+ }
+
+ inWriter.Att(theAtt->m_Name, abbr, theAtt->m_Value);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ theLastAttName = theAtt->m_Name;
+ theLastAttNamespace = theAtt->m_Namespace;
+ }
+ // Elements can either have children or values but not both at this point.
+ if (inElement.m_Children.empty() == false) {
+ for (SDOMElement::TElementChildList::iterator iter = inElement.m_Children.begin(),
+ end = inElement.m_Children.end();
+ iter != end; ++iter)
+ WriteElement(inAlloc, *iter, inWriter, inAttSorter, inNamespace, inReverseNamespaces,
+ inStrTable, inTrimEmptyElems, false);
+
+ inWriter.End();
+ } else {
+ if (!isTrivial(inElement.m_Value))
+ inWriter.Value(inElement.m_Value);
+
+ inWriter.End();
+ }
+}
+
+void CDOMSerializer::Write(NVAllocatorCallback &inAlloc, SDOMElement &inElement,
+ IOutStream &inStream, IStringTable &inStrTable,
+ NVConstDataRef<SNamespacePair> inNamespaces, bool inTrimEmptyElements,
+ QT3DSU32 inTabs, bool inWriteNamespaces)
+{
+ TAttVector theAttSorter(ForwardingAllocator(inAlloc, "CDOMSerializer::AttributeList"));
+ TNSMap theNamespaces(ForwardingAllocator(inAlloc, "CDOMSerializer::NamespaceMap"));
+ TNSMap theReverseNamespaces(ForwardingAllocator(inAlloc, "CDOMSerializer::NamespaceMap"));
+ for (QT3DSU32 idx = 0, end = inNamespaces.size(); idx < end; ++idx) {
+ theNamespaces.insert(
+ eastl::make_pair(inNamespaces[idx].m_Namespace, inNamespaces[idx].m_Abbreviation));
+ theReverseNamespaces.insert(
+ eastl::make_pair(inNamespaces[idx].m_Abbreviation, inNamespaces[idx].m_Namespace));
+ }
+ SimpleXmlWriter writer(inAlloc, inStream, inTabs);
+ WriteElement(inAlloc, inElement, writer, theAttSorter, theNamespaces, theReverseNamespaces,
+ inStrTable, inTrimEmptyElements, inWriteNamespaces);
+}
+
+eastl::pair<SNamespacePairNode *, SDOMElement *>
+CDOMSerializer::Read(IDOMFactory &inFactory, IInStream &inStream, CXmlErrorHandler *inErrorHandler)
+{
+ return DOMParser::ParseXMLFile(inFactory, inStream, inErrorHandler);
+}
diff --git a/src/foundation/XML.h b/src/foundation/XML.h
new file mode 100644
index 0000000..360bfdd
--- /dev/null
+++ b/src/foundation/XML.h
@@ -0,0 +1,680 @@
+/****************************************************************************
+**
+** 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
+#ifndef QT3DS_FOUNDATION_XML_H
+#define QT3DS_FOUNDATION_XML_H
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSMemoryBuffer.h"
+#include "foundation/StringConversion.h" //Conversion between string and various datatypes.
+#include "foundation/Qt3DSFlags.h"
+#include "EASTL/algorithm.h"
+#include "foundation/IOStreams.h"
+#include "EASTL/string.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSRefCounted.h"
+#include "foundation/StringTable.h"
+#include "foundation/Qt3DSInvasiveLinkedList.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ class IStringTable;
+
+ class IDOMFactory;
+
+ class IInStream;
+ class IOutStream;
+ struct SDOMAttribute;
+ struct SDOMElement;
+ struct SNamespacePairNode;
+
+ typedef const char8_t *TXMLCharPtr;
+
+ typedef eastl::basic_string<char8_t, ForwardingAllocator> TXMLStr;
+
+ // When the factor is destroyed, all elements and attributes are destroyed.
+ class IDOMFactory : public NVRefCounted
+ {
+ protected:
+ virtual ~IDOMFactory() {}
+ public:
+ // Str does not need to be null terminated.
+ virtual void AppendStrBuf(TXMLCharPtr str, QT3DSU32 len) = 0;
+ // Null terminate what is there and return the buffer.
+ // This pointer needs to be persistent.
+ virtual TXMLCharPtr FinalizeStrBuf() = 0;
+ virtual void IgnoreStrBuf() = 0;
+
+ virtual SDOMAttribute *NextAttribute(CRegisteredString name, TXMLCharPtr val,
+ CRegisteredString ns = CRegisteredString(),
+ int inLine = 0) = 0;
+ virtual SDOMElement *NextElement(CRegisteredString name,
+ CRegisteredString ns = CRegisteredString(),
+ int inLine = 0) = 0;
+ virtual SNamespacePairNode *NextNSPairNode(CRegisteredString ns,
+ CRegisteredString abbr) = 0;
+
+ TXMLCharPtr RegisterValue(TXMLCharPtr inValue);
+
+ virtual NVScopedRefCounted<IStringTable> GetStringTable() = 0;
+ virtual NVAllocatorCallback &GetAllocator() = 0;
+
+ static NVScopedRefCounted<IDOMFactory>
+ CreateDOMFactory(NVAllocatorCallback &inAllocator,
+ NVScopedRefCounted<IStringTable> inStrTable);
+ };
+
+ struct SDOMAttribute
+ {
+ CRegisteredString m_Namespace;
+ CRegisteredString m_Name;
+ const char8_t *m_Value;
+ SDOMAttribute *m_NextAttribute;
+ SDOMAttribute *m_PreviousAttribute;
+ int m_Line;
+ SDOMAttribute()
+ : m_Value(NULL)
+ , m_NextAttribute(NULL)
+ , m_PreviousAttribute(NULL)
+ , m_Line(0)
+ {
+ }
+
+ SDOMAttribute(CRegisteredString inName, CRegisteredString inNs, const char8_t *inValue,
+ int line)
+ : m_Namespace(inNs)
+ , m_Name(inName)
+ , m_Value(inValue)
+ , m_NextAttribute(NULL)
+ , m_PreviousAttribute(NULL)
+ , m_Line(line)
+ {
+ }
+
+ bool Value(const char8_t *&outValue)
+ {
+ outValue = m_Value;
+ return true;
+ }
+
+ template <typename TDataType>
+ bool Value(TDataType &outValue)
+ {
+ StringConversion<TDataType>().StrTo(m_Value, outValue);
+ return true;
+ }
+ };
+
+ struct SNextAttOp
+ {
+ SDOMAttribute *get(SDOMAttribute &inAtt) { return inAtt.m_NextAttribute; }
+ const SDOMAttribute *get(const SDOMAttribute &inAtt) { return inAtt.m_NextAttribute; }
+ void set(SDOMAttribute &inAtt, SDOMAttribute *next) { inAtt.m_NextAttribute = next; }
+ };
+ struct SPrevAttOp
+ {
+ SDOMAttribute *get(SDOMAttribute &inAtt) { return inAtt.m_PreviousAttribute; }
+ const SDOMAttribute *get(const SDOMAttribute &inAtt) { return inAtt.m_PreviousAttribute; }
+ void set(SDOMAttribute &inAtt, SDOMAttribute *prev) { inAtt.m_PreviousAttribute = prev; }
+ };
+
+ typedef InvasiveLinkedList<SDOMAttribute, SPrevAttOp, SNextAttOp> TAttributeList;
+
+ struct SNamespacePair
+ {
+ CRegisteredString m_Namespace;
+ CRegisteredString m_Abbreviation;
+ SNamespacePair(CRegisteredString ns = CRegisteredString(),
+ CRegisteredString abbr = CRegisteredString())
+ : m_Namespace(ns)
+ , m_Abbreviation(abbr)
+ {
+ }
+ };
+
+ struct SNamespacePairNode : public SNamespacePair
+ {
+ SNamespacePairNode *m_NextNode;
+ SNamespacePairNode(const SNamespacePair &inSrc = SNamespacePair())
+ : SNamespacePair(inSrc)
+ , m_NextNode(NULL)
+ {
+ }
+ };
+
+ // Simplified dom element. All it has is one character value and list of attributes
+ // and children. So you can't mix elements and character data like you can in
+ // full xml, but this simplifies parsing.
+ struct SDOMElement
+ {
+ struct SNextElemOp
+ {
+ SDOMElement *get(SDOMElement &elem) { return elem.m_NextSibling; }
+ const SDOMElement *get(const SDOMElement &elem) { return elem.m_NextSibling; }
+ void set(SDOMElement &elem, SDOMElement *next) { elem.m_NextSibling = next; }
+ };
+ struct SPrevElemOp
+ {
+ SDOMElement *get(SDOMElement &elem) { return elem.m_PreviousSibling; }
+ const SDOMElement *get(const SDOMElement &elem) { return elem.m_PreviousSibling; }
+ void set(SDOMElement &elem, SDOMElement *prev) { elem.m_PreviousSibling = prev; }
+ };
+ typedef InvasiveLinkedList<SDOMElement, SPrevElemOp, SNextElemOp> TElementChildList;
+
+ CRegisteredString m_Namespace;
+ CRegisteredString m_Name;
+ const char8_t *m_Value;
+ SDOMElement *m_Parent;
+ SDOMElement *m_NextSibling;
+ SDOMElement *m_PreviousSibling;
+ TAttributeList m_Attributes;
+ TElementChildList m_Children;
+ int m_Line;
+
+ SDOMElement()
+ : m_Value(NULL)
+ , m_Parent(NULL)
+ , m_NextSibling(NULL)
+ , m_PreviousSibling(NULL)
+ , m_Line(0)
+ {
+ }
+
+ SDOMElement(CRegisteredString name, CRegisteredString ns, int inLine)
+ : m_Namespace(ns)
+ , m_Name(name)
+ , m_Value(NULL)
+ , m_Parent(NULL)
+ , m_NextSibling(NULL)
+ , m_PreviousSibling(NULL)
+ , m_Line(inLine)
+ {
+ }
+
+ void AppendChild(SDOMElement &inElem, SDOMElement *inPos = NULL)
+ {
+ if (inElem.m_Parent)
+ inElem.m_Parent->RemoveChild(inElem);
+ inElem.m_Parent = this;
+ if (inPos) {
+ QT3DS_ASSERT(inPos->m_Parent == this);
+ m_Children.insert_after(*inPos, inElem);
+ } else
+ m_Children.push_back(inElem);
+ }
+
+ void PrependChild(SDOMElement &inElem, SDOMElement *inPos = NULL)
+ {
+ if (inElem.m_Parent)
+ inElem.m_Parent->RemoveChild(inElem);
+ inElem.m_Parent = this;
+ if (inPos) {
+ QT3DS_ASSERT(inPos->m_Parent == this);
+ m_Children.insert_before(*inPos, inElem);
+ } else
+ m_Children.push_front(inElem);
+ }
+
+ void RemoveChild(SDOMElement &inElem)
+ {
+ if (inElem.m_Parent == this) {
+ m_Children.remove(inElem);
+ } else {
+ if (inElem.m_Parent) {
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+ SDOMElement *FindNext(CRegisteredString inName, Option<CRegisteredString> inNamespace,
+ TElementChildList::iterator iter)
+ {
+ for (TElementChildList::iterator end(NULL); iter != end; ++iter) {
+ if (inName.IsValid() == false || inName == iter->m_Name) {
+ if (inNamespace.hasValue() == false || *inNamespace == iter->m_Namespace)
+ return &(*iter);
+ }
+ }
+ return NULL;
+ }
+ // Search starts just *after inStartPos if provided
+ SDOMElement *FindChild(CRegisteredString inName, Option<CRegisteredString> inNamespace,
+ SDOMElement *inStartPos = NULL)
+ {
+ TElementChildList::iterator iter = m_Children.begin();
+ if (inStartPos) {
+ QT3DS_ASSERT(inStartPos->m_Parent == this);
+ iter = TElementChildList::iterator(inStartPos->m_NextSibling);
+ }
+ return FindNext(inName, inNamespace, iter);
+ }
+ // Search starts just *after inStartPos if provided
+ SDOMElement *FindSibling(CRegisteredString inName, Option<CRegisteredString> inNamespace)
+ {
+ TElementChildList::iterator iter(m_NextSibling);
+ return FindNext(inName, inNamespace, iter);
+ }
+
+ SDOMAttribute *FindAttribute(CRegisteredString inName,
+ Option<CRegisteredString> inNamespace)
+ {
+ for (TAttributeList::iterator iter = m_Attributes.begin(), end = m_Attributes.end();
+ iter != end; ++iter) {
+ if (iter->m_Name == inName) {
+ if (inNamespace.hasValue() == false || *inNamespace == iter->m_Namespace)
+ return &(*iter);
+ }
+ }
+ return NULL;
+ }
+
+ template <typename TDataType>
+ bool AttValue(CRegisteredString inName, Option<CRegisteredString> inNamespace,
+ TDataType &outValue)
+ {
+ SDOMAttribute *att = FindAttribute(inName, inNamespace);
+ if (att)
+ return att->Value(outValue);
+ return false;
+ }
+
+ QT3DSU32 GetNumChildren(CRegisteredString inName,
+ Option<CRegisteredString> inNamespace = Empty()) const
+ {
+ QT3DSU32 count = 0;
+ if (inName.IsValid() == false) {
+ // empty loop intentional
+ for (TElementChildList::iterator iter = m_Children.begin(), end = m_Children.end();
+ iter != end; ++iter, ++count)
+ ;
+ } else {
+ for (TElementChildList::iterator iter = m_Children.begin(), end = m_Children.end();
+ iter != end; ++iter) {
+ if (iter->m_Name == inName
+ && (inNamespace.isEmpty() || iter->m_Namespace == *inNamespace))
+ ++count;
+ }
+ }
+ return count;
+ }
+
+ void SetAttributeValue(CRegisteredString inName, Option<CRegisteredString> inNamespace,
+ TXMLCharPtr inValue, IDOMFactory &inFactory, int inLine)
+ {
+ SDOMAttribute *att = FindAttribute(inName, inNamespace);
+ if (att) {
+ att->m_Value = inFactory.RegisterValue(inValue);
+ } else {
+ m_Attributes.push_back(*inFactory.NextAttribute(
+ inName, inValue, inNamespace.unsafeGetValue(), inLine));
+ }
+ }
+
+ void RemoveAttribute(CRegisteredString nm, Option<CRegisteredString> inNamespace)
+ {
+ SDOMAttribute *theAttribute = FindAttribute(nm, inNamespace);
+ if (theAttribute)
+ m_Attributes.remove(*theAttribute);
+ }
+ };
+
+ struct SReaderScope
+ {
+ SDOMElement *m_Element;
+ SDOMAttribute *m_Attribute;
+ SReaderScope(SDOMElement *inElem = NULL, SDOMAttribute *inAtt = NULL)
+ : m_Element(inElem)
+ , m_Attribute(inAtt)
+ {
+ }
+ };
+
+ class IDOMReader : public NVRefCounted
+ {
+ protected:
+ virtual ~IDOMReader() {}
+ public:
+ // Stack object to save the reader's state.
+ struct Scope
+ {
+ IDOMReader &m_Reader;
+ Scope(IDOMReader &reader)
+ : m_Reader(reader)
+ {
+ m_Reader.PushScope();
+ }
+ Scope(NVScopedRefCounted<IDOMReader> reader)
+ : m_Reader(*reader)
+ {
+ m_Reader.PushScope();
+ }
+ ~Scope() { m_Reader.PopScope(); }
+ };
+
+ // Parse buffer
+ MemoryBuffer<ForwardingAllocator> m_TempBuf;
+ NVScopedRefCounted<IStringTable> m_StringTable;
+
+ IDOMReader(NVAllocatorCallback &inAlloc, NVScopedRefCounted<IStringTable> inStringTable)
+ : m_TempBuf(ForwardingAllocator(inAlloc, "IDOMReader::m_TempBuf"))
+ , m_StringTable(inStringTable)
+ {
+ }
+
+ NVScopedRefCounted<IStringTable> GetStringTable() { return m_StringTable; }
+
+ // Pushing scope saves your state so no matter where you are when
+ // you next pop scope, you come back to the same state.
+ virtual void PushScope() = 0;
+ virtual void PopScope() = 0;
+
+ // Sometimes pushing and popping scope isn't enough and you need
+ // somewhat random access to scope.
+ // This scope does not remember the current attribute.
+ virtual SReaderScope GetScope() = 0;
+ virtual void SetScope(SReaderScope inScope) = 0;
+ // Return an attribute whose value is *not* registered with the string table.
+ // You can't hold onto this value for any length of time, but when you need to
+ // immediately convert to a different value this is the most efficient way.
+ virtual bool UnregisteredAtt(TXMLCharPtr name, TXMLCharPtr &outValue,
+ TXMLCharPtr ns = NULL) = 0;
+ // Return an attribute whose value *is* registered with the string table.
+ virtual bool Att(TXMLCharPtr name, CRegisteredString &outValue, TXMLCharPtr ns = NULL) = 0;
+ virtual SDOMAttribute *GetFirstAttribute() = 0;
+ virtual SDOMAttribute *GetNextAttribute() = 0;
+ virtual QT3DSU32 CountChildren(TXMLCharPtr childName = NULL, TXMLCharPtr ns = NULL) = 0;
+ virtual bool MoveToFirstChild(TXMLCharPtr childName = NULL, TXMLCharPtr ns = NULL) = 0;
+ virtual bool MoveToNextSibling(TXMLCharPtr siblingName = NULL, TXMLCharPtr ns = NULL) = 0;
+ // Leave element means go to its parent.
+ virtual void Leave() = 0;
+ virtual SDOMElement *GetElement() const = 0;
+ CRegisteredString GetElementName() const
+ {
+ SDOMElement *elem = GetElement();
+ if (elem)
+ return elem->m_Name;
+ return CRegisteredString();
+ }
+
+ // Value is the concatentated text node values inside the element
+ virtual bool Value(TXMLCharPtr &outValue) = 0;
+
+ // Get the element this reader was created with
+ virtual SDOMElement *GetTopElement() = 0;
+
+ bool Att(TXMLCharPtr name, TXMLStr &outValue)
+ {
+ TXMLCharPtr temp;
+ if (UnregisteredAtt(name, temp)) {
+ outValue.assign(temp);
+ return true;
+ }
+ return false;
+ }
+
+ template <typename TDataType>
+ bool Att(TXMLCharPtr name, TDataType &outValue)
+ {
+ TXMLCharPtr temp;
+ if (UnregisteredAtt(name, temp)) {
+ StringConversion<TDataType>().StrTo(temp, outValue);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ bool ChildValue(TXMLCharPtr name, TXMLCharPtr &value)
+ {
+ if (MoveToFirstChild(name)) {
+ Value(value);
+ Leave();
+ return true;
+ }
+ return false;
+ }
+
+ bool RegisteredChildValue(TXMLCharPtr name, TXMLCharPtr &value)
+ {
+ if (MoveToFirstChild(name)) {
+ RegisteredValue(value);
+ Leave();
+ return true;
+ }
+ return false;
+ }
+ bool RegisteredValue(TXMLCharPtr &outValue)
+ {
+ bool retval = Value(outValue);
+ if (retval)
+ outValue = m_StringTable->RegisterStr(outValue);
+ return retval;
+ }
+
+ template <typename TDataType>
+ bool Value(TDataType &outValue)
+ {
+ TXMLCharPtr value;
+ if (Value(value)) {
+ StringConversion<TDataType>().StrTo(value, outValue);
+ return true;
+ }
+ return false;
+ }
+
+ // IDOMReader implementations
+ template <typename TDataType>
+ bool ValueList(NVDataRef<TDataType> data)
+ {
+ const char8_t *value;
+ if (Value(value)) {
+ Char8TReader reader(const_cast<char8_t *>(value), m_TempBuf);
+ reader.ReadRef(data);
+ }
+ return true;
+ }
+
+ // Destructive operation because we can't trust
+ // strtod to do the right thing. On windows, for long strings,
+ // it calls strlen every operation thus leading to basically N^2
+ // behavior
+ template <typename TDataType>
+ NVConstDataRef<TDataType> ChildValueList(TXMLCharPtr listName)
+ {
+ NVConstDataRef<TDataType> retval;
+ TXMLCharPtr childValue = NULL;
+ if (ChildValue(listName, childValue)) {
+ Char8TReader reader(const_cast<char8_t *>(childValue), m_TempBuf);
+ reader.ReadBuffer(retval);
+ }
+ return retval;
+ }
+
+ template <typename TSerializer>
+ void Serialize(const char8_t *elemName, TSerializer &serializer,
+ const char8_t *inNamespace = NULL)
+ {
+ IDOMReader::Scope __theScope(*this);
+ if (MoveToFirstChild(elemName, inNamespace)) {
+ serializer.Serialize(*this);
+ }
+ }
+ // Optionally hold on to the factory to keep our elements in memory as long as we are.
+ static NVScopedRefCounted<IDOMReader> CreateDOMReader(
+ NVAllocatorCallback &inAlloc, SDOMElement &inRootElement,
+ NVScopedRefCounted<IStringTable> inStringTable,
+ NVScopedRefCounted<IDOMFactory> inFactory = NVScopedRefCounted<IDOMFactory>());
+ };
+
+ // Write out data in an xml-like fasion without specifying exactly
+ // where that data is being written.
+ class IDOMWriter : public NVRefCounted
+ {
+ protected:
+ virtual ~IDOMWriter() {}
+ public:
+ // Control the element scope.
+ struct Scope
+ {
+ IDOMWriter &m_Writer;
+ Scope(IDOMWriter &writer, TXMLCharPtr inElemName, TXMLCharPtr inNamespace = NULL)
+ : m_Writer(writer)
+ {
+ m_Writer.Begin(inElemName, inNamespace);
+ }
+ ~Scope() { m_Writer.End(); }
+ };
+
+ char8_t m_NarrowBuf[256];
+
+ // There tend to be two types of elements.
+ // Containers (<a>\n\t<b/><b/>\n</a>)
+ // and Values <b>onetwothree</b>
+ virtual void Begin(TXMLCharPtr inElemName, TXMLCharPtr inNamespace = NULL,
+ int inLine = 0) = 0;
+ // Attributes. They may be sorted just before write
+ virtual void Att(TXMLCharPtr name, TXMLCharPtr value, TXMLCharPtr inNamespace = NULL,
+ int inLine = 0) = 0;
+ virtual void Value(TXMLCharPtr value) = 0;
+ virtual void End() = 0;
+ virtual void RemoveCurrent() = 0;
+ virtual void RemoveAttribute(TXMLCharPtr inItem, TXMLCharPtr inNamespace = NULL) = 0;
+ // Get the number of tabs required to line up the next line
+ // with the opening of the previous line
+ virtual QT3DSU32 GetTabs() = 0;
+ virtual SDOMElement *GetTopElement() = 0;
+ virtual NVScopedRefCounted<IDOMFactory> GetFactory() = 0;
+ // Move this item before this sibling. Function does not rearrange the
+ // tree in any major way and will not work if inItem and inSibling aren't
+ // siblings.
+ virtual void MoveBefore(TXMLCharPtr inItem, TXMLCharPtr inSibling,
+ TXMLCharPtr inNamespace = NULL) = 0;
+ virtual NVAllocatorCallback &GetAllocator() = 0;
+
+ virtual void ChildValue(TXMLCharPtr name, TXMLCharPtr value, TXMLCharPtr inNamespace = NULL)
+ {
+ Begin(name, inNamespace);
+ Value(value);
+ End();
+ }
+
+ TXMLCharPtr ToStr(char8_t val)
+ {
+ m_NarrowBuf[0] = val;
+ m_NarrowBuf[1] = 0;
+ return m_NarrowBuf;
+ }
+
+ template <typename TDataType>
+ TXMLCharPtr ToStr(TDataType val)
+ {
+ StringConversion<TDataType>().ToStr(val, NVDataRef<char8_t>(m_NarrowBuf, 256));
+ return m_NarrowBuf;
+ }
+
+ void Att(TXMLCharPtr name, const TXMLStr &inValue, TXMLCharPtr inNamespace = NULL)
+ {
+ return Att(name, inValue.c_str(), inNamespace);
+ }
+
+ template <typename TData>
+ void Att(TXMLCharPtr name, TData value, TXMLCharPtr inNamespace = NULL)
+ {
+ Att(name, ToStr(value), inNamespace);
+ }
+
+ template <typename TSerializer>
+ void Serialize(const char8_t *elemName, TSerializer &serializer,
+ TXMLCharPtr inNamespace = NULL)
+ {
+ IDOMWriter::Scope __theScope(*this, elemName, inNamespace);
+ serializer.Serialize(*this);
+ }
+
+ NVScopedRefCounted<IDOMReader> CreateDOMReader()
+ {
+ NVScopedRefCounted<IDOMFactory> theFactory(GetFactory());
+ return IDOMReader::CreateDOMReader(GetAllocator(), *GetTopElement(),
+ theFactory->GetStringTable(), theFactory);
+ }
+
+ // Note that the default method of creating a writer also creates a reader; they can
+ // both manipulation the DOM hierarch.
+ static eastl::pair<NVScopedRefCounted<IDOMWriter>, NVScopedRefCounted<IDOMReader>>
+ CreateDOMWriter(NVScopedRefCounted<IDOMFactory> inFactory, SDOMElement &inRootElement,
+ NVScopedRefCounted<IStringTable> inStringTable);
+
+ static eastl::pair<NVScopedRefCounted<IDOMWriter>, NVScopedRefCounted<IDOMReader>>
+ CreateDOMWriter(NVAllocatorCallback &inAlloc, const char8_t *inTopElemName,
+ NVScopedRefCounted<IStringTable> inStringTable,
+ const char8_t *inNamespace = NULL)
+ {
+ NVScopedRefCounted<IDOMFactory> theFactory(
+ IDOMFactory::CreateDOMFactory(inAlloc, inStringTable));
+ SDOMElement *theRoot =
+ theFactory->NextElement(theFactory->GetStringTable()->RegisterStr(inTopElemName),
+ theFactory->GetStringTable()->RegisterStr(inNamespace));
+ return CreateDOMWriter(theFactory, *theRoot, inStringTable);
+ }
+ };
+
+ class CXmlErrorHandler
+ {
+ protected:
+ virtual ~CXmlErrorHandler() {}
+ public:
+ virtual void OnXmlError(TXMLCharPtr errorName, int line, int column) = 0;
+ };
+
+ class CDOMSerializer
+ {
+ public:
+ static void WriteXMLHeader(IOutStream &inStream);
+
+ // Write out the elements. These pairs will be used in order to abbreviate namespaces with
+ // nicer abbreviations.
+ // Any namespaces not found in those pairs will get auto-generated abbreviations
+ // The document will be assumed to be in the namespace that has no abbreviation.
+ // For fragments or snippets, it is better to avoid writing out the namespace declarations
+ static void
+ Write(NVAllocatorCallback &inAlloc, SDOMElement &inElement, IOutStream &inStream,
+ IStringTable &inStrTable,
+ NVConstDataRef<SNamespacePair> inNamespaces = NVConstDataRef<SNamespacePair>(),
+ bool inTrimEmptyElements = true, QT3DSU32 inTabs = 0, bool inWriteNamespaces = true);
+
+ // Returns a pair of the namespace pair nodes and the dom element. The ns pair nodes allow
+ // us to at least keep the same abbreviations
+ // used if namespace are used.
+ static eastl::pair<SNamespacePairNode *, SDOMElement *>
+ Read(IDOMFactory &inFactory, IInStream &inStream, CXmlErrorHandler *inErrorHandler = NULL);
+ };
+}
+}
+#endif
diff --git a/src/foundation/linux/LICENSE.TXT b/src/foundation/linux/LICENSE.TXT
new file mode 100644
index 0000000..f40caef
--- /dev/null
+++ b/src/foundation/linux/LICENSE.TXT
@@ -0,0 +1,7 @@
+ Copyright (c) 2001 Intel Corporation.
+
+Permition is granted to use, copy, distribute and prepare derivative works
+of this library for any purpose and without fee, provided, that the above
+copyright notice and this statement appear in all copies.
+Intel makes no representations about the suitability of this library for
+any purpose, and specifically disclaims all warranties.
diff --git a/src/foundation/linux/Qt3DSLinuxAoS.h b/src/foundation/linux/Qt3DSLinuxAoS.h
new file mode 100644
index 0000000..6bcb440
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxAoS.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_LINUX_AOS_H
+#define QT3DS_LINUX_AOS_H
+
+// no includes here! this file should be included from NVcVecMath.h only!!!
+
+#if !COMPILE_VECTOR_INTRINSICS
+#error Vector intrinsics should not be included when using scalar implementation.
+#endif
+
+// only SSE compatible platforms should reach this
+// likely to be split up when we add NEON support.
+#include <xmmintrin.h>
+
+typedef union UnionM128 {
+ UnionM128() {}
+ UnionM128(__m128 in) { m128 = in; }
+
+ UnionM128(__m128i in) { m128i = in; }
+
+ operator __m128() { return m128; }
+
+ operator const __m128() const { return m128; }
+
+ float m128_f32[4];
+ __int8_t m128_i8[16];
+ __int16_t m128_i16[8];
+ __int32_t m128_i32[4];
+ __int64_t m128_i64[2];
+ __uint16_t m128_u16[8];
+ __uint32_t m128_u32[4];
+ __uint64_t m128_u64[2];
+ __m128 m128;
+ __m128i m128i;
+} UnionM128;
+
+typedef __m128 FloatV;
+typedef __m128 Vec3V;
+typedef __m128 Vec4V;
+typedef __m128 BoolV;
+typedef __m128 QuatV;
+// typedef __m128 VecU32V;
+// typedef __m128 VecI32V;
+// typedef __m128 VecU16V;
+// typedef __m128 VecI16V;
+// typedef __m128 VecU8V;
+typedef UnionM128 VecU32V;
+typedef UnionM128 VecI32V;
+typedef UnionM128 VecU16V;
+typedef UnionM128 VecI16V;
+typedef UnionM128 VecU8V;
+
+#define FloatVArg FloatV &
+#define Vec3VArg Vec3V &
+#define Vec4VArg Vec4V &
+#define BoolVArg BoolV &
+#define VecU32VArg VecU32V &
+#define VecI32VArg VecI32V &
+#define VecU16VArg VecU16V &
+#define VecI16VArg VecI16V &
+#define VecU8VArg VecU8V &
+#define QuatVArg QuatV &
+
+QT3DS_ALIGN_PREFIX(16)
+struct Mat33V
+{
+ Mat33V() {}
+ Mat33V(const Vec3V &c0, const Vec3V &c1, const Vec3V &c2)
+ : col0(c0)
+ , col1(c1)
+ , col2(c2)
+ {
+ }
+ Vec3V QT3DS_ALIGN(16, col0);
+ Vec3V QT3DS_ALIGN(16, col1);
+ Vec3V QT3DS_ALIGN(16, col2);
+} QT3DS_ALIGN_SUFFIX(16);
+
+QT3DS_ALIGN_PREFIX(16)
+struct Mat34V
+{
+ Mat34V() {}
+ Mat34V(const Vec3V &c0, const Vec3V &c1, const Vec3V &c2, const Vec3V &c3)
+ : col0(c0)
+ , col1(c1)
+ , col2(c2)
+ , col3(c3)
+ {
+ }
+ Vec3V QT3DS_ALIGN(16, col0);
+ Vec3V QT3DS_ALIGN(16, col1);
+ Vec3V QT3DS_ALIGN(16, col2);
+ Vec3V QT3DS_ALIGN(16, col3);
+} QT3DS_ALIGN_SUFFIX(16);
+
+QT3DS_ALIGN_PREFIX(16)
+struct Mat43V
+{
+ Mat43V() {}
+ Mat43V(const Vec4V &c0, const Vec4V &c1, const Vec4V &c2)
+ : col0(c0)
+ , col1(c1)
+ , col2(c2)
+ {
+ }
+ Vec4V QT3DS_ALIGN(16, col0);
+ Vec4V QT3DS_ALIGN(16, col1);
+ Vec4V QT3DS_ALIGN(16, col2);
+} QT3DS_ALIGN_SUFFIX(16);
+
+QT3DS_ALIGN_PREFIX(16)
+struct Mat44V
+{
+ Mat44V() {}
+ Mat44V(const Vec4V &c0, const Vec4V &c1, const Vec4V &c2, const Vec4V &c3)
+ : col0(c0)
+ , col1(c1)
+ , col2(c2)
+ , col3(c3)
+ {
+ }
+ Vec4V QT3DS_ALIGN(16, col0);
+ Vec4V QT3DS_ALIGN(16, col1);
+ Vec4V QT3DS_ALIGN(16, col2);
+ Vec4V QT3DS_ALIGN(16, col3);
+} QT3DS_ALIGN_SUFFIX(16);
+
+#endif // QT3DS_LINUX_AOS_H
diff --git a/src/foundation/linux/Qt3DSLinuxAtomic.cpp b/src/foundation/linux/Qt3DSLinuxAtomic.cpp
new file mode 100644
index 0000000..f0045dd
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxAtomic.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAtomic.h"
+#ifdef __QNX__
+#include <atomic.h>
+#endif
+#ifdef __INTEGRITY
+#include <QtCore/qmutex.h>
+#endif
+
+#define PAUSE() asm("nop")
+
+namespace qt3ds {
+namespace foundation {
+#ifdef __QNX__
+ QT3DSI32 atomicIncrement(volatile QT3DSI32 *val)
+ {
+ atomic_add((volatile unsigned *)val, 1);
+ return *val;
+ }
+
+ QT3DSI32 atomicDecrement(volatile QT3DSI32 *val)
+ {
+ atomic_sub((volatile unsigned *)val, 1);
+ return *val;
+ }
+#elif defined (__INTEGRITY)
+ // TestAndSet and AtomicModify take in volatile Address* leading to overflow error if used
+
+ QT3DSI32 atomicCompareExchange(volatile QT3DSI32 *dest, QT3DSI32 exch, QT3DSI32 comp)
+ {
+ static QMutex mutex;
+ QMutexLocker lock(&mutex);
+ QT3DSI32 ret = *dest;
+ *dest = (*dest == comp) ? exch : ret;
+ return ret;
+ }
+
+ QT3DSI32 atomicIncrement(volatile QT3DSI32 *val)
+ {
+ static QMutex mutex;
+ QMutexLocker lock(&mutex);
+ return ++(*val);
+ }
+
+ QT3DSI32 atomicDecrement(volatile QT3DSI32 *val)
+ {
+ static QMutex mutex;
+ QMutexLocker lock(&mutex);
+ return --(*val);
+ }
+#else
+ void *atomicCompareExchangePointer(volatile void **dest, void *exch, void *comp)
+ {
+ return __sync_val_compare_and_swap((void **)dest, comp, exch);
+ }
+
+ QT3DSI32 atomicCompareExchange(volatile QT3DSI32 *dest, QT3DSI32 exch, QT3DSI32 comp)
+ {
+ return __sync_val_compare_and_swap(dest, comp, exch);
+ }
+
+ QT3DSI32 atomicIncrement(volatile QT3DSI32 *val) { return __sync_add_and_fetch(val, 1); }
+
+ QT3DSI32 atomicDecrement(volatile QT3DSI32 *val) { return __sync_sub_and_fetch(val, 1); }
+
+ QT3DSI32 atomicAdd(volatile QT3DSI32 *val, QT3DSI32 delta) { return __sync_add_and_fetch(val, delta); }
+
+ QT3DSI32 atomicMax(volatile QT3DSI32 *val, QT3DSI32 val2)
+ {
+ QT3DSI32 oldVal, newVal;
+
+ do {
+ PAUSE();
+ oldVal = *val;
+
+ if (val2 > oldVal)
+ newVal = val2;
+ else
+ newVal = oldVal;
+
+ } while (atomicCompareExchange(val, newVal, oldVal) != oldVal);
+
+ return *val;
+ }
+
+ QT3DSI32 atomicExchange(volatile QT3DSI32 *val, QT3DSI32 val2)
+ {
+ QT3DSI32 newVal, oldVal;
+
+ do {
+ PAUSE();
+ oldVal = *val;
+ newVal = val2;
+ } while (atomicCompareExchange(val, newVal, oldVal) != oldVal);
+
+ return newVal;
+ }
+#endif
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/linux/Qt3DSLinuxFPU.cpp b/src/foundation/linux/Qt3DSLinuxFPU.cpp
new file mode 100644
index 0000000..c3eae21
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxFPU.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "foundation/Qt3DSFPU.h"
+#include <fenv.h>
+
+QT3DS_COMPILE_TIME_ASSERT(8 * sizeof(qt3ds::QT3DSU32) >= sizeof(fenv_t));
+
+qt3ds::foundation::FPUGuard::FPUGuard()
+{
+#ifdef __CYGWIN__
+#pragma message "FPUGuard::FPUGuard() is not implemented"
+#else
+ fegetenv(reinterpret_cast<fenv_t *>(mControlWords));
+ fesetenv(FE_DFL_ENV);
+#endif
+}
+
+qt3ds::foundation::FPUGuard::~FPUGuard()
+{
+#ifdef __CYGWIN__
+#pragma message "FPUGuard::~FPUGuard() is not implemented"
+#else
+ fesetenv(reinterpret_cast<fenv_t *>(mControlWords));
+#endif
+}
diff --git a/src/foundation/linux/Qt3DSLinuxFile.h b/src/foundation/linux/Qt3DSLinuxFile.h
new file mode 100644
index 0000000..1369735
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxFile.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_LINUX_FILE_H
+#define QT3DS_FOUNDATION_QT3DS_LINUX_FILE_H
+
+#include "foundation/Qt3DS.h"
+#include <stdio.h>
+
+namespace qt3ds {
+namespace foundation {
+ QT3DS_INLINE int fopen_s(FILE **_File, const char *_Filename, const char *_Mode)
+ {
+ FILE *fp = ::fopen(_Filename, _Mode);
+ return fp ? *_File = fp, 0 : -1;
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/linux/Qt3DSLinuxInlineAoS.h b/src/foundation/linux/Qt3DSLinuxInlineAoS.h
new file mode 100644
index 0000000..0443ba9
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxInlineAoS.h
@@ -0,0 +1,2666 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+//
+// Copyright (c) 2001 Intel Corporation.
+//
+// Permition is granted to use, copy, distribute and prepare derivative works
+// of this library for any purpose and without fee, provided, that the above
+// copyright notice and this statement appear in all copies.
+// Intel makes no representations about the suitability of this library for
+// any purpose, and specifically disclaims all warranties.
+// See LEGAL.TXT for all the legal information.
+//
+
+#ifndef QT3DS_LINUX_INLINE_AOS_H
+#define QT3DS_LINUX_INLINE_AOS_H
+
+#if !COMPILE_VECTOR_INTRINSICS
+#error Vector intrinsics should not be included when using scalar implementation.
+#endif
+
+// Remove this define when all platforms use simd solver.
+#define QT3DS_SUPPORT_SIMD
+
+#define _QT3DS_FPCLASS_SNAN 0x0001 /* signaling NaN */
+#define _QT3DS_FPCLASS_QNAN 0x0002 /* quiet NaN */
+#define _QT3DS_FPCLASS_NINF 0x0004 /* negative infinity */
+#define _QT3DS_FPCLASS_PINF 0x0200 /* positive infinity */
+
+QT3DS_FORCE_INLINE __m128 m128_I2F(__m128i n)
+{
+ return _mm_castsi128_ps(n);
+}
+QT3DS_FORCE_INLINE __m128i m128_F2I(__m128 n)
+{
+ return _mm_castps_si128(n);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAllTrue4_R(const BoolV a)
+{
+ const QT3DSI32 moveMask = _mm_movemask_ps(a);
+ return moveMask == (0xf);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAnyTrue4_R(const BoolV a)
+{
+ const QT3DSI32 moveMask = _mm_movemask_ps(a);
+ return moveMask != (0x0);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAllTrue3_R(const BoolV a)
+{
+ const QT3DSI32 moveMask = _mm_movemask_ps(a);
+ return (moveMask & 0x7) == (0x7);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAnyTrue3_R(const BoolV a)
+{
+ const QT3DSI32 moveMask = _mm_movemask_ps(a);
+ return (moveMask & 0x7) != (0x0);
+}
+
+/////////////////////////////////////////////////////////////////////
+////FUNCTIONS USED ONLY FOR ASSERTS IN VECTORISED IMPLEMENTATIONS
+/////////////////////////////////////////////////////////////////////
+
+QT3DS_FORCE_INLINE QT3DSU32 FiniteTestEq(const Vec4V a, const Vec4V b)
+{
+ // This is a bit of a bodge.
+ //_mm_comieq_ss returns 1 if either value is nan so we need to re-cast a and b with true encoded
+ //as a non-nan number.
+ // There must be a better way of doing this in sse.
+ const BoolV one = FOne();
+ const BoolV zero = FZero();
+ const BoolV a1 = V4Sel(a, one, zero);
+ const BoolV b1 = V4Sel(b, one, zero);
+ return (_mm_comieq_ss(a1, b1) && _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(1, 1, 1, 1)),
+ _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(1, 1, 1, 1)))
+ && _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(2, 2, 2, 2)),
+ _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(2, 2, 2, 2)))
+ && _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(3, 3, 3, 3)),
+ _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(3, 3, 3, 3))));
+}
+
+QT3DS_FORCE_INLINE bool isValidFloatV(const FloatV a)
+{
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)))
+ && _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)))
+ && _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))));
+}
+
+QT3DS_FORCE_INLINE bool isValidVec3V(const Vec3V a)
+{
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3)), FZero()) ? true : false);
+}
+
+QT3DS_FORCE_INLINE bool isFiniteFloatV(const FloatV a)
+{
+ const QT3DSU32 badNumber =
+ (_QT3DS_FPCLASS_SNAN | _QT3DS_FPCLASS_QNAN | _QT3DS_FPCLASS_NINF | _QT3DS_FPCLASS_PINF);
+ const FloatV vBadNum = FloatV_From_F32((QT3DSF32 &)badNumber);
+ const BoolV vMask = BAnd(vBadNum, a);
+ return FiniteTestEq(vMask, BFFFF()) == 1;
+}
+
+QT3DS_FORCE_INLINE bool isFiniteVec3V(const Vec3V a)
+{
+ const QT3DSU32 badNumber =
+ (_QT3DS_FPCLASS_SNAN | _QT3DS_FPCLASS_QNAN | _QT3DS_FPCLASS_NINF | _QT3DS_FPCLASS_PINF);
+ const Vec3V vBadNum = Vec3V_From_F32((QT3DSF32 &)badNumber);
+ const BoolV vMask = BAnd(BAnd(vBadNum, a), BTTTF());
+ return FiniteTestEq(vMask, BFFFF()) == 1;
+}
+
+QT3DS_FORCE_INLINE bool isFiniteVec4V(const Vec4V a)
+{
+ /*Vec4V a;
+ QT3DS_ALIGN(16, QT3DSF32 f[4]);
+ F32Array_Aligned_From_Vec4V(a, f);
+ return NVIsFinite(f[0])
+ && NVIsFinite(f[1])
+ && NVIsFinite(f[2])
+ && NVIsFinite(f[3]);*/
+
+ const QT3DSU32 badNumber =
+ (_QT3DS_FPCLASS_SNAN | _QT3DS_FPCLASS_QNAN | _QT3DS_FPCLASS_NINF | _QT3DS_FPCLASS_PINF);
+ const Vec4V vBadNum = Vec4V_From_F32((QT3DSF32 &)badNumber);
+ const BoolV vMask = BAnd(vBadNum, a);
+
+ return FiniteTestEq(vMask, BFFFF()) == 1;
+}
+
+QT3DS_FORCE_INLINE bool hasZeroElementinFloatV(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FloatV_From_F32(0.0f))
+ ? true
+ : false);
+}
+
+QT3DS_FORCE_INLINE bool hasZeroElementInVec3V(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FloatV_From_F32(0.0f))
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)), FloatV_From_F32(0.0f))
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)), FloatV_From_F32(0.0f)));
+}
+
+QT3DS_FORCE_INLINE bool hasZeroElementInVec4V(const Vec4V a)
+{
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FloatV_From_F32(0.0f))
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)), FloatV_From_F32(0.0f))
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)), FloatV_From_F32(0.0f))
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3)), FloatV_From_F32(0.0f)));
+}
+
+/////////////////////////////////////////////////////////////////////
+////VECTORISED FUNCTION IMPLEMENTATIONS
+/////////////////////////////////////////////////////////////////////
+
+QT3DS_FORCE_INLINE FloatV FloatV_From_F32(const QT3DSF32 f)
+{
+ return (_mm_load1_ps(&f));
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_F32(const QT3DSF32 f)
+{
+ return _mm_set_ps(0.0f, f, f, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_F32(const QT3DSF32 f)
+{
+ return (_mm_load1_ps(&f));
+}
+
+QT3DS_FORCE_INLINE BoolV BoolV_From_Bool32(const bool f)
+{
+ const QT3DSU32 i = -(QT3DSI32)f;
+ return _mm_load1_ps((float *)&i);
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_NVVec3_Aligned(const QT3DSVec3 &f)
+{
+ VECMATHAOS_ASSERT(0 == ((size_t)&f & 0x0f));
+ return (_mm_set_ps(0.0f, f.z, f.y, f.x));
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_NVVec3(const QT3DSVec3 &f)
+{
+ return (_mm_set_ps(0.0f, f.z, f.y, f.x));
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_NVVec3_WUndefined(const QT3DSVec3 &f)
+{
+ return (_mm_set_ps(0.0f, f.z, f.y, f.x));
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_Vec4V(Vec4V v)
+{
+ return V4SetW(v, V4Zero());
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_Vec3V(Vec3V f)
+{
+ return f; // ok if it is implemented as the same type.
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_NVVec3_WUndefined(const QT3DSVec3 &f)
+{
+ return (_mm_set_ps(0.0f, f.z, f.y, f.x));
+}
+
+QT3DS_FORCE_INLINE Mat33V Mat33V_From_NVMat33(const QT3DSMat33 &m)
+{
+ return Mat33V(Vec3V_From_NVVec3(m.column0), Vec3V_From_NVVec3(m.column1),
+ Vec3V_From_NVVec3(m.column2));
+}
+
+QT3DS_FORCE_INLINE void NVMat33_From_Mat33V(const Mat33V &m, QT3DSMat33 &out)
+{
+ QT3DS_ASSERT((size_t(&out) & 15) == 0);
+ NVVec3_From_Vec3V(m.col0, out.column0);
+ NVVec3_From_Vec3V(m.col1, out.column1);
+ NVVec3_From_Vec3V(m.col2, out.column2);
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_F32Array_Aligned(const QT3DSF32 *const f)
+{
+ VECMATHAOS_ASSERT(0 == ((QT3DSU64)f & 0x0f));
+ return (_mm_load_ps(f));
+}
+
+QT3DS_FORCE_INLINE void F32Array_Aligned_From_Vec4V(Vec4V a, QT3DSF32 *f)
+{
+ VECMATHAOS_ASSERT(0 == ((QT3DSU64)f & 0x0f));
+ _mm_store_ps(f, a);
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_F32Array(const QT3DSF32 *const f)
+{
+ return (_mm_loadu_ps(f));
+}
+
+QT3DS_FORCE_INLINE BoolV BoolV_From_Bool32Array(const bool *const f)
+{
+ const QT3DS_ALIGN(16, QT3DSU32) b[4] = { -(QT3DSI32)f[0], -(QT3DSI32)f[1], -(QT3DSI32)f[2], -(QT3DSI32)f[3] };
+ return _mm_load1_ps((float *)&b);
+}
+
+QT3DS_FORCE_INLINE QT3DSF32 NVF32_From_FloatV(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ QT3DSF32 f;
+ _mm_store_ss(&f, a);
+ return f;
+}
+
+QT3DS_FORCE_INLINE void NVF32_From_FloatV(const FloatV a, QT3DSF32 *QT3DS_RESTRICT f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ _mm_store_ss(f, a);
+}
+
+QT3DS_FORCE_INLINE void NVVec3Aligned_From_Vec3V(const Vec3V a, QT3DSVec3 &f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(0 == ((int)&a & 0x0F));
+ VECMATHAOS_ASSERT(0 == ((int)&f & 0x0F));
+ QT3DS_ALIGN(16, QT3DSF32) f2[4];
+ _mm_store_ps(f2, a);
+ f = QT3DSVec3(f2[0], f2[1], f2[2]);
+}
+
+QT3DS_FORCE_INLINE void NVVec3_From_Vec3V(const Vec3V a, QT3DSVec3 &f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(0 == ((int)&a & 0x0F));
+ QT3DS_ALIGN(16, QT3DSF32) f2[4];
+ _mm_store_ps(f2, a);
+ f = QT3DSVec3(f2[0], f2[1], f2[2]);
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsEqualFloatV(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return (_mm_comieq_ss(a, b) != 0);
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsEqualVec3V(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return V3AllEq(a, b) != 0;
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsEqualVec4V(const Vec4V a, const Vec4V b)
+{
+ return V4AllEq(a, b) != 0;
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsEqualBoolV(const BoolV a, const BoolV b)
+{
+ return BAllTrue4_R(VecI32V_IsEq(a, b)) != 0;
+}
+
+#define VECMATH_AOS_EPSILON (1e-3f)
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsNearEqualFloatV(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ const FloatV c = FSub(a, b);
+ const FloatV minError = FloatV_From_F32(-VECMATH_AOS_EPSILON);
+ const FloatV maxError = FloatV_From_F32(VECMATH_AOS_EPSILON);
+ return (_mm_comigt_ss(c, minError) && _mm_comilt_ss(c, maxError));
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsNearEqualVec3V(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ const Vec3V c = V3Sub(a, b);
+ const Vec3V minError = Vec3V_From_F32(-VECMATH_AOS_EPSILON);
+ const Vec3V maxError = Vec3V_From_F32(VECMATH_AOS_EPSILON);
+ return (_mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), maxError));
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsNearEqualVec4V(const Vec4V a, const Vec4V b)
+{
+ const Vec4V c = V4Sub(a, b);
+ const Vec4V minError = Vec4V_From_F32(-VECMATH_AOS_EPSILON);
+ const Vec4V maxError = Vec4V_From_F32(VECMATH_AOS_EPSILON);
+ return (_mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3)), maxError));
+}
+
+//////////////////////////////////
+// FLOATV
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE FloatV FZero()
+{
+ return FloatV_From_F32(0.0f);
+}
+
+QT3DS_FORCE_INLINE FloatV FOne()
+{
+ return FloatV_From_F32(1.0f);
+}
+
+QT3DS_FORCE_INLINE FloatV FHalf()
+{
+ return FloatV_From_F32(0.5f);
+}
+
+QT3DS_FORCE_INLINE FloatV FEps()
+{
+ return FloatV_From_F32(QT3DS_ENV_REAL);
+}
+
+QT3DS_FORCE_INLINE FloatV FEps6()
+{
+ return FloatV_From_F32(1e-6f);
+}
+
+QT3DS_FORCE_INLINE FloatV FMax()
+{
+ return FloatV_From_F32(QT3DS_MAX_REAL);
+}
+
+QT3DS_FORCE_INLINE FloatV FNegMax()
+{
+ return FloatV_From_F32(-QT3DS_MAX_REAL);
+}
+
+QT3DS_FORCE_INLINE FloatV IZero()
+{
+ const QT3DSU32 zero = 0;
+ return _mm_load1_ps((QT3DSF32 *)&zero);
+}
+
+QT3DS_FORCE_INLINE FloatV IOne()
+{
+ const QT3DSU32 one = 1;
+ return _mm_load1_ps((QT3DSF32 *)&one);
+}
+
+QT3DS_FORCE_INLINE FloatV ITwo()
+{
+ const QT3DSU32 two = 2;
+ return _mm_load1_ps((QT3DSF32 *)&two);
+}
+
+QT3DS_FORCE_INLINE FloatV IThree()
+{
+ const QT3DSU32 three = 3;
+ return _mm_load1_ps((QT3DSF32 *)&three);
+}
+
+QT3DS_FORCE_INLINE FloatV IFour()
+{
+ QT3DSU32 four = 4;
+ return _mm_load1_ps((QT3DSF32 *)&four);
+}
+
+QT3DS_FORCE_INLINE FloatV FNeg(const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return _mm_sub_ps(_mm_setzero_ps(), f);
+}
+
+QT3DS_FORCE_INLINE FloatV FAdd(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_add_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FSub(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_sub_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FMul(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FDiv(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FDivFast(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+QT3DS_FORCE_INLINE FloatV FRecip(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ return _mm_rcp_ps(a);
+}
+
+QT3DS_FORCE_INLINE FloatV FRecipFast(const FloatV a)
+{
+ return FRecip(a);
+}
+
+QT3DS_FORCE_INLINE FloatV FRsqrt(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ return _mm_rsqrt_ps(a);
+}
+
+QT3DS_FORCE_INLINE FloatV FSqrt(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ return _mm_sqrt_ps(a);
+}
+
+QT3DS_FORCE_INLINE FloatV FRsqrtFast(const FloatV a)
+{
+ return FRsqrt(a);
+}
+
+QT3DS_FORCE_INLINE FloatV FScaleAdd(const FloatV a, const FloatV b, const FloatV c)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ VECMATHAOS_ASSERT(isValidFloatV(c));
+ return FAdd(FMul(a, b), c);
+}
+
+QT3DS_FORCE_INLINE FloatV FNegScaleSub(const FloatV a, const FloatV b, const FloatV c)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ VECMATHAOS_ASSERT(isValidFloatV(c));
+ return FSub(c, FMul(a, b));
+}
+
+QT3DS_FORCE_INLINE FloatV FAbs(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ QT3DS_ALIGN(16, const QT3DSU32) absMask[4] = { 0x7fFFffFF, 0x7fFFffFF, 0x7fFFffFF, 0x7fFFffFF };
+ return _mm_and_ps(a, _mm_load_ps((QT3DSF32 *)absMask));
+}
+
+QT3DS_FORCE_INLINE FloatV FSel(const BoolV c, const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(_VecMathTests::allElementsEqualBoolV(c, BTTTT())
+ || _VecMathTests::allElementsEqualBoolV(c, BFFFF()));
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
+}
+
+QT3DS_FORCE_INLINE BoolV FIsGrtr(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_cmpgt_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV FIsGrtrOrEq(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_cmpge_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV FIsEq(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_cmpeq_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FMax(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_max_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FMin(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_min_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FClamp(const FloatV a, const FloatV minV, const FloatV maxV)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(minV));
+ VECMATHAOS_ASSERT(isValidFloatV(maxV));
+ return FMax(FMin(a, maxV), minV);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FAllGrtr(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return (_mm_comigt_ss(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FAllGrtrOrEq(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+
+ return (_mm_comige_ss(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FAllEq(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+
+ return (_mm_comieq_ss(a, b));
+}
+
+QT3DS_FORCE_INLINE FloatV FRound(const FloatV a)
+{
+ // return _mm_round_ps(a, 0x0);
+ const Vec3V half = Vec3V_From_F32(0.5f);
+ const Vec3V aPlusHalf = V3Add(a, half);
+ __m128i tmp = _mm_cvttps_epi32(aPlusHalf);
+ return _mm_cvtepi32_ps(tmp);
+}
+
+QT3DS_FORCE_INLINE FloatV FSin(const FloatV a)
+{
+ // Vec4V V1, V2, V3, V5, V7, V9, V11, V13, V15, V17, V19, V21, V23;
+ // Vec4V S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11;
+ FloatV Result;
+
+ // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
+ const FloatV twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const FloatV tmp = FMul(a, twoPi);
+ const FloatV b = FRound(tmp);
+ const FloatV V1 = FNegMulSub(twoPi, b, a);
+
+ // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
+ // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
+ const FloatV V2 = FMul(V1, V1);
+ const FloatV V3 = FMul(V2, V1);
+ const FloatV V5 = FMul(V3, V2);
+ const FloatV V7 = FMul(V5, V2);
+ const FloatV V9 = FMul(V7, V2);
+ const FloatV V11 = FMul(V9, V2);
+ const FloatV V13 = FMul(V11, V2);
+ const FloatV V15 = FMul(V13, V2);
+ const FloatV V17 = FMul(V15, V2);
+ const FloatV V19 = FMul(V17, V2);
+ const FloatV V21 = FMul(V19, V2);
+ const FloatV V23 = FMul(V21, V2);
+
+ const Vec4V sinCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients0.f);
+ const Vec4V sinCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients1.f);
+ const Vec4V sinCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients2.f);
+
+ const FloatV S1 = V4GetY(sinCoefficients0);
+ const FloatV S2 = V4GetZ(sinCoefficients0);
+ const FloatV S3 = V4GetW(sinCoefficients0);
+ const FloatV S4 = V4GetX(sinCoefficients1);
+ const FloatV S5 = V4GetY(sinCoefficients1);
+ const FloatV S6 = V4GetZ(sinCoefficients1);
+ const FloatV S7 = V4GetW(sinCoefficients1);
+ const FloatV S8 = V4GetX(sinCoefficients2);
+ const FloatV S9 = V4GetY(sinCoefficients2);
+ const FloatV S10 = V4GetZ(sinCoefficients2);
+ const FloatV S11 = V4GetW(sinCoefficients2);
+
+ Result = FMulAdd(S1, V3, V1);
+ Result = FMulAdd(S2, V5, Result);
+ Result = FMulAdd(S3, V7, Result);
+ Result = FMulAdd(S4, V9, Result);
+ Result = FMulAdd(S5, V11, Result);
+ Result = FMulAdd(S6, V13, Result);
+ Result = FMulAdd(S7, V15, Result);
+ Result = FMulAdd(S8, V17, Result);
+ Result = FMulAdd(S9, V19, Result);
+ Result = FMulAdd(S10, V21, Result);
+ Result = FMulAdd(S11, V23, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE FloatV FCos(const FloatV a)
+{
+ // XMVECTOR V1, V2, V4, V6, V8, V10, V12, V14, V16, V18, V20, V22;
+ // XMVECTOR C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11;
+ FloatV Result;
+
+ // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
+ const FloatV twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const FloatV tmp = FMul(a, twoPi);
+ const FloatV b = FRound(tmp);
+ const FloatV V1 = FNegMulSub(twoPi, b, a);
+
+ // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
+ // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
+ const FloatV V2 = FMul(V1, V1);
+ const FloatV V4 = FMul(V2, V2);
+ const FloatV V6 = FMul(V4, V2);
+ const FloatV V8 = FMul(V4, V4);
+ const FloatV V10 = FMul(V6, V4);
+ const FloatV V12 = FMul(V6, V6);
+ const FloatV V14 = FMul(V8, V6);
+ const FloatV V16 = FMul(V8, V8);
+ const FloatV V18 = FMul(V10, V8);
+ const FloatV V20 = FMul(V10, V10);
+ const FloatV V22 = FMul(V12, V10);
+
+ const Vec4V cosCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients0.f);
+ const Vec4V cosCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients1.f);
+ const Vec4V cosCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients2.f);
+
+ const FloatV C1 = V4GetY(cosCoefficients0);
+ const FloatV C2 = V4GetZ(cosCoefficients0);
+ const FloatV C3 = V4GetW(cosCoefficients0);
+ const FloatV C4 = V4GetX(cosCoefficients1);
+ const FloatV C5 = V4GetY(cosCoefficients1);
+ const FloatV C6 = V4GetZ(cosCoefficients1);
+ const FloatV C7 = V4GetW(cosCoefficients1);
+ const FloatV C8 = V4GetX(cosCoefficients2);
+ const FloatV C9 = V4GetY(cosCoefficients2);
+ const FloatV C10 = V4GetZ(cosCoefficients2);
+ const FloatV C11 = V4GetW(cosCoefficients2);
+
+ Result = FMulAdd(C1, V2, V4One());
+ Result = FMulAdd(C2, V4, Result);
+ Result = FMulAdd(C3, V6, Result);
+ Result = FMulAdd(C4, V8, Result);
+ Result = FMulAdd(C5, V10, Result);
+ Result = FMulAdd(C6, V12, Result);
+ Result = FMulAdd(C7, V14, Result);
+ Result = FMulAdd(C8, V16, Result);
+ Result = FMulAdd(C9, V18, Result);
+ Result = FMulAdd(C10, V20, Result);
+ Result = FMulAdd(C11, V22, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FOutOfBounds(const FloatV a, const FloatV min, const FloatV max)
+{
+ const BoolV ffff = BFFFF();
+ const BoolV c = BOr(FIsGrtr(a, max), FIsGrtr(min, a));
+ return !BAllEq(c, ffff);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FInBounds(const FloatV a, const FloatV min, const FloatV max)
+{
+ const BoolV tttt = BTTTT();
+ const BoolV c = BAnd(FIsGrtrOrEq(a, min), FIsGrtrOrEq(max, a));
+ return BAllEq(c, tttt);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FOutOfBounds(const FloatV a, const FloatV bounds)
+{
+ return FOutOfBounds(a, FNeg(bounds), bounds);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FInBounds(const FloatV a, const FloatV bounds)
+{
+ return FInBounds(a, FNeg(bounds), bounds);
+}
+
+//////////////////////////////////
+// VEC3V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec3V V3Splat(const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ const __m128 zero = FloatV_From_F32(0.0f);
+ const __m128 fff0 = _mm_move_ss(f, zero);
+ return _mm_shuffle_ps(fff0, fff0, _MM_SHUFFLE(0, 1, 2, 3));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Merge(const FloatVArg x, const FloatVArg y, const FloatVArg z)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(x));
+ VECMATHAOS_ASSERT(isValidFloatV(y));
+ VECMATHAOS_ASSERT(isValidFloatV(z));
+ // static on zero causes compiler crash on x64 debug_opt
+ const __m128 zero = FloatV_From_F32(0.0f);
+ const __m128 xy = _mm_move_ss(x, y);
+ const __m128 z0 = _mm_move_ss(zero, z);
+
+ return _mm_shuffle_ps(xy, z0, _MM_SHUFFLE(1, 0, 0, 1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3UnitX()
+{
+ const QT3DS_ALIGN(16, QT3DSF32) x[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
+ const __m128 x128 = _mm_load_ps(x);
+ return x128;
+}
+
+QT3DS_FORCE_INLINE Vec3V V3UnitY()
+{
+ const QT3DS_ALIGN(16, QT3DSF32) y[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
+ const __m128 y128 = _mm_load_ps(y);
+ return y128;
+}
+
+QT3DS_FORCE_INLINE Vec3V V3UnitZ()
+{
+ const QT3DS_ALIGN(16, QT3DSF32) z[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
+ const __m128 z128 = _mm_load_ps(z);
+ return z128;
+}
+
+QT3DS_FORCE_INLINE FloatV V3GetX(const Vec3V f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(f));
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
+}
+
+QT3DS_FORCE_INLINE FloatV V3GetY(const Vec3V f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(f));
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
+}
+
+QT3DS_FORCE_INLINE FloatV V3GetZ(const Vec3V f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(f));
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3SetX(const Vec3V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v));
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V3Sel(BFTTT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3SetY(const Vec3V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v));
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V3Sel(BTFTT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3SetZ(const Vec3V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v));
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V3Sel(BTTFT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ColX(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 0, 3, 0));
+ return V3SetY(r, V3GetX(b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ColY(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 1, 3, 1));
+ return V3SetY(r, V3GetY(b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ColZ(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 2, 3, 2));
+ return V3SetY(r, V3GetZ(b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Zero()
+{
+ return Vec3V_From_F32(0.0f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Eps()
+{
+ return Vec3V_From_F32(QT3DS_ENV_REAL);
+}
+QT3DS_FORCE_INLINE Vec3V V3One()
+{
+ return Vec3V_From_F32(1.0f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Neg(const Vec3V f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(f));
+ return _mm_sub_ps(_mm_setzero_ps(), f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Add(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_add_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Sub(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_sub_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Scale(const Vec3V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Mul(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ScaleInv(const Vec3V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Div(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ const __m128 one = Vec3V_From_F32(1.0f);
+ const __m128 tttf = BTTTF();
+ const __m128 b1 = V3Sel(tttf, b, one);
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ScaleInvFast(const Vec3V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3DivFast(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ const __m128 one = Vec3V_From_F32(1.0f);
+ const __m128 tttf = BTTTF();
+ const __m128 b1 = V3Sel(tttf, b, one);
+ return _mm_mul_ps(a, _mm_rcp_ps(b1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Recip(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = Vec3V_From_F32(0.0f);
+ const __m128 tttf = BTTTF();
+ const __m128 recipA = _mm_rcp_ps(a);
+ return V3Sel(tttf, recipA, zero);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3RecipFast(const Vec3V a)
+{
+ return V3Recip(a);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Rsqrt(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = Vec3V_From_F32(0.0f);
+ const __m128 tttf = BTTTF();
+ const __m128 recipA = _mm_rsqrt_ps(a);
+ return V3Sel(tttf, recipA, zero);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3RsqrtFast(const Vec3V a)
+{
+ return V3Rsqrt(a);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ScaleAdd(const Vec3V a, const FloatV b, const Vec3V c)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ VECMATHAOS_ASSERT(isValidVec3V(c));
+ return V3Add(V3Scale(a, b), c);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3NegScaleSub(const Vec3V a, const FloatV b, const Vec3V c)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ VECMATHAOS_ASSERT(isValidVec3V(c));
+ return V3Sub(c, V3Scale(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3MulAdd(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ VECMATHAOS_ASSERT(isValidVec3V(c));
+ return V3Add(V3Mul(a, b), c);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3NegMulSub(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ VECMATHAOS_ASSERT(isValidVec3V(c));
+ return V3Sub(c, V3Scale(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Abs(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return V3Max(
+ a, V3Neg(a)); // sw/physx/shared/reviewed/3/feature/sdk/include/windows/Qt3DSWindowsInlineAoS.h
+}
+
+QT3DS_FORCE_INLINE FloatV V3Dot(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ //__m128 dot1 = _mm_mul_ps(a, b);
+ ////w,z,y,x
+ //__m128 shuf1 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(2,1,0,3)); //z,y,x,w
+ //__m128 shuf2 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(1,0,3,2)); //y,x,w,z
+ //__m128 shuf3 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(0,3,2,1)); //x,w,z,y
+ // return _mm_add_ps(_mm_add_ps(shuf2, shuf3), _mm_add_ps(dot1,shuf1));
+
+ __m128 dot1 = _mm_mul_ps(a, b);
+ __m128 shuf1 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(0, 0, 0, 0)); // z,y,x,w
+ __m128 shuf2 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(1, 1, 1, 1)); // y,x,w,z
+ __m128 shuf3 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(2, 2, 2, 2)); // x,w,z,y
+ return _mm_add_ps(_mm_add_ps(shuf2, shuf3), shuf1);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Cross(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ __m128 l1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
+ __m128 l2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
+ __m128 r1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
+ __m128 r2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
+ return _mm_sub_ps(_mm_mul_ps(l1, l2), _mm_mul_ps(r1, r2));
+}
+
+QT3DS_FORCE_INLINE FloatV V3Length(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_sqrt_ps(V3Dot(a, a));
+}
+
+QT3DS_FORCE_INLINE FloatV V3LengthSq(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return V3Dot(a, a);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Normalize(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return V3Scale(a, _mm_rsqrt_ps(V3Dot(a, a)));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3NormalizeFast(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return V3Scale(a, _mm_rsqrt_ps(V3Dot(a, a)));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3NormalizeSafe(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = FloatV_From_F32(0.0f);
+ const __m128 length = V3Length(a);
+ const __m128 isGreaterThanZero = FIsGrtr(length, zero);
+ return V3Sel(isGreaterThanZero, V3ScaleInv(a, length), zero);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Sel(const BoolV c, const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
+}
+
+QT3DS_FORCE_INLINE BoolV V3IsGrtr(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_cmpgt_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V3IsGrtrOrEq(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_cmpge_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V3IsEq(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_cmpeq_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Max(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_max_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Min(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_min_ps(a, b);
+}
+
+// Extract the maximum value from a
+QT3DS_FORCE_INLINE FloatV V3ExtractMax(const Vec3V a)
+{
+ const __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0));
+ const __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1));
+ const __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2));
+
+ return _mm_max_ps(_mm_max_ps(shuf1, shuf2), shuf3);
+}
+
+// Extract the maximum value from a
+QT3DS_FORCE_INLINE FloatV V3ExtractMin(const Vec3V a)
+{
+ const __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0));
+ const __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1));
+ const __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2));
+
+ return _mm_min_ps(_mm_min_ps(shuf1, shuf2), shuf3);
+}
+
+// return (a >= 0.0f) ? 1.0f : -1.0f;
+QT3DS_FORCE_INLINE Vec3V V3Sign(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = V3Zero();
+ const __m128 one = V3One();
+ const __m128 none = V3Neg(one);
+ return V3Sel(V3IsGrtrOrEq(a, zero), one, none);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Clamp(const Vec3V a, const Vec3V minV, const Vec3V maxV)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(minV));
+ VECMATHAOS_ASSERT(isValidVec3V(maxV));
+ return V3Max(V3Min(a, maxV), minV);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3AllGrtr(const Vec3V a, const Vec3V b)
+{
+ return BAllTrue3_R(V4IsGrtr(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3AllGrtrOrEq(const Vec3V a, const Vec3V b)
+{
+ return BAllTrue3_R(V4IsGrtrOrEq(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3AllEq(const Vec3V a, const Vec3V b)
+{
+ return BAllTrue3_R(V4IsEq(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Round(const Vec3V a)
+{
+ // return _mm_round_ps(a, 0x0);
+ const Vec3V half = Vec3V_From_F32(0.5f);
+ const Vec3V aPlusHalf = V3Add(a, half);
+ __m128i tmp = _mm_cvttps_epi32(aPlusHalf);
+ return _mm_cvtepi32_ps(tmp);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Sin(const Vec3V a)
+{
+ // Vec4V V1, V2, V3, V5, V7, V9, V11, V13, V15, V17, V19, V21, V23;
+ // Vec4V S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11;
+ Vec3V Result;
+
+ // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
+ const Vec3V twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const Vec3V tmp = V3Mul(a, twoPi);
+ const Vec3V b = V3Round(tmp);
+ const Vec3V V1 = V3NegMulSub(twoPi, b, a);
+
+ // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
+ // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
+ const Vec3V V2 = V3Mul(V1, V1);
+ const Vec3V V3 = V3Mul(V2, V1);
+ const Vec3V V5 = V3Mul(V3, V2);
+ const Vec3V V7 = V3Mul(V5, V2);
+ const Vec3V V9 = V3Mul(V7, V2);
+ const Vec3V V11 = V3Mul(V9, V2);
+ const Vec3V V13 = V3Mul(V11, V2);
+ const Vec3V V15 = V3Mul(V13, V2);
+ const Vec3V V17 = V3Mul(V15, V2);
+ const Vec3V V19 = V3Mul(V17, V2);
+ const Vec3V V21 = V3Mul(V19, V2);
+ const Vec3V V23 = V3Mul(V21, V2);
+
+ const Vec4V sinCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients0.f);
+ const Vec4V sinCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients1.f);
+ const Vec4V sinCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients2.f);
+
+ const FloatV S1 = V4GetY(sinCoefficients0);
+ const FloatV S2 = V4GetZ(sinCoefficients0);
+ const FloatV S3 = V4GetW(sinCoefficients0);
+ const FloatV S4 = V4GetX(sinCoefficients1);
+ const FloatV S5 = V4GetY(sinCoefficients1);
+ const FloatV S6 = V4GetZ(sinCoefficients1);
+ const FloatV S7 = V4GetW(sinCoefficients1);
+ const FloatV S8 = V4GetX(sinCoefficients2);
+ const FloatV S9 = V4GetY(sinCoefficients2);
+ const FloatV S10 = V4GetZ(sinCoefficients2);
+ const FloatV S11 = V4GetW(sinCoefficients2);
+
+ Result = V3MulAdd(S1, V3, V1);
+ Result = V3MulAdd(S2, V5, Result);
+ Result = V3MulAdd(S3, V7, Result);
+ Result = V3MulAdd(S4, V9, Result);
+ Result = V3MulAdd(S5, V11, Result);
+ Result = V3MulAdd(S6, V13, Result);
+ Result = V3MulAdd(S7, V15, Result);
+ Result = V3MulAdd(S8, V17, Result);
+ Result = V3MulAdd(S9, V19, Result);
+ Result = V3MulAdd(S10, V21, Result);
+ Result = V3MulAdd(S11, V23, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Cos(const Vec3V a)
+{
+ // XMVECTOR V1, V2, V4, V6, V8, V10, V12, V14, V16, V18, V20, V22;
+ // XMVECTOR C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11;
+ Vec3V Result;
+
+ // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
+ const Vec3V twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const Vec3V tmp = V3Mul(a, twoPi);
+ const Vec3V b = V3Round(tmp);
+ const Vec3V V1 = V3NegMulSub(twoPi, b, a);
+
+ // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
+ // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
+ const Vec3V V2 = V3Mul(V1, V1);
+ const Vec3V V4 = V3Mul(V2, V2);
+ const Vec3V V6 = V3Mul(V4, V2);
+ const Vec3V V8 = V3Mul(V4, V4);
+ const Vec3V V10 = V3Mul(V6, V4);
+ const Vec3V V12 = V3Mul(V6, V6);
+ const Vec3V V14 = V3Mul(V8, V6);
+ const Vec3V V16 = V3Mul(V8, V8);
+ const Vec3V V18 = V3Mul(V10, V8);
+ const Vec3V V20 = V3Mul(V10, V10);
+ const Vec3V V22 = V3Mul(V12, V10);
+
+ const Vec4V cosCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients0.f);
+ const Vec4V cosCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients1.f);
+ const Vec4V cosCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients2.f);
+
+ const FloatV C1 = V4GetY(cosCoefficients0);
+ const FloatV C2 = V4GetZ(cosCoefficients0);
+ const FloatV C3 = V4GetW(cosCoefficients0);
+ const FloatV C4 = V4GetX(cosCoefficients1);
+ const FloatV C5 = V4GetY(cosCoefficients1);
+ const FloatV C6 = V4GetZ(cosCoefficients1);
+ const FloatV C7 = V4GetW(cosCoefficients1);
+ const FloatV C8 = V4GetX(cosCoefficients2);
+ const FloatV C9 = V4GetY(cosCoefficients2);
+ const FloatV C10 = V4GetZ(cosCoefficients2);
+ const FloatV C11 = V4GetW(cosCoefficients2);
+
+ Result = V3MulAdd(C1, V2, V4One());
+ Result = V3MulAdd(C2, V4, Result);
+ Result = V3MulAdd(C3, V6, Result);
+ Result = V3MulAdd(C4, V8, Result);
+ Result = V3MulAdd(C5, V10, Result);
+ Result = V3MulAdd(C6, V12, Result);
+ Result = V3MulAdd(C7, V14, Result);
+ Result = V3MulAdd(C8, V16, Result);
+ Result = V3MulAdd(C9, V18, Result);
+ Result = V3MulAdd(C10, V20, Result);
+ Result = V3MulAdd(C11, V22, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermYZZ(const Vec3V a)
+{
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 2, 1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermXYX(const Vec3V a)
+{
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 1, 0));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermYZX(const Vec3V a)
+{
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermZXY(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermZZY(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 2, 2));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermYXX(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 0, 1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Perm_Zero_1Z_0Y(const Vec3V v0, const Vec3V v1)
+{
+ return _mm_shuffle_ps(v1, v0, _MM_SHUFFLE(3, 1, 2, 3));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Perm_0Z_Zero_1X(const Vec3V v0, const Vec3V v1)
+{
+ return _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(3, 0, 3, 2));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Perm_1Y_0X_Zero(const Vec3V v0, const Vec3V v1)
+{
+ // There must be a better way to do this.
+ Vec3V v2 = V3Zero();
+ FloatV y1 = V3GetY(v1);
+ FloatV x0 = V3GetX(v0);
+ v2 = V3SetX(v2, y1);
+ return V3SetY(v2, x0);
+}
+
+QT3DS_FORCE_INLINE FloatV V3SumElems(const Vec3V a)
+{
+ __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)); // z,y,x,w
+ __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)); // y,x,w,z
+ __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)); // x,w,z,y
+ return _mm_add_ps(_mm_add_ps(shuf1, shuf2), shuf3);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3OutOfBounds(const Vec3V a, const Vec3V min, const Vec3V max)
+{
+ const BoolV ffff = BFFFF();
+ const BoolV c = BOr(V3IsGrtr(a, max), V3IsGrtr(min, a));
+ return !BAllEq(c, ffff);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3InBounds(const Vec3V a, const Vec3V min, const Vec3V max)
+{
+ const BoolV tttt = BTTTT();
+ const BoolV c = BAnd(V3IsGrtrOrEq(a, min), V3IsGrtrOrEq(max, a));
+ return BAllEq(c, tttt);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3OutOfBounds(const Vec3V a, const Vec3V bounds)
+{
+ return V3OutOfBounds(a, V3Neg(bounds), bounds);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3InBounds(const Vec3V a, const Vec3V bounds)
+{
+ return V3InBounds(a, V3Neg(bounds), bounds);
+}
+
+//////////////////////////////////
+// VEC4V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec4V V4Splat(const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Merge(const FloatV *const floatVArray)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(floatVArray[0]));
+ VECMATHAOS_ASSERT(isValidFloatV(floatVArray[1]));
+ VECMATHAOS_ASSERT(isValidFloatV(floatVArray[2]));
+ VECMATHAOS_ASSERT(isValidFloatV(floatVArray[3]));
+ __m128 xw = _mm_move_ss(floatVArray[1], floatVArray[0]); // y, y, y, x
+ __m128 yz = _mm_move_ss(floatVArray[2], floatVArray[3]); // z, z, z, w
+ return (_mm_shuffle_ps(xw, yz, _MM_SHUFFLE(0, 2, 1, 0)));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Merge(const FloatVArg x, const FloatVArg y, const FloatVArg z,
+ const FloatVArg w)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(x));
+ VECMATHAOS_ASSERT(isValidFloatV(y));
+ VECMATHAOS_ASSERT(isValidFloatV(z));
+ VECMATHAOS_ASSERT(isValidFloatV(w));
+ __m128 xw = _mm_move_ss(y, x); // y, y, y, x
+ __m128 yz = _mm_move_ss(z, w); // z, z, z, w
+ return (_mm_shuffle_ps(xw, yz, _MM_SHUFFLE(0, 2, 1, 0)));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4UnitW()
+{
+ const QT3DS_ALIGN(16, QT3DSF32) w[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
+ const __m128 w128 = _mm_load_ps(w);
+ return w128;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4UnitX()
+{
+ const QT3DS_ALIGN(16, QT3DSF32) x[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
+ const __m128 x128 = _mm_load_ps(x);
+ return x128;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4UnitY()
+{
+ const QT3DS_ALIGN(16, QT3DSF32) y[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
+ const __m128 y128 = _mm_load_ps(y);
+ return y128;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4UnitZ()
+{
+ const QT3DS_ALIGN(16, QT3DSF32) z[4] = { 0.0f, 0.0f, 1.0f, 0.0f };
+ const __m128 z128 = _mm_load_ps(z);
+ return z128;
+}
+
+QT3DS_FORCE_INLINE FloatV V4GetW(const Vec4V f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(3, 3, 3, 3));
+}
+
+QT3DS_FORCE_INLINE FloatV V4GetX(const Vec4V f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
+}
+
+QT3DS_FORCE_INLINE FloatV V4GetY(const Vec4V f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
+}
+
+QT3DS_FORCE_INLINE FloatV V4GetZ(const Vec4V f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4SetW(const Vec4V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V4Sel(BTTTF(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4SetX(const Vec4V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V4Sel(BFTTT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4SetY(const Vec4V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V4Sel(BTFTT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4SetZ(const Vec4V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v));
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V4Sel(BTTFT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Zero()
+{
+ return Vec4V_From_F32(0.0f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4One()
+{
+ return Vec4V_From_F32(1.0f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V4Eps()
+{
+ return Vec3V_From_F32(QT3DS_ENV_REAL);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Neg(const Vec4V f)
+{
+ return _mm_sub_ps(_mm_setzero_ps(), f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Add(const Vec4V a, const Vec4V b)
+{
+ return _mm_add_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Sub(const Vec4V a, const Vec4V b)
+{
+ return _mm_sub_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Scale(const Vec4V a, const FloatV b)
+{
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Mul(const Vec4V a, const Vec4V b)
+{
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4ScaleInv(const Vec4V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Div(const Vec4V a, const Vec4V b)
+{
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4ScaleInvFast(const Vec4V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4DivFast(const Vec4V a, const Vec4V b)
+{
+ return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Recip(const Vec4V a)
+{
+ return _mm_rcp_ps(a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4RecipFast(const Vec4V a)
+{
+ return V4Recip(a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Rsqrt(const Vec4V a)
+{
+ return _mm_rsqrt_ps(a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4RsqrtFast(const Vec4V a)
+{
+ return V4Rsqrt(a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4ScaleAdd(const Vec4V a, const FloatV b, const Vec4V c)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return V4Add(V4Scale(a, b), c);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4NegScaleSub(const Vec4V a, const FloatV b, const Vec4V c)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return V4Sub(c, V4Scale(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4MulAdd(const Vec4V a, const Vec4V b, const Vec4V c)
+{
+ return V4Add(V4Scale(a, b), c);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4NegMulSub(const Vec4V a, const Vec4V b, const Vec4V c)
+{
+ return V4Sub(c, V4Scale(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Abs(const Vec4V a)
+{
+ return V4Max(a, V3Neg(a));
+}
+
+QT3DS_FORCE_INLINE FloatV V4Dot(const Vec4V a, const Vec4V b)
+{
+ __m128 dot1 = _mm_mul_ps(a, b); // x,y,z,w
+ __m128 shuf1 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(2, 1, 0, 3)); // w,x,y,z
+ __m128 shuf2 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(1, 0, 3, 2)); // z,w,x,y
+ __m128 shuf3 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(0, 3, 2, 1)); // y,z,w,x
+ return _mm_add_ps(_mm_add_ps(shuf2, shuf3), _mm_add_ps(dot1, shuf1));
+}
+
+QT3DS_FORCE_INLINE FloatV V4Length(const Vec4V a)
+{
+ return _mm_sqrt_ps(V4Dot(a, a));
+}
+
+QT3DS_FORCE_INLINE FloatV V4LengthSq(const Vec4V a)
+{
+ return V4Dot(a, a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Normalize(const Vec4V a)
+{
+ return V4ScaleInv(a, _mm_sqrt_ps(V4Dot(a, a)));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4NormalizeFast(const Vec4V a)
+{
+ return V4ScaleInvFast(a, _mm_sqrt_ps(V4Dot(a, a)));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4NormalizeSafe(const Vec4V a)
+{
+ const __m128 zero = FloatV_From_F32(0.0f);
+ const __m128 length = V4Length(a);
+ const __m128 isGreaterThanZero = FIsGrtr(length, zero);
+ return V4Sel(isGreaterThanZero, V4ScaleInv(a, length), zero);
+}
+
+QT3DS_FORCE_INLINE BoolV V4IsEqU32(const VecU32V a, const VecU32V b)
+{
+ return _mm_cmpeq_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Sel(const BoolV c, const Vec4V a, const Vec4V b)
+{
+ return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
+}
+
+QT3DS_FORCE_INLINE BoolV V4IsGrtr(const Vec4V a, const Vec4V b)
+{
+ return _mm_cmpgt_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V4IsGrtrOrEq(const Vec4V a, const Vec4V b)
+{
+ return _mm_cmpge_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V4IsEq(const Vec4V a, const Vec4V b)
+{
+ return _mm_cmpeq_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V4Max(const Vec4V a, const Vec4V b)
+{
+ return _mm_max_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Min(const Vec4V a, const Vec4V b)
+{
+ return _mm_min_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV V4ExtractMax(const Vec4V a)
+{
+ __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 1, 0, 3));
+ __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 3, 2, 1));
+
+ return _mm_max_ps(_mm_max_ps(a, shuf1), _mm_max_ps(shuf2, shuf3));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Clamp(const Vec4V a, const Vec4V minV, const Vec4V maxV)
+{
+ return V4Max(V4Min(a, maxV), minV);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V4AllGrtr(const Vec4V a, const Vec4V b)
+{
+ return BAllTrue4_R(V4IsGrtr(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V4AllGrtrOrEq(const Vec4V a, const Vec4V b)
+{
+ return BAllTrue4_R(V4IsGrtrOrEq(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V4AllEq(const Vec4V a, const Vec4V b)
+{
+ return BAllTrue4_R(V4IsEq(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Round(const Vec4V a)
+{
+ // return _mm_round_ps(a, 0x0);
+ const Vec3V half = Vec3V_From_F32(0.5f);
+ const Vec3V aPlusHalf = V3Add(a, half);
+ __m128i tmp = _mm_cvttps_epi32(aPlusHalf);
+ return _mm_cvtepi32_ps(tmp);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Sin(const Vec4V a)
+{
+ // Vec4V V1, V2, V3, V5, V7, V9, V11, V13, V15, V17, V19, V21, V23;
+ // Vec4V S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11;
+ Vec4V Result;
+
+ const Vec4V twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const Vec4V tmp = V4Mul(a, twoPi);
+ const Vec4V b = V4Round(tmp);
+ const Vec4V V1 = V4NegMulSub(twoPi, b, a);
+
+ // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
+ // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
+ const Vec4V V2 = V4Mul(V1, V1);
+ const Vec4V V3 = V4Mul(V2, V1);
+ const Vec4V V5 = V4Mul(V3, V2);
+ const Vec4V V7 = V4Mul(V5, V2);
+ const Vec4V V9 = V4Mul(V7, V2);
+ const Vec4V V11 = V4Mul(V9, V2);
+ const Vec4V V13 = V4Mul(V11, V2);
+ const Vec4V V15 = V4Mul(V13, V2);
+ const Vec4V V17 = V4Mul(V15, V2);
+ const Vec4V V19 = V4Mul(V17, V2);
+ const Vec4V V21 = V4Mul(V19, V2);
+ const Vec4V V23 = V4Mul(V21, V2);
+
+ const Vec4V sinCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients0.f);
+ const Vec4V sinCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients1.f);
+ const Vec4V sinCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients2.f);
+
+ const FloatV S1 = V4GetY(sinCoefficients0);
+ const FloatV S2 = V4GetZ(sinCoefficients0);
+ const FloatV S3 = V4GetW(sinCoefficients0);
+ const FloatV S4 = V4GetX(sinCoefficients1);
+ const FloatV S5 = V4GetY(sinCoefficients1);
+ const FloatV S6 = V4GetZ(sinCoefficients1);
+ const FloatV S7 = V4GetW(sinCoefficients1);
+ const FloatV S8 = V4GetX(sinCoefficients2);
+ const FloatV S9 = V4GetY(sinCoefficients2);
+ const FloatV S10 = V4GetZ(sinCoefficients2);
+ const FloatV S11 = V4GetW(sinCoefficients2);
+
+ Result = V4MulAdd(S1, V3, V1);
+ Result = V4MulAdd(S2, V5, Result);
+ Result = V4MulAdd(S3, V7, Result);
+ Result = V4MulAdd(S4, V9, Result);
+ Result = V4MulAdd(S5, V11, Result);
+ Result = V4MulAdd(S6, V13, Result);
+ Result = V4MulAdd(S7, V15, Result);
+ Result = V4MulAdd(S8, V17, Result);
+ Result = V4MulAdd(S9, V19, Result);
+ Result = V4MulAdd(S10, V21, Result);
+ Result = V4MulAdd(S11, V23, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Cos(const Vec4V a)
+{
+ // XMVECTOR V1, V2, V4, V6, V8, V10, V12, V14, V16, V18, V20, V22;
+ // XMVECTOR C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11;
+ Vec4V Result;
+
+ const Vec4V twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const Vec4V tmp = V4Mul(a, twoPi);
+ const Vec4V b = V4Round(tmp);
+ const Vec4V V1 = V4NegMulSub(twoPi, b, a);
+
+ // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
+ // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
+ const Vec4V V2 = V4Mul(V1, V1);
+ const Vec4V V4 = V4Mul(V2, V2);
+ const Vec4V V6 = V4Mul(V4, V2);
+ const Vec4V V8 = V4Mul(V4, V4);
+ const Vec4V V10 = V4Mul(V6, V4);
+ const Vec4V V12 = V4Mul(V6, V6);
+ const Vec4V V14 = V4Mul(V8, V6);
+ const Vec4V V16 = V4Mul(V8, V8);
+ const Vec4V V18 = V4Mul(V10, V8);
+ const Vec4V V20 = V4Mul(V10, V10);
+ const Vec4V V22 = V4Mul(V12, V10);
+
+ const Vec4V cosCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients0.f);
+ const Vec4V cosCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients1.f);
+ const Vec4V cosCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients2.f);
+
+ const FloatV C1 = V4GetY(cosCoefficients0);
+ const FloatV C2 = V4GetZ(cosCoefficients0);
+ const FloatV C3 = V4GetW(cosCoefficients0);
+ const FloatV C4 = V4GetX(cosCoefficients1);
+ const FloatV C5 = V4GetY(cosCoefficients1);
+ const FloatV C6 = V4GetZ(cosCoefficients1);
+ const FloatV C7 = V4GetW(cosCoefficients1);
+ const FloatV C8 = V4GetX(cosCoefficients2);
+ const FloatV C9 = V4GetY(cosCoefficients2);
+ const FloatV C10 = V4GetZ(cosCoefficients2);
+ const FloatV C11 = V4GetW(cosCoefficients2);
+
+ Result = V4MulAdd(C1, V2, V4One());
+ Result = V4MulAdd(C2, V4, Result);
+ Result = V4MulAdd(C3, V6, Result);
+ Result = V4MulAdd(C4, V8, Result);
+ Result = V4MulAdd(C5, V10, Result);
+ Result = V4MulAdd(C6, V12, Result);
+ Result = V4MulAdd(C7, V14, Result);
+ Result = V4MulAdd(C8, V16, Result);
+ Result = V4MulAdd(C9, V18, Result);
+ Result = V4MulAdd(C10, V20, Result);
+ Result = V4MulAdd(C11, V22, Result);
+
+ return Result;
+}
+
+//////////////////////////////////
+// VEC4V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE BoolV BFFFF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0, 0, 0 };
+ const __m128 ffff = _mm_load_ps((float *)&f);
+ return ffff;
+}
+
+QT3DS_FORCE_INLINE BoolV BFFFT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0, 0, 0xFFFFFFFF };
+ const __m128 ffft = _mm_load_ps((float *)&f);
+ return ffft;
+}
+
+QT3DS_FORCE_INLINE BoolV BFFTF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0, 0xFFFFFFFF, 0 };
+ const __m128 fftf = _mm_load_ps((float *)&f);
+ return fftf;
+}
+
+QT3DS_FORCE_INLINE BoolV BFFTT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0, 0xFFFFFFFF, 0xFFFFFFFF };
+ const __m128 fftt = _mm_load_ps((float *)&f);
+ return fftt;
+}
+
+QT3DS_FORCE_INLINE BoolV BFTFF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0xFFFFFFFF, 0, 0 };
+ const __m128 ftff = _mm_load_ps((float *)&f);
+ return ftff;
+}
+
+QT3DS_FORCE_INLINE BoolV BFTFT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0xFFFFFFFF, 0, 0xFFFFFFFF };
+ const __m128 ftft = _mm_load_ps((float *)&f);
+ return ftft;
+}
+
+QT3DS_FORCE_INLINE BoolV BFTTF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0xFFFFFFFF, 0xFFFFFFFF, 0 };
+ const __m128 fttf = _mm_load_ps((float *)&f);
+ return fttf;
+}
+
+QT3DS_FORCE_INLINE BoolV BFTTT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ const __m128 fttt = _mm_load_ps((float *)&f);
+ return fttt;
+}
+
+QT3DS_FORCE_INLINE BoolV BTFFF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0, 0, 0 };
+ const __m128 tfff = _mm_load_ps((float *)&f);
+ return tfff;
+}
+
+QT3DS_FORCE_INLINE BoolV BTFFT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0, 0, 0xFFFFFFFF };
+ const __m128 tfft = _mm_load_ps((float *)&f);
+ return tfft;
+}
+
+QT3DS_FORCE_INLINE BoolV BTFTF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0, 0xFFFFFFFF, 0 };
+ const __m128 tftf = _mm_load_ps((float *)&f);
+ return tftf;
+}
+
+QT3DS_FORCE_INLINE BoolV BTFTT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0, 0xFFFFFFFF, 0xFFFFFFFF };
+ const __m128 tftt = _mm_load_ps((float *)&f);
+ return tftt;
+}
+
+QT3DS_FORCE_INLINE BoolV BTTFF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0, 0 };
+ const __m128 ttff = _mm_load_ps((float *)&f);
+ return ttff;
+}
+
+QT3DS_FORCE_INLINE BoolV BTTFT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0, 0xFFFFFFFF };
+ const __m128 ttft = _mm_load_ps((float *)&f);
+ return ttft;
+}
+
+QT3DS_FORCE_INLINE BoolV BTTTF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0 };
+ const __m128 tttf = _mm_load_ps((float *)&f);
+ return tttf;
+}
+
+QT3DS_FORCE_INLINE BoolV BTTTT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ const __m128 tttt = _mm_load_ps((float *)&f);
+ return tttt;
+}
+
+QT3DS_FORCE_INLINE BoolV BXMask()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0xFFFFFFFF, 0, 0, 0 };
+ const __m128 tfff = _mm_load_ps((float *)&f);
+ return tfff;
+}
+
+QT3DS_FORCE_INLINE BoolV BYMask()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0xFFFFFFFF, 0, 0 };
+ const __m128 ftff = _mm_load_ps((float *)&f);
+ return ftff;
+}
+
+QT3DS_FORCE_INLINE BoolV BZMask()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0, 0xFFFFFFFF, 0 };
+ const __m128 fftf = _mm_load_ps((float *)&f);
+ return fftf;
+}
+
+QT3DS_FORCE_INLINE BoolV BWMask()
+{
+ const QT3DS_ALIGN(16, QT3DSU32) f[4] = { 0, 0, 0, 0xFFFFFFFF };
+ const __m128 ffft = _mm_load_ps((float *)&f);
+ return ffft;
+}
+
+QT3DS_FORCE_INLINE BoolV BGetX(const BoolV f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
+}
+
+QT3DS_FORCE_INLINE BoolV BGetY(const BoolV f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
+}
+
+QT3DS_FORCE_INLINE BoolV BGetZ(const BoolV f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
+}
+
+QT3DS_FORCE_INLINE BoolV BGetW(const BoolV f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(3, 3, 3, 3));
+}
+
+QT3DS_FORCE_INLINE BoolV BAnd(const BoolV a, const BoolV b)
+{
+ return (_mm_and_ps(a, b));
+}
+
+QT3DS_FORCE_INLINE BoolV BNot(const BoolV a)
+{
+ const BoolV bAllTrue(BTTTT());
+ return _mm_xor_ps(a, bAllTrue);
+}
+
+QT3DS_FORCE_INLINE BoolV BAndNot(const BoolV a, const BoolV b)
+{
+ return (_mm_andnot_ps(a, b));
+}
+
+QT3DS_FORCE_INLINE BoolV BOr(const BoolV a, const BoolV b)
+{
+ return (_mm_or_ps(a, b));
+}
+
+QT3DS_FORCE_INLINE BoolV BAllTrue4(const BoolV a)
+{
+ const BoolV bTmp = _mm_and_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 3, 2, 3)));
+ return _mm_and_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
+}
+
+QT3DS_FORCE_INLINE BoolV BAnyTrue4(const BoolV a)
+{
+ const BoolV bTmp = _mm_or_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 3, 2, 3)));
+ return _mm_or_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
+}
+
+QT3DS_FORCE_INLINE BoolV BAllTrue3(const BoolV a)
+{
+ const BoolV bTmp = _mm_and_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
+ return _mm_and_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
+}
+
+QT3DS_FORCE_INLINE BoolV BAnyTrue3(const BoolV a)
+{
+ const BoolV bTmp = _mm_or_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
+ return _mm_or_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAllEq(const BoolV a, const BoolV b)
+{
+ const BoolV bTest = m128_I2F(_mm_cmpeq_epi32(m128_F2I(a), m128_F2I(b)));
+ return BAllTrue4_R(bTest);
+}
+
+//////////////////////////////////
+// MAT33V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec3V M33MulV3(const Mat33V &a, const Vec3V b)
+{
+ const FloatV x = V3GetX(b);
+ const FloatV y = V3GetY(b);
+ const FloatV z = V3GetZ(b);
+ const Vec3V v0 = V3Scale(a.col0, x);
+ const Vec3V v1 = V3Scale(a.col1, y);
+ const Vec3V v2 = V3Scale(a.col2, z);
+ const Vec3V v0PlusV1 = V3Add(v0, v1);
+ return V3Add(v0PlusV1, v2);
+}
+
+QT3DS_FORCE_INLINE Vec3V M33TrnspsMulV3(const Mat33V &a, const Vec3V b)
+{
+ const FloatV x = V3Dot(a.col0, b);
+ const FloatV y = V3Dot(a.col1, b);
+ const FloatV z = V3Dot(a.col2, b);
+ return V3Merge(x, y, z);
+}
+
+QT3DS_FORCE_INLINE Vec3V M33MulV3AddV3(const Mat33V &A, const Vec3V b, const Vec3V c)
+{
+ const FloatV x = V3GetX(b);
+ const FloatV y = V3GetY(b);
+ const FloatV z = V3GetZ(b);
+ Vec3V result = V3MulAdd(A.col0, x, c);
+ result = V3MulAdd(A.col1, y, result);
+ return V3MulAdd(A.col2, z, result);
+}
+
+QT3DS_FORCE_INLINE Mat33V M33MulM33(const Mat33V &a, const Mat33V &b)
+{
+ return Mat33V(M33MulV3(a, b.col0), M33MulV3(a, b.col1), M33MulV3(a, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Add(const Mat33V &a, const Mat33V &b)
+{
+ return Mat33V(V3Add(a.col0, b.col0), V3Add(a.col1, b.col1), V3Add(a.col2, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Inverse(const Mat33V &a)
+{
+ const BoolV tfft = BTFFT();
+ const BoolV tttf = BTTTF();
+ const FloatV zero = FloatV_From_F32(0.0f);
+ const Vec3V cross01 = V3Cross(a.col0, a.col1);
+ const Vec3V cross12 = V3Cross(a.col1, a.col2);
+ const Vec3V cross20 = V3Cross(a.col2, a.col0);
+ const FloatV dot = V3Dot(cross01, a.col2);
+ const FloatV invDet = _mm_rcp_ps(dot);
+ const Vec3V mergeh = _mm_unpacklo_ps(cross12, cross01);
+ const Vec3V mergel = _mm_unpackhi_ps(cross12, cross01);
+ Vec3V colInv0 = _mm_unpacklo_ps(mergeh, cross20);
+ colInv0 = _mm_or_ps(_mm_andnot_ps(tttf, zero), _mm_and_ps(tttf, colInv0));
+ const Vec3V zppd = _mm_shuffle_ps(mergeh, cross20, _MM_SHUFFLE(3, 0, 0, 2));
+ const Vec3V pbwp = _mm_shuffle_ps(cross20, mergeh, _MM_SHUFFLE(3, 3, 1, 0));
+ const Vec3V colInv1 = _mm_or_ps(_mm_andnot_ps(BTFFT(), pbwp), _mm_and_ps(BTFFT(), zppd));
+ const Vec3V xppd = _mm_shuffle_ps(mergel, cross20, _MM_SHUFFLE(3, 0, 0, 0));
+ const Vec3V pcyp = _mm_shuffle_ps(cross20, mergel, _MM_SHUFFLE(3, 1, 2, 0));
+ const Vec3V colInv2 = _mm_or_ps(_mm_andnot_ps(tfft, pcyp), _mm_and_ps(tfft, xppd));
+
+ return Mat33V(_mm_mul_ps(colInv0, invDet), _mm_mul_ps(colInv1, invDet),
+ _mm_mul_ps(colInv2, invDet));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Trnsps(const Mat33V &a)
+{
+ return Mat33V(V3Merge(V3GetX(a.col0), V3GetX(a.col1), V3GetX(a.col2)),
+ V3Merge(V3GetY(a.col0), V3GetY(a.col1), V3GetY(a.col2)),
+ V3Merge(V3GetZ(a.col0), V3GetZ(a.col1), V3GetZ(a.col2)));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Identity()
+{
+ return Mat33V(V3UnitX(), V3UnitY(), V3UnitZ());
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Sub(const Mat33V &a, const Mat33V &b)
+{
+ return Mat33V(V3Sub(a.col0, b.col0), V3Sub(a.col1, b.col1), V3Sub(a.col2, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Neg(const Mat33V &a)
+{
+ return Mat33V(V3Neg(a.col0), V3Neg(a.col1), V3Neg(a.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Abs(const Mat33V &a)
+{
+ return Mat33V(V3Abs(a.col0), V3Abs(a.col1), V3Abs(a.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V PromoteVec3V(const Vec3V v)
+{
+ const BoolV bTFFF = BTFFF();
+ const BoolV bFTFF = BFTFF();
+ const BoolV bFFTF = BTFTF();
+
+ const Vec3V zero = V3Zero();
+
+ return Mat33V(V3Sel(bTFFF, v, zero), V3Sel(bFTFF, v, zero), V3Sel(bFFTF, v, zero));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Diagonal(const Vec3VArg d)
+{
+ const FloatV x = V3Mul(V3UnitX(), d);
+ const FloatV y = V3Mul(V3UnitY(), d);
+ const FloatV z = V3Mul(V3UnitZ(), d);
+ return Mat33V(x, y, z);
+}
+
+//////////////////////////////////
+// MAT34V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec3V M34MulV3(const Mat34V &a, const Vec3V b)
+{
+ const FloatV x = V3GetX(b);
+ const FloatV y = V3GetY(b);
+ const FloatV z = V3GetZ(b);
+ const Vec3V v0 = V3Scale(a.col0, x);
+ const Vec3V v1 = V3Scale(a.col1, y);
+ const Vec3V v2 = V3Scale(a.col2, z);
+ const Vec3V v0PlusV1 = V3Add(v0, v1);
+ const Vec3V v0PlusV1Plusv2 = V3Add(v0PlusV1, v2);
+ return (V3Add(v0PlusV1Plusv2, a.col3));
+}
+
+QT3DS_FORCE_INLINE Vec3V M34Mul33V3(const Mat34V &a, const Vec3V b)
+{
+ const FloatV x = V3GetX(b);
+ const FloatV y = V3GetY(b);
+ const FloatV z = V3GetZ(b);
+ const Vec3V v0 = V3Scale(a.col0, x);
+ const Vec3V v1 = V3Scale(a.col1, y);
+ const Vec3V v2 = V3Scale(a.col2, z);
+ const Vec3V v0PlusV1 = V3Add(v0, v1);
+ return V3Add(v0PlusV1, v2);
+}
+
+QT3DS_FORCE_INLINE Vec3V M34TrnspsMul33V3(const Mat34V &a, const Vec3V b)
+{
+ const FloatV x = V3Dot(a.col0, b);
+ const FloatV y = V3Dot(a.col1, b);
+ const FloatV z = V3Dot(a.col2, b);
+ return V3Merge(x, y, z);
+}
+
+QT3DS_FORCE_INLINE Mat34V M34MulM34(const Mat34V &a, const Mat34V &b)
+{
+ return Mat34V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2),
+ M34MulV3(a, b.col3));
+}
+
+QT3DS_FORCE_INLINE Mat33V M34MulM33(const Mat34V &a, const Mat33V &b)
+{
+ return Mat33V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M34Mul33MM34(const Mat34V &a, const Mat34V &b)
+{
+ return Mat33V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat34V M34Add(const Mat34V &a, const Mat34V &b)
+{
+ return Mat34V(V3Add(a.col0, b.col0), V3Add(a.col1, b.col1), V3Add(a.col2, b.col2),
+ V3Add(a.col3, b.col3));
+}
+
+QT3DS_FORCE_INLINE Mat34V M34InverseV(const Mat34V &a)
+{
+ Mat34V aInv;
+ const BoolV tfft = BTFFT();
+ const BoolV tttf = BTTTF();
+ const FloatV zero = FloatV_From_F32(0.0f);
+ const Vec3V cross01 = V3Cross(a.col0, a.col1);
+ const Vec3V cross12 = V3Cross(a.col1, a.col2);
+ const Vec3V cross20 = V3Cross(a.col2, a.col0);
+ const FloatV dot = V3Dot(cross01, a.col2);
+ const FloatV invDet = _mm_rcp_ps(dot);
+ const Vec3V mergeh = _mm_unpacklo_ps(cross12, cross01);
+ const Vec3V mergel = _mm_unpackhi_ps(cross12, cross01);
+ Vec3V colInv0 = _mm_unpacklo_ps(mergeh, cross20);
+ colInv0 = _mm_or_ps(_mm_andnot_ps(tttf, zero), _mm_and_ps(tttf, colInv0));
+ const Vec3V zppd = _mm_shuffle_ps(mergeh, cross20, _MM_SHUFFLE(3, 0, 0, 2));
+ const Vec3V pbwp = _mm_shuffle_ps(cross20, mergeh, _MM_SHUFFLE(3, 3, 1, 0));
+ const Vec3V colInv1 = _mm_or_ps(_mm_andnot_ps(BTFFT(), pbwp), _mm_and_ps(BTFFT(), zppd));
+ const Vec3V xppd = _mm_shuffle_ps(mergel, cross20, _MM_SHUFFLE(3, 0, 0, 0));
+ const Vec3V pcyp = _mm_shuffle_ps(cross20, mergel, _MM_SHUFFLE(3, 1, 2, 0));
+ const Vec3V colInv2 = _mm_or_ps(_mm_andnot_ps(tfft, pcyp), _mm_and_ps(tfft, xppd));
+ aInv.col0 = _mm_mul_ps(colInv0, invDet);
+ aInv.col1 = _mm_mul_ps(colInv1, invDet);
+ aInv.col2 = _mm_mul_ps(colInv2, invDet);
+ aInv.col3 = M34Mul33V3(aInv, V3Neg(a.col3));
+ return aInv;
+}
+
+QT3DS_FORCE_INLINE Mat33V M34Trnsps33(const Mat34V &a)
+{
+ return Mat33V(V3Merge(V3GetX(a.col0), V3GetX(a.col1), V3GetX(a.col2)),
+ V3Merge(V3GetY(a.col0), V3GetY(a.col1), V3GetY(a.col2)),
+ V3Merge(V3GetZ(a.col0), V3GetZ(a.col1), V3GetZ(a.col2)));
+}
+
+//////////////////////////////////
+// MAT44V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec4V M44MulV4(const Mat44V &a, const Vec4V b)
+{
+ const FloatV x = V4GetX(b);
+ const FloatV y = V4GetY(b);
+ const FloatV z = V4GetZ(b);
+ const FloatV w = V4GetW(b);
+
+ const Vec4V v0 = V4Scale(a.col0, x);
+ const Vec4V v1 = V4Scale(a.col1, y);
+ const Vec4V v2 = V4Scale(a.col2, z);
+ const Vec4V v3 = V4Scale(a.col3, w);
+ const Vec4V v0PlusV1 = V4Add(v0, v1);
+ const Vec4V v0PlusV1Plusv2 = V4Add(v0PlusV1, v2);
+ return (V4Add(v0PlusV1Plusv2, v3));
+}
+
+QT3DS_FORCE_INLINE Vec4V M44TrnspsMulV4(const Mat44V &a, const Vec4V b)
+{
+ QT3DS_ALIGN(16, FloatV)
+ dotProdArray[4] = { V4Dot(a.col0, b), V4Dot(a.col1, b), V4Dot(a.col2, b), V4Dot(a.col3, b) };
+ return V4Merge(dotProdArray);
+}
+
+QT3DS_FORCE_INLINE Mat44V M44MulM44(const Mat44V &a, const Mat44V &b)
+{
+ return Mat44V(M44MulV4(a, b.col0), M44MulV4(a, b.col1), M44MulV4(a, b.col2),
+ M44MulV4(a, b.col3));
+}
+
+QT3DS_FORCE_INLINE Mat44V M44Add(const Mat44V &a, const Mat44V &b)
+{
+ return Mat44V(V4Add(a.col0, b.col0), V4Add(a.col1, b.col1), V4Add(a.col2, b.col2),
+ V4Add(a.col3, b.col3));
+}
+
+QT3DS_FORCE_INLINE Mat44V M44Trnsps(const Mat44V &a)
+{
+ const Vec4V v0 = _mm_unpacklo_ps(a.col0, a.col2);
+ const Vec4V v1 = _mm_unpackhi_ps(a.col0, a.col2);
+ const Vec4V v2 = _mm_unpacklo_ps(a.col1, a.col3);
+ const Vec4V v3 = _mm_unpackhi_ps(a.col1, a.col3);
+ return Mat44V(_mm_unpacklo_ps(v0, v2), _mm_unpackhi_ps(v0, v2), _mm_unpacklo_ps(v1, v3),
+ _mm_unpackhi_ps(v1, v3));
+}
+
+QT3DS_FORCE_INLINE Mat44V M44Inverse(const Mat44V &a)
+{
+ __m128 minor0, minor1, minor2, minor3;
+ __m128 row0, row1, row2, row3;
+ __m128 det, tmp1;
+
+ tmp1 = FloatV_From_F32(0.0f);
+ row1 = FloatV_From_F32(0.0f);
+ row3 = FloatV_From_F32(0.0f);
+
+ row0 = a.col0;
+ row1 = _mm_shuffle_ps(a.col1, a.col1, _MM_SHUFFLE(1, 0, 3, 2));
+ row2 = a.col2;
+ row3 = _mm_shuffle_ps(a.col3, a.col3, _MM_SHUFFLE(1, 0, 3, 2));
+
+ tmp1 = _mm_mul_ps(row2, row3);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor0 = _mm_mul_ps(row1, tmp1);
+ minor1 = _mm_mul_ps(row0, tmp1);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor0 = _mm_sub_ps(_mm_mul_ps(row1, tmp1), minor0);
+ minor1 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor1);
+ minor1 = _mm_shuffle_ps(minor1, minor1, 0x4E);
+
+ tmp1 = _mm_mul_ps(row1, row2);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor0 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor0);
+ minor3 = _mm_mul_ps(row0, tmp1);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor0 = _mm_sub_ps(minor0, _mm_mul_ps(row3, tmp1));
+ minor3 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor3);
+ minor3 = _mm_shuffle_ps(minor3, minor3, 0x4E);
+
+ tmp1 = _mm_mul_ps(_mm_shuffle_ps(row1, row1, 0x4E), row3);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ row2 = _mm_shuffle_ps(row2, row2, 0x4E);
+ minor0 = _mm_add_ps(_mm_mul_ps(row2, tmp1), minor0);
+ minor2 = _mm_mul_ps(row0, tmp1);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor0 = _mm_sub_ps(minor0, _mm_mul_ps(row2, tmp1));
+ minor2 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor2);
+ minor2 = _mm_shuffle_ps(minor2, minor2, 0x4E);
+
+ tmp1 = _mm_mul_ps(row0, row1);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor2 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor2);
+ minor3 = _mm_sub_ps(_mm_mul_ps(row2, tmp1), minor3);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor2 = _mm_sub_ps(_mm_mul_ps(row3, tmp1), minor2);
+ minor3 = _mm_sub_ps(minor3, _mm_mul_ps(row2, tmp1));
+
+ tmp1 = _mm_mul_ps(row0, row3);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor1 = _mm_sub_ps(minor1, _mm_mul_ps(row2, tmp1));
+ minor2 = _mm_add_ps(_mm_mul_ps(row1, tmp1), minor2);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor1 = _mm_add_ps(_mm_mul_ps(row2, tmp1), minor1);
+ minor2 = _mm_sub_ps(minor2, _mm_mul_ps(row1, tmp1));
+
+ tmp1 = _mm_mul_ps(row0, row2);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor1 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor1);
+ minor3 = _mm_sub_ps(minor3, _mm_mul_ps(row1, tmp1));
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor1 = _mm_sub_ps(minor1, _mm_mul_ps(row3, tmp1));
+ minor3 = _mm_add_ps(_mm_mul_ps(row1, tmp1), minor3);
+
+ det = _mm_mul_ps(row0, minor0);
+ det = _mm_add_ps(_mm_shuffle_ps(det, det, 0x4E), det);
+ det = _mm_add_ss(_mm_shuffle_ps(det, det, 0xB1), det);
+ tmp1 = _mm_rcp_ss(det);
+#if 0
+ det = _mm_sub_ss(_mm_add_ss(tmp1, tmp1), _mm_mul_ss(det, _mm_mul_ss(tmp1, tmp1)));
+ det = _mm_shuffle_ps(det, det, 0x00);
+#else
+ det = _mm_shuffle_ps(tmp1, tmp1, _MM_SHUFFLE(0, 0, 0, 0));
+#endif
+
+ minor0 = _mm_mul_ps(det, minor0);
+ minor1 = _mm_mul_ps(det, minor1);
+ minor2 = _mm_mul_ps(det, minor2);
+ minor3 = _mm_mul_ps(det, minor3);
+ Mat44V invTrans(minor0, minor1, minor2, minor3);
+ return M44Trnsps(invTrans);
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_XYZW(QT3DSF32 x, QT3DSF32 y, QT3DSF32 z, QT3DSF32 w)
+{
+ return _mm_set_ps(w, z, y, x);
+}
+
+// AP: work in progress - use proper SSE intrinsics where possible
+QT3DS_FORCE_INLINE VecU16V V4U32PK(VecU32V a, VecU32V b)
+{
+ VecU16V result;
+ result.m128_u16[0] = QT3DSU16(NVClamp<QT3DSU32>((a).m128_u32[0], 0, 0xFFFF));
+ result.m128_u16[1] = QT3DSU16(NVClamp<QT3DSU32>((a).m128_u32[1], 0, 0xFFFF));
+ result.m128_u16[2] = QT3DSU16(NVClamp<QT3DSU32>((a).m128_u32[2], 0, 0xFFFF));
+ result.m128_u16[3] = QT3DSU16(NVClamp<QT3DSU32>((a).m128_u32[3], 0, 0xFFFF));
+ result.m128_u16[4] = QT3DSU16(NVClamp<QT3DSU32>((b).m128_u32[0], 0, 0xFFFF));
+ result.m128_u16[5] = QT3DSU16(NVClamp<QT3DSU32>((b).m128_u32[1], 0, 0xFFFF));
+ result.m128_u16[6] = QT3DSU16(NVClamp<QT3DSU32>((b).m128_u32[2], 0, 0xFFFF));
+ result.m128_u16[7] = QT3DSU16(NVClamp<QT3DSU32>((b).m128_u32[3], 0, 0xFFFF));
+ return result;
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U32or(VecU32V a, VecU32V b)
+{
+ return m128_I2F(_mm_or_si128(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U32and(VecU32V a, VecU32V b)
+{
+ return m128_I2F(_mm_and_si128(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U32Andc(VecU32V a, VecU32V b)
+{
+ return m128_I2F(_mm_andnot_si128(m128_F2I(b), m128_F2I(a)));
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16Or(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_or_si128(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16And(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_and_si128(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16Andc(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_andnot_si128(m128_F2I(b), m128_F2I(a)));
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_From_I32(const QT3DSI32 i)
+{
+ return (_mm_load1_ps((QT3DSF32 *)&i));
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_From_I32Array(const QT3DSI32 *i)
+{
+ return _mm_loadu_ps((QT3DSF32 *)i);
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_From_I32Array_Aligned(const QT3DSI32 *i)
+{
+ return _mm_load_ps((QT3DSF32 *)i);
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_Add(const VecI32VArg a, const VecI32VArg b)
+{
+ return m128_I2F(_mm_add_epi32(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_Sub(const VecI32VArg a, const VecI32VArg b)
+{
+ return m128_I2F(_mm_sub_epi32(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE BoolV VecI32V_IsGrtr(const VecI32VArg a, const VecI32VArg b)
+{
+ return m128_I2F(_mm_cmpgt_epi32(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE BoolV VecI32V_IsEq(const VecI32VArg a, const VecI32VArg b)
+{
+ return m128_I2F(_mm_cmpeq_epi32(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_Zero()
+{
+ return V4Zero();
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_Merge(const VecI32VArg a, const VecI32VArg b, const VecI32VArg c,
+ const VecI32VArg d)
+{
+ return V4Merge(a, b, c, d);
+}
+
+template <int a>
+QT3DS_FORCE_INLINE VecI32V V4ISplat()
+{
+ VecI32V result;
+ result.m128_i32[0] = a;
+ result.m128_i32[1] = a;
+ result.m128_i32[2] = a;
+ result.m128_i32[3] = a;
+ return result;
+}
+
+QT3DS_FORCE_INLINE void V4U16StoreAligned(VecU16V val, VecU16V *address)
+{
+ *address = val;
+}
+
+QT3DS_FORCE_INLINE void V4U32StoreAligned(VecU32V val, VecU32V *address)
+{
+ *address = val;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4LoadAligned(Vec4V *addr)
+{
+ return *addr;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4LoadUnaligned(Vec4V *addr)
+{
+ return Vec4V_From_F32Array((float *)addr);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Andc(const Vec4V a, const VecU32V b)
+{
+ VecU32V result32(a);
+ result32 = V4U32Andc(result32, b);
+ return Vec4V(result32);
+}
+
+QT3DS_FORCE_INLINE VecU32V V4IsGrtrV32u(const Vec4V a, const Vec4V b)
+{
+ return V4IsGrtr(a, b);
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16LoadAligned(VecU16V *addr)
+{
+ return *addr;
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16LoadUnaligned(VecU16V *addr)
+{
+ return *addr;
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16CompareGt(VecU16V a, VecU16V b)
+{
+ // _mm_cmpgt_epi16 doesn't work for unsigned values unfortunately
+ // return m128_I2F(_mm_cmpgt_epi16(m128_F2I(a), m128_F2I(b)));
+ VecU16V result;
+ result.m128_u16[0] = (a).m128_u16[0] > (b).m128_u16[0];
+ result.m128_u16[1] = (a).m128_u16[1] > (b).m128_u16[1];
+ result.m128_u16[2] = (a).m128_u16[2] > (b).m128_u16[2];
+ result.m128_u16[3] = (a).m128_u16[3] > (b).m128_u16[3];
+ result.m128_u16[4] = (a).m128_u16[4] > (b).m128_u16[4];
+ result.m128_u16[5] = (a).m128_u16[5] > (b).m128_u16[5];
+ result.m128_u16[6] = (a).m128_u16[6] > (b).m128_u16[6];
+ result.m128_u16[7] = (a).m128_u16[7] > (b).m128_u16[7];
+ return result;
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_VecU32V(VecU32V a)
+{
+ Vec4V result = Vec4V_From_XYZW(QT3DSF32(a.m128_u32[0]), QT3DSF32(a.m128_u32[1]), QT3DSF32(a.m128_u32[2]),
+ QT3DSF32(a.m128_u32[3]));
+ return result;
+}
+
+template <int index>
+QT3DS_FORCE_INLINE VecU32V V4U32SplatElement(VecU32V a)
+{
+ VecU32V result;
+ result.m128_u32[0] = result.m128_u32[1] = result.m128_u32[2] = result.m128_u32[3] =
+ a.m128_u32[index];
+ return result;
+}
+
+template <int index>
+QT3DS_FORCE_INLINE Vec4V V4SplatElement(Vec4V a)
+{
+ float *data = (float *)&a;
+ return Vec4V_From_F32(data[index]);
+}
+
+template <int index>
+QT3DS_FORCE_INLINE VecU16V V4U16SplatElement(VecU16V a)
+{
+ VecU16V result;
+ for (int i = 0; i < 8; i++)
+ result.m128_u16[i] = a.m128_u16[index];
+ return result;
+}
+
+template <int imm>
+QT3DS_FORCE_INLINE VecI16V V4I16SplatImmediate()
+{
+ VecI16V result;
+ result.m128_i16[0] = imm;
+ result.m128_i16[1] = imm;
+ result.m128_i16[2] = imm;
+ result.m128_i16[3] = imm;
+ result.m128_i16[4] = imm;
+ result.m128_i16[5] = imm;
+ result.m128_i16[6] = imm;
+ result.m128_i16[7] = imm;
+ return result;
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16SubtractModulo(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_sub_epi16(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16AddModulo(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_add_epi16(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U16GetLo16(VecU16V a)
+{
+ VecU32V result;
+ result.m128_u32[0] = a.m128_u16[0];
+ result.m128_u32[1] = a.m128_u16[2];
+ result.m128_u32[2] = a.m128_u16[4];
+ result.m128_u32[3] = a.m128_u16[6];
+ return result;
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U16GetHi16(VecU16V a)
+{
+ VecU32V result;
+ result.m128_u32[0] = a.m128_u16[1];
+ result.m128_u32[1] = a.m128_u16[3];
+ result.m128_u32[2] = a.m128_u16[5];
+ result.m128_u32[3] = a.m128_u16[7];
+ return result;
+}
+
+QT3DS_FORCE_INLINE VecU32V VecU32V_From_XYZW(QT3DSU32 x, QT3DSU32 y, QT3DSU32 z, QT3DSU32 w)
+{
+ VecU32V result;
+ result.m128_u32[0] = x;
+ result.m128_u32[1] = y;
+ result.m128_u32[2] = z;
+ result.m128_u32[3] = w;
+ return result;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Ceil(const Vec4V in)
+{
+ UnionM128 a(in);
+ return Vec4V_From_XYZW(NVCeil(a.m128_f32[0]), NVCeil(a.m128_f32[1]), NVCeil(a.m128_f32[2]),
+ NVCeil(a.m128_f32[3]));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Floor(const Vec4V in)
+{
+ UnionM128 a(in);
+ return Vec4V_From_XYZW(NVFloor(a.m128_f32[0]), NVFloor(a.m128_f32[1]), NVFloor(a.m128_f32[2]),
+ NVFloor(a.m128_f32[3]));
+}
+
+QT3DS_FORCE_INLINE VecU32V V4ConvertToU32VSaturate(const Vec4V in, QT3DSU32 power)
+{
+ QT3DS_ASSERT(power == 0 && "Non-zero power not supported in convertToU32VSaturate");
+ QT3DS_FORCE_PARAMETER_REFERENCE(power); // prevent warning in release builds
+ QT3DSF32 ffffFFFFasFloat = QT3DSF32(0xFFFF0000);
+ UnionM128 a(in);
+ VecU32V result;
+ result.m128_u32[0] = QT3DSU32(NVClamp<QT3DSF32>((a).m128_f32[0], 0.0f, ffffFFFFasFloat));
+ result.m128_u32[1] = QT3DSU32(NVClamp<QT3DSF32>((a).m128_f32[1], 0.0f, ffffFFFFasFloat));
+ result.m128_u32[2] = QT3DSU32(NVClamp<QT3DSF32>((a).m128_f32[2], 0.0f, ffffFFFFasFloat));
+ result.m128_u32[3] = QT3DSU32(NVClamp<QT3DSF32>((a).m128_f32[3], 0.0f, ffffFFFFasFloat));
+ return result;
+}
+
+#endif // QT3DS_LINUX_INLINE_AOS_H
diff --git a/src/foundation/linux/Qt3DSLinuxIntrinsics.h b/src/foundation/linux/Qt3DSLinuxIntrinsics.h
new file mode 100644
index 0000000..7097460
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxIntrinsics.h
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_LINUX_INTRINSICS_H
+#define QT3DS_FOUNDATION_QT3DS_LINUX_INTRINSICS_H
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAssert.h"
+
+#if !(defined QT3DS_LINUX || defined QT3DS_ANDROID || defined QT3DS_APPLE || defined QT3DS_QNX)
+#error "This file should only be included by Linux builds!!"
+#endif
+
+#include <cmath>
+#include <math.h>
+#include <float.h>
+#include <string.h>
+
+namespace qt3ds {
+namespace intrinsics {
+ //! \brief platform-specific absolute value
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float abs(float a) { return ::fabs(a); }
+
+ //! \brief platform-specific select float
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float fsel(float a, float b, float c)
+ {
+ return (a >= 0.0f) ? b : c;
+ }
+
+ //! \brief platform-specific sign
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float sign(float a) { return (a >= 0.0f) ? 1.0f : -1.0f; }
+
+ //! \brief platform-specific reciprocal
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float recip(float a) { return 1.0f / a; }
+
+ //! \brief platform-specific reciprocal estimate
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float recipFast(float a) { return 1.0f / a; }
+
+ //! \brief platform-specific square root
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float sqrt(float a) { return ::sqrtf(a); }
+
+ //! \brief platform-specific reciprocal square root
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float recipSqrt(float a) { return 1.0f / ::sqrtf(a); }
+
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float recipSqrtFast(float a) { return 1.0f / ::sqrtf(a); }
+
+ //! \brief platform-specific sine
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float sin(float a) { return ::sinf(a); }
+
+ //! \brief platform-specific cosine
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float cos(float a) { return ::cosf(a); }
+
+ //! \brief platform-specific minimum
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float selectMin(float a, float b) { return a < b ? a : b; }
+
+ //! \brief platform-specific maximum
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float selectMax(float a, float b) { return a > b ? a : b; }
+
+ //! \brief platform-specific finiteness check (not INF or NAN)
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isFinite(float a) { return std::isfinite(a); }
+
+ //! \brief platform-specific finiteness check (not INF or NAN)
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isFinite(double a) { return std::isfinite(a); }
+ QT3DS_FORCE_INLINE void memoryBarrier()
+ {
+#if 0 //!defined (QT3DS_ARM)
+ smp_mb();
+#endif
+ }
+
+ /*!
+ Return the index of the highest set bit. Undefined for zero arg.
+ */
+ QT3DS_INLINE QT3DSU32 highestSetBitUnsafe(QT3DSU32 v)
+ {
+
+ // http://graphics.stanford.edu/~seander/bithacks.html
+ static const QT3DSU32 MultiplyDeBruijnBitPosition[32] = { 0, 9, 1, 10, 13, 21, 2, 29,
+ 11, 14, 16, 18, 22, 25, 3, 30,
+ 8, 12, 20, 28, 15, 17, 24, 7,
+ 19, 27, 23, 6, 26, 5, 4, 31 };
+
+ v |= v >> 1; // first round up to one less than a power of 2
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+
+ return MultiplyDeBruijnBitPosition[(QT3DSU32)(v * 0x07C4ACDDU) >> 27];
+ }
+
+ /*!
+ Return the index of the highest set bit. Undefined for zero arg.
+ */
+ QT3DS_INLINE QT3DSI32 lowestSetBitUnsafe(QT3DSU32 v)
+ {
+ // http://graphics.stanford.edu/~seander/bithacks.html
+ static const QT3DSU32 MultiplyDeBruijnBitPosition[32] = { 0, 1, 28, 2, 29, 14, 24, 3,
+ 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7,
+ 26, 12, 18, 6, 11, 5, 10, 9 };
+ QT3DSI32 w = v;
+ return MultiplyDeBruijnBitPosition[(QT3DSU32)((w & -w) * 0x077CB531U) >> 27];
+ }
+
+ /*!
+ Returns the index of the highest set bit. Undefined for zero arg.
+ */
+ QT3DS_INLINE QT3DSU32 countLeadingZeros(QT3DSU32 v)
+ {
+ QT3DSI32 result = 0;
+#ifdef _INTEGRITYPLATFORM
+ QT3DSU32 testBit = (1U << 31);
+#else
+ QT3DSU32 testBit = (1 << 31);
+#endif
+ while ((v & testBit) == 0 && testBit != 0)
+ result++, testBit >>= 1;
+ return result;
+ }
+
+ /*!
+ Sets \c count bytes starting at \c dst to zero.
+ */
+ QT3DS_FORCE_INLINE void *memZero(void *QT3DS_RESTRICT dest, QT3DSU32 count)
+ {
+ return memset(dest, 0, count);
+ }
+
+ /*!
+ Sets \c count bytes starting at \c dst to \c c.
+ */
+ QT3DS_FORCE_INLINE void *memSet(void *QT3DS_RESTRICT dest, QT3DSI32 c, QT3DSU32 count)
+ {
+ return memset(dest, c, count);
+ }
+
+ /*!
+ Copies \c count bytes from \c src to \c dst. User memMove if regions overlap.
+ */
+ QT3DS_FORCE_INLINE void *memCopy(void *QT3DS_RESTRICT dest, const void *QT3DS_RESTRICT src, QT3DSU32 count)
+ {
+ return memcpy(dest, src, count);
+ }
+
+ /*!
+ Copies \c count bytes from \c src to \c dst. Supports overlapping regions.
+ */
+ QT3DS_FORCE_INLINE void *memMove(void *QT3DS_RESTRICT dest, const void *QT3DS_RESTRICT src, QT3DSU32 count)
+ {
+ return memmove(dest, src, count);
+ }
+
+ /*!
+ Set 128B to zero starting at \c dst+offset. Must be aligned.
+ */
+ QT3DS_FORCE_INLINE void memZero128(void *QT3DS_RESTRICT dest, QT3DSU32 offset = 0)
+ {
+ QT3DS_ASSERT(((size_t(dest) + offset) & 0x7f) == 0);
+ memSet((char *QT3DS_RESTRICT)dest + offset, 0, 128);
+ }
+
+ /*!
+ Prefetch aligned 128B around \c ptr+offset.
+ */
+ QT3DS_FORCE_INLINE void prefetch128(const void *, QT3DSU32 = 0) {}
+
+ /*!
+ Prefetch \c count bytes starting at \c ptr.
+ */
+ QT3DS_FORCE_INLINE void prefetch(const void *ptr, QT3DSU32 count = 0)
+ {
+ for (QT3DSU32 i = 0; i <= count; i += 128)
+ prefetch128(ptr, i);
+ }
+
+ //! \brief platform-specific floor
+ QT3DS_FORCE_INLINE float floatFloor(float x) { return ::floorf(x); }
+} // namespace intrinsics
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/linux/Qt3DSLinuxMutex.cpp b/src/foundation/linux/Qt3DSLinuxMutex.cpp
new file mode 100644
index 0000000..bbc5582
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxMutex.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSAtomic.h"
+
+#include <pthread.h>
+
+namespace qt3ds {
+namespace foundation {
+
+ namespace {
+ pthread_mutex_t *getMutex(MutexImpl *impl)
+ {
+ return reinterpret_cast<pthread_mutex_t *>(impl);
+ }
+ }
+
+ MutexImpl::MutexImpl()
+ {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(getMutex(this), &attr);
+ pthread_mutexattr_destroy(&attr);
+ }
+
+ MutexImpl::~MutexImpl() { pthread_mutex_destroy(getMutex(this)); }
+
+ bool MutexImpl::lock() { return !pthread_mutex_lock(getMutex(this)); }
+
+ bool MutexImpl::trylock() { return !pthread_mutex_trylock(getMutex(this)); }
+
+ bool MutexImpl::unlock() { return !pthread_mutex_unlock(getMutex(this)); }
+
+ const QT3DSU32 MutexImpl::size = sizeof(pthread_mutex_t);
+
+ class ReadWriteLockImpl
+ {
+ public:
+ ReadWriteLockImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ pthread_mutex_t mutex;
+ volatile int readerCounter;
+ };
+
+ ReadWriteLock::ReadWriteLock(NVAllocatorCallback &alloc)
+ {
+ mImpl = QT3DS_NEW(alloc, ReadWriteLockImpl)(alloc);
+
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mImpl->mutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+
+ mImpl->readerCounter = 0;
+ }
+
+ ReadWriteLock::~ReadWriteLock()
+ {
+ pthread_mutex_destroy(&mImpl->mutex);
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ void ReadWriteLock::lockReader()
+ {
+ pthread_mutex_lock(&mImpl->mutex);
+
+ atomicIncrement(&mImpl->readerCounter);
+
+ pthread_mutex_unlock(&mImpl->mutex);
+ }
+
+ void ReadWriteLock::lockWriter()
+ {
+ pthread_mutex_lock(&mImpl->mutex);
+
+ while (mImpl->readerCounter != 0)
+ ;
+ }
+
+ void ReadWriteLock::unlockReader() { atomicDecrement(&mImpl->readerCounter); }
+
+ void ReadWriteLock::unlockWriter() { pthread_mutex_unlock(&mImpl->mutex); }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/linux/Qt3DSLinuxSemaphore.cpp b/src/foundation/linux/Qt3DSLinuxSemaphore.cpp
new file mode 100644
index 0000000..90aab79
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxSemaphore.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSSemaphore.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+
+namespace qt3ds {
+namespace foundation {
+
+ class SemaphoreImpl
+ {
+ public:
+ SemaphoreImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ QT3DSU32 count;
+ QT3DSU32 maxCount;
+ };
+
+ struct NVLinuxScopeLock
+ {
+ NVLinuxScopeLock(pthread_mutex_t &m)
+ : mMutex(m)
+ {
+ pthread_mutex_lock(&mMutex);
+ }
+
+ ~NVLinuxScopeLock() { pthread_mutex_unlock(&mMutex); }
+ private:
+ pthread_mutex_t &mMutex;
+ };
+
+ Semaphore::Semaphore(NVAllocatorCallback &alloc, QT3DSU32 initialCount, QT3DSU32 maxCount)
+ {
+ mImpl = QT3DS_NEW(alloc, SemaphoreImpl)(alloc);
+ int status = pthread_mutex_init(&mImpl->mutex, 0);
+ QT3DS_ASSERT(!status);
+ status = pthread_cond_init(&mImpl->cond, 0);
+ QT3DS_ASSERT(!status);
+ mImpl->count = initialCount;
+ mImpl->maxCount = maxCount;
+ QT3DS_ASSERT(initialCount <= maxCount);
+ }
+
+ Semaphore::~Semaphore()
+ {
+ pthread_cond_destroy(&mImpl->cond);
+ pthread_mutex_destroy(&mImpl->mutex);
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ bool Semaphore::wait(QT3DSU32 milliseconds)
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+
+ if (mImpl->count > 0) {
+ mImpl->count--;
+ return true;
+ }
+
+ if (milliseconds == 0) {
+ return false;
+ }
+
+ if (milliseconds == QT3DSU32(-1)) {
+ int status = pthread_cond_wait(&mImpl->cond, &mImpl->mutex);
+ QT3DS_ASSERT(!status);
+ (void)status;
+ } else {
+ timespec ts;
+ timeval tp;
+ gettimeofday(&tp, NULL);
+ QT3DSU32 sec = milliseconds / 1000;
+ QT3DSU32 usec = (milliseconds - 1000 * sec) * 1000;
+
+ // sschirm: taking into account that us might accumulate to a second
+ // otherwise the pthread_cond_timedwait complains on osx.
+ usec = tp.tv_usec + usec;
+ QT3DSU32 div_sec = usec / 1000000;
+ QT3DSU32 rem_usec = usec - div_sec * 1000000;
+
+ ts.tv_sec = tp.tv_sec + sec + div_sec;
+ ts.tv_nsec = rem_usec * 1000;
+
+ int ierr = pthread_cond_timedwait(&mImpl->cond, &mImpl->mutex, &ts);
+ QT3DS_ASSERT((ierr == 0) || (ierr == ETIMEDOUT));
+ (void)ierr;
+ return false;
+ }
+
+ return true;
+ }
+
+ void Semaphore::post()
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+ mImpl->count++;
+ if (mImpl->count > mImpl->maxCount)
+ mImpl->count = mImpl->maxCount;
+ else {
+ pthread_cond_broadcast(&mImpl->cond);
+ }
+ }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/linux/Qt3DSLinuxString.h b/src/foundation/linux/Qt3DSLinuxString.h
new file mode 100644
index 0000000..a4645f2
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxString.h
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_LINUX_STRING_H
+#define QT3DS_FOUNDATION_QT3DS_LINUX_STRING_H
+
+#include "foundation/Qt3DS.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#pragma warning(push)
+#pragma warning(disable : 4995 4996)
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+QT3DS_INLINE void NVStrcpy(char *dest, size_t size, const char *src)
+{
+ ::strncpy(dest, src, size);
+}
+
+QT3DS_INLINE int NVStrcat(char *dest, size_t size, const char *src)
+{
+ ::strcat(dest, src);
+ return 0;
+}
+QT3DS_INLINE int NVVsprintf(char *dest, size_t size, const char *src, va_list arg)
+{
+ int r = ::vsprintf(dest, src, arg);
+
+ return r;
+}
+QT3DS_INLINE int NVStricmp(const char *str, const char *str1)
+{
+ return (::strcasecmp(str, str1));
+}
+
+namespace string {
+
+ QT3DS_INLINE void strcpy(char *dest, size_t size, const char *src) { ::strcpy(dest, src); }
+ QT3DS_INLINE void strcat(char *dest, size_t size, const char *src) { ::strcat(dest, src); }
+ // QT3DS_INLINE int strcasecmp(const char *str, const char *str1) {return(::strcasecmp(str,
+ // str1));}
+ QT3DS_INLINE QT3DSI32 stricmp(const char *str, const char *str1) { return (::strcasecmp(str, str1)); }
+ QT3DS_INLINE QT3DSI32 strnicmp(const char *str, const char *str1, size_t len)
+ {
+ return (::strncasecmp(str, str1, len));
+ }
+
+ QT3DS_INLINE QT3DSI32 strncat_s(char *dstBfr, size_t dstSize, const char *srcBfr, size_t numCpy)
+ {
+ if (!dstBfr || !srcBfr || !dstSize)
+ return -1;
+
+ size_t len = strlen(dstBfr);
+
+ if (len >= dstSize)
+ return -1;
+
+ size_t remain = dstSize - len - 1;
+ size_t transfer = remain > numCpy ? numCpy : remain;
+ ::memmove(dstBfr + len, srcBfr, transfer);
+ dstBfr[len + transfer] = '\0';
+ return numCpy <= remain ? 0 : -1;
+ }
+
+ QT3DS_INLINE QT3DSI32 _vsnprintf(char *dest, size_t size, const char *src, va_list arg)
+ {
+ QT3DSI32 r = ::vsnprintf(dest, size, src, arg);
+
+ return r;
+ }
+ QT3DS_INLINE QT3DSI32 vsprintf(char *dest, size_t size, const char *src, va_list arg)
+ {
+ QT3DSI32 r = ::vsprintf(dest, src, arg);
+
+ return r;
+ }
+ QT3DS_INLINE int vsprintf_s(char *dest, size_t size, const char *src, va_list arg)
+ {
+ int r = ::vsprintf(dest, src, arg);
+
+ return r;
+ }
+
+ QT3DS_INLINE int sprintf_s(char *_DstBuf, size_t _DstSize, const char *_Format, ...)
+ {
+ if (_DstBuf == NULL || _Format == NULL) {
+ return -1;
+ }
+
+ va_list arg;
+ va_start(arg, _Format);
+ int r = ::vsprintf(_DstBuf, _Format, arg);
+ va_end(arg);
+
+ return r;
+ }
+
+ QT3DS_INLINE QT3DSI32 sprintf(char *_DstBuf, size_t _DstSize, const char *_Format, ...)
+ {
+ va_list arg;
+ va_start(arg, _Format);
+ QT3DSI32 r = ::vsprintf(_DstBuf, _Format, arg);
+ va_end(arg);
+
+ return r;
+ }
+
+ QT3DS_INLINE int strncpy_s(char *strDest, size_t sizeInBytes, const char *strSource, size_t count)
+ {
+ if (strDest == NULL || strSource == NULL || sizeInBytes == 0) {
+ return -1;
+ }
+
+ if (sizeInBytes < count) {
+ strDest[0] = 0;
+ return -1;
+ }
+
+ ::strncpy(strDest, strSource, count);
+ return 0;
+ }
+
+ QT3DS_INLINE void strcpy_s(char *dest, size_t size, const char *src)
+ {
+ ::strncpy(dest, src, size);
+ }
+
+ QT3DS_INLINE int strcat_s(char *dest, size_t size, const char *src)
+ {
+ ::strcat(dest, src);
+ return 0;
+ }
+
+ QT3DS_INLINE QT3DSI32 sscanf(const char *buffer, const char *format, ...)
+ {
+ va_list arg;
+ va_start(arg, format);
+ QT3DSI32 r = ::sscanf(buffer, format, arg);
+ va_end(arg);
+
+ return r;
+ };
+
+ QT3DS_INLINE void strlwr(char *str)
+ {
+ while (*str) {
+ if (*str >= 'A' && *str <= 'Z')
+ *str += 32;
+ str++;
+ }
+ }
+
+ QT3DS_INLINE void strupr(char *str)
+ {
+ while (*str) {
+ if (*str >= 'a' && *str <= 'z')
+ *str -= 32;
+ str++;
+ }
+ }
+
+} // namespace string
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+#pragma warning(pop)
+
+#endif
diff --git a/src/foundation/linux/Qt3DSLinuxSync.cpp b/src/foundation/linux/Qt3DSLinuxSync.cpp
new file mode 100644
index 0000000..52f9d7a
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxSync.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSSync.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+
+namespace qt3ds {
+namespace foundation {
+
+ class SyncImpl
+ {
+ public:
+ SyncImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ volatile bool is_set;
+ };
+
+ struct NVLinuxScopeLock
+ {
+ NVLinuxScopeLock(pthread_mutex_t &m)
+ : mMutex(m)
+ {
+ pthread_mutex_lock(&mMutex);
+ }
+
+ ~NVLinuxScopeLock() { pthread_mutex_unlock(&mMutex); }
+ private:
+ pthread_mutex_t &mMutex;
+ };
+
+ Sync::Sync(NVAllocatorCallback &alloc)
+ {
+ mImpl = QT3DS_NEW(alloc, SyncImpl)(alloc);
+ int status = pthread_mutex_init(&mImpl->mutex, 0);
+ QT3DS_ASSERT(!status);
+ status = pthread_cond_init(&mImpl->cond, 0);
+ QT3DS_ASSERT(!status);
+ mImpl->is_set = false;
+ }
+
+ Sync::~Sync()
+ {
+ pthread_cond_destroy(&mImpl->cond);
+ pthread_mutex_destroy(&mImpl->mutex);
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ void Sync::reset()
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+ mImpl->is_set = false;
+ }
+
+ void Sync::set()
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+ if (!mImpl->is_set) {
+ mImpl->is_set = true;
+ pthread_cond_broadcast(&mImpl->cond);
+ }
+ }
+
+ bool Sync::wait(QT3DSU32 ms)
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+ if (!mImpl->is_set) {
+ if (ms == QT3DSU32(-1)) {
+ int status = pthread_cond_wait(&mImpl->cond, &mImpl->mutex);
+ QT3DS_ASSERT(!status);
+ (void)status;
+ } else {
+ timespec ts;
+ timeval tp;
+ gettimeofday(&tp, NULL);
+ QT3DSU32 sec = ms / 1000;
+ QT3DSU32 usec = (ms - 1000 * sec) * 1000;
+
+ // sschirm: taking into account that us might accumulate to a second
+ // otherwise the pthread_cond_timedwait complains on osx.
+ usec = tp.tv_usec + usec;
+ QT3DSU32 div_sec = usec / 1000000;
+ QT3DSU32 rem_usec = usec - div_sec * 1000000;
+
+ ts.tv_sec = tp.tv_sec + sec + div_sec;
+ ts.tv_nsec = rem_usec * 1000;
+
+ int ierr = pthread_cond_timedwait(&mImpl->cond, &mImpl->mutex, &ts);
+ QT3DS_ASSERT((ierr == 0) || (ierr == ETIMEDOUT));
+ (void)ierr;
+ }
+ }
+ return mImpl->is_set;
+ }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/linux/Qt3DSLinuxThread.cpp b/src/foundation/linux/Qt3DSLinuxThread.cpp
new file mode 100644
index 0000000..fa6e069
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxThread.cpp
@@ -0,0 +1,384 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSThread.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSIntrinsics.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#if !defined(QT3DS_APPLE) && !defined(ANDROID) && !defined(__CYGWIN__) && !defined(__QNX__) && !defined(__INTEGRITY)
+#include <bits/local_lim.h> // PTHREAD_STACK_MIN
+#endif
+#include <stdio.h>
+#include <pthread.h>
+#if !defined(__QNX__) && !defined(__INTEGRITY)
+#include <unistd.h>
+#include <sys/syscall.h>
+#if !defined(QT3DS_APPLE)
+#include <asm/unistd.h>
+#include <sys/resource.h>
+#endif
+#endif
+
+#define NVSpinLockPause() asm("nop")
+
+namespace qt3ds {
+namespace foundation {
+ using namespace intrinsics;
+
+ typedef enum { _NVThreadNotStarted, _NVThreadStarted, _NVThreadStopped } NVThreadState;
+
+ class ThreadImpl
+ {
+ public:
+ ThreadImpl(NVFoundationBase &foundation)
+ : mFoundation(foundation)
+ {
+ }
+ NVFoundationBase &mFoundation;
+ Thread::ExecuteFn fn;
+ void *arg;
+ volatile QT3DSI32 quitNow;
+ volatile QT3DSI32 threadStarted;
+ NVThreadState state;
+
+ pthread_t thread;
+ pid_t tid;
+ };
+
+ void *NVThreadStart(void *arg);
+
+ Thread::Id Thread::getId() { return Id(pthread_self()); }
+
+ Thread::Thread(NVFoundationBase &foundation)
+ {
+ mImpl = QT3DS_NEW(foundation.getAllocator(), ThreadImpl)(foundation);
+ mImpl->thread = 0;
+ mImpl->tid = 0;
+ mImpl->state = _NVThreadNotStarted;
+ mImpl->quitNow = 0;
+ mImpl->threadStarted = 0;
+ mImpl->fn = NULL;
+ mImpl->arg = NULL;
+ }
+
+ Thread::Thread(NVFoundationBase &foundation, Thread::ExecuteFn fn, void *arg)
+ {
+ mImpl = (ThreadImpl *)QT3DS_NEW(foundation.getAllocator(), ThreadImpl)(foundation);
+ mImpl->thread = 0;
+ mImpl->tid = 0;
+ mImpl->state = _NVThreadNotStarted;
+ mImpl->quitNow = 0;
+ mImpl->threadStarted = 0;
+ mImpl->fn = fn;
+ mImpl->arg = arg;
+
+ start(0);
+ }
+
+ Thread::~Thread()
+ {
+ if (mImpl->state == _NVThreadStarted)
+ kill();
+ QT3DS_FREE(mImpl->mFoundation.getAllocator(), mImpl);
+ }
+
+ void Thread::start(QT3DSU32 stackSize)
+ {
+ if (mImpl->state != _NVThreadNotStarted)
+ return;
+
+ if (stackSize == 0)
+ stackSize = DEFAULT_STACK_SIZE;
+
+#if defined(PTHREAD_STACK_MIN) && !defined(ANDROID)
+ if (stackSize < PTHREAD_STACK_MIN) {
+ qCWarning(WARNING, "Thread::start(): stack size was set below PTHREAD_STACK_MIN");
+ stackSize = PTHREAD_STACK_MIN;
+ }
+#endif
+
+ pthread_attr_t attr;
+ int status = pthread_attr_init(&attr);
+ QT3DS_ASSERT(!status);
+
+ status = pthread_attr_setstacksize(&attr, stackSize);
+ QT3DS_ASSERT(!status);
+ status = pthread_create(&mImpl->thread, &attr, NVThreadStart, this);
+ QT3DS_ASSERT(!status);
+
+#ifndef __QNX__
+ // wait for thread to startup and write out TID
+ // otherwise TID dependent calls like setAffinity will fail.
+ while (atomicCompareExchange(&(mImpl->threadStarted), 1, 1) == 0)
+ yield();
+#endif
+
+ mImpl->state = _NVThreadStarted;
+
+ status = pthread_attr_destroy(&attr);
+ QT3DS_ASSERT(!status);
+ }
+
+ static void setTid(ThreadImpl &threadImpl)
+ {
+#ifndef __QNX__
+// query TID
+#ifdef QT3DS_APPLE
+ threadImpl.tid = syscall(SYS_gettid);
+#elif defined(__INTEGRITY)
+ pthread_t ptid = pthread_self();
+ uint64_t threadId = 0;
+ memcpy(&threadId, &ptid, std::min(sizeof(threadId), sizeof(ptid)));
+ threadImpl.tid = threadId;
+#else
+ threadImpl.tid = syscall(__NR_gettid);
+#endif
+
+ // notify/unblock parent thread
+ atomicCompareExchange(&(threadImpl.threadStarted), 1, 0);
+#else
+ QT3DS_ASSERT(false);
+#endif
+ }
+
+ void *NVThreadStart(void *arg)
+ {
+ // run execute from base class to run gettid in the new thread's context
+ ((Thread *)arg)->Thread::execute();
+ return 0;
+ }
+
+ void Thread::execute(void)
+ {
+ // run setTid in thread's context
+ setTid(*mImpl);
+
+ // then run either the passed in function or execute from the derived class.
+ if (mImpl->fn)
+ (*mImpl->fn)(mImpl->arg);
+ else
+ this->execute();
+ }
+
+ void Thread::signalQuit() { atomicIncrement(&(mImpl->quitNow)); }
+
+ bool Thread::waitForQuit()
+ {
+ if (mImpl->state == _NVThreadNotStarted)
+ return false;
+
+ pthread_join(mImpl->thread, NULL);
+ return true;
+ }
+
+ bool Thread::quitIsSignalled()
+ {
+#ifndef __QNX__
+ return atomicCompareExchange(&(mImpl->quitNow), 0, 0) != 0;
+#else
+ // Hope for memory locking on the arm.
+ return mImpl->quitNow != 0;
+#endif
+ }
+
+ void Thread::quit()
+ {
+ mImpl->state = _NVThreadStopped;
+ pthread_exit(0);
+ }
+
+ void Thread::kill()
+ {
+#ifndef ANDROID
+ if (mImpl->state == _NVThreadStarted)
+ pthread_cancel(mImpl->thread);
+ mImpl->state = _NVThreadStopped;
+#else
+ qCWarning(WARNING, "Thread::kill() called, but is not implemented");
+#endif
+ }
+
+ void Thread::sleep(QT3DSU32 ms)
+ {
+ timespec sleepTime;
+ QT3DSU32 remainder = ms % 1000;
+ sleepTime.tv_sec = ms - remainder;
+ sleepTime.tv_nsec = remainder * 1000000L;
+
+ while (nanosleep(&sleepTime, &sleepTime) == -1)
+ continue;
+ }
+
+ void Thread::yield() { sched_yield(); }
+
+ QT3DSU32 Thread::setAffinityMask(QT3DSU32 mask)
+ {
+ // Same as windows impl if mask is zero
+ if (!mask)
+ return 0;
+
+#ifndef __QNX__
+ QT3DSU64 prevMask = 0;
+
+// Apple doesn't support syscall with getaffinity and setaffinity
+#if !defined(QT3DS_APPLE) && !defined(__INTEGRITY)
+ QT3DSI32 errGet = syscall(__NR_sched_getaffinity, mImpl->tid, sizeof(prevMask), &prevMask);
+ if (errGet < 0)
+ return 0;
+
+ QT3DSI32 errSet = syscall(__NR_sched_setaffinity, mImpl->tid, sizeof(mask), &mask);
+ if (errSet != 0)
+ return 0;
+#endif
+
+ return QT3DSU32(prevMask);
+#else
+ QT3DS_ASSERT(false);
+ return 0;
+#endif
+ }
+
+ void Thread::setName(const char *name)
+ {
+#if (defined(ANDROID) && (__ANDROID_API__ > 8))
+ pthread_setname_np(mImpl->thread, name);
+#else
+// not implemented because most unix APIs expect setName()
+// to be called from the thread's context. Example see next comment:
+
+// this works only with the current thread and can rename
+// the main process if used in the wrong context:
+// prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(name) ,0,0,0);
+#endif
+ }
+
+#if !defined(QT3DS_APPLE) && !defined(__INTEGRITY)
+ static ThreadPriority::Enum convertPriorityFromLinux(QT3DSU32 inPrio, int policy)
+ {
+ QT3DS_COMPILE_TIME_ASSERT(ThreadPriority::eLOW > ThreadPriority::eHIGH);
+ QT3DS_COMPILE_TIME_ASSERT(ThreadPriority::eHIGH == 0);
+
+ int maxL = sched_get_priority_max(policy);
+ int minL = sched_get_priority_min(policy);
+ int rangeL = maxL - minL;
+ int rangeNV = ThreadPriority::eLOW - ThreadPriority::eHIGH;
+
+ // case for default scheduler policy
+ if (rangeL == 0)
+ return ThreadPriority::eNORMAL;
+
+ float floatPrio = (float(maxL - inPrio) * float(rangeNV)) / float(rangeL);
+
+ return ThreadPriority::Enum(int(roundf(floatPrio)));
+ }
+
+ static int convertPriorityToLinux(ThreadPriority::Enum inPrio, int policy)
+ {
+ int maxL = sched_get_priority_max(policy);
+ int minL = sched_get_priority_min(policy);
+ int rangeL = maxL - minL;
+ int rangeNV = ThreadPriority::eLOW - ThreadPriority::eHIGH;
+
+ // case for default scheduler policy
+ if (rangeL == 0)
+ return 0;
+
+ float floatPrio = (float(ThreadPriority::eLOW - inPrio) * float(rangeL)) / float(rangeNV);
+
+ return minL + int(roundf(floatPrio));
+ }
+#endif
+
+ void Thread::setPriority(ThreadPriority::Enum val)
+ {
+#if !defined(QT3DS_APPLE) && !defined(__INTEGRITY)
+ int policy;
+ sched_param s_param;
+ pthread_getschedparam(mImpl->thread, &policy, &s_param);
+ s_param.sched_priority = convertPriorityToLinux(val, policy);
+ pthread_setschedparam(mImpl->thread, policy, &s_param);
+#endif
+ }
+
+ ThreadPriority::Enum Thread::getPriority(Id pthread)
+ {
+#if !defined(QT3DS_APPLE) && !defined(__INTEGRITY)
+ int policy;
+ sched_param s_param;
+ int ret = pthread_getschedparam(pthread_t(pthread), &policy, &s_param);
+ if (ret == 0)
+ return convertPriorityFromLinux(s_param.sched_priority, policy);
+ else
+ return ThreadPriority::eNORMAL;
+#else
+ return ThreadPriority::eNORMAL;
+#endif
+ }
+
+ QT3DSU32 TlsAlloc()
+ {
+#if !defined(__INTEGRITY)
+ pthread_key_t key;
+ int status = pthread_key_create(&key, NULL);
+ QT3DS_ASSERT(!status);
+ (void)status;
+ return (QT3DSU32)key;
+#else
+ QT3DS_ASSERT(false);
+ return 0;
+#endif
+ }
+
+ void TlsFree(QT3DSU32 index)
+ {
+ int status = pthread_key_delete((pthread_key_t)index);
+ QT3DS_ASSERT(!status);
+ (void)status;
+ }
+
+ void *TlsGet(QT3DSU32 index) { return (void *)pthread_getspecific((pthread_key_t)index); }
+
+ QT3DSU32 TlsSet(QT3DSU32 index, void *value)
+ {
+ int status = pthread_setspecific((pthread_key_t)index, value);
+ QT3DS_ASSERT(!status);
+ return !status;
+ }
+
+ // DM: On Linux x86-32, without implementation-specific restrictions
+ // the default stack size for a new thread should be 2 megabytes (kernel.org).
+ // NOTE: take care of this value on other architecutres!
+ const QT3DSU32 Thread::DEFAULT_STACK_SIZE = 1 << 21;
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/linux/Qt3DSLinuxTime.cpp b/src/foundation/linux/Qt3DSLinuxTime.cpp
new file mode 100644
index 0000000..6b3e93e
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxTime.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSTime.h"
+
+#include <time.h>
+#include <sys/time.h>
+
+#if defined QT3DS_APPLE
+#include <mach/mach_time.h>
+#endif
+
+// Use real-time high-precision timer.
+#ifndef QT3DS_APPLE
+#define CLOCKID CLOCK_REALTIME
+#endif
+
+namespace qt3ds {
+namespace foundation {
+
+ const CounterFrequencyToTensOfNanos Time::sCounterFreq = Time::getCounterFrequency();
+
+ static Time::Second getTimeSeconds()
+ {
+ static struct timeval _tv;
+ gettimeofday(&_tv, NULL);
+ return double(_tv.tv_sec) + double(_tv.tv_usec) * 0.000001;
+ }
+
+ Time::Time() { mLastTime = getTimeSeconds(); }
+
+ Time::Second Time::getElapsedSeconds()
+ {
+ Time::Second curTime = getTimeSeconds();
+ Time::Second diff = curTime - mLastTime;
+ mLastTime = curTime;
+ return diff;
+ }
+
+ Time::Second Time::peekElapsedSeconds()
+ {
+ Time::Second curTime = getTimeSeconds();
+ Time::Second diff = curTime - mLastTime;
+ return diff;
+ }
+
+ Time::Second Time::getLastTime() const { return mLastTime; }
+
+#ifdef QT3DS_APPLE
+ CounterFrequencyToTensOfNanos Time::getCounterFrequency()
+ {
+ mach_timebase_info_data_t info;
+ mach_timebase_info(&info);
+ // sschirm: some code in the PhysX samples assumes that
+ // CounterFrequencyToTensOfNanos::mDenominator is #ticks/second
+ // which is bad since it ignores the numenator. This is a temporary fix
+ // with the same setup as windows
+ // return CounterFrequencyToTensOfNanos( info.numer, info.denom*10 );
+ return CounterFrequencyToTensOfNanos(sNumTensOfNanoSecondsInASecond,
+ info.denom * 1000000000 / info.numer);
+ }
+
+ QT3DSU64 Time::getCurrentCounterValue() { return mach_absolute_time(); }
+
+#else
+
+ CounterFrequencyToTensOfNanos Time::getCounterFrequency()
+ {
+ return CounterFrequencyToTensOfNanos(1, 10);
+ }
+
+ QT3DSU64 Time::getCurrentCounterValue()
+ {
+ struct timespec mCurrTimeInt;
+ clock_gettime(CLOCKID, &mCurrTimeInt);
+ // Convert to nanos as this doesn't cause a large divide here
+ return (static_cast<QT3DSU64>(mCurrTimeInt.tv_sec) * 1000000000)
+ + (static_cast<QT3DSU64>(mCurrTimeInt.tv_nsec));
+ }
+#endif
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/linux/Qt3DSLinuxTrigConstants.h b/src/foundation/linux/Qt3DSLinuxTrigConstants.h
new file mode 100644
index 0000000..120dec7
--- /dev/null
+++ b/src/foundation/linux/Qt3DSLinuxTrigConstants.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_LINUX_TRIG_CONSTANTS_H
+#define QT3DS_LINUX_TRIG_CONSTANTS_H
+
+//#define QT3DS_GLOBALCONST extern const __declspec(selectany)
+
+#define QT3DS_GLOBALCONST extern const __attribute__((weak))
+
+QT3DS_ALIGN_PREFIX(16)
+struct QT3DS_VECTORF32
+{
+ float f[4];
+};
+
+#define QT3DS_PI 3.141592654f
+#define QT3DS_2PI 6.283185307f
+#define QT3DS_1DIVPI 0.318309886f
+#define QT3DS_1DIV2PI 0.159154943f
+#define QT3DS_PIDIV2 1.570796327f
+#define QT3DS_PIDIV4 0.785398163f
+
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXSinCoefficients0 = { 1.0f, -0.166666667f, 8.333333333e-3f,
+ -1.984126984e-4f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXSinCoefficients1 = { 2.755731922e-6f, -2.505210839e-8f,
+ 1.605904384e-10f, -7.647163732e-13f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXSinCoefficients2 = { 2.811457254e-15f, -8.220635247e-18f,
+ 1.957294106e-20f, -3.868170171e-23f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXCosCoefficients0 = { 1.0f, -0.5f, 4.166666667e-2f,
+ -1.388888889e-3f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXCosCoefficients1 = { 2.480158730e-5f, -2.755731922e-7f,
+ 2.087675699e-9f, -1.147074560e-11f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXCosCoefficients2 = { 4.779477332e-14f, -1.561920697e-16f,
+ 4.110317623e-19f, -8.896791392e-22f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXTanCoefficients0 = { 1.0f, 0.333333333f, 0.133333333f,
+ 5.396825397e-2f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXTanCoefficients1 = { 2.186948854e-2f, 8.863235530e-3f,
+ 3.592128167e-3f, 1.455834485e-3f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXTanCoefficients2 = { 5.900274264e-4f, 2.391290764e-4f,
+ 9.691537707e-5f, 3.927832950e-5f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinCoefficients0 = { -0.05806367563904f, -0.41861972469416f,
+ 0.22480114791621f, 2.17337241360606f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinCoefficients1 = { 0.61657275907170f, 4.29696498283455f,
+ -1.18942822255452f, -6.53784832094831f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinCoefficients2 = { -1.36926553863413f, -4.48179294237210f,
+ 1.41810672941833f, 5.48179257935713f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXATanCoefficients0 = { 1.0f, 0.333333334f, 0.2f, 0.142857143f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXATanCoefficients1 = { 1.111111111e-1f, 9.090909091e-2f,
+ 7.692307692e-2f, 6.666666667e-2f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXATanCoefficients2 = { 5.882352941e-2f, 5.263157895e-2f,
+ 4.761904762e-2f, 4.347826087e-2f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXSinEstCoefficients = { 1.0f, -1.66521856991541e-1f,
+ 8.199913018755e-3f, -1.61475937228e-4f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXCosEstCoefficients = { 1.0f, -4.95348008918096e-1f,
+ 3.878259962881e-2f, -9.24587976263e-4f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXTanEstCoefficients = { 2.484f, -1.954923183e-1f, 2.467401101f,
+ QT3DS_1DIVPI };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXATanEstCoefficients = { 7.689891418951e-1f, 1.104742493348f,
+ 8.661844266006e-1f, QT3DS_PIDIV2 };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinEstCoefficients = { -1.36178272886711f, 2.37949493464538f,
+ -8.08228565650486e-1f,
+ 2.78440142746736e-1f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinEstConstants = { 1.00000011921f, QT3DS_PIDIV2, 0.0f, 0.0f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXPiConstants0 = { QT3DS_PI, QT3DS_2PI, QT3DS_1DIVPI, QT3DS_1DIV2PI };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXReciprocalTwoPi = { QT3DS_1DIV2PI, QT3DS_1DIV2PI, QT3DS_1DIV2PI,
+ QT3DS_1DIV2PI };
+
+#endif
diff --git a/src/foundation/linux/SocketImpl.h b/src/foundation/linux/SocketImpl.h
new file mode 100644
index 0000000..4c3fcb7
--- /dev/null
+++ b/src/foundation/linux/SocketImpl.h
@@ -0,0 +1,424 @@
+/****************************************************************************
+**
+** 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 FOUNDATION_LINUX_SOCKET_IMPL_H
+#define FOUNDATION_LINUX_SOCKET_IMPL_H
+#pragma once
+
+/*=========================================================================*\
+* BSD include files
+\*=========================================================================*/
+/* error codes */
+#include <errno.h>
+/* close function */
+#include <unistd.h>
+/* fnctnl function and associated constants */
+#include <fcntl.h>
+/* struct sockaddr */
+#include <sys/types.h>
+/* socket function */
+#include <sys/socket.h>
+/* struct timeval */
+#include <sys/time.h>
+/* gethostbyname and gethostbyaddr functions */
+#include <netdb.h>
+/* sigpipe handling */
+#include <signal.h>
+/* IP stuff*/
+#include <netinet/in.h>
+#include <arpa/inet.h>
+/* TCP options (nagle algorithm disable) */
+#include <netinet/tcp.h>
+
+namespace qt3ds {
+namespace foundation {
+ namespace socketimpl {
+ // Functions take from lua socket implementation. Note that it has an MIT license.
+
+ enum {
+ IO_DONE = 0, /* operation completed successfully */
+ IO_TIMEOUT = -1, /* operation timed out */
+ IO_CLOSED = -2, /* the connection has been closed */
+ IO_UNKNOWN = -3
+ };
+
+ /*-------------------------------------------------------------------------*\
+ * I/O error strings
+ \*-------------------------------------------------------------------------*/
+ const char *io_strerror(int err)
+ {
+ switch (err) {
+ case IO_DONE:
+ return NULL;
+ case IO_CLOSED:
+ return "closed";
+ case IO_TIMEOUT:
+ return "timeout";
+ default:
+ return "unknown error";
+ }
+ }
+
+ typedef int t_socket;
+ typedef t_socket *p_socket;
+ typedef struct sockaddr SA;
+
+#define SOCKET_INVALID (-1)
+
+#define WAITFD_R 1
+#define WAITFD_W 2
+#define WAITFD_C (WAITFD_R | WAITFD_W)
+
+ int socket_waitfd(p_socket ps, int sw, QT3DSU32 tm)
+ {
+ int ret;
+ fd_set rfds, wfds, *rp, *wp;
+ struct timeval tv, *tp = NULL;
+ if (tm == 0)
+ return IO_TIMEOUT; /* optimize timeout == 0 case */
+ if (tm < QT3DS_MAX_U32) {
+ // shoule consider max timeout specially by setting tp = NULL
+ // or you get invalid argument errno = 22
+ tv.tv_sec = (int)(tm / 1000);
+ QT3DSU32 leftover = tm % 1000;
+ tv.tv_usec = (int)(leftover * 100000);
+ tp = &tv;
+ }
+ do {
+ /* must set bits within loop, because select may have modifed them */
+ rp = wp = NULL;
+ if (sw & WAITFD_R) {
+ FD_ZERO(&rfds);
+ FD_SET(*ps, &rfds);
+ rp = &rfds;
+ }
+ if (sw & WAITFD_W) {
+ FD_ZERO(&wfds);
+ FD_SET(*ps, &wfds);
+ wp = &wfds;
+ }
+ ret = select(*ps + 1, rp, wp, NULL, tp);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1)
+ return errno;
+ if (ret == 0)
+ return IO_TIMEOUT;
+ if (sw == WAITFD_C && FD_ISSET(*ps, &rfds))
+ return IO_CLOSED;
+ return IO_DONE;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Initializes module
+ \*-------------------------------------------------------------------------*/
+ int socket_open(void)
+ {
+ /* instals a handler to ignore sigpipe or it will crash us */
+ signal(SIGPIPE, SIG_IGN);
+ return 1;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Close module
+ \*-------------------------------------------------------------------------*/
+ int socket_close(void) { return 1; }
+
+ /*-------------------------------------------------------------------------*\
+ * Put socket into blocking mode
+ \*-------------------------------------------------------------------------*/
+ void socket_setblocking(p_socket ps)
+ {
+ int flags = fcntl(*ps, F_GETFL, 0);
+ flags &= (~(O_NONBLOCK));
+ fcntl(*ps, F_SETFL, flags);
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Put socket into non-blocking mode
+ \*-------------------------------------------------------------------------*/
+ void socket_setnonblocking(p_socket ps)
+ {
+ int flags = fcntl(*ps, F_GETFL, 0);
+ flags |= O_NONBLOCK;
+ fcntl(*ps, F_SETFL, flags);
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Close and inutilize socket
+ \*-------------------------------------------------------------------------*/
+ void socket_destroy(p_socket ps)
+ {
+ if (*ps != SOCKET_INVALID) {
+ socket_setblocking(ps);
+ close(*ps);
+ *ps = SOCKET_INVALID;
+ }
+ }
+ /*-------------------------------------------------------------------------*\
+ *
+ \*-------------------------------------------------------------------------*/
+ void socket_shutdown(p_socket ps, int how)
+ {
+ socket_setblocking(ps);
+ shutdown(*ps, how);
+ socket_setnonblocking(ps);
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Creates and sets up a socket
+ \*-------------------------------------------------------------------------*/
+ int socket_create(p_socket ps, int domain, int type, int protocol)
+ {
+ *ps = socket(domain, type, protocol);
+ if (*ps != SOCKET_INVALID)
+ return IO_DONE;
+ else
+ return errno;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ *
+ \*-------------------------------------------------------------------------*/
+ int socket_listen(p_socket ps, int backlog)
+ {
+ int err = IO_DONE;
+ socket_setblocking(ps);
+ if (listen(*ps, backlog))
+ err = errno;
+ socket_setnonblocking(ps);
+ return err;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Binds or returns error message
+ \*-------------------------------------------------------------------------*/
+ int socket_bind(p_socket ps, SA *addr, socklen_t len)
+ {
+ int err = IO_DONE;
+ socket_setblocking(ps);
+ if (bind(*ps, addr, len) < 0)
+ err = errno;
+ socket_setnonblocking(ps);
+ return err;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Connects or returns error message
+ \*-------------------------------------------------------------------------*/
+ int socket_connect(p_socket ps, SA *addr, socklen_t len, QT3DSU32 tm)
+ {
+ int err;
+ /* avoid calling on closed sockets */
+ if (*ps == SOCKET_INVALID)
+ return IO_CLOSED;
+ /* call connect until done or failed without being interrupted */
+ do
+ if (connect(*ps, addr, len) == 0)
+ return IO_DONE;
+ while ((err = errno) == EINTR);
+ /* if connection failed immediately, return error code */
+ if (err != EINPROGRESS && err != EAGAIN)
+ return err;
+ /* zero timeout case optimization */
+ if (tm == 0)
+ return IO_TIMEOUT;
+ /* wait until we have the result of the connection attempt or timeout */
+ err = socket_waitfd(ps, WAITFD_C, tm);
+ if (err == IO_CLOSED) {
+ if (recv(*ps, (char *)&err, 0, 0) == 0)
+ return IO_DONE;
+ else
+ return errno;
+ } else
+ return err;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Accept with timeout
+ \*-------------------------------------------------------------------------*/
+ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, QT3DSU32 tm)
+ {
+ SA daddr;
+ socklen_t dlen = sizeof(daddr);
+ if (*ps == SOCKET_INVALID)
+ return IO_CLOSED;
+ if (!addr)
+ addr = &daddr;
+ if (!len)
+ len = &dlen;
+ for (;;) {
+ int err;
+ if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID)
+ return IO_DONE;
+ err = errno;
+ if (err == EINTR)
+ continue;
+ if (err != EAGAIN && err != ECONNABORTED)
+ return err;
+ if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE)
+ return err;
+ }
+ /* can't reach here */
+ return IO_UNKNOWN;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Send with timeout
+ \*-------------------------------------------------------------------------*/
+ int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, QT3DSU32 tm)
+ {
+ int err;
+ *sent = 0;
+ /* avoid making system calls on closed sockets */
+ if (*ps == SOCKET_INVALID)
+ return IO_CLOSED;
+ /* loop until we send something or we give up on error */
+ for (;;) {
+ long put = (long)send(*ps, data, count, 0);
+ /* if we sent anything, we are done */
+ if (put > 0) {
+ *sent = put;
+ return IO_DONE;
+ }
+ err = errno;
+ /* send can't really return 0, but EPIPE means the connection was closed */
+ if (put == 0 || err == EPIPE)
+ return IO_CLOSED;
+ /* we call was interrupted, just try again */
+ if (err == EINTR)
+ continue;
+ /* if failed fatal reason, report error */
+ if (err != EAGAIN)
+ return err;
+ /* wait until we can send something or we timeout */
+ if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE)
+ return err;
+ }
+ /* can't reach here */
+ return IO_UNKNOWN;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Receive with timeout
+ \*-------------------------------------------------------------------------*/
+ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, QT3DSU32 tm)
+ {
+ int err;
+ *got = 0;
+ if (*ps == SOCKET_INVALID)
+ return IO_CLOSED;
+ for (;;) {
+ long taken = (long)recv(*ps, data, count, 0);
+ if (taken > 0) {
+ *got = taken;
+ return IO_DONE;
+ }
+ err = errno;
+ if (taken == 0)
+ return IO_CLOSED;
+ if (err == EINTR)
+ continue;
+ if (err != EAGAIN)
+ return err;
+ if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE)
+ return err;
+ }
+ return IO_UNKNOWN;
+ }
+
+ int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp)
+ {
+ *hp = gethostbyaddr(addr, len, AF_INET);
+ if (*hp)
+ return IO_DONE;
+ else if (h_errno)
+ return h_errno;
+ else if (errno)
+ return errno;
+ else
+ return IO_UNKNOWN;
+ }
+
+ int socket_gethostbyname(const char *addr, struct hostent **hp)
+ {
+ *hp = gethostbyname(addr);
+ if (*hp)
+ return IO_DONE;
+ else if (h_errno)
+ return h_errno;
+ else if (errno)
+ return errno;
+ else
+ return IO_UNKNOWN;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Error translation functions
+ * Make sure important error messages are standard
+ \*-------------------------------------------------------------------------*/
+ const char *socket_hoststrerror(int err)
+ {
+ if (err <= 0)
+ return io_strerror(err);
+ switch (err) {
+ case HOST_NOT_FOUND:
+ return "host not found";
+ default:
+ return hstrerror(err);
+ }
+ }
+
+ const char *socket_strerror(int err)
+ {
+ if (err <= 0)
+ return io_strerror(err);
+ switch (err) {
+ case EADDRINUSE:
+ return "address already in use";
+ case EISCONN:
+ return "already connected";
+ case EACCES:
+ return "permission denied";
+ case ECONNREFUSED:
+ return "connection refused";
+ case ECONNABORTED:
+ return "closed";
+ case ECONNRESET:
+ return "closed";
+ case ETIMEDOUT:
+ return "timeout";
+ default:
+ return strerror(errno);
+ }
+ }
+ }
+}
+}
+
+#endif
diff --git a/src/foundation/linux/qt_attribution.json b/src/foundation/linux/qt_attribution.json
new file mode 100644
index 0000000..3c3bed6
--- /dev/null
+++ b/src/foundation/linux/qt_attribution.json
@@ -0,0 +1,10 @@
+{
+ "Id": "qt3dslinuxinlineaos",
+ "Name": "Qt3DSLinuxInlineAoS",
+ "QDocModule": "qt3dstudio",
+ "QtUsage": "Used by Qt3DStudio, Runtime component.",
+
+ "License": "Other",
+ "LicenseFile": "LICENSE.TXT",
+ "Copyright": "Copyright (c) 2001 Intel Corporation."
+}
diff --git a/src/foundation/macos/Qt3DSUnixAtomic.cpp b/src/foundation/macos/Qt3DSUnixAtomic.cpp
new file mode 100644
index 0000000..c1ac396
--- /dev/null
+++ b/src/foundation/macos/Qt3DSUnixAtomic.cpp
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2001-2004 NovodeX AG.
+** Copyright (C) 2004-2008 AGEIA Technologies, Inc.
+** Copyright (C) 2008-2013 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 "foundation/Qt3DS.h"
+#include "foundation/Qt3DSAtomic.h"
+
+#define PAUSE() asm("nop")
+
+namespace qt3ds {
+namespace foundation {
+
+ void *atomicCompareExchangePointer(volatile void **dest, void *exch, void *comp)
+ {
+ return __sync_val_compare_and_swap((void **)dest, comp, exch);
+ }
+
+ QT3DSI32 atomicCompareExchange(volatile QT3DSI32 *dest, QT3DSI32 exch, QT3DSI32 comp)
+ {
+ return __sync_val_compare_and_swap(dest, comp, exch);
+ }
+
+ QT3DSI32 atomicIncrement(volatile QT3DSI32 *val) { return __sync_add_and_fetch(val, 1); }
+
+ QT3DSI32 atomicDecrement(volatile QT3DSI32 *val) { return __sync_sub_and_fetch(val, 1); }
+
+ QT3DSI32 atomicAdd(volatile QT3DSI32 *val, QT3DSI32 delta) { return __sync_add_and_fetch(val, delta); }
+
+ QT3DSI32 atomicMax(volatile QT3DSI32 *val, QT3DSI32 val2)
+ {
+ QT3DSI32 oldVal, newVal;
+
+ do {
+ PAUSE();
+ oldVal = *val;
+
+ if (val2 > oldVal)
+ newVal = val2;
+ else
+ newVal = oldVal;
+
+ } while (atomicCompareExchange(val, newVal, oldVal) != oldVal);
+
+ return *val;
+ }
+
+ QT3DSI32 atomicExchange(volatile QT3DSI32 *val, QT3DSI32 val2)
+ {
+ QT3DSI32 newVal, oldVal;
+
+ do {
+ PAUSE();
+ oldVal = *val;
+ newVal = val2;
+ } while (atomicCompareExchange(val, newVal, oldVal) != oldVal);
+
+ return oldVal;
+ }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/macos/Qt3DSUnixFPU.cpp b/src/foundation/macos/Qt3DSUnixFPU.cpp
new file mode 100644
index 0000000..59c9850
--- /dev/null
+++ b/src/foundation/macos/Qt3DSUnixFPU.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2001-2004 NovodeX AG.
+** Copyright (C) 2004-2008 AGEIA Technologies, Inc.
+** Copyright (C) 2008-2013 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 "foundation/Qt3DSFPU.h"
+#include <fenv.h>
+
+#if !(defined(__CYGWIN__) || defined(PX_ANDROID))
+QT3DS_COMPILE_TIME_ASSERT(8 * sizeof(qt3ds::QT3DSU32) >= sizeof(fenv_t));
+#endif
+
+qt3ds::foundation::FPUGuard::FPUGuard()
+{
+#if defined(__CYGWIN__)
+#pragma message "FPUGuard::FPUGuard() is not implemented"
+#elif defined(PX_ANDROID)
+// not supported unless ARM_HARD_FLOAT is enabled.
+#else
+ fegetenv(reinterpret_cast<fenv_t *>(mControlWords));
+ fesetenv(FE_DFL_ENV);
+#endif
+}
+
+qt3ds::foundation::FPUGuard::~FPUGuard()
+{
+#if defined(__CYGWIN__)
+#pragma message "FPUGuard::~FPUGuard() is not implemented"
+#elif defined(PX_ANDROID)
+// not supported unless ARM_HARD_FLOAT is enabled.
+#else
+ fesetenv(reinterpret_cast<fenv_t *>(mControlWords));
+#endif
+}
diff --git a/src/foundation/macos/Qt3DSUnixMutex.cpp b/src/foundation/macos/Qt3DSUnixMutex.cpp
new file mode 100644
index 0000000..bbc5582
--- /dev/null
+++ b/src/foundation/macos/Qt3DSUnixMutex.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSAtomic.h"
+
+#include <pthread.h>
+
+namespace qt3ds {
+namespace foundation {
+
+ namespace {
+ pthread_mutex_t *getMutex(MutexImpl *impl)
+ {
+ return reinterpret_cast<pthread_mutex_t *>(impl);
+ }
+ }
+
+ MutexImpl::MutexImpl()
+ {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(getMutex(this), &attr);
+ pthread_mutexattr_destroy(&attr);
+ }
+
+ MutexImpl::~MutexImpl() { pthread_mutex_destroy(getMutex(this)); }
+
+ bool MutexImpl::lock() { return !pthread_mutex_lock(getMutex(this)); }
+
+ bool MutexImpl::trylock() { return !pthread_mutex_trylock(getMutex(this)); }
+
+ bool MutexImpl::unlock() { return !pthread_mutex_unlock(getMutex(this)); }
+
+ const QT3DSU32 MutexImpl::size = sizeof(pthread_mutex_t);
+
+ class ReadWriteLockImpl
+ {
+ public:
+ ReadWriteLockImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ pthread_mutex_t mutex;
+ volatile int readerCounter;
+ };
+
+ ReadWriteLock::ReadWriteLock(NVAllocatorCallback &alloc)
+ {
+ mImpl = QT3DS_NEW(alloc, ReadWriteLockImpl)(alloc);
+
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&mImpl->mutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+
+ mImpl->readerCounter = 0;
+ }
+
+ ReadWriteLock::~ReadWriteLock()
+ {
+ pthread_mutex_destroy(&mImpl->mutex);
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ void ReadWriteLock::lockReader()
+ {
+ pthread_mutex_lock(&mImpl->mutex);
+
+ atomicIncrement(&mImpl->readerCounter);
+
+ pthread_mutex_unlock(&mImpl->mutex);
+ }
+
+ void ReadWriteLock::lockWriter()
+ {
+ pthread_mutex_lock(&mImpl->mutex);
+
+ while (mImpl->readerCounter != 0)
+ ;
+ }
+
+ void ReadWriteLock::unlockReader() { atomicDecrement(&mImpl->readerCounter); }
+
+ void ReadWriteLock::unlockWriter() { pthread_mutex_unlock(&mImpl->mutex); }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/macos/Qt3DSUnixSemaphore.cpp b/src/foundation/macos/Qt3DSUnixSemaphore.cpp
new file mode 100644
index 0000000..90aab79
--- /dev/null
+++ b/src/foundation/macos/Qt3DSUnixSemaphore.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSSemaphore.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+
+namespace qt3ds {
+namespace foundation {
+
+ class SemaphoreImpl
+ {
+ public:
+ SemaphoreImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ QT3DSU32 count;
+ QT3DSU32 maxCount;
+ };
+
+ struct NVLinuxScopeLock
+ {
+ NVLinuxScopeLock(pthread_mutex_t &m)
+ : mMutex(m)
+ {
+ pthread_mutex_lock(&mMutex);
+ }
+
+ ~NVLinuxScopeLock() { pthread_mutex_unlock(&mMutex); }
+ private:
+ pthread_mutex_t &mMutex;
+ };
+
+ Semaphore::Semaphore(NVAllocatorCallback &alloc, QT3DSU32 initialCount, QT3DSU32 maxCount)
+ {
+ mImpl = QT3DS_NEW(alloc, SemaphoreImpl)(alloc);
+ int status = pthread_mutex_init(&mImpl->mutex, 0);
+ QT3DS_ASSERT(!status);
+ status = pthread_cond_init(&mImpl->cond, 0);
+ QT3DS_ASSERT(!status);
+ mImpl->count = initialCount;
+ mImpl->maxCount = maxCount;
+ QT3DS_ASSERT(initialCount <= maxCount);
+ }
+
+ Semaphore::~Semaphore()
+ {
+ pthread_cond_destroy(&mImpl->cond);
+ pthread_mutex_destroy(&mImpl->mutex);
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ bool Semaphore::wait(QT3DSU32 milliseconds)
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+
+ if (mImpl->count > 0) {
+ mImpl->count--;
+ return true;
+ }
+
+ if (milliseconds == 0) {
+ return false;
+ }
+
+ if (milliseconds == QT3DSU32(-1)) {
+ int status = pthread_cond_wait(&mImpl->cond, &mImpl->mutex);
+ QT3DS_ASSERT(!status);
+ (void)status;
+ } else {
+ timespec ts;
+ timeval tp;
+ gettimeofday(&tp, NULL);
+ QT3DSU32 sec = milliseconds / 1000;
+ QT3DSU32 usec = (milliseconds - 1000 * sec) * 1000;
+
+ // sschirm: taking into account that us might accumulate to a second
+ // otherwise the pthread_cond_timedwait complains on osx.
+ usec = tp.tv_usec + usec;
+ QT3DSU32 div_sec = usec / 1000000;
+ QT3DSU32 rem_usec = usec - div_sec * 1000000;
+
+ ts.tv_sec = tp.tv_sec + sec + div_sec;
+ ts.tv_nsec = rem_usec * 1000;
+
+ int ierr = pthread_cond_timedwait(&mImpl->cond, &mImpl->mutex, &ts);
+ QT3DS_ASSERT((ierr == 0) || (ierr == ETIMEDOUT));
+ (void)ierr;
+ return false;
+ }
+
+ return true;
+ }
+
+ void Semaphore::post()
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+ mImpl->count++;
+ if (mImpl->count > mImpl->maxCount)
+ mImpl->count = mImpl->maxCount;
+ else {
+ pthread_cond_broadcast(&mImpl->cond);
+ }
+ }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/macos/Qt3DSUnixSync.cpp b/src/foundation/macos/Qt3DSUnixSync.cpp
new file mode 100644
index 0000000..52f9d7a
--- /dev/null
+++ b/src/foundation/macos/Qt3DSUnixSync.cpp
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DS.h"
+#include "foundation/Qt3DSSync.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <time.h>
+#include <sys/time.h>
+
+namespace qt3ds {
+namespace foundation {
+
+ class SyncImpl
+ {
+ public:
+ SyncImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ volatile bool is_set;
+ };
+
+ struct NVLinuxScopeLock
+ {
+ NVLinuxScopeLock(pthread_mutex_t &m)
+ : mMutex(m)
+ {
+ pthread_mutex_lock(&mMutex);
+ }
+
+ ~NVLinuxScopeLock() { pthread_mutex_unlock(&mMutex); }
+ private:
+ pthread_mutex_t &mMutex;
+ };
+
+ Sync::Sync(NVAllocatorCallback &alloc)
+ {
+ mImpl = QT3DS_NEW(alloc, SyncImpl)(alloc);
+ int status = pthread_mutex_init(&mImpl->mutex, 0);
+ QT3DS_ASSERT(!status);
+ status = pthread_cond_init(&mImpl->cond, 0);
+ QT3DS_ASSERT(!status);
+ mImpl->is_set = false;
+ }
+
+ Sync::~Sync()
+ {
+ pthread_cond_destroy(&mImpl->cond);
+ pthread_mutex_destroy(&mImpl->mutex);
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ void Sync::reset()
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+ mImpl->is_set = false;
+ }
+
+ void Sync::set()
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+ if (!mImpl->is_set) {
+ mImpl->is_set = true;
+ pthread_cond_broadcast(&mImpl->cond);
+ }
+ }
+
+ bool Sync::wait(QT3DSU32 ms)
+ {
+ NVLinuxScopeLock lock(mImpl->mutex);
+ if (!mImpl->is_set) {
+ if (ms == QT3DSU32(-1)) {
+ int status = pthread_cond_wait(&mImpl->cond, &mImpl->mutex);
+ QT3DS_ASSERT(!status);
+ (void)status;
+ } else {
+ timespec ts;
+ timeval tp;
+ gettimeofday(&tp, NULL);
+ QT3DSU32 sec = ms / 1000;
+ QT3DSU32 usec = (ms - 1000 * sec) * 1000;
+
+ // sschirm: taking into account that us might accumulate to a second
+ // otherwise the pthread_cond_timedwait complains on osx.
+ usec = tp.tv_usec + usec;
+ QT3DSU32 div_sec = usec / 1000000;
+ QT3DSU32 rem_usec = usec - div_sec * 1000000;
+
+ ts.tv_sec = tp.tv_sec + sec + div_sec;
+ ts.tv_nsec = rem_usec * 1000;
+
+ int ierr = pthread_cond_timedwait(&mImpl->cond, &mImpl->mutex, &ts);
+ QT3DS_ASSERT((ierr == 0) || (ierr == ETIMEDOUT));
+ (void)ierr;
+ }
+ }
+ return mImpl->is_set;
+ }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/macos/Qt3DSUnixTime.cpp b/src/foundation/macos/Qt3DSUnixTime.cpp
new file mode 100644
index 0000000..58eadcb
--- /dev/null
+++ b/src/foundation/macos/Qt3DSUnixTime.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2001-2004 NovodeX AG.
+** Copyright (C) 2004-2008 AGEIA Technologies, Inc.
+** Copyright (C) 2008-2013 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 "foundation/Qt3DS.h"
+#include "foundation/Qt3DSTime.h"
+
+#include <time.h>
+#include <sys/time.h>
+
+#if defined QT3DS_APPLE
+#include <mach/mach_time.h>
+#endif
+
+// Use real-time high-precision timer.
+#ifndef QT3DS_APPLE
+#define CLOCKID CLOCK_REALTIME
+#endif
+
+namespace qt3ds {
+namespace foundation {
+
+ const CounterFrequencyToTensOfNanos Time::sCounterFreq = Time::getCounterFrequency();
+
+ static Time::Second getTimeSeconds()
+ {
+ static struct timeval _tv;
+ gettimeofday(&_tv, NULL);
+ return double(_tv.tv_sec) + double(_tv.tv_usec) * 0.000001;
+ }
+
+ Time::Time() { mLastTime = getTimeSeconds(); }
+
+ Time::Second Time::getElapsedSeconds()
+ {
+ Time::Second curTime = getTimeSeconds();
+ Time::Second diff = curTime - mLastTime;
+ mLastTime = curTime;
+ return diff;
+ }
+
+ Time::Second Time::peekElapsedSeconds()
+ {
+ Time::Second curTime = getTimeSeconds();
+ Time::Second diff = curTime - mLastTime;
+ return diff;
+ }
+
+ Time::Second Time::getLastTime() const { return mLastTime; }
+
+#ifdef QT3DS_APPLE
+ CounterFrequencyToTensOfNanos Time::getCounterFrequency()
+ {
+ mach_timebase_info_data_t info;
+ mach_timebase_info(&info);
+ // mach_absolute_time * (info.numer/info.denom) is in units of nano seconds
+ return CounterFrequencyToTensOfNanos(info.numer, info.denom * 10);
+ }
+
+ QT3DSU64 Time::getCurrentCounterValue() { return mach_absolute_time(); }
+
+#else
+
+ CounterFrequencyToTensOfNanos Time::getCounterFrequency()
+ {
+ return CounterFrequencyToTensOfNanos(1, 10);
+ }
+
+ PxU64 Time::getCurrentCounterValue()
+ {
+ struct timespec mCurrTimeInt;
+ clock_gettime(CLOCKID, &mCurrTimeInt);
+ // Convert to nanos as this doesn't cause a large divide here
+ return (static_cast<PxU64>(mCurrTimeInt.tv_sec) * 1000000000)
+ + (static_cast<PxU64>(mCurrTimeInt.tv_nsec));
+ }
+#endif
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/qt/formatdiscovery.cpp b/src/foundation/qt/formatdiscovery.cpp
new file mode 100644
index 0000000..7ea762b
--- /dev/null
+++ b/src/foundation/qt/formatdiscovery.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://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 <QtGui/qopenglcontext.h>
+#include <QtGui/qoffscreensurface.h>
+#include <QtGui/qopenglfunctions.h>
+#include <QtGui/qopengltexture.h>
+
+#include "qstudio3dglobal.h"
+#include "Qt3DSFoundation.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace Q3DS {
+
+static QSurfaceFormat findIdealGLVersion()
+{
+ QSurfaceFormat fmt;
+ fmt.setProfile(QSurfaceFormat::CoreProfile);
+
+ // Advanced: Try 4.3 core (so we get compute shaders for instance)
+ fmt.setVersion(4, 3);
+ QOpenGLContext ctx;
+ ctx.setFormat(fmt);
+ if (ctx.create() && ctx.format().version() >= qMakePair(4, 3)) {
+ qDebug("Requesting OpenGL 4.3 core context succeeded");
+ return ctx.format();
+ }
+
+ // Basic: Stick with 3.3 for now to keep less fortunate, Mesa-based systems happy
+ fmt.setVersion(3, 3);
+ ctx.setFormat(fmt);
+ if (ctx.create() && ctx.format().version() >= qMakePair(3, 3)) {
+ qDebug("Requesting OpenGL 3.3 core context succeeded");
+ return ctx.format();
+ }
+
+ qWarning("Failed to get OpenGL 3.3 or OpenGL 4.3 context!");
+ return fmt;
+}
+
+static QSurfaceFormat findIdealGLESVersion()
+{
+ QSurfaceFormat fmt;
+
+ // Advanced: Try 3.1 (so we get compute shaders for instance)
+ fmt.setVersion(3, 1);
+ QOpenGLContext ctx;
+ ctx.setFormat(fmt);
+
+ // Now, it's important to check the format with the actual version (parsed
+ // back from GL_VERSION) since some implementations, ANGLE for instance,
+ // are broken and succeed the 3.1 context request even though they only
+ // support and return a 3.0 context. This is against the spec since 3.0 is
+ // obviously not backwards compatible with 3.1, but hey...
+ if (ctx.create() && ctx.format().version() >= qMakePair(3, 1)) {
+ qDebug("Requesting OpenGL ES 3.1 context succeeded");
+ return ctx.format();
+ }
+
+ // Basic: OpenGL ES 3.0 is a hard requirement at the moment since we can
+ // only generate 300 ES shaders, uniform buffers are mandatory.
+ fmt.setVersion(3, 0);
+ ctx.setFormat(fmt);
+ if (ctx.create() && ctx.format().version() >= qMakePair(3, 0)) {
+ qDebug("Requesting OpenGL ES 3.0 context succeeded");
+ return ctx.format();
+ }
+
+ fmt.setVersion(2, 0);
+ ctx.setFormat(fmt);
+ if (ctx.create()) {
+ qDebug("Requesting OpenGL ES 2.0 context succeeded");
+ return fmt;
+ }
+
+ qWarning("Failed to get OpenGL ES 2.0, 3.0 or 3.1 context");
+ return fmt;
+}
+
+QSurfaceFormat surfaceFormat()
+{
+ static const QSurfaceFormat f = [] {
+ QSurfaceFormat fmt;
+ // works in dynamic gl builds too because there's a qguiapp already
+ // this requirement is also a problem, see QT3DS-3603
+ if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
+ fmt = findIdealGLVersion();
+ else
+ fmt = findIdealGLESVersion();
+ fmt.setDepthBufferSize(24);
+ fmt.setStencilBufferSize(8);
+ // Ignore MSAA here as that is a per-layer setting.
+ return fmt;
+ }();
+ return f;
+}
+} // End namespace Q3DS
+
+QT_END_NAMESPACE
diff --git a/src/foundation/qt_attribution.json b/src/foundation/qt_attribution.json
new file mode 100644
index 0000000..537d8be
--- /dev/null
+++ b/src/foundation/qt_attribution.json
@@ -0,0 +1,22 @@
+{
+ "Id": "convertutf",
+ "Name": "ConvertUTF",
+ "QDocModule": "qt3dstudio",
+ "QtUsage": "Used by Qt3DStudio, Studio and Runtime components.",
+
+ "License": "Other",
+ "LicenseFile": "LICENSE_CONVERTUTF.TXT",
+ "Copyright": "Copyright 2001-2004 Unicode, Inc."
+}
+,
+{
+ "Id": "socket",
+ "Name": "Socket",
+ "QDocModule": "qt3dstudio",
+ "QtUsage": "Used by Qt3DStudio, Runtime component.",
+
+ "License": "MIT license",
+ "LicenseId": "MIT",
+ "LicenseFile": "LICENCE_SOCKET.TXT",
+ "Copyright": "Copyright (C) 2004-2013 Diego Nehab."
+}
diff --git a/src/foundation/windows/LICENSE.TXT b/src/foundation/windows/LICENSE.TXT
new file mode 100644
index 0000000..f40caef
--- /dev/null
+++ b/src/foundation/windows/LICENSE.TXT
@@ -0,0 +1,7 @@
+ Copyright (c) 2001 Intel Corporation.
+
+Permition is granted to use, copy, distribute and prepare derivative works
+of this library for any purpose and without fee, provided, that the above
+copyright notice and this statement appear in all copies.
+Intel makes no representations about the suitability of this library for
+any purpose, and specifically disclaims all warranties.
diff --git a/src/foundation/windows/Qt3DSWindowsAoS.h b/src/foundation/windows/Qt3DSWindowsAoS.h
new file mode 100644
index 0000000..c654ec7
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsAoS.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_WINDOWS_AOS_H
+#define QT3DS_WINDOWS_AOS_H
+
+// no includes here! this file should be included from NVcVecMath.h only!!!
+
+#if !COMPILE_VECTOR_INTRINSICS
+#error Vector intrinsics should not be included when using scalar implementation.
+#endif
+
+typedef __m128 FloatV;
+typedef __m128 Vec3V;
+typedef __m128 Vec4V;
+typedef __m128 BoolV;
+typedef __m128 VecU32V;
+typedef __m128 VecI32V;
+typedef __m128 VecU16V;
+typedef __m128 VecI16V;
+typedef __m128 VecU8V;
+typedef __m128 QuatV;
+
+#define FloatVArg FloatV &
+#define Vec3VArg Vec3V &
+#define Vec4VArg Vec4V &
+#define BoolVArg BoolV &
+#define VecU32VArg VecU32V &
+#define VecI32VArg VecI32V &
+#define VecU16VArg VecU16V &
+#define VecI16VArg VecI16V &
+#define VecU8VArg VecU8V &
+#define QuatVArg QuatV &
+
+QT3DS_ALIGN_PREFIX(16)
+struct Mat33V
+{
+ Mat33V() {}
+ Mat33V(const Vec3V &c0, const Vec3V &c1, const Vec3V &c2)
+ : col0(c0)
+ , col1(c1)
+ , col2(c2)
+ {
+ }
+ Vec3V QT3DS_ALIGN(16, col0);
+ Vec3V QT3DS_ALIGN(16, col1);
+ Vec3V QT3DS_ALIGN(16, col2);
+} QT3DS_ALIGN_SUFFIX(16);
+
+QT3DS_ALIGN_PREFIX(16)
+struct Mat34V
+{
+ Mat34V() {}
+ Mat34V(const Vec3V &c0, const Vec3V &c1, const Vec3V &c2, const Vec3V &c3)
+ : col0(c0)
+ , col1(c1)
+ , col2(c2)
+ , col3(c3)
+ {
+ }
+ Vec3V QT3DS_ALIGN(16, col0);
+ Vec3V QT3DS_ALIGN(16, col1);
+ Vec3V QT3DS_ALIGN(16, col2);
+ Vec3V QT3DS_ALIGN(16, col3);
+} QT3DS_ALIGN_SUFFIX(16);
+
+QT3DS_ALIGN_PREFIX(16)
+struct Mat43V
+{
+ Mat43V() {}
+ Mat43V(const Vec4V &c0, const Vec4V &c1, const Vec4V &c2)
+ : col0(c0)
+ , col1(c1)
+ , col2(c2)
+ {
+ }
+ Vec4V QT3DS_ALIGN(16, col0);
+ Vec4V QT3DS_ALIGN(16, col1);
+ Vec4V QT3DS_ALIGN(16, col2);
+} QT3DS_ALIGN_SUFFIX(16);
+
+QT3DS_ALIGN_PREFIX(16)
+struct Mat44V
+{
+ Mat44V() {}
+ Mat44V(const Vec4V &c0, const Vec4V &c1, const Vec4V &c2, const Vec4V &c3)
+ : col0(c0)
+ , col1(c1)
+ , col2(c2)
+ , col3(c3)
+ {
+ }
+ Vec4V QT3DS_ALIGN(16, col0);
+ Vec4V QT3DS_ALIGN(16, col1);
+ Vec4V QT3DS_ALIGN(16, col2);
+ Vec4V QT3DS_ALIGN(16, col3);
+} QT3DS_ALIGN_SUFFIX(16);
+
+#endif // QT3DS_WINDOWS_AOS_H
diff --git a/src/foundation/windows/Qt3DSWindowsAtomic.cpp b/src/foundation/windows/Qt3DSWindowsAtomic.cpp
new file mode 100644
index 0000000..4f95d3d
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsAtomic.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/windows/Qt3DSWindowsInclude.h"
+#include "foundation/Qt3DSAtomic.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ QT3DSI32 atomicExchange(volatile QT3DSI32 *val, QT3DSI32 val2)
+ {
+ return (QT3DSI32)InterlockedExchange((volatile LONG *)val, (LONG)val2);
+ }
+
+ QT3DSI32 atomicCompareExchange(volatile QT3DSI32 *dest, QT3DSI32 exch, QT3DSI32 comp)
+ {
+ return (QT3DSI32)InterlockedCompareExchange((volatile LONG *)dest, exch, comp);
+ }
+
+ void *atomicCompareExchangePointer(volatile void **dest, void *exch, void *comp)
+ {
+ return InterlockedCompareExchangePointer((volatile PVOID *)dest, exch, comp);
+ }
+
+ QT3DSI32 atomicIncrement(volatile QT3DSI32 *val)
+ {
+ return (QT3DSI32)InterlockedIncrement((volatile LONG *)val);
+ }
+
+ QT3DSI32 atomicDecrement(volatile QT3DSI32 *val)
+ {
+ return (QT3DSI32)InterlockedDecrement((volatile LONG *)val);
+ }
+
+ QT3DSI32 atomicAdd(volatile QT3DSI32 *val, QT3DSI32 delta)
+ {
+ LONG newValue, oldValue;
+ do {
+ oldValue = *val;
+ newValue = oldValue + delta;
+ } while (InterlockedCompareExchange((volatile LONG *)val, newValue, oldValue) != oldValue);
+
+ return newValue;
+ }
+
+ QT3DSI32 atomicMax(volatile QT3DSI32 *val, QT3DSI32 val2)
+ {
+ // Could do this more efficiently in asm...
+
+ LONG newValue, oldValue;
+
+ do {
+ oldValue = *val;
+
+ if (val2 > oldValue)
+ newValue = val2;
+ else
+ newValue = oldValue;
+
+ } while (InterlockedCompareExchange((volatile LONG *)val, newValue, oldValue) != oldValue);
+
+ return newValue;
+ }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/windows/Qt3DSWindowsFPU.cpp b/src/foundation/windows/Qt3DSWindowsFPU.cpp
new file mode 100644
index 0000000..4724280
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsFPU.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+#include "foundation/Qt3DSFPU.h"
+#include "float.h"
+
+#ifdef QT3DS_X64
+#define _MCW_ALL _MCW_DN | _MCW_EM | _MCW_RC
+#else
+#define _MCW_ALL _MCW_DN | _MCW_EM | _MCW_IC | _MCW_RC | _MCW_PC
+#endif
+
+qt3ds::foundation::FPUGuard::FPUGuard()
+{
+// default plus FTZ and DAZ
+#if defined(QT3DS_WINDOWS) && defined(QT3DS_VC)
+#ifdef QT3DS_X64
+ _controlfp_s(mControlWords, _CW_DEFAULT | _DN_FLUSH, _MCW_ALL);
+#else
+ __control87_2(_CW_DEFAULT | _DN_FLUSH, _MCW_ALL, mControlWords, mControlWords + 1);
+#endif
+#endif
+}
+
+qt3ds::foundation::FPUGuard::~FPUGuard()
+{
+#if defined(QT3DS_WINDOWS) && defined(QT3DS_VC)
+#ifdef QT3DS_X64
+ _controlfp_s(mControlWords, *mControlWords, _MCW_ALL);
+#else
+ __control87_2(mControlWords[0], _MCW_ALL, mControlWords, 0);
+ __control87_2(mControlWords[1], _MCW_ALL, 0, mControlWords + 1);
+#endif
+#endif
+}
diff --git a/src/foundation/windows/Qt3DSWindowsFile.h b/src/foundation/windows/Qt3DSWindowsFile.h
new file mode 100644
index 0000000..6c232a5
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsFile.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_WINDOWS_FILE_H
+#define QT3DS_FOUNDATION_QT3DS_WINDOWS_FILE_H
+
+#include "foundation/Qt3DS.h"
+
+#include <stdio.h>
+
+namespace qt3ds {
+namespace foundation {
+ QT3DS_INLINE errno_t fopen_s(FILE **_File, const char *_Filename, const char *_Mode)
+ {
+ return ::fopen_s(_File, _Filename, _Mode);
+ };
+
+} // namespace foundation
+} // namespace qt3ds
+
+#endif
diff --git a/src/foundation/windows/Qt3DSWindowsInclude.h b/src/foundation/windows/Qt3DSWindowsInclude.h
new file mode 100644
index 0000000..f01c9f1
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsInclude.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef WINDOWSINCLUDE_H
+#define WINDOWSINCLUDE_H
+
+#include "foundation/Qt3DS.h"
+
+#ifndef _WIN32
+#error "This file should only be included by Windows builds!!"
+#endif
+
+#ifdef _WINDOWS_ // windows already included
+#error "Only include windows.h through this file!!"
+#endif
+
+// We only support >= Windows XP, and we need this for critical section and
+#define _WIN32_WINNT 0x0500
+
+// turn off as much as we can for windows. All we really need is the thread functions(critical
+// sections/Interlocked* etc)
+#define NOGDICAPMASKS
+#define NOVIRTUALKEYCODES
+#define NOWINMESSAGES
+#define NOWINSTYLES
+#define NOSYSMETRICS
+#define NOMENUS
+#define NOICONS
+#define NOKEYSTATES
+#define NOSYSCOMMANDS
+#define NORASTEROPS
+#define NOSHOWWINDOW
+#define NOATOM
+#define NOCLIPBOARD
+#define NOCOLOR
+#define NOCTLMGR
+#define NODRAWTEXT
+#define NOGDI
+#define NOUSER
+#define NONLS
+#define NOMB
+#define NOMEMMGR
+#define NOMETAFILE
+#define NOMSG
+#define NOOPENFILE
+#define NOSCROLL
+#define NOSERVICE
+#define NOSOUND
+#define NOTEXTMETRIC
+#define NOWH
+#define NOWINOFFSETS
+#define NOCOMM
+#define NOKANJI
+#define NOHELP
+#define NOPROFILER
+#define NODEFERWINDOWPOS
+#define NOMCX
+#define WIN32_LEAN_AND_MEAN
+
+#include <windows.h>
+
+#ifdef QT3DS_SUPPORT_SSE
+#include <xmmintrin.h>
+#endif
+
+#endif
diff --git a/src/foundation/windows/Qt3DSWindowsInlineAoS.h b/src/foundation/windows/Qt3DSWindowsInlineAoS.h
new file mode 100644
index 0000000..60c5789
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsInlineAoS.h
@@ -0,0 +1,2715 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+//
+// Copyright (c) 2001 Intel Corporation.
+//
+// Permition is granted to use, copy, distribute and prepare derivative works
+// of this library for any purpose and without fee, provided, that the above
+// copyright notice and this statement appear in all copies.
+// Intel makes no representations about the suitability of this library for
+// any purpose, and specifically disclaims all warranties.
+// See LEGAL.TXT for all the legal information.
+//
+
+#ifndef QT3DS_WINDOWS_INLINE_AOS_H
+#define QT3DS_WINDOWS_INLINE_AOS_H
+
+#if !COMPILE_VECTOR_INTRINSICS
+#error Vector intrinsics should not be included when using scalar implementation.
+#endif
+
+// Remove this define when all platforms use simd solver.
+#define QT3DS_SUPPORT_SIMD
+
+QT3DS_FORCE_INLINE __m128 m128_I2F(__m128i n)
+{
+ return _mm_castsi128_ps(n);
+}
+QT3DS_FORCE_INLINE __m128i m128_F2I(__m128 n)
+{
+ return _mm_castps_si128(n);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAllTrue4_R(const BoolV a)
+{
+ const QT3DSI32 moveMask = _mm_movemask_ps(a);
+ return moveMask == (0xf);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAnyTrue4_R(const BoolV a)
+{
+ const QT3DSI32 moveMask = _mm_movemask_ps(a);
+ return moveMask != (0x0);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAllTrue3_R(const BoolV a)
+{
+ const QT3DSI32 moveMask = _mm_movemask_ps(a);
+ return (moveMask & 0x7) == (0x7);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAnyTrue3_R(const BoolV a)
+{
+ const QT3DSI32 moveMask = _mm_movemask_ps(a);
+ return (moveMask & 0x7) != (0x0);
+}
+
+/////////////////////////////////////////////////////////////////////
+////FUNCTIONS USED ONLY FOR ASSERTS IN VECTORISED IMPLEMENTATIONS
+/////////////////////////////////////////////////////////////////////
+
+QT3DS_FORCE_INLINE QT3DSU32 FiniteTestEq(const Vec4V a, const Vec4V b)
+{
+ // This is a bit of a bodge.
+ //_mm_comieq_ss returns 1 if either value is nan so we need to re-cast a and b with true encoded
+ //as a non-nan number.
+ // There must be a better way of doing this in sse.
+ const BoolV one = FOne();
+ const BoolV zero = FZero();
+ const BoolV a1 = V4Sel(a, one, zero);
+ const BoolV b1 = V4Sel(b, one, zero);
+ return (_mm_comieq_ss(a1, b1) && _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(1, 1, 1, 1)),
+ _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(1, 1, 1, 1)))
+ && _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(2, 2, 2, 2)),
+ _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(2, 2, 2, 2)))
+ && _mm_comieq_ss(_mm_shuffle_ps(a1, a1, _MM_SHUFFLE(3, 3, 3, 3)),
+ _mm_shuffle_ps(b1, b1, _MM_SHUFFLE(3, 3, 3, 3))));
+}
+
+QT3DS_FORCE_INLINE bool isValidFloatV(const FloatV a)
+{
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)))
+ && _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)))
+ && _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))));
+}
+
+QT3DS_FORCE_INLINE bool isValidVec3V(const Vec3V a)
+{
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3)), FZero()) ? true : false);
+}
+
+QT3DS_FORCE_INLINE bool isFiniteFloatV(const FloatV a)
+{
+ const QT3DSU32 badNumber = (_FPCLASS_SNAN | _FPCLASS_QNAN | _FPCLASS_NINF | _FPCLASS_PINF);
+ const FloatV vBadNum = FloatV_From_F32((QT3DSF32 &)badNumber);
+ const BoolV vMask = BAnd(vBadNum, a);
+ return FiniteTestEq(vMask, BFFFF()) == 1;
+}
+
+QT3DS_FORCE_INLINE bool isFiniteVec3V(const Vec3V a)
+{
+ const QT3DSU32 badNumber = (_FPCLASS_SNAN | _FPCLASS_QNAN | _FPCLASS_NINF | _FPCLASS_PINF);
+ const Vec3V vBadNum = Vec3V_From_F32((QT3DSF32 &)badNumber);
+ const BoolV vMask = BAnd(BAnd(vBadNum, a), BTTTF());
+ return FiniteTestEq(vMask, BFFFF()) == 1;
+}
+
+QT3DS_FORCE_INLINE bool isFiniteVec4V(const Vec4V a)
+{
+ /*Vec4V a;
+ QT3DS_ALIGN(16, QT3DSF32 f[4]);
+ F32Array_Aligned_From_Vec4V(a, f);
+ return NVIsFinite(f[0])
+ && NVIsFinite(f[1])
+ && NVIsFinite(f[2])
+ && NVIsFinite(f[3]);*/
+
+ const QT3DSU32 badNumber = (_FPCLASS_SNAN | _FPCLASS_QNAN | _FPCLASS_NINF | _FPCLASS_PINF);
+ const Vec4V vBadNum = Vec4V_From_F32((QT3DSF32 &)badNumber);
+ const BoolV vMask = BAnd(vBadNum, a);
+
+ return FiniteTestEq(vMask, BFFFF()) == 1;
+}
+
+QT3DS_FORCE_INLINE bool hasZeroElementinFloatV(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FZero()) ? true : false);
+}
+
+QT3DS_FORCE_INLINE bool hasZeroElementInVec3V(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FZero())
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)), FZero())
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)), FZero()));
+}
+
+QT3DS_FORCE_INLINE bool hasZeroElementInVec4V(const Vec4V a)
+{
+ return (_mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)), FZero())
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)), FZero())
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)), FZero())
+ || _mm_comieq_ss(_mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3)), FZero()));
+}
+
+/////////////////////////////////////////////////////////////////////
+////VECTORISED FUNCTION IMPLEMENTATIONS
+/////////////////////////////////////////////////////////////////////
+
+QT3DS_FORCE_INLINE FloatV FloatV_From_F32(const QT3DSF32 f)
+{
+ return (_mm_load1_ps(&f));
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_F32(const QT3DSF32 f)
+{
+ return _mm_set_ps(0.0f, f, f, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_F32(const QT3DSF32 f)
+{
+ return (_mm_load1_ps(&f));
+}
+
+QT3DS_FORCE_INLINE BoolV BoolV_From_Bool32(const bool f)
+{
+ const QT3DSU32 i = -(QT3DSI32)f;
+ return _mm_load1_ps((float *)&i);
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_NVVec3_Aligned(const QT3DSVec3 &f)
+{
+ VECMATHAOS_ASSERT(0 == ((size_t)&f & 0x0f));
+ return (_mm_set_ps(0.0f, f.z, f.y, f.x));
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_NVVec3(const QT3DSVec3 &f)
+{
+ return (_mm_set_ps(0.0f, f.z, f.y, f.x));
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_NVVec3_WUndefined(const QT3DSVec3 &f)
+{
+ return (_mm_set_ps(0.0f, f.z, f.y, f.x));
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_Vec4V(Vec4V v)
+{
+ return V4SetW(v, V4Zero());
+}
+
+QT3DS_FORCE_INLINE Vec3V Vec3V_From_F32Array_Aligned(const QT3DSF32 *const f)
+{
+ VECMATHAOS_ASSERT(0 == ((QT3DSU64)f & 0x0f));
+ return (_mm_load_ps(f));
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_Vec3V(Vec3V f)
+{
+ return f; // ok if it is implemented as the same type.
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_NVVec3_WUndefined(const QT3DSVec3 &f)
+{
+ return (_mm_set_ps(0.0f, f.z, f.y, f.x));
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_F32Array_Aligned(const QT3DSF32 *const f)
+{
+ VECMATHAOS_ASSERT(0 == ((QT3DSU64)f & 0x0f));
+ return (_mm_load_ps(f));
+}
+
+QT3DS_FORCE_INLINE void F32Array_Aligned_From_Vec4V(const Vec4V a, QT3DSF32 *f)
+{
+ VECMATHAOS_ASSERT(0 == ((QT3DSU64)f & 0x0f));
+ _mm_store_ps(f, a);
+}
+
+QT3DS_FORCE_INLINE void NVU32Array_Aligned_From_BoolV(const BoolV a, QT3DSU32 *f)
+{
+ VECMATHAOS_ASSERT(0 == ((QT3DSU64)f & 0x0f));
+ _mm_store_ps((QT3DSF32 *)f, a);
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_F32Array(const QT3DSF32 *const f)
+{
+ return (_mm_loadu_ps(f));
+}
+
+QT3DS_FORCE_INLINE BoolV BoolV_From_Bool32Array(const bool *const f)
+{
+ const QT3DS_ALIGN(16, QT3DSU32 b[4]) = { -(QT3DSI32)f[0], -(QT3DSI32)f[1], -(QT3DSI32)f[2], -(QT3DSI32)f[3] };
+ return _mm_load1_ps((float *)&b);
+}
+
+QT3DS_FORCE_INLINE QT3DSF32 NVF32_From_FloatV(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ QT3DSF32 f;
+ _mm_store_ss(&f, a);
+ return f;
+}
+
+QT3DS_FORCE_INLINE void NVF32_From_FloatV(const FloatV a, QT3DSF32 *QT3DS_RESTRICT f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ _mm_store_ss(f, a);
+}
+
+QT3DS_FORCE_INLINE void NVVec3Aligned_From_Vec3V(const Vec3V a, QT3DSVec3 &f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(0 == ((int)&a & 0x0F));
+ VECMATHAOS_ASSERT(0 == ((int)&f & 0x0F));
+ QT3DS_ALIGN(16, QT3DSF32 f2[4]);
+ _mm_store_ps(f2, a);
+ f = QT3DSVec3(f2[0], f2[1], f2[2]);
+}
+
+QT3DS_FORCE_INLINE void Store_From_BoolV(const BoolV b, QT3DSU32 *b2)
+{
+ _mm_store_ss((QT3DSF32 *)b2, b);
+}
+
+QT3DS_FORCE_INLINE void NVVec3_From_Vec3V(const Vec3V a, QT3DSVec3 &f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(0 == ((int)&a & 0x0F));
+ QT3DS_ALIGN(16, QT3DSF32 f2[4]);
+ _mm_store_ps(f2, a);
+ f = QT3DSVec3(f2[0], f2[1], f2[2]);
+}
+
+QT3DS_FORCE_INLINE Mat33V Mat33V_From_NVMat33(const QT3DSMat33 &m)
+{
+ return Mat33V(Vec3V_From_NVVec3(m.column0), Vec3V_From_NVVec3(m.column1),
+ Vec3V_From_NVVec3(m.column2));
+}
+
+QT3DS_FORCE_INLINE void NVMat33_From_Mat33V(const Mat33V &m, QT3DSMat33 &out)
+{
+ QT3DS_ASSERT((size_t(&out) & 15) == 0);
+ NVVec3_From_Vec3V(m.col0, out.column0);
+ NVVec3_From_Vec3V(m.col1, out.column1);
+ NVVec3_From_Vec3V(m.col2, out.column2);
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsEqualFloatV(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return (_mm_comieq_ss(a, b) != 0);
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsEqualVec3V(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return V3AllEq(a, b) != 0;
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsEqualVec4V(const Vec4V a, const Vec4V b)
+{
+ return V4AllEq(a, b) != 0;
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsEqualBoolV(const BoolV a, const BoolV b)
+{
+ return BAllTrue4_R(VecI32V_IsEq(a, b)) != 0;
+}
+
+#define VECMATH_AOS_EPSILON (1e-3f)
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsNearEqualFloatV(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ const FloatV c = FSub(a, b);
+ static const FloatV minError = FloatV_From_F32(-VECMATH_AOS_EPSILON);
+ static const FloatV maxError = FloatV_From_F32(VECMATH_AOS_EPSILON);
+ return (_mm_comigt_ss(c, minError) && _mm_comilt_ss(c, maxError));
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsNearEqualVec3V(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ const Vec3V c = V3Sub(a, b);
+ static const Vec3V minError = Vec3V_From_F32(-VECMATH_AOS_EPSILON);
+ static const Vec3V maxError = Vec3V_From_F32(VECMATH_AOS_EPSILON);
+ return (_mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), maxError));
+}
+
+QT3DS_FORCE_INLINE bool _VecMathTests::allElementsNearEqualVec4V(const Vec4V a, const Vec4V b)
+{
+ const Vec4V c = V4Sub(a, b);
+ static const Vec4V minError = Vec4V_From_F32(-VECMATH_AOS_EPSILON);
+ static const Vec4V maxError = Vec4V_From_F32(VECMATH_AOS_EPSILON);
+ return (_mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(0, 0, 0, 0)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(1, 1, 1, 1)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(2, 2, 2, 2)), maxError)
+ && _mm_comigt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3)), minError)
+ && _mm_comilt_ss(_mm_shuffle_ps(c, c, _MM_SHUFFLE(3, 3, 3, 3)), maxError));
+}
+
+//////////////////////////////////
+// FLOATV
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE FloatV FZero()
+{
+ return FloatV_From_F32(0.0f);
+}
+
+QT3DS_FORCE_INLINE FloatV FOne()
+{
+ return FloatV_From_F32(1.0f);
+}
+
+QT3DS_FORCE_INLINE FloatV FHalf()
+{
+ return FloatV_From_F32(0.5f);
+}
+
+QT3DS_FORCE_INLINE FloatV FEps()
+{
+ return FloatV_From_F32(QT3DS_ENV_REAL);
+}
+
+QT3DS_FORCE_INLINE FloatV FEps6()
+{
+ return FloatV_From_F32(1e-6f);
+}
+
+QT3DS_FORCE_INLINE FloatV FMax()
+{
+ return FloatV_From_F32(QT3DS_MAX_REAL);
+}
+
+QT3DS_FORCE_INLINE FloatV FNegMax()
+{
+ return FloatV_From_F32(-QT3DS_MAX_REAL);
+}
+
+QT3DS_FORCE_INLINE FloatV IZero()
+{
+ const QT3DSU32 zero = 0;
+ return _mm_load1_ps((QT3DSF32 *)&zero);
+}
+
+QT3DS_FORCE_INLINE FloatV IOne()
+{
+ const QT3DSU32 one = 1;
+ return _mm_load1_ps((QT3DSF32 *)&one);
+}
+
+QT3DS_FORCE_INLINE FloatV ITwo()
+{
+ const QT3DSU32 two = 2;
+ return _mm_load1_ps((QT3DSF32 *)&two);
+}
+
+QT3DS_FORCE_INLINE FloatV IThree()
+{
+ const QT3DSU32 three = 3;
+ return _mm_load1_ps((QT3DSF32 *)&three);
+}
+
+QT3DS_FORCE_INLINE FloatV IFour()
+{
+ QT3DSU32 four = 4;
+ return _mm_load1_ps((QT3DSF32 *)&four);
+}
+
+QT3DS_FORCE_INLINE FloatV FNeg(const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return _mm_sub_ps(_mm_setzero_ps(), f);
+}
+
+QT3DS_FORCE_INLINE FloatV FAdd(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_add_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FSub(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_sub_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FMul(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FDiv(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FDivFast(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+QT3DS_FORCE_INLINE FloatV FRecip(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ return _mm_div_ps(FOne(), a);
+}
+
+QT3DS_FORCE_INLINE FloatV FRecipFast(const FloatV a)
+{
+ return _mm_rcp_ps(a);
+}
+
+QT3DS_FORCE_INLINE FloatV FRsqrt(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ return _mm_div_ps(FOne(), _mm_sqrt_ps(a));
+}
+
+QT3DS_FORCE_INLINE FloatV FSqrt(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ return _mm_sqrt_ps(a);
+}
+
+QT3DS_FORCE_INLINE FloatV FRsqrtFast(const FloatV a)
+{
+ return _mm_rsqrt_ps(a);
+}
+
+QT3DS_FORCE_INLINE FloatV FScaleAdd(const FloatV a, const FloatV b, const FloatV c)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ VECMATHAOS_ASSERT(isValidFloatV(c));
+ return FAdd(FMul(a, b), c);
+}
+
+QT3DS_FORCE_INLINE FloatV FNegScaleSub(const FloatV a, const FloatV b, const FloatV c)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ VECMATHAOS_ASSERT(isValidFloatV(c));
+ return FSub(c, FMul(a, b));
+}
+
+QT3DS_FORCE_INLINE FloatV FAbs(const FloatV a)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ QT3DS_ALIGN(16, const static QT3DSU32 absMask[4]) = { 0x7fFFffFF, 0x7fFFffFF, 0x7fFFffFF,
+ 0x7fFFffFF };
+ return _mm_and_ps(a, _mm_load_ps((QT3DSF32 *)absMask));
+}
+
+QT3DS_FORCE_INLINE FloatV FSel(const BoolV c, const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(_VecMathTests::allElementsEqualBoolV(c, BTTTT())
+ || _VecMathTests::allElementsEqualBoolV(c, BFFFF()));
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
+}
+
+QT3DS_FORCE_INLINE BoolV FIsGrtr(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_cmpgt_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV FIsGrtrOrEq(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_cmpge_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV FIsEq(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_cmpeq_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FMax(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_max_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FMin(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_min_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE FloatV FClamp(const FloatV a, const FloatV minV, const FloatV maxV)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(minV));
+ VECMATHAOS_ASSERT(isValidFloatV(maxV));
+ return FMax(FMin(a, maxV), minV);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FAllGrtr(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return (_mm_comigt_ss(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FAllGrtrOrEq(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+
+ return (_mm_comige_ss(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FAllEq(const FloatV a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+
+ return (_mm_comieq_ss(a, b));
+}
+
+QT3DS_FORCE_INLINE FloatV FRound(const FloatV a)
+{
+ // return _mm_round_ps(a, 0x0);
+ const Vec3V half = Vec3V_From_F32(0.5f);
+ const Vec3V aPlusHalf = V3Add(a, half);
+ __m128i tmp = _mm_cvttps_epi32(aPlusHalf);
+ return _mm_cvtepi32_ps(tmp);
+}
+
+QT3DS_FORCE_INLINE FloatV FSin(const FloatV a)
+{
+ // Vec4V V1, V2, V3, V5, V7, V9, V11, V13, V15, V17, V19, V21, V23;
+ // Vec4V S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11;
+ FloatV Result;
+
+ // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
+ const FloatV twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const FloatV tmp = FMul(a, twoPi);
+ const FloatV b = FRound(tmp);
+ const FloatV V1 = FNegMulSub(twoPi, b, a);
+
+ // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
+ // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
+ const FloatV V2 = FMul(V1, V1);
+ const FloatV V3 = FMul(V2, V1);
+ const FloatV V5 = FMul(V3, V2);
+ const FloatV V7 = FMul(V5, V2);
+ const FloatV V9 = FMul(V7, V2);
+ const FloatV V11 = FMul(V9, V2);
+ const FloatV V13 = FMul(V11, V2);
+ const FloatV V15 = FMul(V13, V2);
+ const FloatV V17 = FMul(V15, V2);
+ const FloatV V19 = FMul(V17, V2);
+ const FloatV V21 = FMul(V19, V2);
+ const FloatV V23 = FMul(V21, V2);
+
+ const Vec4V sinCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients0.f);
+ const Vec4V sinCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients1.f);
+ const Vec4V sinCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients2.f);
+
+ const FloatV S1 = V4GetY(sinCoefficients0);
+ const FloatV S2 = V4GetZ(sinCoefficients0);
+ const FloatV S3 = V4GetW(sinCoefficients0);
+ const FloatV S4 = V4GetX(sinCoefficients1);
+ const FloatV S5 = V4GetY(sinCoefficients1);
+ const FloatV S6 = V4GetZ(sinCoefficients1);
+ const FloatV S7 = V4GetW(sinCoefficients1);
+ const FloatV S8 = V4GetX(sinCoefficients2);
+ const FloatV S9 = V4GetY(sinCoefficients2);
+ const FloatV S10 = V4GetZ(sinCoefficients2);
+ const FloatV S11 = V4GetW(sinCoefficients2);
+
+ Result = FMulAdd(S1, V3, V1);
+ Result = FMulAdd(S2, V5, Result);
+ Result = FMulAdd(S3, V7, Result);
+ Result = FMulAdd(S4, V9, Result);
+ Result = FMulAdd(S5, V11, Result);
+ Result = FMulAdd(S6, V13, Result);
+ Result = FMulAdd(S7, V15, Result);
+ Result = FMulAdd(S8, V17, Result);
+ Result = FMulAdd(S9, V19, Result);
+ Result = FMulAdd(S10, V21, Result);
+ Result = FMulAdd(S11, V23, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE FloatV FCos(const FloatV a)
+{
+ // XMVECTOR V1, V2, V4, V6, V8, V10, V12, V14, V16, V18, V20, V22;
+ // XMVECTOR C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11;
+ FloatV Result;
+
+ // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
+ const FloatV twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const FloatV tmp = FMul(a, twoPi);
+ const FloatV b = FRound(tmp);
+ const FloatV V1 = FNegMulSub(twoPi, b, a);
+
+ // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
+ // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
+ const FloatV V2 = FMul(V1, V1);
+ const FloatV V4 = FMul(V2, V2);
+ const FloatV V6 = FMul(V4, V2);
+ const FloatV V8 = FMul(V4, V4);
+ const FloatV V10 = FMul(V6, V4);
+ const FloatV V12 = FMul(V6, V6);
+ const FloatV V14 = FMul(V8, V6);
+ const FloatV V16 = FMul(V8, V8);
+ const FloatV V18 = FMul(V10, V8);
+ const FloatV V20 = FMul(V10, V10);
+ const FloatV V22 = FMul(V12, V10);
+
+ const Vec4V cosCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients0.f);
+ const Vec4V cosCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients1.f);
+ const Vec4V cosCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients2.f);
+
+ const FloatV C1 = V4GetY(cosCoefficients0);
+ const FloatV C2 = V4GetZ(cosCoefficients0);
+ const FloatV C3 = V4GetW(cosCoefficients0);
+ const FloatV C4 = V4GetX(cosCoefficients1);
+ const FloatV C5 = V4GetY(cosCoefficients1);
+ const FloatV C6 = V4GetZ(cosCoefficients1);
+ const FloatV C7 = V4GetW(cosCoefficients1);
+ const FloatV C8 = V4GetX(cosCoefficients2);
+ const FloatV C9 = V4GetY(cosCoefficients2);
+ const FloatV C10 = V4GetZ(cosCoefficients2);
+ const FloatV C11 = V4GetW(cosCoefficients2);
+
+ Result = FMulAdd(C1, V2, V4One());
+ Result = FMulAdd(C2, V4, Result);
+ Result = FMulAdd(C3, V6, Result);
+ Result = FMulAdd(C4, V8, Result);
+ Result = FMulAdd(C5, V10, Result);
+ Result = FMulAdd(C6, V12, Result);
+ Result = FMulAdd(C7, V14, Result);
+ Result = FMulAdd(C8, V16, Result);
+ Result = FMulAdd(C9, V18, Result);
+ Result = FMulAdd(C10, V20, Result);
+ Result = FMulAdd(C11, V22, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FOutOfBounds(const FloatV a, const FloatV min, const FloatV max)
+{
+ const BoolV ffff = BFFFF();
+ const BoolV c = BOr(FIsGrtr(a, max), FIsGrtr(min, a));
+ return !BAllEq(c, ffff);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FInBounds(const FloatV a, const FloatV min, const FloatV max)
+{
+ const BoolV tttt = BTTTT();
+ const BoolV c = BAnd(FIsGrtrOrEq(a, min), FIsGrtrOrEq(max, a));
+ return BAllEq(c, tttt);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FOutOfBounds(const FloatV a, const FloatV bounds)
+{
+ return FOutOfBounds(a, FNeg(bounds), bounds);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 FInBounds(const FloatV a, const FloatV bounds)
+{
+ return FInBounds(a, FNeg(bounds), bounds);
+}
+
+//////////////////////////////////
+// VEC3V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec3V V3Splat(const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ const __m128 zero = V3Zero();
+ const __m128 fff0 = _mm_move_ss(f, zero);
+ return _mm_shuffle_ps(fff0, fff0, _MM_SHUFFLE(0, 1, 2, 3));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Merge(const FloatVArg x, const FloatVArg y, const FloatVArg z)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(x));
+ VECMATHAOS_ASSERT(isValidFloatV(y));
+ VECMATHAOS_ASSERT(isValidFloatV(z));
+ // static on zero causes compiler crash on x64 debug_opt
+ const __m128 zero = V3Zero();
+ const __m128 xy = _mm_move_ss(x, y);
+ const __m128 z0 = _mm_move_ss(zero, z);
+
+ return _mm_shuffle_ps(xy, z0, _MM_SHUFFLE(1, 0, 0, 1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3UnitX()
+{
+ const QT3DS_ALIGN(16, QT3DSF32 x[4]) = { 1.0f, 0.0f, 0.0f, 0.0f };
+ const __m128 x128 = _mm_load_ps(x);
+ return x128;
+}
+
+QT3DS_FORCE_INLINE Vec3V V3UnitY()
+{
+ const QT3DS_ALIGN(16, QT3DSF32 y[4]) = { 0.0f, 1.0f, 0.0f, 0.0f };
+ const __m128 y128 = _mm_load_ps(y);
+ return y128;
+}
+
+QT3DS_FORCE_INLINE Vec3V V3UnitZ()
+{
+ const QT3DS_ALIGN(16, QT3DSF32 z[4]) = { 0.0f, 0.0f, 1.0f, 0.0f };
+ const __m128 z128 = _mm_load_ps(z);
+ return z128;
+}
+
+QT3DS_FORCE_INLINE FloatV V3GetX(const Vec3V f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(f));
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
+}
+
+QT3DS_FORCE_INLINE FloatV V3GetY(const Vec3V f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(f));
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
+}
+
+QT3DS_FORCE_INLINE FloatV V3GetZ(const Vec3V f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(f));
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3SetX(const Vec3V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v));
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V3Sel(BFTTT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3SetY(const Vec3V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v));
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V3Sel(BTFTT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3SetZ(const Vec3V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v));
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V3Sel(BTTFT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ColX(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 0, 3, 0));
+ return V3SetY(r, V3GetX(b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ColY(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 1, 3, 1));
+ return V3SetY(r, V3GetY(b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ColZ(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ Vec3V r = _mm_shuffle_ps(a, c, _MM_SHUFFLE(3, 2, 3, 2));
+ return V3SetY(r, V3GetZ(b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Zero()
+{
+ return Vec3V_From_F32(0.0f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3One()
+{
+ return Vec3V_From_F32(1.0f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Eps()
+{
+ return Vec3V_From_F32(QT3DS_ENV_REAL);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Neg(const Vec3V f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(f));
+ return _mm_sub_ps(_mm_setzero_ps(), f);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Add(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_add_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Sub(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_sub_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Scale(const Vec3V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Mul(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ScaleInv(const Vec3V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Div(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ // why are these here?
+ // static const __m128 one=V3One();
+ // static const __m128 tttf=BTTTF();
+ // const __m128 b1=V3Sel(tttf,b,one);
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ScaleInvFast(const Vec3V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3DivFast(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ const __m128 one = V3One();
+ const __m128 tttf = BTTTF();
+ const __m128 b1 = V3Sel(tttf, b, one);
+ return _mm_mul_ps(a, _mm_rcp_ps(b1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Recip(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = V3Zero();
+ const __m128 tttf = BTTTF();
+ const __m128 recipA = _mm_div_ps(V3One(), a);
+ return V3Sel(tttf, recipA, zero);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3RecipFast(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = V3Zero();
+ const __m128 tttf = BTTTF();
+ const __m128 recipA = _mm_rcp_ps(a);
+ return V3Sel(tttf, recipA, zero);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Rsqrt(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = V3Zero();
+ const __m128 tttf = BTTTF();
+ const __m128 recipA = _mm_div_ps(V3One(), _mm_sqrt_ps(a));
+ return V3Sel(tttf, recipA, zero);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3RsqrtFast(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = V3Zero();
+ const __m128 tttf = BTTTF();
+ const __m128 recipA = _mm_rsqrt_ps(a);
+ return V3Sel(tttf, recipA, zero);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3ScaleAdd(const Vec3V a, const FloatV b, const Vec3V c)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ VECMATHAOS_ASSERT(isValidVec3V(c));
+ return V3Add(V3Scale(a, b), c);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3NegScaleSub(const Vec3V a, const FloatV b, const Vec3V c)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ VECMATHAOS_ASSERT(isValidVec3V(c));
+ return V3Sub(c, V3Scale(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3MulAdd(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ VECMATHAOS_ASSERT(isValidVec3V(c));
+ return V3Add(V3Mul(a, b), c);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3NegMulSub(const Vec3V a, const Vec3V b, const Vec3V c)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ VECMATHAOS_ASSERT(isValidVec3V(c));
+ return V3Sub(c, V3Mul(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Abs(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return V3Max(a, V3Neg(a));
+}
+
+QT3DS_FORCE_INLINE FloatV V3Dot(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ __m128 dot1 = _mm_mul_ps(a, b); // w,z,y,x
+ //__m128 shuf1 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(2,1,0,3)); //z,y,x,w
+ //__m128 shuf2 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(1,0,3,2)); //y,x,w,z
+ //__m128 shuf3 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(0,3,2,1)); //x,w,z,y
+ // return _mm_add_ps(_mm_add_ps(shuf2, shuf3), _mm_add_ps(dot1,shuf1));
+
+ __m128 shuf1 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(0, 0, 0, 0)); // z,y,x,w
+ __m128 shuf2 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(1, 1, 1, 1)); // y,x,w,z
+ __m128 shuf3 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(2, 2, 2, 2)); // x,w,z,y
+ return _mm_add_ps(_mm_add_ps(shuf1, shuf2), shuf3);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Cross(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ __m128 l1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
+ __m128 l2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
+ __m128 r1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2)); // z,x,y,w
+ __m128 r2 = _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 0, 2, 1)); // y,z,x,w
+ return _mm_sub_ps(_mm_mul_ps(l1, l2), _mm_mul_ps(r1, r2));
+}
+
+QT3DS_FORCE_INLINE FloatV V3Length(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_sqrt_ps(V3Dot(a, a));
+}
+
+QT3DS_FORCE_INLINE FloatV V3LengthSq(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return V3Dot(a, a);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Normalize(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(V3Dot(a, a) != FZero())
+ return V3ScaleInv(a, _mm_sqrt_ps(V3Dot(a, a)));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3NormalizeFast(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return V3Mul(a, _mm_rsqrt_ps(V3Dot(a, a)));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3NormalizeSafe(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = V3Zero();
+ const __m128 eps = V3Eps();
+ const __m128 length = V3Length(a);
+ const __m128 isGreaterThanZero = FIsGrtr(length, eps);
+ return V3Sel(isGreaterThanZero, V3ScaleInv(a, length), zero);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Sel(const BoolV c, const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
+}
+
+QT3DS_FORCE_INLINE BoolV V3IsGrtr(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_cmpgt_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V3IsGrtrOrEq(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_cmpge_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V3IsEq(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_cmpeq_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Max(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_max_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Min(const Vec3V a, const Vec3V b)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(b));
+ return _mm_min_ps(a, b);
+}
+
+// Extract the maximum value from a
+QT3DS_FORCE_INLINE FloatV V3ExtractMax(const Vec3V a)
+{
+ const __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0));
+ const __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1));
+ const __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2));
+
+ return _mm_max_ps(_mm_max_ps(shuf1, shuf2), shuf3);
+}
+
+// Extract the maximum value from a
+QT3DS_FORCE_INLINE FloatV V3ExtractMin(const Vec3V a)
+{
+ const __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0));
+ const __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1));
+ const __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2));
+
+ return _mm_min_ps(_mm_min_ps(shuf1, shuf2), shuf3);
+}
+
+//// if(a > 0.0f) return 1.0f; else if a == 0.f return 0.f, else return -1.f;
+// QT3DS_FORCE_INLINE Vec3V V3MathSign(const Vec3V a)
+//{
+// VECMATHAOS_ASSERT(isValidVec3V(a));
+//
+// const __m128i ai = _mm_cvtps_epi32(a);
+// const __m128i bi = _mm_cvtps_epi32(V3Neg(a));
+// const __m128 aa = _mm_cvtepi32_ps(_mm_srai_epi32(ai, 31));
+// const __m128 bb = _mm_cvtepi32_ps(_mm_srai_epi32(bi, 31));
+// return _mm_or_ps(aa, bb);
+//}
+
+// return (a >= 0.0f) ? 1.0f : -1.0f;
+QT3DS_FORCE_INLINE Vec3V V3Sign(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ const __m128 zero = V3Zero();
+ const __m128 one = V3One();
+ const __m128 none = V3Neg(one);
+ return V3Sel(V3IsGrtrOrEq(a, zero), one, none);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Clamp(const Vec3V a, const Vec3V minV, const Vec3V maxV)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(minV));
+ VECMATHAOS_ASSERT(isValidVec3V(maxV));
+ return V3Max(V3Min(a, maxV), minV);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3AllGrtr(const Vec3V a, const Vec3V b)
+{
+ return BAllTrue3_R(V4IsGrtr(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3AllGrtrOrEq(const Vec3V a, const Vec3V b)
+{
+ return BAllTrue3_R(V4IsGrtrOrEq(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3AllEq(const Vec3V a, const Vec3V b)
+{
+ return BAllTrue3_R(V4IsEq(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Round(const Vec3V a)
+{
+ // return _mm_round_ps(a, 0x0);
+ const Vec3V half = Vec3V_From_F32(0.5f);
+ const Vec3V aPlusHalf = V3Add(a, half);
+ const __m128i tmp = _mm_cvttps_epi32(aPlusHalf);
+ return _mm_cvtepi32_ps(tmp);
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Sin(const Vec3V a)
+{
+ // Vec4V V1, V2, V3, V5, V7, V9, V11, V13, V15, V17, V19, V21, V23;
+ // Vec4V S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11;
+ Vec3V Result;
+
+ // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
+ const Vec3V twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const Vec3V tmp = V3Mul(a, twoPi);
+ const Vec3V b = V3Round(tmp);
+ const Vec3V V1 = V3NegMulSub(twoPi, b, a);
+
+ // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
+ // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
+ const Vec3V V2 = V3Mul(V1, V1);
+ const Vec3V V3 = V3Mul(V2, V1);
+ const Vec3V V5 = V3Mul(V3, V2);
+ const Vec3V V7 = V3Mul(V5, V2);
+ const Vec3V V9 = V3Mul(V7, V2);
+ const Vec3V V11 = V3Mul(V9, V2);
+ const Vec3V V13 = V3Mul(V11, V2);
+ const Vec3V V15 = V3Mul(V13, V2);
+ const Vec3V V17 = V3Mul(V15, V2);
+ const Vec3V V19 = V3Mul(V17, V2);
+ const Vec3V V21 = V3Mul(V19, V2);
+ const Vec3V V23 = V3Mul(V21, V2);
+
+ const Vec4V sinCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients0.f);
+ const Vec4V sinCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients1.f);
+ const Vec4V sinCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients2.f);
+
+ const FloatV S1 = V4GetY(sinCoefficients0);
+ const FloatV S2 = V4GetZ(sinCoefficients0);
+ const FloatV S3 = V4GetW(sinCoefficients0);
+ const FloatV S4 = V4GetX(sinCoefficients1);
+ const FloatV S5 = V4GetY(sinCoefficients1);
+ const FloatV S6 = V4GetZ(sinCoefficients1);
+ const FloatV S7 = V4GetW(sinCoefficients1);
+ const FloatV S8 = V4GetX(sinCoefficients2);
+ const FloatV S9 = V4GetY(sinCoefficients2);
+ const FloatV S10 = V4GetZ(sinCoefficients2);
+ const FloatV S11 = V4GetW(sinCoefficients2);
+
+ Result = V3MulAdd(S1, V3, V1);
+ Result = V3MulAdd(S2, V5, Result);
+ Result = V3MulAdd(S3, V7, Result);
+ Result = V3MulAdd(S4, V9, Result);
+ Result = V3MulAdd(S5, V11, Result);
+ Result = V3MulAdd(S6, V13, Result);
+ Result = V3MulAdd(S7, V15, Result);
+ Result = V3MulAdd(S8, V17, Result);
+ Result = V3MulAdd(S9, V19, Result);
+ Result = V3MulAdd(S10, V21, Result);
+ Result = V3MulAdd(S11, V23, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Cos(const Vec3V a)
+{
+ // XMVECTOR V1, V2, V4, V6, V8, V10, V12, V14, V16, V18, V20, V22;
+ // XMVECTOR C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11;
+ Vec3V Result;
+
+ // Modulo the range of the given angles such that -XM_PI <= Angles < XM_PI
+ const Vec3V twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const Vec3V tmp = V3Mul(a, twoPi);
+ const Vec3V b = V3Round(tmp);
+ const Vec3V V1 = V3NegMulSub(twoPi, b, a);
+
+ // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
+ // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
+ const Vec3V V2 = V3Mul(V1, V1);
+ const Vec3V V4 = V3Mul(V2, V2);
+ const Vec3V V6 = V3Mul(V4, V2);
+ const Vec3V V8 = V3Mul(V4, V4);
+ const Vec3V V10 = V3Mul(V6, V4);
+ const Vec3V V12 = V3Mul(V6, V6);
+ const Vec3V V14 = V3Mul(V8, V6);
+ const Vec3V V16 = V3Mul(V8, V8);
+ const Vec3V V18 = V3Mul(V10, V8);
+ const Vec3V V20 = V3Mul(V10, V10);
+ const Vec3V V22 = V3Mul(V12, V10);
+
+ const Vec4V cosCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients0.f);
+ const Vec4V cosCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients1.f);
+ const Vec4V cosCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients2.f);
+
+ const FloatV C1 = V4GetY(cosCoefficients0);
+ const FloatV C2 = V4GetZ(cosCoefficients0);
+ const FloatV C3 = V4GetW(cosCoefficients0);
+ const FloatV C4 = V4GetX(cosCoefficients1);
+ const FloatV C5 = V4GetY(cosCoefficients1);
+ const FloatV C6 = V4GetZ(cosCoefficients1);
+ const FloatV C7 = V4GetW(cosCoefficients1);
+ const FloatV C8 = V4GetX(cosCoefficients2);
+ const FloatV C9 = V4GetY(cosCoefficients2);
+ const FloatV C10 = V4GetZ(cosCoefficients2);
+ const FloatV C11 = V4GetW(cosCoefficients2);
+
+ Result = V3MulAdd(C1, V2, V4One());
+ Result = V3MulAdd(C2, V4, Result);
+ Result = V3MulAdd(C3, V6, Result);
+ Result = V3MulAdd(C4, V8, Result);
+ Result = V3MulAdd(C5, V10, Result);
+ Result = V3MulAdd(C6, V12, Result);
+ Result = V3MulAdd(C7, V14, Result);
+ Result = V3MulAdd(C8, V16, Result);
+ Result = V3MulAdd(C9, V18, Result);
+ Result = V3MulAdd(C10, V20, Result);
+ Result = V3MulAdd(C11, V22, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermYZZ(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 2, 1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermXYX(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 1, 0));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermYZX(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a))
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 2, 1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermZXY(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 0, 2));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermZZY(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 1, 2, 2));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3PermYXX(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 0, 0, 1));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Perm_Zero_1Z_0Y(const Vec3V v0, const Vec3V v1)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v0));
+ VECMATHAOS_ASSERT(isValidVec3V(v1));
+ return _mm_shuffle_ps(v1, v0, _MM_SHUFFLE(3, 1, 2, 3));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Perm_0Z_Zero_1X(const Vec3V v0, const Vec3V v1)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v0));
+ VECMATHAOS_ASSERT(isValidVec3V(v1));
+ return _mm_shuffle_ps(v0, v1, _MM_SHUFFLE(3, 0, 3, 2));
+}
+
+QT3DS_FORCE_INLINE Vec3V V3Perm_1Y_0X_Zero(const Vec3V v0, const Vec3V v1)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v0));
+ VECMATHAOS_ASSERT(isValidVec3V(v1));
+ // There must be a better way to do this.
+ Vec3V v2 = V3Zero();
+ FloatV y1 = V3GetY(v1);
+ FloatV x0 = V3GetX(v0);
+ v2 = V3SetX(v2, y1);
+ return V3SetY(v2, x0);
+}
+
+QT3DS_FORCE_INLINE FloatV V3SumElems(const Vec3V a)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+
+ __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0)); // z,y,x,w
+ __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1)); // y,x,w,z
+ __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)); // x,w,z,y
+ return _mm_add_ps(_mm_add_ps(shuf1, shuf2), shuf3);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3OutOfBounds(const Vec3V a, const Vec3V min, const Vec3V max)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(min));
+ VECMATHAOS_ASSERT(isValidVec3V(max));
+ const BoolV ffff = BFFFF();
+ const BoolV c = BOr(V3IsGrtr(a, max), V3IsGrtr(min, a));
+ return !BAllEq(c, ffff);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3InBounds(const Vec3V a, const Vec3V min, const Vec3V max)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(a));
+ VECMATHAOS_ASSERT(isValidVec3V(min));
+ VECMATHAOS_ASSERT(isValidVec3V(max));
+ const BoolV tttt = BTTTT();
+ const BoolV c = BAnd(V3IsGrtrOrEq(a, min), V3IsGrtrOrEq(max, a));
+ return BAllEq(c, tttt);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3OutOfBounds(const Vec3V a, const Vec3V bounds)
+{
+ return V3OutOfBounds(a, V3Neg(bounds), bounds);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V3InBounds(const Vec3V a, const Vec3V bounds)
+{
+ return V3InBounds(a, V3Neg(bounds), bounds);
+}
+
+//////////////////////////////////
+// VEC4V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec4V V4Splat(const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ // return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0,0,0,0));
+ return f;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Merge(const FloatV *const floatVArray)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(floatVArray[0]));
+ VECMATHAOS_ASSERT(isValidFloatV(floatVArray[1]));
+ VECMATHAOS_ASSERT(isValidFloatV(floatVArray[2]));
+ VECMATHAOS_ASSERT(isValidFloatV(floatVArray[3]));
+ __m128 xw = _mm_move_ss(floatVArray[1], floatVArray[0]); // y, y, y, x
+ __m128 yz = _mm_move_ss(floatVArray[2], floatVArray[3]); // z, z, z, w
+ return (_mm_shuffle_ps(xw, yz, _MM_SHUFFLE(0, 2, 1, 0)));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Merge(const FloatVArg x, const FloatVArg y, const FloatVArg z,
+ const FloatVArg w)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(x));
+ VECMATHAOS_ASSERT(isValidFloatV(y));
+ VECMATHAOS_ASSERT(isValidFloatV(z));
+ VECMATHAOS_ASSERT(isValidFloatV(w));
+ __m128 xw = _mm_move_ss(y, x); // y, y, y, x
+ __m128 yz = _mm_move_ss(z, w); // z, z, z, w
+ return (_mm_shuffle_ps(xw, yz, _MM_SHUFFLE(0, 2, 1, 0)));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4UnitW()
+{
+ const QT3DS_ALIGN(16, QT3DSF32 w[4]) = { 0.0f, 0.0f, 0.0f, 1.0f };
+ const __m128 w128 = _mm_load_ps(w);
+ return w128;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4UnitX()
+{
+ const QT3DS_ALIGN(16, QT3DSF32 x[4]) = { 1.0f, 0.0f, 0.0f, 0.0f };
+ const __m128 x128 = _mm_load_ps(x);
+ return x128;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4UnitY()
+{
+ const QT3DS_ALIGN(16, QT3DSF32 y[4]) = { 0.0f, 1.0f, 0.0f, 0.0f };
+ const __m128 y128 = _mm_load_ps(y);
+ return y128;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4UnitZ()
+{
+ const QT3DS_ALIGN(16, QT3DSF32 z[4]) = { 0.0f, 0.0f, 1.0f, 0.0f };
+ const __m128 z128 = _mm_load_ps(z);
+ return z128;
+}
+
+QT3DS_FORCE_INLINE FloatV V4GetW(const Vec4V f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(3, 3, 3, 3));
+}
+
+QT3DS_FORCE_INLINE FloatV V4GetX(const Vec4V f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
+}
+
+QT3DS_FORCE_INLINE FloatV V4GetY(const Vec4V f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
+}
+
+QT3DS_FORCE_INLINE FloatV V4GetZ(const Vec4V f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4SetW(const Vec4V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V4Sel(BTTTF(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4SetX(const Vec4V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V4Sel(BFTTT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4SetY(const Vec4V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V4Sel(BTFTT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4SetZ(const Vec4V v, const FloatV f)
+{
+ VECMATHAOS_ASSERT(isValidVec3V(v));
+ VECMATHAOS_ASSERT(isValidFloatV(f));
+ return V4Sel(BTTFT(), v, f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Zero()
+{
+ return Vec4V_From_F32(0.0f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4One()
+{
+ return Vec4V_From_F32(1.0f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Eps()
+{
+ return Vec4V_From_F32(QT3DS_ENV_REAL);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Neg(const Vec4V f)
+{
+ return _mm_sub_ps(_mm_setzero_ps(), f);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Add(const Vec4V a, const Vec4V b)
+{
+ return _mm_add_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Sub(const Vec4V a, const Vec4V b)
+{
+ return _mm_sub_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Scale(const Vec4V a, const FloatV b)
+{
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Mul(const Vec4V a, const Vec4V b)
+{
+ return _mm_mul_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4ScaleInv(const Vec4V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Div(const Vec4V a, const Vec4V b)
+{
+ return _mm_div_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4ScaleInvFast(const Vec4V a, const FloatV b)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4DivFast(const Vec4V a, const Vec4V b)
+{
+ return _mm_mul_ps(a, _mm_rcp_ps(b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Recip(const Vec4V a)
+{
+ return _mm_div_ps(V4One(), a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4RecipFast(const Vec4V a)
+{
+ return _mm_rcp_ps(a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Rsqrt(const Vec4V a)
+{
+ return _mm_div_ps(V4One(), _mm_sqrt_ps(a));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4RsqrtFast(const Vec4V a)
+{
+ return _mm_rsqrt_ps(a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4ScaleAdd(const Vec4V a, const FloatV b, const Vec4V c)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return V4Add(V4Scale(a, b), c);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4NegScaleSub(const Vec4V a, const FloatV b, const Vec4V c)
+{
+ VECMATHAOS_ASSERT(isValidFloatV(b));
+ return V4Sub(c, V4Scale(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4MulAdd(const Vec4V a, const Vec4V b, const Vec4V c)
+{
+ return V4Add(V4Mul(a, b), c);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4NegMulSub(const Vec4V a, const Vec4V b, const Vec4V c)
+{
+ return V4Sub(c, V4Mul(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Abs(const Vec4V a)
+{
+ return V4Max(a, V4Neg(a));
+}
+
+QT3DS_FORCE_INLINE FloatV V4Dot(const Vec4V a, const Vec4V b)
+{
+ __m128 dot1 = _mm_mul_ps(a, b); // x,y,z,w
+ __m128 shuf1 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(2, 1, 0, 3)); // w,x,y,z
+ __m128 shuf2 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(1, 0, 3, 2)); // z,w,x,y
+ __m128 shuf3 = _mm_shuffle_ps(dot1, dot1, _MM_SHUFFLE(0, 3, 2, 1)); // y,z,w,x
+ return _mm_add_ps(_mm_add_ps(shuf2, shuf3), _mm_add_ps(dot1, shuf1));
+}
+
+QT3DS_FORCE_INLINE FloatV V4Length(const Vec4V a)
+{
+ return _mm_sqrt_ps(V4Dot(a, a));
+}
+
+QT3DS_FORCE_INLINE FloatV V4LengthSq(const Vec4V a)
+{
+ return V4Dot(a, a);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Normalize(const Vec4V a)
+{
+ VECMATHAOS_ASSERT(V4Dot(a, a) != FZero())
+ return V4ScaleInv(a, _mm_sqrt_ps(V4Dot(a, a)));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4NormalizeFast(const Vec4V a)
+{
+ return V4ScaleInvFast(a, _mm_sqrt_ps(V4Dot(a, a)));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4NormalizeSafe(const Vec4V a)
+{
+ const __m128 zero = FZero();
+ const __m128 eps = V3Eps();
+ const __m128 length = V4Length(a);
+ const __m128 isGreaterThanZero = V4IsGrtr(length, eps);
+ return V4Sel(isGreaterThanZero, V4ScaleInv(a, length), zero);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Sel(const BoolV c, const Vec4V a, const Vec4V b)
+{
+ return _mm_or_ps(_mm_andnot_ps(c, b), _mm_and_ps(c, a));
+}
+
+QT3DS_FORCE_INLINE BoolV V4IsGrtr(const Vec4V a, const Vec4V b)
+{
+ return _mm_cmpgt_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V4IsGrtrOrEq(const Vec4V a, const Vec4V b)
+{
+ return _mm_cmpge_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V4IsEq(const Vec4V a, const Vec4V b)
+{
+ return _mm_cmpeq_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE BoolV V4IsEqU32(const VecU32V a, const VecU32V b)
+{
+ return _mm_cmpeq_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec3V V4Max(const Vec4V a, const Vec4V b)
+{
+ return _mm_max_ps(a, b);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Min(const Vec4V a, const Vec4V b)
+{
+ return _mm_min_ps(a, b);
+}
+
+// Extract the maximum value from a
+QT3DS_FORCE_INLINE FloatV V4ExtractMax(const Vec4V a)
+{
+ __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 1, 0, 3));
+ __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 3, 2, 1));
+
+ return _mm_max_ps(_mm_max_ps(a, shuf1), _mm_max_ps(shuf2, shuf3));
+}
+
+// Extract the maximum value from a
+QT3DS_FORCE_INLINE FloatV V4ExtractMin(const Vec4V a)
+{
+ __m128 shuf1 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 1, 0, 3));
+ __m128 shuf2 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 0, 3, 2));
+ __m128 shuf3 = _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 3, 2, 1));
+
+ return _mm_min_ps(_mm_min_ps(a, shuf1), _mm_min_ps(shuf2, shuf3));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Clamp(const Vec4V a, const Vec4V minV, const Vec4V maxV)
+{
+ return V4Max(V4Min(a, maxV), minV);
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V4AllGrtr(const Vec4V a, const Vec4V b)
+{
+ return BAllTrue4_R(V4IsGrtr(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V4AllGrtrOrEq(const Vec4V a, const Vec4V b)
+{
+ return BAllTrue4_R(V4IsGrtrOrEq(a, b));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 V4AllEq(const Vec4V a, const Vec4V b)
+{
+ return BAllTrue4_R(V4IsEq(a, b));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Round(const Vec4V a)
+{
+ // return _mm_round_ps(a, 0x0);
+ const Vec3V half = Vec3V_From_F32(0.5f);
+ const Vec3V aPlusHalf = V3Add(a, half);
+ __m128i tmp = _mm_cvttps_epi32(aPlusHalf);
+ return _mm_cvtepi32_ps(tmp);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Sin(const Vec4V a)
+{
+ // Vec4V V1, V2, V3, V5, V7, V9, V11, V13, V15, V17, V19, V21, V23;
+ // Vec4V S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11;
+ Vec4V Result;
+
+ const Vec4V twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const Vec4V tmp = V4Mul(a, twoPi);
+ const Vec4V b = V4Round(tmp);
+ const Vec4V V1 = V4NegMulSub(twoPi, b, a);
+
+ // sin(V) ~= V - V^3 / 3! + V^5 / 5! - V^7 / 7! + V^9 / 9! - V^11 / 11! + V^13 / 13! -
+ // V^15 / 15! + V^17 / 17! - V^19 / 19! + V^21 / 21! - V^23 / 23! (for -PI <= V < PI)
+ const Vec4V V2 = V4Mul(V1, V1);
+ const Vec4V V3 = V4Mul(V2, V1);
+ const Vec4V V5 = V4Mul(V3, V2);
+ const Vec4V V7 = V4Mul(V5, V2);
+ const Vec4V V9 = V4Mul(V7, V2);
+ const Vec4V V11 = V4Mul(V9, V2);
+ const Vec4V V13 = V4Mul(V11, V2);
+ const Vec4V V15 = V4Mul(V13, V2);
+ const Vec4V V17 = V4Mul(V15, V2);
+ const Vec4V V19 = V4Mul(V17, V2);
+ const Vec4V V21 = V4Mul(V19, V2);
+ const Vec4V V23 = V4Mul(V21, V2);
+
+ const Vec4V sinCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients0.f);
+ const Vec4V sinCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients1.f);
+ const Vec4V sinCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXSinCoefficients2.f);
+
+ const FloatV S1 = V4GetY(sinCoefficients0);
+ const FloatV S2 = V4GetZ(sinCoefficients0);
+ const FloatV S3 = V4GetW(sinCoefficients0);
+ const FloatV S4 = V4GetX(sinCoefficients1);
+ const FloatV S5 = V4GetY(sinCoefficients1);
+ const FloatV S6 = V4GetZ(sinCoefficients1);
+ const FloatV S7 = V4GetW(sinCoefficients1);
+ const FloatV S8 = V4GetX(sinCoefficients2);
+ const FloatV S9 = V4GetY(sinCoefficients2);
+ const FloatV S10 = V4GetZ(sinCoefficients2);
+ const FloatV S11 = V4GetW(sinCoefficients2);
+
+ Result = V4MulAdd(S1, V3, V1);
+ Result = V4MulAdd(S2, V5, Result);
+ Result = V4MulAdd(S3, V7, Result);
+ Result = V4MulAdd(S4, V9, Result);
+ Result = V4MulAdd(S5, V11, Result);
+ Result = V4MulAdd(S6, V13, Result);
+ Result = V4MulAdd(S7, V15, Result);
+ Result = V4MulAdd(S8, V17, Result);
+ Result = V4MulAdd(S9, V19, Result);
+ Result = V4MulAdd(S10, V21, Result);
+ Result = V4MulAdd(S11, V23, Result);
+
+ return Result;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Cos(const Vec4V a)
+{
+ // XMVECTOR V1, V2, V4, V6, V8, V10, V12, V14, V16, V18, V20, V22;
+ // XMVECTOR C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11;
+ Vec4V Result;
+
+ const Vec4V twoPi = Vec4V_From_F32Array_Aligned(g_PXReciprocalTwoPi.f);
+ const Vec4V tmp = V4Mul(a, twoPi);
+ const Vec4V b = V4Round(tmp);
+ const Vec4V V1 = V4NegMulSub(twoPi, b, a);
+
+ // cos(V) ~= 1 - V^2 / 2! + V^4 / 4! - V^6 / 6! + V^8 / 8! - V^10 / 10! + V^12 / 12! -
+ // V^14 / 14! + V^16 / 16! - V^18 / 18! + V^20 / 20! - V^22 / 22! (for -PI <= V < PI)
+ const Vec4V V2 = V4Mul(V1, V1);
+ const Vec4V V4 = V4Mul(V2, V2);
+ const Vec4V V6 = V4Mul(V4, V2);
+ const Vec4V V8 = V4Mul(V4, V4);
+ const Vec4V V10 = V4Mul(V6, V4);
+ const Vec4V V12 = V4Mul(V6, V6);
+ const Vec4V V14 = V4Mul(V8, V6);
+ const Vec4V V16 = V4Mul(V8, V8);
+ const Vec4V V18 = V4Mul(V10, V8);
+ const Vec4V V20 = V4Mul(V10, V10);
+ const Vec4V V22 = V4Mul(V12, V10);
+
+ const Vec4V cosCoefficients0 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients0.f);
+ const Vec4V cosCoefficients1 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients1.f);
+ const Vec4V cosCoefficients2 = Vec4V_From_F32Array_Aligned(g_PXCosCoefficients2.f);
+
+ const FloatV C1 = V4GetY(cosCoefficients0);
+ const FloatV C2 = V4GetZ(cosCoefficients0);
+ const FloatV C3 = V4GetW(cosCoefficients0);
+ const FloatV C4 = V4GetX(cosCoefficients1);
+ const FloatV C5 = V4GetY(cosCoefficients1);
+ const FloatV C6 = V4GetZ(cosCoefficients1);
+ const FloatV C7 = V4GetW(cosCoefficients1);
+ const FloatV C8 = V4GetX(cosCoefficients2);
+ const FloatV C9 = V4GetY(cosCoefficients2);
+ const FloatV C10 = V4GetZ(cosCoefficients2);
+ const FloatV C11 = V4GetW(cosCoefficients2);
+
+ Result = V4MulAdd(C1, V2, V4One());
+ Result = V4MulAdd(C2, V4, Result);
+ Result = V4MulAdd(C3, V6, Result);
+ Result = V4MulAdd(C4, V8, Result);
+ Result = V4MulAdd(C5, V10, Result);
+ Result = V4MulAdd(C6, V12, Result);
+ Result = V4MulAdd(C7, V14, Result);
+ Result = V4MulAdd(C8, V16, Result);
+ Result = V4MulAdd(C9, V18, Result);
+ Result = V4MulAdd(C10, V20, Result);
+ Result = V4MulAdd(C11, V22, Result);
+
+ return Result;
+}
+
+//////////////////////////////////
+// BoolV
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE BoolV BFFFF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0, 0, 0 };
+ const __m128 ffff = _mm_load_ps((float *)&f);
+ return ffff;
+}
+
+QT3DS_FORCE_INLINE BoolV BFFFT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0, 0, 0xFFFFFFFF };
+ const __m128 ffft = _mm_load_ps((float *)&f);
+ return ffft;
+}
+
+QT3DS_FORCE_INLINE BoolV BFFTF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0, 0xFFFFFFFF, 0 };
+ const __m128 fftf = _mm_load_ps((float *)&f);
+ return fftf;
+}
+
+QT3DS_FORCE_INLINE BoolV BFFTT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0, 0xFFFFFFFF, 0xFFFFFFFF };
+ const __m128 fftt = _mm_load_ps((float *)&f);
+ return fftt;
+}
+
+QT3DS_FORCE_INLINE BoolV BFTFF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0xFFFFFFFF, 0, 0 };
+ const __m128 ftff = _mm_load_ps((float *)&f);
+ return ftff;
+}
+
+QT3DS_FORCE_INLINE BoolV BFTFT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0xFFFFFFFF, 0, 0xFFFFFFFF };
+ const __m128 ftft = _mm_load_ps((float *)&f);
+ return ftft;
+}
+
+QT3DS_FORCE_INLINE BoolV BFTTF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0xFFFFFFFF, 0xFFFFFFFF, 0 };
+ const __m128 fttf = _mm_load_ps((float *)&f);
+ return fttf;
+}
+
+QT3DS_FORCE_INLINE BoolV BFTTT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ const __m128 fttt = _mm_load_ps((float *)&f);
+ return fttt;
+}
+
+QT3DS_FORCE_INLINE BoolV BTFFF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0, 0, 0 };
+ const __m128 tfff = _mm_load_ps((float *)&f);
+ return tfff;
+}
+
+QT3DS_FORCE_INLINE BoolV BTFFT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0, 0, 0xFFFFFFFF };
+ const __m128 tfft = _mm_load_ps((float *)&f);
+ return tfft;
+}
+
+QT3DS_FORCE_INLINE BoolV BTFTF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0, 0xFFFFFFFF, 0 };
+ const __m128 tftf = _mm_load_ps((float *)&f);
+ return tftf;
+}
+
+QT3DS_FORCE_INLINE BoolV BTFTT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0, 0xFFFFFFFF, 0xFFFFFFFF };
+ const __m128 tftt = _mm_load_ps((float *)&f);
+ return tftt;
+}
+
+QT3DS_FORCE_INLINE BoolV BTTFF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0, 0 };
+ const __m128 ttff = _mm_load_ps((float *)&f);
+ return ttff;
+}
+
+QT3DS_FORCE_INLINE BoolV BTTFT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0, 0xFFFFFFFF };
+ const __m128 ttft = _mm_load_ps((float *)&f);
+ return ttft;
+}
+
+QT3DS_FORCE_INLINE BoolV BTTTF()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0 };
+ const __m128 tttf = _mm_load_ps((float *)&f);
+ return tttf;
+}
+
+QT3DS_FORCE_INLINE BoolV BTTTT()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ const __m128 tttt = _mm_load_ps((float *)&f);
+ return tttt;
+}
+
+QT3DS_FORCE_INLINE BoolV BXMask()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0xFFFFFFFF, 0, 0, 0 };
+ const __m128 tfff = _mm_load_ps((float *)&f);
+ return tfff;
+}
+
+QT3DS_FORCE_INLINE BoolV BYMask()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0xFFFFFFFF, 0, 0 };
+ const __m128 ftff = _mm_load_ps((float *)&f);
+ return ftff;
+}
+
+QT3DS_FORCE_INLINE BoolV BZMask()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0, 0xFFFFFFFF, 0 };
+ const __m128 fftf = _mm_load_ps((float *)&f);
+ return fftf;
+}
+
+QT3DS_FORCE_INLINE BoolV BWMask()
+{
+ const QT3DS_ALIGN(16, QT3DSU32 f[4]) = { 0, 0, 0, 0xFFFFFFFF };
+ const __m128 ffft = _mm_load_ps((float *)&f);
+ return ffft;
+}
+
+QT3DS_FORCE_INLINE BoolV BGetX(const BoolV f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(0, 0, 0, 0));
+}
+
+QT3DS_FORCE_INLINE BoolV BGetY(const BoolV f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(1, 1, 1, 1));
+}
+
+QT3DS_FORCE_INLINE BoolV BGetZ(const BoolV f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(2, 2, 2, 2));
+}
+
+QT3DS_FORCE_INLINE BoolV BGetW(const BoolV f)
+{
+ return _mm_shuffle_ps(f, f, _MM_SHUFFLE(3, 3, 3, 3));
+}
+
+QT3DS_FORCE_INLINE BoolV BAnd(const BoolV a, const BoolV b)
+{
+ return (_mm_and_ps(a, b));
+}
+
+QT3DS_FORCE_INLINE BoolV BNot(const BoolV a)
+{
+ const BoolV bAllTrue(BTTTT());
+ return _mm_xor_ps(a, bAllTrue);
+}
+
+QT3DS_FORCE_INLINE BoolV BAndNot(const BoolV a, const BoolV b)
+{
+ return (_mm_andnot_ps(a, b));
+}
+
+QT3DS_FORCE_INLINE BoolV BOr(const BoolV a, const BoolV b)
+{
+ return (_mm_or_ps(a, b));
+}
+
+QT3DS_FORCE_INLINE BoolV BAllTrue4(const BoolV a)
+{
+ const BoolV bTmp = _mm_and_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 3, 2, 3)));
+ return _mm_and_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
+}
+
+QT3DS_FORCE_INLINE BoolV BAnyTrue4(const BoolV a)
+{
+ const BoolV bTmp = _mm_or_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 3, 2, 3)));
+ return _mm_or_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
+}
+
+QT3DS_FORCE_INLINE BoolV BAllTrue3(const BoolV a)
+{
+ const BoolV bTmp = _mm_and_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
+ return _mm_and_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
+}
+
+QT3DS_FORCE_INLINE BoolV BAnyTrue3(const BoolV a)
+{
+ const BoolV bTmp = _mm_or_ps(_mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 1, 0, 1)),
+ _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2)));
+ return _mm_or_ps(_mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(0, 0, 0, 0)),
+ _mm_shuffle_ps(bTmp, bTmp, _MM_SHUFFLE(1, 1, 1, 1)));
+}
+
+QT3DS_FORCE_INLINE QT3DSU32 BAllEq(const BoolV a, const BoolV b)
+{
+ const BoolV bTest = m128_I2F(_mm_cmpeq_epi32(m128_F2I(a), m128_F2I(b)));
+ return BAllTrue4_R(bTest);
+}
+
+//////////////////////////////////
+// MAT33V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec3V M33MulV3(const Mat33V &a, const Vec3V b)
+{
+ const FloatV x = V3GetX(b);
+ const FloatV y = V3GetY(b);
+ const FloatV z = V3GetZ(b);
+ const Vec3V v0 = V3Scale(a.col0, x);
+ const Vec3V v1 = V3Scale(a.col1, y);
+ const Vec3V v2 = V3Scale(a.col2, z);
+ const Vec3V v0PlusV1 = V3Add(v0, v1);
+ return V3Add(v0PlusV1, v2);
+}
+
+QT3DS_FORCE_INLINE Vec3V M33TrnspsMulV3(const Mat33V &a, const Vec3V b)
+{
+ const FloatV x = V3Dot(a.col0, b);
+ const FloatV y = V3Dot(a.col1, b);
+ const FloatV z = V3Dot(a.col2, b);
+ return V3Merge(x, y, z);
+}
+
+QT3DS_FORCE_INLINE Vec3V M33MulV3AddV3(const Mat33V &A, const Vec3V b, const Vec3V c)
+{
+ const FloatV x = V3GetX(b);
+ const FloatV y = V3GetY(b);
+ const FloatV z = V3GetZ(b);
+ Vec3V result = V3MulAdd(A.col0, x, c);
+ result = V3MulAdd(A.col1, y, result);
+ return V3MulAdd(A.col2, z, result);
+}
+
+QT3DS_FORCE_INLINE Mat33V M33MulM33(const Mat33V &a, const Mat33V &b)
+{
+ return Mat33V(M33MulV3(a, b.col0), M33MulV3(a, b.col1), M33MulV3(a, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Add(const Mat33V &a, const Mat33V &b)
+{
+ return Mat33V(V3Add(a.col0, b.col0), V3Add(a.col1, b.col1), V3Add(a.col2, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Sub(const Mat33V &a, const Mat33V &b)
+{
+ return Mat33V(V3Sub(a.col0, b.col0), V3Sub(a.col1, b.col1), V3Sub(a.col2, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Neg(const Mat33V &a)
+{
+ return Mat33V(V3Neg(a.col0), V3Neg(a.col1), V3Neg(a.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Abs(const Mat33V &a)
+{
+ return Mat33V(V3Abs(a.col0), V3Abs(a.col1), V3Abs(a.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Inverse(const Mat33V &a)
+{
+ const BoolV tfft = BTFFT();
+ const BoolV tttf = BTTTF();
+ const FloatV zero = V3Zero();
+ const Vec3V cross01 = V3Cross(a.col0, a.col1);
+ const Vec3V cross12 = V3Cross(a.col1, a.col2);
+ const Vec3V cross20 = V3Cross(a.col2, a.col0);
+ const FloatV dot = V3Dot(cross01, a.col2);
+ const FloatV invDet = _mm_rcp_ps(dot);
+ const Vec3V mergeh = _mm_unpacklo_ps(cross12, cross01);
+ const Vec3V mergel = _mm_unpackhi_ps(cross12, cross01);
+ Vec3V colInv0 = _mm_unpacklo_ps(mergeh, cross20);
+ colInv0 = _mm_or_ps(_mm_andnot_ps(tttf, zero), _mm_and_ps(tttf, colInv0));
+ const Vec3V zppd = _mm_shuffle_ps(mergeh, cross20, _MM_SHUFFLE(3, 0, 0, 2));
+ const Vec3V pbwp = _mm_shuffle_ps(cross20, mergeh, _MM_SHUFFLE(3, 3, 1, 0));
+ const Vec3V colInv1 = _mm_or_ps(_mm_andnot_ps(BTFFT(), pbwp), _mm_and_ps(BTFFT(), zppd));
+ const Vec3V xppd = _mm_shuffle_ps(mergel, cross20, _MM_SHUFFLE(3, 0, 0, 0));
+ const Vec3V pcyp = _mm_shuffle_ps(cross20, mergel, _MM_SHUFFLE(3, 1, 2, 0));
+ const Vec3V colInv2 = _mm_or_ps(_mm_andnot_ps(tfft, pcyp), _mm_and_ps(tfft, xppd));
+
+ return Mat33V(_mm_mul_ps(colInv0, invDet), _mm_mul_ps(colInv1, invDet),
+ _mm_mul_ps(colInv2, invDet));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Trnsps(const Mat33V &a)
+{
+ return Mat33V(V3Merge(V3GetX(a.col0), V3GetX(a.col1), V3GetX(a.col2)),
+ V3Merge(V3GetY(a.col0), V3GetY(a.col1), V3GetY(a.col2)),
+ V3Merge(V3GetZ(a.col0), V3GetZ(a.col1), V3GetZ(a.col2)));
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Identity()
+{
+ return Mat33V(V3UnitX(), V3UnitY(), V3UnitZ());
+}
+
+QT3DS_FORCE_INLINE Mat33V M33Diagonal(const Vec3VArg d)
+{
+ const FloatV x = V3Mul(V3UnitX(), d);
+ const FloatV y = V3Mul(V3UnitY(), d);
+ const FloatV z = V3Mul(V3UnitZ(), d);
+ return Mat33V(x, y, z);
+}
+
+//////////////////////////////////
+// MAT34V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec3V M34MulV3(const Mat34V &a, const Vec3V b)
+{
+ const FloatV x = V3GetX(b);
+ const FloatV y = V3GetY(b);
+ const FloatV z = V3GetZ(b);
+ const Vec3V v0 = V3Scale(a.col0, x);
+ const Vec3V v1 = V3Scale(a.col1, y);
+ const Vec3V v2 = V3Scale(a.col2, z);
+ const Vec3V v0PlusV1 = V3Add(v0, v1);
+ const Vec3V v0PlusV1Plusv2 = V3Add(v0PlusV1, v2);
+ return (V3Add(v0PlusV1Plusv2, a.col3));
+}
+
+QT3DS_FORCE_INLINE Vec3V M34Mul33V3(const Mat34V &a, const Vec3V b)
+{
+ const FloatV x = V3GetX(b);
+ const FloatV y = V3GetY(b);
+ const FloatV z = V3GetZ(b);
+ const Vec3V v0 = V3Scale(a.col0, x);
+ const Vec3V v1 = V3Scale(a.col1, y);
+ const Vec3V v2 = V3Scale(a.col2, z);
+ const Vec3V v0PlusV1 = V3Add(v0, v1);
+ return V3Add(v0PlusV1, v2);
+}
+
+QT3DS_FORCE_INLINE Vec3V M34TrnspsMul33V3(const Mat34V &a, const Vec3V b)
+{
+ const FloatV x = V3Dot(a.col0, b);
+ const FloatV y = V3Dot(a.col1, b);
+ const FloatV z = V3Dot(a.col2, b);
+ return V3Merge(x, y, z);
+}
+
+QT3DS_FORCE_INLINE Mat34V M34MulM34(const Mat34V &a, const Mat34V &b)
+{
+ return Mat34V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2),
+ M34MulV3(a, b.col3));
+}
+
+QT3DS_FORCE_INLINE Mat33V M34MulM33(const Mat34V &a, const Mat33V &b)
+{
+ return Mat33V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat33V M34Mul33MM34(const Mat34V &a, const Mat34V &b)
+{
+ return Mat33V(M34Mul33V3(a, b.col0), M34Mul33V3(a, b.col1), M34Mul33V3(a, b.col2));
+}
+
+QT3DS_FORCE_INLINE Mat34V M34Add(const Mat34V &a, const Mat34V &b)
+{
+ return Mat34V(V3Add(a.col0, b.col0), V3Add(a.col1, b.col1), V3Add(a.col2, b.col2),
+ V3Add(a.col3, b.col3));
+}
+
+QT3DS_FORCE_INLINE Mat34V M34Inverse(const Mat34V &a)
+{
+ Mat34V aInv;
+ const BoolV tfft = BTFFT();
+ const BoolV tttf = BTTTF();
+ const FloatV zero = V3Zero();
+ const Vec3V cross01 = V3Cross(a.col0, a.col1);
+ const Vec3V cross12 = V3Cross(a.col1, a.col2);
+ const Vec3V cross20 = V3Cross(a.col2, a.col0);
+ const FloatV dot = V3Dot(cross01, a.col2);
+ const FloatV invDet = _mm_rcp_ps(dot);
+ const Vec3V mergeh = _mm_unpacklo_ps(cross12, cross01);
+ const Vec3V mergel = _mm_unpackhi_ps(cross12, cross01);
+ Vec3V colInv0 = _mm_unpacklo_ps(mergeh, cross20);
+ colInv0 = _mm_or_ps(_mm_andnot_ps(tttf, zero), _mm_and_ps(tttf, colInv0));
+ const Vec3V zppd = _mm_shuffle_ps(mergeh, cross20, _MM_SHUFFLE(3, 0, 0, 2));
+ const Vec3V pbwp = _mm_shuffle_ps(cross20, mergeh, _MM_SHUFFLE(3, 3, 1, 0));
+ const Vec3V colInv1 = _mm_or_ps(_mm_andnot_ps(BTFFT(), pbwp), _mm_and_ps(BTFFT(), zppd));
+ const Vec3V xppd = _mm_shuffle_ps(mergel, cross20, _MM_SHUFFLE(3, 0, 0, 0));
+ const Vec3V pcyp = _mm_shuffle_ps(cross20, mergel, _MM_SHUFFLE(3, 1, 2, 0));
+ const Vec3V colInv2 = _mm_or_ps(_mm_andnot_ps(tfft, pcyp), _mm_and_ps(tfft, xppd));
+ aInv.col0 = _mm_mul_ps(colInv0, invDet);
+ aInv.col1 = _mm_mul_ps(colInv1, invDet);
+ aInv.col2 = _mm_mul_ps(colInv2, invDet);
+ aInv.col3 = M34Mul33V3(aInv, V3Neg(a.col3));
+ return aInv;
+}
+
+QT3DS_FORCE_INLINE Mat33V M34Trnsps33(const Mat34V &a)
+{
+ return Mat33V(V3Merge(V3GetX(a.col0), V3GetX(a.col1), V3GetX(a.col2)),
+ V3Merge(V3GetY(a.col0), V3GetY(a.col1), V3GetY(a.col2)),
+ V3Merge(V3GetZ(a.col0), V3GetZ(a.col1), V3GetZ(a.col2)));
+}
+
+//////////////////////////////////
+// MAT44V
+//////////////////////////////////
+
+QT3DS_FORCE_INLINE Vec4V M44MulV4(const Mat44V &a, const Vec4V b)
+{
+ const FloatV x = V4GetX(b);
+ const FloatV y = V4GetY(b);
+ const FloatV z = V4GetZ(b);
+ const FloatV w = V4GetW(b);
+
+ const Vec4V v0 = V4Scale(a.col0, x);
+ const Vec4V v1 = V4Scale(a.col1, y);
+ const Vec4V v2 = V4Scale(a.col2, z);
+ const Vec4V v3 = V4Scale(a.col3, w);
+ const Vec4V v0PlusV1 = V4Add(v0, v1);
+ const Vec4V v0PlusV1Plusv2 = V4Add(v0PlusV1, v2);
+ return (V4Add(v0PlusV1Plusv2, v3));
+}
+
+QT3DS_FORCE_INLINE Vec4V M44TrnspsMulV4(const Mat44V &a, const Vec4V b)
+{
+ QT3DS_ALIGN(16, FloatV dotProdArray[4]) = { V4Dot(a.col0, b), V4Dot(a.col1, b), V4Dot(a.col2, b),
+ V4Dot(a.col3, b) };
+ return V4Merge(dotProdArray);
+}
+
+QT3DS_FORCE_INLINE Mat44V M44MulM44(const Mat44V &a, const Mat44V &b)
+{
+ return Mat44V(M44MulV4(a, b.col0), M44MulV4(a, b.col1), M44MulV4(a, b.col2),
+ M44MulV4(a, b.col3));
+}
+
+QT3DS_FORCE_INLINE Mat44V M44Add(const Mat44V &a, const Mat44V &b)
+{
+ return Mat44V(V4Add(a.col0, b.col0), V4Add(a.col1, b.col1), V4Add(a.col2, b.col2),
+ V4Add(a.col3, b.col3));
+}
+
+QT3DS_FORCE_INLINE Mat44V M44Trnsps(const Mat44V &a)
+{
+ const Vec4V v0 = _mm_unpacklo_ps(a.col0, a.col2);
+ const Vec4V v1 = _mm_unpackhi_ps(a.col0, a.col2);
+ const Vec4V v2 = _mm_unpacklo_ps(a.col1, a.col3);
+ const Vec4V v3 = _mm_unpackhi_ps(a.col1, a.col3);
+ return Mat44V(_mm_unpacklo_ps(v0, v2), _mm_unpackhi_ps(v0, v2), _mm_unpacklo_ps(v1, v3),
+ _mm_unpackhi_ps(v1, v3));
+}
+
+// The original code as provided by Intel in
+// "Streaming SIMD Extensions - Inverse of 4x4 Matrix"
+// (ftp://download.intel.com/design/pentiumiii/sml/24504301.pdf)
+QT3DS_FORCE_INLINE Mat44V M44Inverse(const Mat44V &a)
+{
+ __m128 minor0, minor1, minor2, minor3;
+ __m128 row0, row1, row2, row3;
+ __m128 det, tmp1;
+
+ tmp1 = V4Zero();
+ row1 = V4Zero();
+ row3 = V4Zero();
+
+ row0 = a.col0;
+ row1 = _mm_shuffle_ps(a.col1, a.col1, _MM_SHUFFLE(1, 0, 3, 2));
+ row2 = a.col2;
+ row3 = _mm_shuffle_ps(a.col3, a.col3, _MM_SHUFFLE(1, 0, 3, 2));
+
+ tmp1 = _mm_mul_ps(row2, row3);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor0 = _mm_mul_ps(row1, tmp1);
+ minor1 = _mm_mul_ps(row0, tmp1);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor0 = _mm_sub_ps(_mm_mul_ps(row1, tmp1), minor0);
+ minor1 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor1);
+ minor1 = _mm_shuffle_ps(minor1, minor1, 0x4E);
+
+ tmp1 = _mm_mul_ps(row1, row2);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor0 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor0);
+ minor3 = _mm_mul_ps(row0, tmp1);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor0 = _mm_sub_ps(minor0, _mm_mul_ps(row3, tmp1));
+ minor3 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor3);
+ minor3 = _mm_shuffle_ps(minor3, minor3, 0x4E);
+
+ tmp1 = _mm_mul_ps(_mm_shuffle_ps(row1, row1, 0x4E), row3);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ row2 = _mm_shuffle_ps(row2, row2, 0x4E);
+ minor0 = _mm_add_ps(_mm_mul_ps(row2, tmp1), minor0);
+ minor2 = _mm_mul_ps(row0, tmp1);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor0 = _mm_sub_ps(minor0, _mm_mul_ps(row2, tmp1));
+ minor2 = _mm_sub_ps(_mm_mul_ps(row0, tmp1), minor2);
+ minor2 = _mm_shuffle_ps(minor2, minor2, 0x4E);
+
+ tmp1 = _mm_mul_ps(row0, row1);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor2 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor2);
+ minor3 = _mm_sub_ps(_mm_mul_ps(row2, tmp1), minor3);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor2 = _mm_sub_ps(_mm_mul_ps(row3, tmp1), minor2);
+ minor3 = _mm_sub_ps(minor3, _mm_mul_ps(row2, tmp1));
+
+ tmp1 = _mm_mul_ps(row0, row3);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor1 = _mm_sub_ps(minor1, _mm_mul_ps(row2, tmp1));
+ minor2 = _mm_add_ps(_mm_mul_ps(row1, tmp1), minor2);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor1 = _mm_add_ps(_mm_mul_ps(row2, tmp1), minor1);
+ minor2 = _mm_sub_ps(minor2, _mm_mul_ps(row1, tmp1));
+
+ tmp1 = _mm_mul_ps(row0, row2);
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0xB1);
+ minor1 = _mm_add_ps(_mm_mul_ps(row3, tmp1), minor1);
+ minor3 = _mm_sub_ps(minor3, _mm_mul_ps(row1, tmp1));
+ tmp1 = _mm_shuffle_ps(tmp1, tmp1, 0x4E);
+ minor1 = _mm_sub_ps(minor1, _mm_mul_ps(row3, tmp1));
+ minor3 = _mm_add_ps(_mm_mul_ps(row1, tmp1), minor3);
+
+ det = _mm_mul_ps(row0, minor0);
+ det = _mm_add_ps(_mm_shuffle_ps(det, det, 0x4E), det);
+ det = _mm_add_ss(_mm_shuffle_ps(det, det, 0xB1), det);
+ tmp1 = _mm_rcp_ss(det);
+#if 0
+ det = _mm_sub_ss(_mm_add_ss(tmp1, tmp1), _mm_mul_ss(det, _mm_mul_ss(tmp1, tmp1)));
+ det = _mm_shuffle_ps(det, det, 0x00);
+#else
+ det = _mm_shuffle_ps(tmp1, tmp1, _MM_SHUFFLE(0, 0, 0, 0));
+#endif
+
+ minor0 = _mm_mul_ps(det, minor0);
+ minor1 = _mm_mul_ps(det, minor1);
+ minor2 = _mm_mul_ps(det, minor2);
+ minor3 = _mm_mul_ps(det, minor3);
+ Mat44V invTrans(minor0, minor1, minor2, minor3);
+ return M44Trnsps(invTrans);
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_XYZW(QT3DSF32 x, QT3DSF32 y, QT3DSF32 z, QT3DSF32 w)
+{
+ return _mm_set_ps(w, z, y, x);
+}
+
+// AP: work in progress - use proper SSE intrinsics where possible
+QT3DS_FORCE_INLINE VecU16V V4U32PK(VecU32V a, VecU32V b)
+{
+ VecU16V result;
+ result.m128_u16[0] = QT3DSU16(NVClamp<QT3DSU32>((a).m128_u32[0], 0, 0xFFFF));
+ result.m128_u16[1] = QT3DSU16(NVClamp<QT3DSU32>((a).m128_u32[1], 0, 0xFFFF));
+ result.m128_u16[2] = QT3DSU16(NVClamp<QT3DSU32>((a).m128_u32[2], 0, 0xFFFF));
+ result.m128_u16[3] = QT3DSU16(NVClamp<QT3DSU32>((a).m128_u32[3], 0, 0xFFFF));
+ result.m128_u16[4] = QT3DSU16(NVClamp<QT3DSU32>((b).m128_u32[0], 0, 0xFFFF));
+ result.m128_u16[5] = QT3DSU16(NVClamp<QT3DSU32>((b).m128_u32[1], 0, 0xFFFF));
+ result.m128_u16[6] = QT3DSU16(NVClamp<QT3DSU32>((b).m128_u32[2], 0, 0xFFFF));
+ result.m128_u16[7] = QT3DSU16(NVClamp<QT3DSU32>((b).m128_u32[3], 0, 0xFFFF));
+ return result;
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U32or(VecU32V a, VecU32V b)
+{
+ return m128_I2F(_mm_or_si128(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U32and(VecU32V a, VecU32V b)
+{
+ return m128_I2F(_mm_and_si128(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U32Andc(VecU32V a, VecU32V b)
+{
+ return m128_I2F(_mm_andnot_si128(m128_F2I(b), m128_F2I(a)));
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16Or(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_or_si128(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16And(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_and_si128(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16Andc(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_andnot_si128(m128_F2I(b), m128_F2I(a)));
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_From_I32(const QT3DSI32 i)
+{
+ return (_mm_load1_ps((QT3DSF32 *)&i));
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_From_I32Array(const QT3DSI32 *i)
+{
+ return _mm_loadu_ps((QT3DSF32 *)i);
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_From_I32Array_Aligned(const QT3DSI32 *i)
+{
+ return _mm_load_ps((QT3DSF32 *)i);
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_Add(const VecI32VArg a, const VecI32VArg b)
+{
+ return m128_I2F(_mm_add_epi32(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_Sub(const VecI32VArg a, const VecI32VArg b)
+{
+ return m128_I2F(_mm_sub_epi32(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE BoolV VecI32V_IsGrtr(const VecI32VArg a, const VecI32VArg b)
+{
+ return m128_I2F(_mm_cmpgt_epi32(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE BoolV VecI32V_IsEq(const VecI32VArg a, const VecI32VArg b)
+{
+ return m128_I2F(_mm_cmpeq_epi32(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_Zero()
+{
+ return V4Zero();
+}
+
+QT3DS_FORCE_INLINE VecI32V VecI32V_Merge(const VecI32VArg a, const VecI32VArg b, const VecI32VArg c,
+ const VecI32VArg d)
+{
+ return V4Merge(a, b, c, d);
+}
+
+template <int a>
+QT3DS_FORCE_INLINE VecI32V V4ISplat()
+{
+ VecI32V result;
+ result.m128_i32[0] = a;
+ result.m128_i32[1] = a;
+ result.m128_i32[2] = a;
+ result.m128_i32[3] = a;
+ return result;
+}
+
+QT3DS_FORCE_INLINE void V4U16StoreAligned(VecU16V val, VecU16V *address)
+{
+ *address = val;
+}
+
+QT3DS_FORCE_INLINE void V4U32StoreAligned(VecU32V val, VecU32V *address)
+{
+ *address = val;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4LoadAligned(Vec4V *addr)
+{
+ return *addr;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4LoadUnaligned(Vec4V *addr)
+{
+ return Vec4V_From_F32Array((float *)addr);
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Andc(const Vec4V a, const VecU32V b)
+{
+ VecU32V result32(a);
+ result32 = V4U32Andc(result32, b);
+ return Vec4V(result32);
+}
+
+QT3DS_FORCE_INLINE VecU32V V4IsGrtrV32u(const Vec4V a, const Vec4V b)
+{
+ return V4IsGrtr(a, b);
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16LoadAligned(VecU16V *addr)
+{
+ return *addr;
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16LoadUnaligned(VecU16V *addr)
+{
+ return *addr;
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16CompareGt(VecU16V a, VecU16V b)
+{
+ // _mm_cmpgt_epi16 doesn't work for unsigned values unfortunately
+ // return m128_I2F(_mm_cmpgt_epi16(m128_F2I(a), m128_F2I(b)));
+ VecU16V result;
+ result.m128_u16[0] = (a).m128_u16[0] > (b).m128_u16[0];
+ result.m128_u16[1] = (a).m128_u16[1] > (b).m128_u16[1];
+ result.m128_u16[2] = (a).m128_u16[2] > (b).m128_u16[2];
+ result.m128_u16[3] = (a).m128_u16[3] > (b).m128_u16[3];
+ result.m128_u16[4] = (a).m128_u16[4] > (b).m128_u16[4];
+ result.m128_u16[5] = (a).m128_u16[5] > (b).m128_u16[5];
+ result.m128_u16[6] = (a).m128_u16[6] > (b).m128_u16[6];
+ result.m128_u16[7] = (a).m128_u16[7] > (b).m128_u16[7];
+ return result;
+}
+
+QT3DS_FORCE_INLINE Vec4V Vec4V_From_VecU32V(VecU32V a)
+{
+ Vec4V result = Vec4V_From_XYZW(QT3DSF32(a.m128_u32[0]), QT3DSF32(a.m128_u32[1]), QT3DSF32(a.m128_u32[2]),
+ QT3DSF32(a.m128_u32[3]));
+ return result;
+}
+
+template <int index>
+QT3DS_FORCE_INLINE VecU32V V4U32SplatElement(VecU32V a)
+{
+ VecU32V result;
+ result.m128_u32[0] = result.m128_u32[1] = result.m128_u32[2] = result.m128_u32[3] =
+ a.m128_u32[index];
+ return result;
+}
+
+template <int index>
+QT3DS_FORCE_INLINE Vec4V V4SplatElement(Vec4V a)
+{
+ float *data = (float *)&a;
+ return Vec4V_From_F32(data[index]);
+}
+
+template <int index>
+QT3DS_FORCE_INLINE VecU16V V4U16SplatElement(VecU16V a)
+{
+ VecU16V result = a; // AM: initializing to avoid nonsensical warning 4701 here with VC10.
+ for (int i = 0; i < 8; i++)
+ result.m128_u16[i] = a.m128_u16[index];
+ return result;
+}
+
+template <int imm>
+QT3DS_FORCE_INLINE VecI16V V4I16SplatImmediate()
+{
+ VecI16V result;
+ result.m128_i16[0] = imm;
+ result.m128_i16[1] = imm;
+ result.m128_i16[2] = imm;
+ result.m128_i16[3] = imm;
+ result.m128_i16[4] = imm;
+ result.m128_i16[5] = imm;
+ result.m128_i16[6] = imm;
+ result.m128_i16[7] = imm;
+ return result;
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16SubtractModulo(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_sub_epi16(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU16V V4U16AddModulo(VecU16V a, VecU16V b)
+{
+ return m128_I2F(_mm_add_epi16(m128_F2I(a), m128_F2I(b)));
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U16GetLo16(VecU16V a)
+{
+ VecU32V result;
+ result.m128_u32[0] = a.m128_u16[0];
+ result.m128_u32[1] = a.m128_u16[2];
+ result.m128_u32[2] = a.m128_u16[4];
+ result.m128_u32[3] = a.m128_u16[6];
+ return result;
+}
+
+QT3DS_FORCE_INLINE VecU32V V4U16GetHi16(VecU16V a)
+{
+ VecU32V result;
+ result.m128_u32[0] = a.m128_u16[1];
+ result.m128_u32[1] = a.m128_u16[3];
+ result.m128_u32[2] = a.m128_u16[5];
+ result.m128_u32[3] = a.m128_u16[7];
+ return result;
+}
+
+QT3DS_FORCE_INLINE VecU32V VecU32V_From_XYZW(QT3DSU32 x, QT3DSU32 y, QT3DSU32 z, QT3DSU32 w)
+{
+ VecU32V result;
+ result.m128_u32[0] = x;
+ result.m128_u32[1] = y;
+ result.m128_u32[2] = z;
+ result.m128_u32[3] = w;
+ return result;
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Ceil(const Vec4V a)
+{
+ return Vec4V_From_XYZW(NVCeil(a.m128_f32[0]), NVCeil(a.m128_f32[1]), NVCeil(a.m128_f32[2]),
+ NVCeil(a.m128_f32[3]));
+}
+
+QT3DS_FORCE_INLINE Vec4V V4Floor(const Vec4V a)
+{
+ return Vec4V_From_XYZW(NVFloor(a.m128_f32[0]), NVFloor(a.m128_f32[1]), NVFloor(a.m128_f32[2]),
+ NVFloor(a.m128_f32[3]));
+}
+
+QT3DS_FORCE_INLINE VecU32V V4ConvertToU32VSaturate(const Vec4V a, QT3DSU32 power)
+{
+ QT3DS_ASSERT(power == 0 && "Non-zero power not supported in convertToU32VSaturate");
+ QT3DS_FORCE_PARAMETER_REFERENCE(power); // prevent warning in release builds
+ QT3DSF32 ffffFFFFasFloat = QT3DSF32(0xFFFF0000);
+ VecU32V result;
+ result.m128_u32[0] = QT3DSU32(NVClamp<QT3DSF32>((a).m128_f32[0], 0.0f, ffffFFFFasFloat));
+ result.m128_u32[1] = QT3DSU32(NVClamp<QT3DSF32>((a).m128_f32[1], 0.0f, ffffFFFFasFloat));
+ result.m128_u32[2] = QT3DSU32(NVClamp<QT3DSF32>((a).m128_f32[2], 0.0f, ffffFFFFasFloat));
+ result.m128_u32[3] = QT3DSU32(NVClamp<QT3DSF32>((a).m128_f32[3], 0.0f, ffffFFFFasFloat));
+ return result;
+}
+
+#endif // QT3DS_WINDOWS_INLINE_AOS_H
diff --git a/src/foundation/windows/Qt3DSWindowsIntrinsics.h b/src/foundation/windows/Qt3DSWindowsIntrinsics.h
new file mode 100644
index 0000000..3e0b3e8
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsIntrinsics.h
@@ -0,0 +1,230 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_WINDOWS_INTRINSICS_H
+#define QT3DS_FOUNDATION_QT3DS_WINDOWS_INTRINSICS_H
+
+#include "foundation/Qt3DS.h"
+
+#if !defined QT3DS_WINDOWS && !defined QT3DS_WIN8ARM
+#error "This file should only be included by Windows builds!!"
+#endif
+
+#ifdef QT3DS_GNUC
+#include <cmath>
+#else
+#include <math.h>
+#endif
+#include <float.h>
+#include <intrin.h>
+#include <string.h>
+#include "foundation/Qt3DSAssert.h"
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+namespace intrinsics {
+#endif
+
+ //! \brief platform-specific absolute value
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float abs(float a) { return float(::fabs(a)); }
+
+ //! \brief platform-specific select float
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float fsel(float a, float b, float c)
+ {
+ return (a >= 0.0f) ? b : c;
+ }
+
+ //! \brief platform-specific sign
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float sign(float a) { return (a >= 0.0f) ? 1.0f : -1.0f; }
+
+ //! \brief platform-specific reciprocal
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float recip(float a) { return 1.0f / a; }
+
+ //! \brief platform-specific square root
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float sqrt(float a) { return ::sqrtf(a); }
+
+ //! \brief platform-specific reciprocal square root
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float recipSqrt(float a) { return 1.0f / ::sqrtf(a); }
+
+ //! \brief platform-specific sine
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float sin(float a) { return ::sinf(a); }
+
+ //! \brief platform-specific cosine
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float cos(float a) { return ::cosf(a); }
+
+ //! \brief platform-specific minimum
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float selectMin(float a, float b) { return a < b ? a : b; }
+
+ //! \brief platform-specific maximum
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float selectMax(float a, float b) { return a > b ? a : b; }
+
+ //! \brief platform-specific finiteness check (not INF or NAN)
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isFinite(float a)
+ {
+#if defined(__CUDACC__)
+ return isfinite(a)? true : false;
+#elif defined(QT3DS_GNUC)
+ return (std::isfinite(a) && !std::isinf(a)) ? true : false;
+#else
+ return (0 == ((_FPCLASS_SNAN | _FPCLASS_QNAN | _FPCLASS_NINF | _FPCLASS_PINF) & _fpclass(a)));
+#endif
+ }
+
+ //! \brief platform-specific finiteness check (not INF or NAN)
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE bool isFinite(double a)
+ {
+#if defined(__CUDACC__)
+ return isfinite(a)? true : false;
+#elif defined(QT3DS_GNUC)
+ return (std::isfinite(a) && !std::isinf(a)) ? true : false;
+#else
+ return (0 == ((_FPCLASS_SNAN | _FPCLASS_QNAN | _FPCLASS_NINF | _FPCLASS_PINF) & _fpclass(a)));
+#endif
+ }
+ /*
+* Implements a memory barrier
+*/
+ QT3DS_FORCE_INLINE void memoryBarrier()
+ {
+ _ReadWriteBarrier();
+ /* long Barrier;
+ __asm {
+ xchg Barrier, eax
+ }*/
+ }
+
+ /*!
+ Returns the index of the highest set bit. Not valid for zero arg.
+ */
+ QT3DS_FORCE_INLINE QT3DSU32 highestSetBitUnsafe(QT3DSU32 v)
+ {
+ unsigned long retval;
+ _BitScanReverse(&retval, v);
+ return retval;
+ }
+
+ /*!
+ Returns the index of the highest set bit. Undefined for zero arg.
+ */
+ QT3DS_FORCE_INLINE QT3DSU32 lowestSetBitUnsafe(QT3DSU32 v)
+ {
+ unsigned long retval;
+ _BitScanForward(&retval, v);
+ return retval;
+ }
+
+ /*!
+ Returns the number of leading zeros in v. Returns 32 for v=0.
+ */
+ QT3DS_FORCE_INLINE QT3DSU32 countLeadingZeros(QT3DSU32 v)
+ {
+ if (v) {
+ unsigned long bsr = (unsigned long)-1;
+ _BitScanReverse(&bsr, v);
+ return 31 - bsr;
+ } else
+ return 32;
+ }
+
+ /*!
+ Sets \c count bytes starting at \c dst to zero.
+ */
+ QT3DS_FORCE_INLINE void *memZero(void *QT3DS_RESTRICT dest, QT3DSU32 count)
+ {
+ return memset(dest, 0, count);
+ }
+
+ /*!
+ Sets \c count bytes starting at \c dst to \c c.
+ */
+ QT3DS_FORCE_INLINE void *memSet(void *QT3DS_RESTRICT dest, QT3DSI32 c, QT3DSU32 count)
+ {
+ return memset(dest, c, count);
+ }
+
+ /*!
+ Copies \c count bytes from \c src to \c dst. User memMove if regions overlap.
+ */
+ QT3DS_FORCE_INLINE void *memCopy(void *QT3DS_RESTRICT dest, const void *QT3DS_RESTRICT src, QT3DSU32 count)
+ {
+ return memcpy(dest, src, count);
+ }
+
+ /*!
+ Copies \c count bytes from \c src to \c dst. Supports overlapping regions.
+ */
+ QT3DS_FORCE_INLINE void *memMove(void *QT3DS_RESTRICT dest, const void *QT3DS_RESTRICT src, QT3DSU32 count)
+ {
+ return memmove(dest, src, count);
+ }
+
+ /*!
+ Set 128B to zero starting at \c dst+offset. Must be aligned.
+ */
+ QT3DS_FORCE_INLINE void memZero128(void *QT3DS_RESTRICT dest, QT3DSU32 offset = 0)
+ {
+ QT3DS_ASSERT(((size_t(dest) + offset) & 0x7f) == 0);
+ memSet((char *QT3DS_RESTRICT)dest + offset, 0, 128);
+ }
+
+ /*!
+ Prefetch aligned 128B around \c ptr+offset.
+ */
+ QT3DS_FORCE_INLINE void prefetch128(const void *ptr, QT3DSU32 offset = 0)
+ {
+#ifdef QT3DS_WINDOWS
+ _mm_prefetch(((const char *)ptr + offset), _MM_HINT_T0);
+#endif
+ }
+
+ /*!
+ Prefetch \c count bytes starting at \c ptr.
+ */
+ QT3DS_FORCE_INLINE void prefetch(const void *ptr, QT3DSU32 count = 0)
+ {
+ for (QT3DSU32 i = 0; i <= count; i += 128)
+ prefetch128(ptr, i);
+ }
+
+ //! \brief platform-specific reciprocal
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float recipFast(float a) { return 1.0f / a; }
+
+ //! \brief platform-specific fast reciprocal square root
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float recipSqrtFast(float a) { return 1.0f / ::sqrtf(a); }
+
+ //! \brief platform-specific floor
+ QT3DS_CUDA_CALLABLE QT3DS_FORCE_INLINE float floatFloor(float x) { return ::floorf(x); }
+
+#ifndef QT3DS_DOXYGEN
+} // namespace intrinsics
+} // namespace qt3ds
+#endif
+
+#endif
diff --git a/src/foundation/windows/Qt3DSWindowsMutex.cpp b/src/foundation/windows/Qt3DSWindowsMutex.cpp
new file mode 100644
index 0000000..c5fef09
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsMutex.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/windows/Qt3DSWindowsInclude.h"
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSAssert.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ namespace {
+ CRITICAL_SECTION *getMutex(MutexImpl *impl)
+ {
+ return reinterpret_cast<CRITICAL_SECTION *>(impl);
+ }
+ }
+
+ MutexImpl::MutexImpl() { InitializeCriticalSection(getMutex(this)); }
+
+ MutexImpl::~MutexImpl() { DeleteCriticalSection(getMutex(this)); }
+
+ bool MutexImpl::lock()
+ {
+ EnterCriticalSection(getMutex(this));
+ return true;
+ }
+
+ bool MutexImpl::trylock() { return TryEnterCriticalSection(getMutex(this)) != 0; }
+
+ bool MutexImpl::unlock()
+ {
+ LeaveCriticalSection(getMutex(this));
+ return true;
+ }
+
+ const QT3DSU32 MutexImpl::size = sizeof(CRITICAL_SECTION);
+
+ class ReadWriteLockImpl
+ {
+ public:
+ ReadWriteLockImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ HANDLE hReaderEvent;
+ HANDLE hMutex;
+ CRITICAL_SECTION writerMutex;
+ LONG counter; // count the number of readers in the lock.
+ LONG recursionCounter; // handle recursive writer locking
+ };
+
+ ReadWriteLock::ReadWriteLock(NVAllocatorCallback &alloc)
+ {
+ mImpl = QT3DS_NEW(alloc, ReadWriteLockImpl)(alloc);
+
+ mImpl->hReaderEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ QT3DS_ASSERT(mImpl->hReaderEvent != NULL);
+
+ mImpl->hMutex = CreateEvent(NULL, FALSE, TRUE, NULL);
+ QT3DS_ASSERT(mImpl->hMutex != NULL);
+
+ InitializeCriticalSection(&mImpl->writerMutex);
+ mImpl->counter = -1;
+ mImpl->recursionCounter = 0;
+ }
+
+ ReadWriteLock::~ReadWriteLock()
+ {
+ if (mImpl->hReaderEvent != NULL) {
+ CloseHandle(mImpl->hReaderEvent);
+ }
+
+ if (mImpl->hMutex != NULL) {
+ CloseHandle(mImpl->hMutex);
+ }
+
+ DeleteCriticalSection(&mImpl->writerMutex);
+
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ void ReadWriteLock::lockReader()
+ {
+ if (InterlockedIncrement(&mImpl->counter) == 0) {
+ WaitForSingleObject(mImpl->hMutex, INFINITE);
+ SetEvent(mImpl->hReaderEvent);
+ }
+
+ WaitForSingleObject(mImpl->hReaderEvent, INFINITE);
+ }
+
+ void ReadWriteLock::lockWriter()
+ {
+ EnterCriticalSection(&mImpl->writerMutex);
+
+ // we may already have the global mutex(really an event so we have to handle recursion
+ // ourselves)
+ if (++mImpl->recursionCounter == 1) {
+ WaitForSingleObject(mImpl->hMutex, INFINITE);
+ }
+ }
+
+ void ReadWriteLock::unlockReader()
+ {
+ if (InterlockedDecrement(&mImpl->counter) < 0) {
+ ResetEvent(mImpl->hReaderEvent);
+ SetEvent(mImpl->hMutex);
+ }
+ }
+
+ void ReadWriteLock::unlockWriter()
+ {
+ if (--mImpl->recursionCounter == 0) {
+ SetEvent(mImpl->hMutex);
+ }
+
+ LeaveCriticalSection(&mImpl->writerMutex);
+ }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/windows/Qt3DSWindowsSemaphore.cpp b/src/foundation/windows/Qt3DSWindowsSemaphore.cpp
new file mode 100644
index 0000000..bb14c10
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsSemaphore.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/windows/Qt3DSWindowsInclude.h"
+#include "foundation/Qt3DSSemaphore.h"
+#include "foundation/Qt3DSAllocator.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ class SemaphoreImpl
+ {
+ public:
+ SemaphoreImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ HANDLE handle;
+ };
+
+ Semaphore::Semaphore(NVAllocatorCallback &alloc, QT3DSU32 initialCount, QT3DSU32 maxCount)
+ {
+ mImpl = QT3DS_NEW(alloc, SemaphoreImpl)(alloc);
+ mImpl->handle = CreateSemaphore(0, initialCount, maxCount, (LPCTSTR)NULL);
+ }
+
+ Semaphore::~Semaphore()
+ {
+ CloseHandle(mImpl->handle);
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ bool Semaphore::wait(QT3DSU32 milliseconds)
+ {
+ if (milliseconds == -1)
+ milliseconds = INFINITE;
+
+ return WaitForSingleObject(mImpl->handle, milliseconds) == WAIT_OBJECT_0 ? true : false;
+ }
+
+ void Semaphore::post() { ReleaseSemaphore(mImpl->handle, 1, (LPLONG)NULL); }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/windows/Qt3DSWindowsString.h b/src/foundation/windows/Qt3DSWindowsString.h
new file mode 100644
index 0000000..8d5fcd3
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsString.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_FOUNDATION_QT3DS_WINDOWS_STRING_H
+#define QT3DS_FOUNDATION_QT3DS_WINDOWS_STRING_H
+
+#include "foundation/Qt3DS.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#pragma warning(push)
+#pragma warning(disable : 4995 4996)
+
+#ifndef QT3DS_DOXYGEN
+namespace qt3ds {
+#endif
+
+QT3DS_INLINE void NVStrcpy(char *dest, size_t size, const char *src)
+{
+ ::strcpy_s(dest, size, src);
+}
+QT3DS_INLINE void NVStrcat(char *dest, size_t size, const char *src)
+{
+ ::strcat_s(dest, size, src);
+}
+QT3DS_INLINE QT3DSI32 NVVsprintf(char *dest, size_t size, const char *src, va_list arg)
+{
+ QT3DSI32 r = ::vsprintf_s(dest, size, src, arg);
+
+ return r;
+}
+QT3DS_INLINE QT3DSI32 NVStricmp(const char *str, const char *str1)
+{
+ return (::_stricmp(str, str1));
+}
+
+namespace string {
+ QT3DS_INLINE QT3DSI32 stricmp(const char *str, const char *str1) { return (::_stricmp(str, str1)); }
+ QT3DS_INLINE QT3DSI32 strnicmp(const char *str, const char *str1, size_t len)
+ {
+ return (::_strnicmp(str, str1, len));
+ }
+ QT3DS_INLINE QT3DSI32 strncat_s(char *a, QT3DSI32 b, const char *c, size_t d)
+ {
+ return (::strncat_s(a, b, c, d));
+ }
+ QT3DS_INLINE QT3DSI32 strncpy_s(char *strDest, size_t sizeInBytes, const char *strSource,
+ size_t count)
+ {
+ return (::strncpy_s(strDest, sizeInBytes, strSource, count));
+ }
+ QT3DS_INLINE void strcpy_s(char *dest, size_t size, const char *src)
+ {
+ ::strcpy_s(dest, size, src);
+ }
+ QT3DS_INLINE void strcat_s(char *dest, size_t size, const char *src)
+ {
+ ::strcat_s(dest, size, src);
+ }
+ QT3DS_INLINE QT3DSI32 _vsnprintf(char *dest, size_t size, const char *src, va_list arg)
+ {
+ QT3DSI32 r = ::_vsnprintf(dest, size, src, arg);
+
+ return r;
+ }
+ QT3DS_INLINE QT3DSI32 vsprintf_s(char *dest, size_t size, const char *src, va_list arg)
+ {
+ QT3DSI32 r = ::vsprintf_s(dest, size, src, arg);
+
+ return r;
+ }
+
+ QT3DS_INLINE QT3DSI32 sprintf_s(char *_DstBuf, size_t _DstSize, const char *_Format, ...)
+ {
+ va_list arg;
+ va_start(arg, _Format);
+ QT3DSI32 r = ::vsprintf_s(_DstBuf, _DstSize, _Format, arg);
+ va_end(arg);
+
+ return r;
+ }
+ QT3DS_INLINE QT3DSI32 sscanf_s(const char *buffer, const char *format, ...)
+ {
+ va_list arg;
+ va_start(arg, format);
+ QT3DSI32 r = ::sscanf_s(buffer, format, arg);
+ va_end(arg);
+
+ return r;
+ };
+
+ QT3DS_INLINE void strlwr(char *str)
+ {
+ while (*str) {
+ if (*str >= 'A' && *str <= 'Z')
+ *str += 32;
+ str++;
+ }
+ }
+
+ QT3DS_INLINE void strupr(char *str)
+ {
+ while (*str) {
+ if (*str >= 'a' && *str <= 'z')
+ *str -= 32;
+ str++;
+ }
+ }
+
+} // namespace string
+
+#ifndef QT3DS_DOXYGEN
+} // namespace qt3ds
+#endif
+
+#pragma warning(pop)
+
+#endif
diff --git a/src/foundation/windows/Qt3DSWindowsSync.cpp b/src/foundation/windows/Qt3DSWindowsSync.cpp
new file mode 100644
index 0000000..49667e9
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsSync.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/windows/Qt3DSWindowsInclude.h"
+#include "foundation/Qt3DSSync.h"
+#include "foundation/Qt3DSAllocator.h"
+
+namespace qt3ds {
+namespace foundation {
+
+ class SyncImpl
+ {
+ public:
+ SyncImpl(NVAllocatorCallback &alloc)
+ : mAllocator(alloc)
+ {
+ }
+ NVAllocatorCallback &mAllocator;
+ HANDLE handle;
+ };
+
+ Sync::Sync(NVAllocatorCallback &alloc)
+ {
+ mImpl = QT3DS_NEW(alloc, SyncImpl)(alloc);
+ mImpl->handle = CreateEvent(0, true, false, 0);
+ }
+
+ Sync::~Sync()
+ {
+ CloseHandle(mImpl->handle);
+ QT3DS_FREE(mImpl->mAllocator, mImpl);
+ }
+
+ void Sync::reset() { ResetEvent(mImpl->handle); }
+
+ void Sync::set() { SetEvent(mImpl->handle); }
+
+ bool Sync::wait(QT3DSU32 milliseconds)
+ {
+ if (milliseconds == -1)
+ milliseconds = INFINITE;
+
+ return WaitForSingleObject(mImpl->handle, milliseconds) == WAIT_OBJECT_0 ? true : false;
+ }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/windows/Qt3DSWindowsThread.cpp b/src/foundation/windows/Qt3DSWindowsThread.cpp
new file mode 100644
index 0000000..3a30de8
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsThread.cpp
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/windows/Qt3DSWindowsInclude.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSThread.h"
+#include "foundation/Qt3DSAssert.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+
+// an exception for setting the thread name in microsoft debuggers
+#define QT3DS_MS_VC_EXCEPTION 0x406D1388
+
+namespace qt3ds {
+namespace foundation {
+
+// struct for naming a thread in the debugger
+#pragma pack(push, 8)
+
+ typedef struct tagTHREADNAME_INFO
+ {
+ DWORD dwType; // Must be 0x1000.
+ LPCSTR szName; // Pointer to name (in user addr space).
+ DWORD dwThreadID; // Thread ID (-1=caller thread).
+ DWORD dwFlags; // Reserved for future use, must be zero.
+ } THREADNAME_INFO;
+
+#pragma pack(pop)
+
+ namespace {
+
+ DWORD WINAPI NVThreadStart(LPVOID arg)
+ {
+ ((Thread *)arg)->execute();
+ return 0;
+ }
+ }
+
+ class ThreadImpl
+ {
+ public:
+ enum State { NotStarted, Started, Stopped };
+ ThreadImpl(NVFoundationBase &foundation)
+ : mFoundation(foundation)
+ {
+ }
+ NVFoundationBase &mFoundation;
+ HANDLE thread;
+ LONG quitNow; // Should be 32bit aligned on SMP systems.
+ State state;
+ DWORD threadID;
+
+ Thread::ExecuteFn fn;
+ void *arg;
+ };
+
+ Thread::Id Thread::getId() { return static_cast<Id>(GetCurrentThreadId()); }
+
+ Thread::Thread(NVFoundationBase &foundation)
+ {
+ mImpl = (ThreadImpl *)QT3DS_NEW(foundation.getAllocator(), ThreadImpl)(foundation);
+ mImpl->thread = NULL;
+ mImpl->state = ThreadImpl::NotStarted;
+ mImpl->quitNow = 0;
+ }
+
+ Thread::Thread(NVFoundationBase &foundation, ExecuteFn fn, void *arg)
+ {
+ mImpl = (ThreadImpl *)QT3DS_NEW(foundation.getAllocator(), ThreadImpl)(foundation);
+ mImpl->thread = NULL;
+ mImpl->state = ThreadImpl::NotStarted;
+ mImpl->quitNow = 0;
+ mImpl->fn = fn;
+ mImpl->arg = arg;
+
+ start(0);
+ }
+
+ Thread::~Thread()
+ {
+ if (mImpl->state == ThreadImpl::Started)
+ kill();
+ CloseHandle(mImpl->thread);
+ QT3DS_FREE(mImpl->mFoundation.getAllocator(), mImpl);
+ }
+
+ void Thread::start(QT3DSU32 stackSize)
+ {
+ if (mImpl->state != ThreadImpl::NotStarted)
+ return;
+ mImpl->state = ThreadImpl::Started;
+
+ mImpl->thread =
+ CreateThread(NULL, stackSize, NVThreadStart, (LPVOID)this, 0, &mImpl->threadID);
+ }
+
+ void Thread::signalQuit() { InterlockedIncrement(&(mImpl->quitNow)); }
+
+ bool Thread::waitForQuit()
+ {
+ if (mImpl->state == ThreadImpl::NotStarted)
+ return false;
+
+ WaitForSingleObject(mImpl->thread, INFINITE);
+ return true;
+ }
+
+ bool Thread::quitIsSignalled()
+ {
+ return InterlockedCompareExchange(&(mImpl->quitNow), 0, 0) != 0;
+ }
+
+ void Thread::quit()
+ {
+ mImpl->state = ThreadImpl::Stopped;
+ ExitThread(0);
+ }
+
+ void Thread::kill()
+ {
+ if (mImpl->state == ThreadImpl::Started)
+ TerminateThread(mImpl->thread, 0);
+ mImpl->state = ThreadImpl::Stopped;
+ }
+
+ void Thread::sleep(QT3DSU32 ms) { Sleep(ms); }
+
+ void Thread::yield() { SwitchToThread(); }
+
+ void Thread::execute(void) { (*mImpl->fn)(mImpl->arg); }
+
+ QT3DSU32 Thread::setAffinityMask(QT3DSU32 mask)
+ {
+ return mask ? (QT3DSU32)SetThreadAffinityMask(mImpl->thread, mask) : 0;
+ }
+
+ void Thread::setName(const char *name)
+ {
+ THREADNAME_INFO info;
+ info.dwType = 0x1000;
+ info.szName = name;
+ info.dwThreadID = mImpl->threadID;
+ info.dwFlags = 0;
+
+#ifdef QT3DS_VC
+ // C++ Exceptions are disabled for this project, but SEH is not (and cannot be)
+ // http://stackoverflow.com/questions/943087/what-exactly-will-happen-if-i-disable-c-exceptions-in-a-project
+ __try {
+ RaiseException(QT3DS_MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
+ (ULONG_PTR *)&info);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ // this runs if not attached to a debugger (thus not really naming the thread)
+ }
+#else
+ RaiseException(QT3DS_MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
+ (ULONG_PTR *)&info);
+#endif
+ }
+
+ void Thread::setPriority(ThreadPriority::Enum prio)
+ {
+ switch (prio) {
+ case ThreadPriority::eHIGH:
+ SetThreadPriority(mImpl->thread, THREAD_PRIORITY_HIGHEST);
+ break;
+ case ThreadPriority::eABOVE_NORMAL:
+ SetThreadPriority(mImpl->thread, THREAD_PRIORITY_ABOVE_NORMAL);
+ break;
+ case ThreadPriority::eNORMAL:
+ SetThreadPriority(mImpl->thread, THREAD_PRIORITY_NORMAL);
+ break;
+ case ThreadPriority::eBELOW_NORMAL:
+ SetThreadPriority(mImpl->thread, THREAD_PRIORITY_BELOW_NORMAL);
+ break;
+ case ThreadPriority::eLOW:
+ SetThreadPriority(mImpl->thread, THREAD_PRIORITY_LOWEST);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ThreadPriority::Enum Thread::getPriority(Id threadId)
+ {
+ ThreadPriority::Enum retval = ThreadPriority::eLOW;
+ int priority = GetThreadPriority((HANDLE)threadId);
+ StaticAssert<(THREAD_PRIORITY_HIGHEST > THREAD_PRIORITY_ABOVE_NORMAL)>::valid_expression();
+ if (priority >= THREAD_PRIORITY_HIGHEST)
+ retval = ThreadPriority::eHIGH;
+ else if (priority >= THREAD_PRIORITY_ABOVE_NORMAL)
+ retval = ThreadPriority::eABOVE_NORMAL;
+ else if (priority >= THREAD_PRIORITY_NORMAL)
+ retval = ThreadPriority::eNORMAL;
+ else if (priority >= THREAD_PRIORITY_BELOW_NORMAL)
+ retval = ThreadPriority::eBELOW_NORMAL;
+ return retval;
+ }
+
+ QT3DSU32 TlsAlloc()
+ {
+ DWORD rv = ::TlsAlloc();
+ QT3DS_ASSERT(rv != TLS_OUT_OF_INDEXES);
+ return (QT3DSU32)rv;
+ }
+
+ void TlsFree(QT3DSU32 index) { ::TlsFree(index); }
+
+ void *TlsGet(QT3DSU32 index) { return ::TlsGetValue(index); }
+
+ QT3DSU32 TlsSet(QT3DSU32 index, void *value) { return ::TlsSetValue(index, value); }
+
+ const QT3DSU32 Thread::DEFAULT_STACK_SIZE = 1048576;
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/windows/Qt3DSWindowsTime.cpp b/src/foundation/windows/Qt3DSWindowsTime.cpp
new file mode 100644
index 0000000..9215d64
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsTime.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#include "foundation/Qt3DSTime.h"
+#include "foundation/windows/Qt3DSWindowsInclude.h"
+
+namespace {
+::qt3ds::QT3DSI64 getTimeTicks()
+{
+ LARGE_INTEGER a;
+ QueryPerformanceCounter(&a);
+ return a.QuadPart;
+}
+
+double getTickDuration()
+{
+ LARGE_INTEGER a;
+ QueryPerformanceFrequency(&a);
+ return 1.0f / double(a.QuadPart);
+}
+
+double sTickDuration = getTickDuration();
+} // namespace
+
+namespace qt3ds {
+namespace foundation {
+
+ const CounterFrequencyToTensOfNanos Time::sCounterFreq = Time::getCounterFrequency();
+
+ CounterFrequencyToTensOfNanos Time::getCounterFrequency()
+ {
+ LARGE_INTEGER freq;
+ QueryPerformanceFrequency(&freq);
+ return CounterFrequencyToTensOfNanos(Time::sNumTensOfNanoSecondsInASecond, freq.QuadPart);
+ }
+
+ QT3DSU64 Time::getCurrentCounterValue()
+ {
+ LARGE_INTEGER ticks;
+ QueryPerformanceCounter(&ticks);
+ return ticks.QuadPart;
+ }
+
+ Time::Time()
+ : mTickCount(0)
+ {
+ getElapsedSeconds();
+ }
+
+ Time::Second Time::getElapsedSeconds()
+ {
+ QT3DSI64 lastTickCount = mTickCount;
+ mTickCount = getTimeTicks();
+ return (mTickCount - lastTickCount) * sTickDuration;
+ }
+
+ Time::Second Time::peekElapsedSeconds()
+ {
+ return (getTimeTicks() - mTickCount) * sTickDuration;
+ }
+
+ Time::Second Time::getLastTime() const { return mTickCount * sTickDuration; }
+
+} // namespace foundation
+} // namespace qt3ds
diff --git a/src/foundation/windows/Qt3DSWindowsTrigConstants.h b/src/foundation/windows/Qt3DSWindowsTrigConstants.h
new file mode 100644
index 0000000..e3da844
--- /dev/null
+++ b/src/foundation/windows/Qt3DSWindowsTrigConstants.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DS_WINDOWS_TRIG_CONSTANTS_H
+#define QT3DS_WINDOWS_TRIG_CONSTANTS_H
+
+#define QT3DS_GLOBALCONST extern const __declspec(selectany)
+
+__declspec(align(16)) struct QT3DS_VECTORF32
+{
+ float f[4];
+};
+
+#define QT3DS_PI 3.141592654f
+#define QT3DS_2PI 6.283185307f
+#define QT3DS_1DIVPI 0.318309886f
+#define QT3DS_1DIV2PI 0.159154943f
+#define QT3DS_PIDIV2 1.570796327f
+#define QT3DS_PIDIV4 0.785398163f
+
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXSinCoefficients0 = { 1.0f, -0.166666667f, 8.333333333e-3f,
+ -1.984126984e-4f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXSinCoefficients1 = { 2.755731922e-6f, -2.505210839e-8f,
+ 1.605904384e-10f, -7.647163732e-13f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXSinCoefficients2 = { 2.811457254e-15f, -8.220635247e-18f,
+ 1.957294106e-20f, -3.868170171e-23f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXCosCoefficients0 = { 1.0f, -0.5f, 4.166666667e-2f,
+ -1.388888889e-3f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXCosCoefficients1 = { 2.480158730e-5f, -2.755731922e-7f,
+ 2.087675699e-9f, -1.147074560e-11f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXCosCoefficients2 = { 4.779477332e-14f, -1.561920697e-16f,
+ 4.110317623e-19f, -8.896791392e-22f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXTanCoefficients0 = { 1.0f, 0.333333333f, 0.133333333f,
+ 5.396825397e-2f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXTanCoefficients1 = { 2.186948854e-2f, 8.863235530e-3f,
+ 3.592128167e-3f, 1.455834485e-3f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXTanCoefficients2 = { 5.900274264e-4f, 2.391290764e-4f,
+ 9.691537707e-5f, 3.927832950e-5f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinCoefficients0 = { -0.05806367563904f, -0.41861972469416f,
+ 0.22480114791621f, 2.17337241360606f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinCoefficients1 = { 0.61657275907170f, 4.29696498283455f,
+ -1.18942822255452f, -6.53784832094831f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinCoefficients2 = { -1.36926553863413f, -4.48179294237210f,
+ 1.41810672941833f, 5.48179257935713f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXATanCoefficients0 = { 1.0f, 0.333333334f, 0.2f, 0.142857143f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXATanCoefficients1 = { 1.111111111e-1f, 9.090909091e-2f,
+ 7.692307692e-2f, 6.666666667e-2f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXATanCoefficients2 = { 5.882352941e-2f, 5.263157895e-2f,
+ 4.761904762e-2f, 4.347826087e-2f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXSinEstCoefficients = { 1.0f, -1.66521856991541e-1f,
+ 8.199913018755e-3f, -1.61475937228e-4f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXCosEstCoefficients = { 1.0f, -4.95348008918096e-1f,
+ 3.878259962881e-2f, -9.24587976263e-4f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXTanEstCoefficients = { 2.484f, -1.954923183e-1f, 2.467401101f,
+ QT3DS_1DIVPI };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXATanEstCoefficients = { 7.689891418951e-1f, 1.104742493348f,
+ 8.661844266006e-1f, QT3DS_PIDIV2 };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinEstCoefficients = { -1.36178272886711f, 2.37949493464538f,
+ -8.08228565650486e-1f,
+ 2.78440142746736e-1f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXASinEstConstants = { 1.00000011921f, QT3DS_PIDIV2, 0.0f, 0.0f };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXPiConstants0 = { QT3DS_PI, QT3DS_2PI, QT3DS_1DIVPI, QT3DS_1DIV2PI };
+QT3DS_GLOBALCONST QT3DS_VECTORF32 g_PXReciprocalTwoPi = { QT3DS_1DIV2PI, QT3DS_1DIV2PI, QT3DS_1DIV2PI,
+ QT3DS_1DIV2PI };
+
+#endif
diff --git a/src/foundation/windows/SocketImpl.h b/src/foundation/windows/SocketImpl.h
new file mode 100644
index 0000000..f72203b
--- /dev/null
+++ b/src/foundation/windows/SocketImpl.h
@@ -0,0 +1,506 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+/*
+LuaSocket 3.0 license
+Copyright � 2004-2013 Diego Nehab
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef FOUNDATION_WINDOWS_SOCKET_IMPL_H
+#define FOUNDATION_WINDOWS_SOCKET_IMPL_H
+#pragma once
+#include <winsock.h>
+#pragma warning(disable : 4127)
+#pragma warning(disable : 4702)
+
+namespace qt3ds {
+namespace foundation {
+ namespace socketimpl {
+
+ // Functions take from lua socket implementation. Note that it has an MIT license.
+
+ enum {
+ IO_DONE = 0, /* operation completed successfully */
+ IO_TIMEOUT = -1, /* operation timed out */
+ IO_CLOSED = -2, /* the connection has been closed */
+ IO_UNKNOWN = -3
+ };
+
+ /*-------------------------------------------------------------------------*\
+ * I/O error strings
+ \*-------------------------------------------------------------------------*/
+ const char *io_strerror(int err)
+ {
+ switch (err) {
+ case IO_DONE:
+ return NULL;
+ case IO_CLOSED:
+ return "closed";
+ case IO_TIMEOUT:
+ return "timeout";
+ default:
+ return "unknown error";
+ }
+ }
+
+ typedef int socklen_t;
+ typedef SOCKET t_socket;
+ typedef t_socket *p_socket;
+ typedef struct sockaddr SA;
+
+#define SOCKET_INVALID (INVALID_SOCKET)
+
+ static const char *wstrerror(int err)
+ {
+ switch (err) {
+ case WSAEINTR:
+ return "Interrupted function call";
+ case WSAEACCES:
+ return "Permission denied";
+ case WSAEFAULT:
+ return "Bad address";
+ case WSAEINVAL:
+ return "Invalid argument";
+ case WSAEMFILE:
+ return "Too many open files";
+ case WSAEWOULDBLOCK:
+ return "Resource temporarily unavailable";
+ case WSAEINPROGRESS:
+ return "Operation now in progress";
+ case WSAEALREADY:
+ return "Operation already in progress";
+ case WSAENOTSOCK:
+ return "Socket operation on nonsocket";
+ case WSAEDESTADDRREQ:
+ return "Destination address required";
+ case WSAEMSGSIZE:
+ return "Message too long";
+ case WSAEPROTOTYPE:
+ return "Protocol wrong type for socket";
+ case WSAENOPROTOOPT:
+ return "Bad protocol option";
+ case WSAEPROTONOSUPPORT:
+ return "Protocol not supported";
+ case WSAESOCKTNOSUPPORT:
+ return "Socket type not supported";
+ case WSAEOPNOTSUPP:
+ return "Operation not supported";
+ case WSAEPFNOSUPPORT:
+ return "Protocol family not supported";
+ case WSAEAFNOSUPPORT:
+ return "Address family not supported by protocol family";
+ case WSAEADDRINUSE:
+ return "Address already in use";
+ case WSAEADDRNOTAVAIL:
+ return "Cannot assign requested address";
+ case WSAENETDOWN:
+ return "Network is down";
+ case WSAENETUNREACH:
+ return "Network is unreachable";
+ case WSAENETRESET:
+ return "Network dropped connection on reset";
+ case WSAECONNABORTED:
+ return "Software caused connection abort";
+ case WSAECONNRESET:
+ return "Connection reset by peer";
+ case WSAENOBUFS:
+ return "No buffer space available";
+ case WSAEISCONN:
+ return "Socket is already connected";
+ case WSAENOTCONN:
+ return "Socket is not connected";
+ case WSAESHUTDOWN:
+ return "Cannot send after socket shutdown";
+ case WSAETIMEDOUT:
+ return "Connection timed out";
+ case WSAECONNREFUSED:
+ return "Connection refused";
+ case WSAEHOSTDOWN:
+ return "Host is down";
+ case WSAEHOSTUNREACH:
+ return "No route to host";
+ case WSAEPROCLIM:
+ return "Too many processes";
+ case WSASYSNOTREADY:
+ return "Network subsystem is unavailable";
+ case WSAVERNOTSUPPORTED:
+ return "Winsock.dll version out of range";
+ case WSANOTINITIALISED:
+ return "Successful WSAStartup not yet performed";
+ case WSAEDISCON:
+ return "Graceful shutdown in progress";
+ case WSAHOST_NOT_FOUND:
+ return "Host not found";
+ case WSATRY_AGAIN:
+ return "Nonauthoritative host not found";
+ case WSANO_RECOVERY:
+ return "Nonrecoverable name lookup error";
+ case WSANO_DATA:
+ return "Valid name, no data record of requested type";
+ default:
+ return "Unknown error";
+ }
+ }
+
+ const char *socket_strerror(int err)
+ {
+ switch (err) {
+ case WSAEADDRINUSE:
+ return "address already in use";
+ case WSAECONNREFUSED:
+ return "connection refused";
+ case WSAEISCONN:
+ return "already connected";
+ case WSAEACCES:
+ return "permission denied";
+ case WSAECONNABORTED:
+ return "closed";
+ case WSAECONNRESET:
+ return "closed";
+ case WSAETIMEDOUT:
+ return "timeout";
+ default:
+ return wstrerror(err);
+ }
+ }
+
+ int socket_open(void)
+ {
+ WSADATA wsaData;
+ WORD wVersionRequested = MAKEWORD(2, 0);
+ int err = WSAStartup(wVersionRequested, &wsaData);
+ if (err != 0)
+ return 0;
+ if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0)
+ && (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) {
+ WSACleanup();
+ return 0;
+ }
+ return 1;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Close module
+ \*-------------------------------------------------------------------------*/
+ int socket_close(void)
+ {
+ WSACleanup();
+ return 1;
+ }
+
+/*-------------------------------------------------------------------------*\
+* Wait for readable/writable/connected socket with timeout
+\*-------------------------------------------------------------------------*/
+#define WAITFD_R 1
+#define WAITFD_W 2
+#define WAITFD_E 4
+#define WAITFD_C (WAITFD_E | WAITFD_W)
+
+ static int socket_waitfd(p_socket ps, int sw, QT3DSU32 timeoutMilliseconds)
+ {
+ int ret;
+ fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL;
+ struct timeval tv, *tp = NULL;
+ if (timeoutMilliseconds == 0)
+ return IO_TIMEOUT; /* optimize timeout == 0 case */
+ if (sw & WAITFD_R) {
+ FD_ZERO(&rfds);
+ FD_SET(*ps, &rfds);
+ rp = &rfds;
+ }
+ if (sw & WAITFD_W) {
+ FD_ZERO(&wfds);
+ FD_SET(*ps, &wfds);
+ wp = &wfds;
+ }
+ if (sw & WAITFD_C) {
+ FD_ZERO(&efds);
+ FD_SET(*ps, &efds);
+ ep = &efds;
+ }
+ if (timeoutMilliseconds >= 0.0) {
+ tv.tv_sec = (int)(timeoutMilliseconds / 1000);
+ QT3DSU32 leftover = timeoutMilliseconds % 1000;
+ tv.tv_usec = (int)(leftover * 100000);
+ tp = &tv;
+ }
+ ret = select(0, rp, wp, ep, tp);
+ if (ret == -1)
+ return WSAGetLastError();
+ if (ret == 0)
+ return IO_TIMEOUT;
+ if (sw == WAITFD_C && FD_ISSET(*ps, &efds))
+ return IO_CLOSED;
+ return IO_DONE;
+ }
+
+ static int socket_send(p_socket ps, const char *data, size_t count, size_t *sent,
+ QT3DSU32 timeoutMilliseconds)
+ {
+ int err;
+ *sent = 0;
+ /* avoid making system calls on closed sockets */
+ if (*ps == SOCKET_INVALID)
+ return IO_CLOSED;
+ /* loop until we send something or we give up on error */
+ for (;;) {
+ /* try to send something */
+ int put = send(*ps, data, (int)count, 0);
+ /* if we sent something, we are done */
+ if (put > 0) {
+ *sent = put;
+ return IO_DONE;
+ }
+ /* deal with failure */
+ err = WSAGetLastError();
+ /* we can only proceed if there was no serious error */
+ if (err != WSAEWOULDBLOCK)
+ return err;
+ /* avoid busy wait */
+ if ((err = socket_waitfd(ps, WAITFD_W, timeoutMilliseconds)) != IO_DONE)
+ return err;
+ }
+ /* can't reach here */
+ return IO_UNKNOWN;
+ }
+ /*-------------------------------------------------------------------------*\
+ * Receive with timeout
+ \*-------------------------------------------------------------------------*/
+ static int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
+ QT3DSU32 timeoutMilliseconds)
+ {
+ int err;
+ *got = 0;
+ if (*ps == SOCKET_INVALID)
+ return IO_CLOSED;
+ for (;;) {
+ int taken = recv(*ps, data, (int)count, 0);
+ if (taken > 0) {
+ *got = taken;
+ return IO_DONE;
+ }
+ if (taken == 0)
+ return IO_CLOSED;
+ err = WSAGetLastError();
+ if (err != WSAEWOULDBLOCK)
+ return err;
+ if ((err = socket_waitfd(ps, WAITFD_R, timeoutMilliseconds)) != IO_DONE)
+ return err;
+ }
+ return IO_UNKNOWN;
+ }
+
+ void socket_setblocking(p_socket ps)
+ {
+ u_long argp = 0;
+ ioctlsocket(*ps, FIONBIO, &argp);
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Put socket into non-blocking mode
+ \*-------------------------------------------------------------------------*/
+ void socket_setnonblocking(p_socket ps)
+ {
+ u_long argp = 1;
+ ioctlsocket(*ps, FIONBIO, &argp);
+ }
+
+ int socket_listen(p_socket ps, int backlog)
+ {
+ int err = IO_DONE;
+ socket_setblocking(ps);
+ if (listen(*ps, backlog) < 0)
+ err = WSAGetLastError();
+ socket_setnonblocking(ps);
+ return err;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Accept with timeout
+ \*-------------------------------------------------------------------------*/
+ static int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, QT3DSU32 tm)
+ {
+ SA daddr;
+ socklen_t dlen = sizeof(daddr);
+ if (*ps == SOCKET_INVALID)
+ return IO_CLOSED;
+ if (!addr)
+ addr = &daddr;
+ if (!len)
+ len = &dlen;
+ for (;;) {
+ int err;
+ /* try to get client socket */
+ if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID)
+ return IO_DONE;
+ /* find out why we failed */
+ err = WSAGetLastError();
+ /* if we failed because there was no connectoin, keep trying */
+ if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED)
+ return err;
+ /* call select to avoid busy wait */
+ if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE)
+ return err;
+ }
+ /* can't reach here */
+ return IO_UNKNOWN;
+ }
+
+ int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp)
+ {
+ *hp = gethostbyaddr(addr, len, AF_INET);
+ if (*hp)
+ return IO_DONE;
+ else
+ return WSAGetLastError();
+ }
+
+ int socket_gethostbyname(const char *addr, struct hostent **hp)
+ {
+ *hp = gethostbyname(addr);
+ if (*hp)
+ return IO_DONE;
+ else
+ return WSAGetLastError();
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Error translation functions
+ \*-------------------------------------------------------------------------*/
+ const char *socket_hoststrerror(int err)
+ {
+ if (err <= 0)
+ return io_strerror(err);
+ switch (err) {
+ case WSAHOST_NOT_FOUND:
+ return "host not found";
+ default:
+ return wstrerror(err);
+ }
+ }
+ /*-------------------------------------------------------------------------*\
+ * Close and inutilize socket
+ \*-------------------------------------------------------------------------*/
+ void socket_destroy(p_socket ps)
+ {
+ if (*ps != SOCKET_INVALID) {
+ socket_setblocking(ps); /* close can take a long time on WIN32 */
+ closesocket(*ps);
+ *ps = SOCKET_INVALID;
+ }
+ }
+
+ /*-------------------------------------------------------------------------*\
+ *
+ \*-------------------------------------------------------------------------*/
+ void socket_shutdown(p_socket ps, int how)
+ {
+ socket_setblocking(ps);
+ shutdown(*ps, how);
+ }
+
+ int socket_create(p_socket ps, int domain, int type, int protocol)
+ {
+ *ps = socket(domain, type, protocol);
+ if (*ps != SOCKET_INVALID)
+ return IO_DONE;
+ else
+ return WSAGetLastError();
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Connects or returns error message
+ \*-------------------------------------------------------------------------*/
+ int socket_connect(p_socket ps, SA *addr, socklen_t len, QT3DSU32 tm)
+ {
+ int err;
+ /* don't call on closed socket */
+ if (*ps == SOCKET_INVALID)
+ return IO_CLOSED;
+ /* ask system to connect */
+ if (connect(*ps, addr, len) == 0)
+ return IO_DONE;
+ /* make sure the system is trying to connect */
+ err = WSAGetLastError();
+ if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS)
+ return err;
+ /* zero timeout case optimization */
+ if (tm == 0)
+ return IO_TIMEOUT;
+ /* we wait until something happens */
+ err = socket_waitfd(ps, WAITFD_C, tm);
+ if (err == IO_CLOSED) {
+ int len = sizeof(err);
+ /* give windows time to set the error (yes, disgusting) */
+ Sleep(10);
+ /* find out why we failed */
+ getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
+ /* we KNOW there was an error. if 'why' is 0, we will return
+ * "unknown error", but it's not really our fault */
+ return err > 0 ? err : IO_UNKNOWN;
+ } else
+ return err;
+ }
+
+ /*-------------------------------------------------------------------------*\
+ * Binds or returns error message
+ \*-------------------------------------------------------------------------*/
+ int socket_bind(p_socket ps, SA *addr, socklen_t len)
+ {
+ int err = IO_DONE;
+ socket_setblocking(ps);
+ if (bind(*ps, addr, len) < 0)
+ err = WSAGetLastError();
+ socket_setnonblocking(ps);
+ return err;
+ }
+ }
+}
+}
+
+#endif \ No newline at end of file
diff --git a/src/foundation/windows/qt_attribution.json b/src/foundation/windows/qt_attribution.json
new file mode 100644
index 0000000..e0310cf
--- /dev/null
+++ b/src/foundation/windows/qt_attribution.json
@@ -0,0 +1,10 @@
+{
+ "Id": "qt3dswindowsaos",
+ "Name": "Qt3DSWindowsAoS",
+ "QDocModule": "qt3dstudio",
+ "QtUsage": "Used by Qt3DStudio, Runtime component.",
+
+ "License": "Other",
+ "LicenseFile": "LICENSE.TXT",
+ "Copyright": "Copyright (c) 2001 Intel Corporation."
+}