From b7b7356af8019f51af431b62567030732115296e Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Tue, 18 Feb 2014 19:23:25 -0800 Subject: [PATCH 001/116] Draft Parallel Linear BVH Broadphase. --- Demos3/GpuDemos/broadphase/PairBench.cpp | 2 + build3/stringify.bat | 1 + build3/stringify_linux.sh | 1 + .../b3GpuParallelLinearBvh.h | 416 ++++++++++++++++++ .../b3GpuParallelLinearBvhBroadphase.h | 98 +++++ .../kernels/parallelLinearBvh.cl | 399 +++++++++++++++++ .../kernels/parallelLinearBvhKernels.h | 325 ++++++++++++++ 7 files changed, 1242 insertions(+) create mode 100644 src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h create mode 100644 src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h create mode 100644 src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl create mode 100644 src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h diff --git a/Demos3/GpuDemos/broadphase/PairBench.cpp b/Demos3/GpuDemos/broadphase/PairBench.cpp index 9c445417c..53995fd65 100644 --- a/Demos3/GpuDemos/broadphase/PairBench.cpp +++ b/Demos3/GpuDemos/broadphase/PairBench.cpp @@ -9,6 +9,7 @@ #include "OpenGLWindow/b3gWindowInterface.h" #include "Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h" #include "Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h" #include "../GpuDemoInternalData.h" #include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" @@ -108,6 +109,7 @@ static int curSelectedBroadphase = 0; static BroadphaseEntry allBroadphases[]= { {"Gpu Grid",b3GpuGridBroadphase::CreateFunc}, + {"Parallel Linear BVH",b3GpuParallelLinearBvhBroadphase::CreateFunc}, {"CPU Brute Force",b3GpuSapBroadphase::CreateFuncBruteForceCpu}, {"GPU Brute Force",b3GpuSapBroadphase::CreateFuncBruteForceGpu}, {"GPU 1-SAP Original",b3GpuSapBroadphase::CreateFuncOriginal}, diff --git a/build3/stringify.bat b/build3/stringify.bat index 7c65b8149..8876515c7 100644 --- a/build3/stringify.bat +++ b/build3/stringify.bat @@ -13,6 +13,7 @@ premake4 --file=stringifyKernel.lua --kernelfile="../src/Bullet3OpenCL/Broadphas premake4 --file=stringifyKernel.lua --kernelfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/sapFast.cl" --headerfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/sapFastKernels.h" --stringname="sapFastCL" stringify premake4 --file=stringifyKernel.lua --kernelfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphase.cl" --headerfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphaseKernels.h" --stringname="gridBroadphaseCL" stringify +premake4 --file=stringifyKernel.lua --kernelfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl" --headerfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h" --stringname="parallelLinearBvhCL" stringify diff --git a/build3/stringify_linux.sh b/build3/stringify_linux.sh index ed1627c27..751574af8 100755 --- a/build3/stringify_linux.sh +++ b/build3/stringify_linux.sh @@ -14,6 +14,7 @@ rem @echo off ./premake4_linux64 --file=stringifyKernel.lua --kernelfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/sapFast.cl" --headerfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/sapFastKernels.h" --stringname="sapFastCL" stringify ./premake4_linux64 --file=stringifyKernel.lua --kernelfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphase.cl" --headerfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/gridBroadphaseKernels.h" --stringname="gridBroadphaseCL" stringify +./premake4_linux64 --file=stringifyKernel.lua --kernelfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl" --headerfile="../src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h" --stringname="parallelLinearBvhCL" stringify diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h new file mode 100644 index 000000000..10fbeb79f --- /dev/null +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -0,0 +1,416 @@ +/* +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +//Initial Author Jackson Lee, 2014 + +#ifndef B3_GPU_PARALLEL_LINEAR_BVH_H +#define B3_GPU_PARALLEL_LINEAR_BVH_H + +//#include "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h" +#include "Bullet3Common/shared/b3Int2.h" +#include "Bullet3Common/shared/b3Int4.h" + +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3FillCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" + +#include "Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h" + +#define B3_PLBVH_ROOT_NODE_MARKER -1 //Syncronize with parallelLinearBvh.cl + +///@brief GPU Parallel Linearized Bounding Volume Heirarchy(LBVH) that is reconstructed every frame +///@remarks +///Main references: \n +///"Fast BVH Construction on GPUs" [Lauterbach et al. 2009] \n +///"Maximizing Parallelism in the Construction of BVHs, Octrees, and k-d trees" [Karras 2012] \n +///@par +///The basic algorithm for building the BVH as presented in [Lauterbach et al. 2009] consists of 4 stages: +/// - [fully parallel] Assign morton codes for each AABB using its center (after quantizing the AABB centers into a virtual grid) +/// - [fully parallel] Sort morton codes +/// - [somewhat parallel] Build radix binary tree (assign parent/child pointers for internal nodes of the BVH) +/// - [somewhat parallel] Set internal node AABBs +///@par +///[Karras 2012] improves on the algorithm by introducing fully parallel methods for the last 2 stages. +///The BVH implementation here is almost the same as [Karras 2012], but a different method is used for constructing the tree. +/// - Instead of building a binary radix tree, we simply pair each node with its nearest sibling. +/// This has the effect of further worsening the quality of the BVH, but the main spatial partitioning is done by the +/// Z-curve anyways, and this method should be simpler and faster during construction. Additionally, it is still possible +/// to improve the quality of the BVH by rearranging the connections between nodes. +/// - Due to the way the tree is constructed, it becomes unnecessary to use atomic_inc to get +/// the AABB for each internal node. Rather than traveling upwards from the leaf nodes, as in the paper, +/// each internal node checks its child nodes to get its AABB. +class b3GpuParallelLinearBvh +{ + cl_command_queue m_queue; + + cl_program m_parallelLinearBvhProgram; + + cl_kernel m_assignMortonCodesAndAabbIndiciesKernel; + cl_kernel m_constructBinaryTreeKernel; + cl_kernel m_determineInternalNodeAabbsKernel; + + cl_kernel m_plbvhCalculateOverlappingPairsKernel; + + b3FillCL m_fill; + b3RadixSort32CL m_radixSorter; + + //1 element per level in the tree + b3AlignedObjectArray m_numNodesPerLevelCpu; //Level 0(m_numNodesPerLevelCpu[0]) is the root, last level contains the leaf nodes + b3AlignedObjectArray m_firstIndexOffsetPerLevelCpu; //Contains the index/offset of the first node in that level + b3OpenCLArray m_numNodesPerLevelGpu; + b3OpenCLArray m_firstIndexOffsetPerLevelGpu; + + //1 element per internal node (number_of_internal_nodes = number_of_leaves - 1); index 0 is the root node + b3OpenCLArray m_internalNodeAabbs; + b3OpenCLArray m_internalNodeChildNodes; //x == left child, y == right child + b3OpenCLArray m_internalNodeParentNodes; + + //1 element per leaf node + b3OpenCLArray m_leafNodeParentNodes; + b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key = morton code, m_value == aabb index + +public: + b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue) : + m_queue(queue), + m_fill(context, device, queue), + m_radixSorter(context, device, queue), + + m_numNodesPerLevelGpu(context, queue), + m_firstIndexOffsetPerLevelGpu(context, queue), + m_internalNodeAabbs(context, queue), + m_internalNodeChildNodes(context, queue), + m_internalNodeParentNodes(context, queue), + m_leafNodeParentNodes(context, queue), + m_mortonCodesAndAabbIndicies(context, queue) + { + const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; + + const char* kernelSource = parallelLinearBvhCL; //parallelLinearBvhCL.h + cl_int error; + char* additionalMacros = 0; + m_parallelLinearBvhProgram = b3OpenCLUtils::compileCLProgramFromString(context, device, kernelSource, &error, additionalMacros, CL_PROGRAM_PATH); + b3Assert(m_parallelLinearBvhProgram); + + m_assignMortonCodesAndAabbIndiciesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "assignMortonCodesAndAabbIndicies", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_assignMortonCodesAndAabbIndiciesKernel); + m_constructBinaryTreeKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "constructBinaryTree", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_constructBinaryTreeKernel); + m_determineInternalNodeAabbsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "determineInternalNodeAabbs", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_determineInternalNodeAabbsKernel); + + m_plbvhCalculateOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhCalculateOverlappingPairs", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhCalculateOverlappingPairsKernel); + } + + virtual ~b3GpuParallelLinearBvh() + { + clReleaseKernel(m_assignMortonCodesAndAabbIndiciesKernel); + clReleaseKernel(m_constructBinaryTreeKernel); + clReleaseKernel(m_determineInternalNodeAabbsKernel); + + clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); + + clReleaseProgram(m_parallelLinearBvhProgram); + } + + // fix: need to handle/test case with 2 nodes + + ///@param cellsize A virtual grid of size 2^10^3 is used in the process of creating the BVH + void build(const b3OpenCLArray& worldSpaceAabbs, b3Scalar cellSize) + { + B3_PROFILE("b3ParallelLinearBvh::build()"); + + int numLeaves = worldSpaceAabbs.size(); //Number of leaves in the BVH == Number of rigid body AABBs + int numInternalNodes = numLeaves - 1; + + if(numLeaves < 2) return; + + // + { + m_internalNodeAabbs.resize(numInternalNodes); + m_internalNodeChildNodes.resize(numInternalNodes); + m_internalNodeParentNodes.resize(numInternalNodes); + + m_leafNodeParentNodes.resize(numLeaves); + m_mortonCodesAndAabbIndicies.resize(numLeaves); + } + + //Determine number of levels in the binary tree( numLevels = ceil( log2(numLeaves) ) ) + //The number of levels is equivalent to the number of bits needed to uniquely identify each node(including both internal and leaf nodes) + int numLevels = 0; + { + //Find the most significant bit(msb) + int mostSignificantBit = 0; + { + int temp = numLeaves; + while(temp >>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1) + } + numLevels = mostSignificantBit + 1; + + //If the number of nodes is not a power of 2(as in, can be expressed as 2^N where N is an integer), then there is 1 additional level + if( ~(1 << mostSignificantBit) & numLeaves ) numLevels++; + + if(1) printf("numLeaves, numLevels, mostSignificantBit: %d, %d, %d \n", numLeaves, numLevels, mostSignificantBit); + } + + //Determine number of nodes per level, use prefix sum to get offsets of each level, and send to GPU + { + B3_PROFILE("Determine number of nodes per level"); + + m_numNodesPerLevelCpu.resize(numLevels); + + //The last level contains the leaf nodes; number of leaves is already known + if(numLevels - 1 >= 0) m_numNodesPerLevelCpu[numLevels - 1] = numLeaves; + + //Calculate number of nodes in each level; + //start from the second to last level(level right next to leaf nodes) and move towards the root(level 0) + int hasRemainder = 0; + for(int levelIndex = numLevels - 2; levelIndex >= 0; --levelIndex) + { + int numNodesPreviousLevel = m_numNodesPerLevelCpu[levelIndex + 1]; //For first iteration this == numLeaves + + bool allNodesAllocated = ( (numNodesPreviousLevel + hasRemainder) % 2 == 0 ); + + int numNodesCurrentLevel = (allNodesAllocated) ? (numNodesPreviousLevel + hasRemainder) / 2 : numNodesPreviousLevel / 2; + m_numNodesPerLevelCpu[levelIndex] = numNodesCurrentLevel; + + hasRemainder = static_cast(!allNodesAllocated); + } + + //Prefix sum to calculate the first index offset of each level + { + m_firstIndexOffsetPerLevelCpu = m_numNodesPerLevelCpu; + + //Perform inclusive scan + for(int i = 1; i < m_firstIndexOffsetPerLevelCpu.size(); ++i) + m_firstIndexOffsetPerLevelCpu[i] += m_firstIndexOffsetPerLevelCpu[i - 1]; + + //Convert inclusive scan to exclusive scan to get the offsets + //This is equivalent to shifting each element in m_firstIndexOffsetPerLevelCpu[] by 1 to the right, + //and setting the first element to 0 + for(int i = 0; i < m_firstIndexOffsetPerLevelCpu.size(); ++i) + m_firstIndexOffsetPerLevelCpu[i] -= m_numNodesPerLevelCpu[i]; + } + + if(1) + { + int numInternalNodes = 0; + for(int i = 0; i < numLevels; ++i) + if(i < numLevels - 1) numInternalNodes += m_numNodesPerLevelCpu[i]; + printf("numInternalNodes: %d\n", numInternalNodes); + + for(int i = 0; i < numLevels; ++i) + printf("numNodes, offset[%d]: %d, %d \n", i, m_numNodesPerLevelCpu[i], m_firstIndexOffsetPerLevelCpu[i]); + printf("\n"); + } + + //Copy to GPU + m_numNodesPerLevelGpu.copyFromHost(m_numNodesPerLevelCpu, false); + m_firstIndexOffsetPerLevelGpu.copyFromHost(m_firstIndexOffsetPerLevelCpu, false); + clFinish(m_queue); + } + + //Find the AABB of all input AABBs; this is used to define the size of + //each cell in the virtual grid(2^10 cells in each dimension). + { + B3_PROFILE("Find AABB of merged nodes"); + + /*b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( m_allNodesMergedAabb.getBufferCL() ), + }; + + b3LauncherCL launcher(m_queue, m_findAllNodesMergedAabb, "m_findAllNodesMergedAabb"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLeaves); + + launcher.launch1D(numLeaves); + clFinish(m_queue);*/ + } + + //Insert the center of the AABBs into a virtual grid, + //then convert the discrete grid coordinates into a morton code + //For each element in m_mortonCodesAndAabbIndicies, set + // m_key == morton code (value to sort by) + // m_value = AABB index + { + B3_PROFILE("Assign morton codes"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_assignMortonCodesAndAabbIndiciesKernel, "m_assignMortonCodesAndAabbIndiciesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(cellSize); + launcher.setConst(numLeaves); + + launcher.launch1D(numLeaves); + clFinish(m_queue); + } + + // + { + B3_PROFILE("Sort leaves by morton codes"); + + m_radixSorter.execute(m_mortonCodesAndAabbIndicies); + clFinish(m_queue); + } + + //Optional; only element at m_internalNodeParentNodes[0], the root node, needs to be set here + //as the parent indices of other nodes are overwritten during m_constructBinaryTreeKernel + { + B3_PROFILE("Reset parent node indices"); + + m_fill.execute( m_internalNodeParentNodes, B3_PLBVH_ROOT_NODE_MARKER, m_internalNodeParentNodes.size() ); + m_fill.execute( m_leafNodeParentNodes, B3_PLBVH_ROOT_NODE_MARKER, m_leafNodeParentNodes.size() ); + clFinish(m_queue); + } + + //Construct binary tree; find the children of each internal node, and assign parent nodes + { + B3_PROFILE("Construct binary tree"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_leafNodeParentNodes.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_constructBinaryTreeKernel, "m_constructBinaryTreeKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLevels); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + + if(1) + { + static b3AlignedObjectArray internalNodeChildNodes; + m_internalNodeChildNodes.copyToHost(internalNodeChildNodes, false); + clFinish(m_queue); + + for(int i = 0; i < 256; ++i) printf("ch[%d]: %d, %d\n", i, internalNodeChildNodes[i].x, internalNodeChildNodes[i].y); + printf("\n"); + } + } + + //For each internal node, check children to get its AABB; start from the + //last level and move towards the root + { + B3_PROFILE("Set AABBs"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_determineInternalNodeAabbsKernel, "m_determineInternalNodeAabbsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLevels); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numLeaves); + clFinish(m_queue); + + if(0) + { + static b3AlignedObjectArray rigidAabbs; + worldSpaceAabbs.copyToHost(rigidAabbs, false); + clFinish(m_queue); + + b3SapAabb actualRootAabb; + actualRootAabb.m_minVec = b3MakeVector3(B3_LARGE_FLOAT, B3_LARGE_FLOAT, B3_LARGE_FLOAT); + actualRootAabb.m_maxVec = b3MakeVector3(-B3_LARGE_FLOAT, -B3_LARGE_FLOAT, -B3_LARGE_FLOAT); + for(int i = 0; i < rigidAabbs.size(); ++i) + { + actualRootAabb.m_minVec.setMin(rigidAabbs[i].m_minVec); + actualRootAabb.m_maxVec.setMax(rigidAabbs[i].m_maxVec); + } + printf("actualRootMin: %f, %f, %f \n", actualRootAabb.m_minVec.x, actualRootAabb.m_minVec.y, actualRootAabb.m_minVec.z); + printf("actualRootMax: %f, %f, %f \n", actualRootAabb.m_maxVec.x, actualRootAabb.m_maxVec.y, actualRootAabb.m_maxVec.z); + + b3SapAabb rootAabb = m_internalNodeAabbs.at(0); + printf("rootMin: %f, %f, %f \n", rootAabb.m_minVec.x, rootAabb.m_minVec.y, rootAabb.m_minVec.z); + printf("rootMax: %f, %f, %f \n", rootAabb.m_maxVec.x, rootAabb.m_maxVec.y, rootAabb.m_maxVec.z); + printf("\n"); + } + } + } + + //Max number of pairs is out_overlappingPairs.size() + //If the number of overlapping pairs is < out_overlappingPairs.size(), the array is resized + void calculateOverlappingPairs(const b3OpenCLArray& worldSpaceAabbs, + b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs) + { + b3Assert( out_numPairs.size() == 1 ); + + int maxPairs = out_overlappingPairs.size(); + + int reset = 0; + out_numPairs.copyFromHostPointer(&reset, 1); + + { + B3_PROFILE("PLBVH calculateOverlappingPairs"); + + int numQueryAabbs = worldSpaceAabbs.size(); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + + b3BufferInfoCL( out_numPairs.getBufferCL() ), + b3BufferInfoCL( out_overlappingPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhCalculateOverlappingPairsKernel, "m_plbvhCalculateOverlappingPairsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxPairs); + launcher.setConst(numQueryAabbs); + + launcher.launch1D(numQueryAabbs); + clFinish(m_queue); + } + + + // + int numPairs = -1; + out_numPairs.copyToHostPointer(&numPairs, 1); + if(numPairs > maxPairs) + { + b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); + numPairs = maxPairs; + out_numPairs.copyFromHostPointer(&maxPairs, 1); + } + + out_overlappingPairs.resize(numPairs); + } +}; + +#endif diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h new file mode 100644 index 000000000..728215b7a --- /dev/null +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h @@ -0,0 +1,98 @@ +/* +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +//Initial Author Jackson Lee, 2014 + +#ifndef B3_GPU_PARALLEL_LINEAR_BVH_BROADPHASE_H +#define B3_GPU_PARALLEL_LINEAR_BVH_BROADPHASE_H + +#include "Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h" + +#include "b3GpuParallelLinearBvh.h" + +class b3GpuParallelLinearBvhBroadphase : public b3GpuBroadphaseInterface +{ + b3GpuParallelLinearBvh m_plbvh; + + b3OpenCLArray m_overlappingPairsGpu; + b3OpenCLArray m_aabbsGpu; + b3OpenCLArray m_tempNumPairs; + + b3AlignedObjectArray m_aabbsCpu; + +public: + b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue) : + m_plbvh(context, device, queue), + + m_overlappingPairsGpu(context, queue), + m_aabbsGpu(context, queue), + m_tempNumPairs(context, queue) + { + m_tempNumPairs.resize(1); + } + virtual ~b3GpuParallelLinearBvhBroadphase() {} + + virtual void createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) + { + b3SapAabb aabb; + aabb.m_minVec = aabbMin; + aabb.m_maxVec = aabbMax; + aabb.m_minIndices[3] = userPtr; + + m_aabbsCpu.push_back(aabb); + } + virtual void createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) + { + b3Assert(0); //Not implemented + } + + virtual void calculateOverlappingPairs(int maxPairs) + { + //Detect overall min/max + { + //Not implemented + } + + //Reconstruct BVH + const b3Scalar CELL_SIZE(0.1); + m_plbvh.build(m_aabbsGpu, CELL_SIZE); + + // + m_overlappingPairsGpu.resize(maxPairs); + m_plbvh.calculateOverlappingPairs(m_aabbsGpu, m_tempNumPairs, m_overlappingPairsGpu); + } + virtual void calculateOverlappingPairsHost(int maxPairs) + { + b3Assert(0); //CPU version not implemented + } + + //call writeAabbsToGpu after done making all changes (createProxy etc) + virtual void writeAabbsToGpu() { m_aabbsGpu.copyFromHost(m_aabbsCpu); } + + virtual int getNumOverlap() { return m_overlappingPairsGpu.size(); } + virtual cl_mem getOverlappingPairBuffer() { return m_overlappingPairsGpu.getBufferCL(); } + + virtual cl_mem getAabbBufferWS() { return m_aabbsGpu.getBufferCL(); } + virtual b3OpenCLArray& getAllAabbsGPU() { return m_aabbsGpu; } + + virtual b3AlignedObjectArray& getAllAabbsCPU() + { + b3Assert(0); //CPU version not implemented + return m_aabbsCpu; + } + + static b3GpuBroadphaseInterface* CreateFunc(cl_context context, cl_device_id device, cl_command_queue queue) + { + return new b3GpuParallelLinearBvhBroadphase(context, device, queue); + } +}; + +#endif diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl new file mode 100644 index 000000000..a5127c3aa --- /dev/null +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -0,0 +1,399 @@ +/* +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +//Initial Author Jackson Lee, 2014 + +typedef float b3Scalar; +typedef float4 b3Vector3; +#define b3Max max +#define b3Min min + +typedef struct +{ + unsigned int m_key; + unsigned int m_value; +} SortDataCL; + +typedef struct +{ + union + { + float4 m_min; + float m_minElems[4]; + int m_minIndices[4]; + }; + union + { + float4 m_max; + float m_maxElems[4]; + int m_maxIndices[4]; + }; +} b3AabbCL; + + +unsigned int interleaveBits(unsigned int x) +{ + //........ ........ ......12 3456789A //x + //....1..2 ..3..4.. 5..6..7. .8..9..A //x after interleaving bits + + //........ ....1234 56789A12 3456789A //x |= (x << 10) + //........ ....1111 1....... ...11111 //0x 00 0F 80 1F + //........ ....1234 5....... ...6789A //x = ( x | (x << 10) ) & 0x000F801F; + + //.......1 23451234 5.....67 89A6789A //x |= (x << 5) + //.......1 1.....11 1.....11 .....111 //0x 01 83 83 07 + //.......1 2.....34 5.....67 .....89A //x = ( x | (x << 5) ) & 0x01838307; + + //....12.1 2..34534 5..67.67 ..89A89A //x |= (x << 3) + //....1... 1..1...1 1..1...1 ..1...11 //0x 08 91 91 23 + //....1... 2..3...4 5..6...7 ..8...9A //x = ( x | (x << 3) ) & 0x08919123; + + //...11..2 2.33..4N 5.66..77 .88..9NA //x |= (x << 1) ( N indicates overlapping bits, first overlap is bit {4,5} second is {9,A} ) + //....1..1 ..1...1. 1..1..1. .1...1.1 //0x 09 22 92 45 + //....1..2 ..3...4. 5..6..7. .8...9.A //x = ( x | (x << 1) ) & 0x09229245; + + //...11.22 .33..445 5.66.77. 88..99AA //x |= (x << 1) + //....1..1 ..1..1.. 1..1..1. .1..1..1 //0x 09 34 92 29 + //....1..2 ..3..4.. 5..6..7. .8..9..A //x = ( x | (x << 1) ) & 0x09349229; + + //........ ........ ......11 11111111 //0x000003FF + x &= 0x000003FF; //Clear all bits above bit 10 + + x = ( x | (x << 10) ) & 0x000F801F; + x = ( x | (x << 5) ) & 0x01838307; + x = ( x | (x << 3) ) & 0x08919123; + x = ( x | (x << 1) ) & 0x09229245; + x = ( x | (x << 1) ) & 0x09349229; + + return x; +} +unsigned int getMortonCode(unsigned int x, unsigned int y, unsigned int z) +{ + return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2; +} + +/* +__kernel void findAllNodesMergedAabb(__global b3AabbCL* worldSpaceAabbs, __global b3AabbCL* out_mergedAabb, int numAabbs) +{ + int aabbIndex = get_global_id(0); + if(aabbIndex >= numAabbs) return; + + //Find the most significant bit(msb) + int mostSignificantBit = 0; + { + int temp = numLeaves; + while(temp >>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1) + } + + int numberOfAabbsAboveMsbSplit = numAabbs & ~( ~(0) << mostSignificantBit ); // verify + int numRemainingAabbs = (1 << mostSignificantBit); + + //Merge AABBs above most significant bit so that the number of remaining AABBs is a power of 2 + //For example, if there are 159 AABBs = 128 + 31, then merge indices [0, 30] and 128 + [0, 30] + if(aabbIndex < numberOfAabbsAboveMsbSplit) + { + int otherAabbIndex = numRemainingAabbs + aabbIndex; + + b3AabbCL aabb = worldSpaceAabbs[aabbIndex]; + b3AabbCL otherAabb = worldSpaceAabbs[otherAabbIndex]; + + b3AabbCL mergedAabb; + mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min); + mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max); + out_mergedAabb[aabbIndex] = mergedAabb; + } + + barrier(CLK_GLOBAL_MEM_FENCE); + + // + int offset = numRemainingAabbs / 2; + while(offset >= 1) + { + if(aabbIndex < offset) + { + int otherAabbIndex = aabbIndex + offset; + + b3AabbCL aabb = worldSpaceAabbs[aabbIndex]; + b3AabbCL otherAabb = worldSpaceAabbs[otherAabbIndex]; + + b3AabbCL mergedAabb; + mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min); + mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max); + out_mergedAabb[aabbIndex] = mergedAabb; + } + + offset = offset / 2; + + barrier(CLK_GLOBAL_MEM_FENCE); + } +} +*/ + +__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, + __global SortDataCL* out_mortonCodesAndAabbIndices, + b3Scalar cellSize, int numAabbs) +{ + int leafNodeIndex = get_global_id(0); //Leaf node index == AABB index + if(leafNodeIndex >= numAabbs) return; + + b3AabbCL aabb = worldSpaceAabbs[leafNodeIndex]; + + b3Vector3 center = (aabb.m_min + aabb.m_max) * 0.5f; + + //Quantize into integer coordinates + //floor() is needed to prevent the center cell, at (0,0,0) from being twice the size + b3Vector3 gridPosition = center / cellSize; + + int4 discretePosition; + discretePosition.x = (int)( (gridPosition.x >= 0.0f) ? gridPosition.x : floor(gridPosition.x) ); + discretePosition.y = (int)( (gridPosition.y >= 0.0f) ? gridPosition.y : floor(gridPosition.y) ); + discretePosition.z = (int)( (gridPosition.z >= 0.0f) ? gridPosition.z : floor(gridPosition.z) ); + + //Clamp coordinates into [-512, 511], then convert range from [-512, 511] to [0, 1023] + discretePosition = b3Max( -512, b3Min(discretePosition, 511) ); + discretePosition += 512; + + //Interleave bits(assign a morton code, also known as a z-curve) + unsigned int mortonCode = getMortonCode(discretePosition.x, discretePosition.y, discretePosition.z); + + // + SortDataCL mortonCodeIndexPair; + mortonCodeIndexPair.m_key = mortonCode; + mortonCodeIndexPair.m_value = leafNodeIndex; + + out_mortonCodesAndAabbIndices[leafNodeIndex] = mortonCodeIndexPair; +} + +#define B3_PLVBH_TRAVERSE_MAX_STACK_SIZE 128 +#define B3_PLBVH_ROOT_NODE_MARKER -1 //Used to indicate that the (root) node has no parent +#define B3_PLBVH_ROOT_NODE_INDEX 0 + +//For elements of internalNodeChildIndices(int2), the negative bit determines whether it is a leaf or internal node. +//Positive index == leaf node, while negative index == internal node (remove negative sign to get index). +// +//Since the root internal node is at index 0, no internal nodes should reference it as a child, +//and so index 0 is always used to indicate a leaf node. +int isLeafNode(int index) { return (index >= 0); } +int getIndexWithInternalNodeMarkerRemoved(int index) { return (index >= 0) ? index : -index; } +int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : -index; } + +__kernel void constructBinaryTree(__global int* firstIndexOffsetPerLevel, + __global int* numNodesPerLevel, + __global int2* out_internalNodeChildIndices, + __global int* out_internalNodeParentNodes, + __global int* out_leafNodeParentNodes, + int numLevels, int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if(internalNodeIndex >= numInternalNodes) return; + + //Find the level that this node is in, using linear search(could replace with binary search) + int level = 0; + int numInternalLevels = numLevels - 1; //All levels except the last are internal nodes + for(; level < numInternalLevels; ++level) + { + if( firstIndexOffsetPerLevel[level] <= internalNodeIndex && internalNodeIndex < firstIndexOffsetPerLevel[level + 1]) break; + } + + //Check lower levels to find child nodes + //Left child is always in the next level, but the same does not apply to the right child + int indexInLevel = internalNodeIndex - firstIndexOffsetPerLevel[level]; + int firstIndexInNextLevel = firstIndexOffsetPerLevel[level + 1]; //Should never be out of bounds(see for loop above) + + int leftChildLevel = level + 1; + int leftChildIndex = firstIndexInNextLevel + indexInLevel * 2; + + int rightChildLevel = level + 1; + int rightChildIndex = leftChildIndex + 1; + + //Under certain conditions, the right child index as calculated above is invalid; need to find the correct index + // + //First condition: must be at least 2 levels apart from the leaf node level; + //if the current level is right next to the leaf node level, then the right child + //will never be invalid due to the way the nodes are allocated (also avoid a out-of-bounds memory access) + // + //Second condition: not enough nodes in the next level for each parent to have 2 children, so the right child is invalid + // + //Third condition: must be the last node in its level + if( level < numLevels - 2 + && numNodesPerLevel[level] * 2 > numNodesPerLevel[level + 1] + && indexInLevel == numNodesPerLevel[level] - 1 ) + { + //Check lower levels until we find a node without a parent + for(; rightChildLevel < numLevels - 1; ++rightChildLevel) + { + int rightChildNextLevel = rightChildLevel + 1; + + //If this branch is taken, it means that the last node in rightChildNextLevel has no parent + if( numNodesPerLevel[rightChildLevel] * 2 < numNodesPerLevel[rightChildNextLevel] ) + { + //Set the node to the last node in rightChildNextLevel + rightChildLevel = rightChildNextLevel; + rightChildIndex = firstIndexOffsetPerLevel[rightChildNextLevel] + numNodesPerLevel[rightChildNextLevel] - 1; + break; + } + } + } + + int isLeftChildLeaf = (leftChildLevel >= numLevels - 1); + int isRightChildLeaf = (rightChildLevel >= numLevels - 1); + + //If left/right child is a leaf node, the index needs to be corrected + //the way the index is calculated assumes that the leaf and internal nodes are in a contiguous array, + //with leaf nodes at the end of the array; in actuality, the leaf and internal nodes are in separate arrays + { + int leafNodeLevel = numLevels - 1; + leftChildIndex = (isLeftChildLeaf) ? leftChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : leftChildIndex; + rightChildIndex = (isLeftChildLeaf) ? rightChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : rightChildIndex; + } + + //Set the negative sign bit if the node is internal + int2 childIndices; + childIndices.x = getIndexWithInternalNodeMarkerSet(isLeftChildLeaf, leftChildIndex); + childIndices.y = getIndexWithInternalNodeMarkerSet(isRightChildLeaf, rightChildIndex); + out_internalNodeChildIndices[internalNodeIndex] = childIndices; + + //Assign parent node index to children + __global int* out_leftChildParentNodeIndices = (isLeftChildLeaf) ? out_leafNodeParentNodes : out_internalNodeParentNodes; + out_leftChildParentNodeIndices[leftChildIndex] = internalNodeIndex; + + __global int* out_rightChildParentNodeIndices = (isRightChildLeaf) ? out_leafNodeParentNodes : out_internalNodeParentNodes; + out_rightChildParentNodeIndices[rightChildIndex] = internalNodeIndex; +} + +__kernel void determineInternalNodeAabbs(__global int* firstIndexOffsetPerLevel, + __global int* numNodesPerLevel, + __global int2* internalNodeChildIndices, + __global SortDataCL* mortonCodesAndAabbIndices, + __global b3AabbCL* leafNodeAabbs, + __global b3AabbCL* out_internalNodeAabbs, int numLevels, int numInternalNodes) +{ + int i = get_global_id(0); + if(i >= numInternalNodes) return; + + int numInternalLevels = numLevels - 1; + + //Starting from the level next to the leaf nodes, move towards the root(level 0) + for(int level = numInternalLevels - 1; level >= 0; --level) + { + int indexInLevel = i; //Index relative to firstIndexOffsetPerLevel[level] + + int numNodesInLevel = numNodesPerLevel[level]; + if(i < numNodesInLevel) + { + int internalNodeIndexGlobal = indexInLevel + firstIndexOffsetPerLevel[level]; + int2 childIndicies = internalNodeChildIndices[internalNodeIndexGlobal]; + + int leftChildIndex = getIndexWithInternalNodeMarkerRemoved(childIndicies.x); + int rightChildIndex = getIndexWithInternalNodeMarkerRemoved(childIndicies.y); + + int isLeftChildLeaf = isLeafNode(childIndicies.x); + int isRightChildLeaf = isLeafNode(childIndicies.y); + + int leftChildLeafIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1; + int rightChildLeafIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1; + + b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftChildLeafIndex] : out_internalNodeAabbs[leftChildIndex]; + b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightChildLeafIndex] : out_internalNodeAabbs[rightChildIndex]; + + b3AabbCL internalNodeAabb; + internalNodeAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min); + internalNodeAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max); + out_internalNodeAabbs[internalNodeIndexGlobal] = internalNodeAabb; + } + + barrier(CLK_GLOBAL_MEM_FENCE); + } +} + + +//From sap.cl +#define NEW_PAIR_MARKER -1 + +bool TestAabbAgainstAabb2(const b3AabbCL* aabb1, const b3AabbCL* aabb2) +{ + bool overlap = true; + overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap; + overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap; + overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap; + return overlap; +} +//From sap.cl + +__kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, + __global int2* internalNodeChildIndices, __global b3AabbCL* internalNodeAabbs, + __global SortDataCL* mortonCodesAndAabbIndices, + __global int* out_numPairs, __global int4* out_overlappingPairs, + int maxPairs, int numQueryAabbs) +{ +#define USE_SPATIALLY_COHERENT_INDICIES //mortonCodesAndAabbIndices[] contains rigid body indices sorted along the z-curve +#ifdef USE_SPATIALLY_COHERENT_INDICIES + int queryRigidIndex = get_group_id(0) * get_local_size(0) + get_local_id(0); + if(queryRigidIndex >= numQueryAabbs) return; + + queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value; +#else + int queryRigidIndex = get_global_id(0); + if(queryRigidIndex >= numQueryAabbs) return; +#endif + + b3AabbCL queryAabb = rigidAabbs[queryRigidIndex]; + + int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; + + //Starting by placing only the root node index, 0, in the stack causes it to be detected as a leaf node(see isLeafNode() in loop) + int stackSize = 2; + stack[0] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].x; + stack[1] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].y; + + while(stackSize) + { + int internalOrLeafNodeIndex = stack[ stackSize - 1 ]; + --stackSize; + + int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false + int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex); + + //bvhRigidIndex is not used if internal node + int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1; + + b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex]; + if( queryRigidIndex != bvhRigidIndex && TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) ) + { + if(isLeaf && rigidAabbs[queryRigidIndex].m_minIndices[3] < rigidAabbs[bvhRigidIndex].m_minIndices[3]) + { + int4 pair; + pair.x = rigidAabbs[queryRigidIndex].m_minIndices[3]; + pair.y = rigidAabbs[bvhRigidIndex].m_minIndices[3]; + pair.z = NEW_PAIR_MARKER; + pair.w = NEW_PAIR_MARKER; + + int pairIndex = atomic_inc(out_numPairs); + if(pairIndex < maxPairs) out_overlappingPairs[pairIndex] = pair; + } + + if(!isLeaf) //Internal node + { + if(stackSize + 2 > B3_PLVBH_TRAVERSE_MAX_STACK_SIZE) + { + //Error + } + else + { + stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].x; + stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].y; + } + } + } + + } +} + diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h new file mode 100644 index 000000000..a6cabdb99 --- /dev/null +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -0,0 +1,325 @@ +//this file is autogenerated using stringify.bat (premake --stringify) in the build folder of this project +static const char* parallelLinearBvhCL= \ +"/*\n" +"This software is provided 'as-is', without any express or implied warranty.\n" +"In no event will the authors be held liable for any damages arising from the use of this software.\n" +"Permission is granted to anyone to use this software for any purpose,\n" +"including commercial applications, and to alter it and redistribute it freely,\n" +"subject to the following restrictions:\n" +"1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.\n" +"2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.\n" +"3. This notice may not be removed or altered from any source distribution.\n" +"*/\n" +"//Initial Author Jackson Lee, 2014\n" +"typedef float b3Scalar;\n" +"typedef float4 b3Vector3;\n" +"#define b3Max max\n" +"#define b3Min min\n" +"typedef struct\n" +"{\n" +" unsigned int m_key;\n" +" unsigned int m_value;\n" +"} SortDataCL;\n" +"typedef struct \n" +"{\n" +" union\n" +" {\n" +" float4 m_min;\n" +" float m_minElems[4];\n" +" int m_minIndices[4];\n" +" };\n" +" union\n" +" {\n" +" float4 m_max;\n" +" float m_maxElems[4];\n" +" int m_maxIndices[4];\n" +" };\n" +"} b3AabbCL;\n" +"unsigned int interleaveBits(unsigned int x)\n" +"{\n" +" //........ ........ ......12 3456789A //x\n" +" //....1..2 ..3..4.. 5..6..7. .8..9..A //x after interleaving bits\n" +" \n" +" //........ ....1234 56789A12 3456789A //x |= (x << 10)\n" +" //........ ....1111 1....... ...11111 //0x 00 0F 80 1F\n" +" //........ ....1234 5....... ...6789A //x = ( x | (x << 10) ) & 0x000F801F; \n" +" \n" +" //.......1 23451234 5.....67 89A6789A //x |= (x << 5)\n" +" //.......1 1.....11 1.....11 .....111 //0x 01 83 83 07\n" +" //.......1 2.....34 5.....67 .....89A //x = ( x | (x << 5) ) & 0x01838307;\n" +" \n" +" //....12.1 2..34534 5..67.67 ..89A89A //x |= (x << 3)\n" +" //....1... 1..1...1 1..1...1 ..1...11 //0x 08 91 91 23\n" +" //....1... 2..3...4 5..6...7 ..8...9A //x = ( x | (x << 3) ) & 0x08919123;\n" +" \n" +" //...11..2 2.33..4N 5.66..77 .88..9NA //x |= (x << 1) ( N indicates overlapping bits, first overlap is bit {4,5} second is {9,A} )\n" +" //....1..1 ..1...1. 1..1..1. .1...1.1 //0x 09 22 92 45\n" +" //....1..2 ..3...4. 5..6..7. .8...9.A //x = ( x | (x << 1) ) & 0x09229245;\n" +" \n" +" //...11.22 .33..445 5.66.77. 88..99AA //x |= (x << 1)\n" +" //....1..1 ..1..1.. 1..1..1. .1..1..1 //0x 09 34 92 29\n" +" //....1..2 ..3..4.. 5..6..7. .8..9..A //x = ( x | (x << 1) ) & 0x09349229;\n" +" \n" +" //........ ........ ......11 11111111 //0x000003FF\n" +" x &= 0x000003FF; //Clear all bits above bit 10\n" +" \n" +" x = ( x | (x << 10) ) & 0x000F801F;\n" +" x = ( x | (x << 5) ) & 0x01838307;\n" +" x = ( x | (x << 3) ) & 0x08919123;\n" +" x = ( x | (x << 1) ) & 0x09229245;\n" +" x = ( x | (x << 1) ) & 0x09349229;\n" +" \n" +" return x;\n" +"}\n" +"unsigned int getMortonCode(unsigned int x, unsigned int y, unsigned int z)\n" +"{\n" +" return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2;\n" +"}\n" +"__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, \n" +" __global SortDataCL* out_mortonCodesAndAabbIndices, \n" +" b3Scalar cellSize, int numAabbs)\n" +"{\n" +" int leafNodeIndex = get_global_id(0); //Leaf node index == AABB index\n" +" if(leafNodeIndex >= numAabbs) return;\n" +" \n" +" b3AabbCL aabb = worldSpaceAabbs[leafNodeIndex];\n" +" \n" +" b3Vector3 center = (aabb.m_min + aabb.m_max) * 0.5f;\n" +" \n" +" //Quantize into integer coordinates\n" +" //floor() is needed to prevent the center cell, at (0,0,0) from being twice the size\n" +" b3Vector3 gridPosition = center / cellSize;\n" +" \n" +" int4 discretePosition;\n" +" discretePosition.x = (int)( (gridPosition.x >= 0.0f) ? gridPosition.x : floor(gridPosition.x) );\n" +" discretePosition.y = (int)( (gridPosition.y >= 0.0f) ? gridPosition.y : floor(gridPosition.y) );\n" +" discretePosition.z = (int)( (gridPosition.z >= 0.0f) ? gridPosition.z : floor(gridPosition.z) );\n" +" \n" +" //Clamp coordinates into [-512, 511], then convert range from [-512, 511] to [0, 1023]\n" +" discretePosition = b3Max( -512, b3Min(discretePosition, 511) );\n" +" discretePosition += 512;\n" +" \n" +" //Interleave bits(assign a morton code, also known as a z-curve)\n" +" unsigned int mortonCode = getMortonCode(discretePosition.x, discretePosition.y, discretePosition.z);\n" +" \n" +" //\n" +" SortDataCL mortonCodeIndexPair;\n" +" mortonCodeIndexPair.m_key = mortonCode;\n" +" mortonCodeIndexPair.m_value = leafNodeIndex;\n" +" \n" +" out_mortonCodesAndAabbIndices[leafNodeIndex] = mortonCodeIndexPair;\n" +"}\n" +"#define B3_PLVBH_TRAVERSE_MAX_STACK_SIZE 128\n" +"#define B3_PLBVH_ROOT_NODE_MARKER -1 //Used to indicate that the node has no parent \n" +"#define B3_PLBVH_ROOT_NODE_INDEX 0\n" +"//For elements of internalNodeChildIndices(int2), the negative bit determines whether it is a leaf or internal node.\n" +"//Positive index == leaf node, while negative index == internal node (remove negative sign to get index).\n" +"//\n" +"//Since the root internal node is at index 0, no internal nodes should reference it as a child,\n" +"//and so index 0 is always used to indicate a leaf node.\n" +"int isLeafNode(int index) { return (index >= 0); }\n" +"int getIndexWithInternalNodeMarkerRemoved(int index) { return (index >= 0) ? index : -index; }\n" +"int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : -index; }\n" +"__kernel void constructBinaryTree(__global int* firstIndexOffsetPerLevel,\n" +" __global int* numNodesPerLevel,\n" +" __global int2* out_internalNodeChildIndices, \n" +" __global int* out_internalNodeParentNodes, \n" +" __global int* out_leafNodeParentNodes, \n" +" int numLevels, int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" //Find the level that this node is in, using linear search(could replace with binary search)\n" +" int level = 0;\n" +" int numInternalLevels = numLevels - 1; //All levels except the last are internal nodes\n" +" for(; level < numInternalLevels; ++level)\n" +" {\n" +" if( firstIndexOffsetPerLevel[level] <= internalNodeIndex && internalNodeIndex < firstIndexOffsetPerLevel[level + 1]) break;\n" +" }\n" +" \n" +" //Check lower levels to find child nodes\n" +" //Left child is always in the next level, but the same does not apply to the right child\n" +" int indexInLevel = internalNodeIndex - firstIndexOffsetPerLevel[level];\n" +" int firstIndexInNextLevel = firstIndexOffsetPerLevel[level + 1]; //Should never be out of bounds(see for loop above)\n" +" \n" +" int leftChildLevel = level + 1;\n" +" int leftChildIndex = firstIndexInNextLevel + indexInLevel * 2;\n" +" \n" +" int rightChildLevel = level + 1;\n" +" int rightChildIndex = leftChildIndex + 1;\n" +" \n" +" //Under certain conditions, the right child index as calculated above is invalid; need to find the correct index\n" +" //\n" +" //First condition: must be at least 2 levels apart from the leaf node level;\n" +" //if the current level is right next to the leaf node level, then the right child\n" +" //will never be invalid due to the way the nodes are allocated (also avoid a out-of-bounds memory access)\n" +" //\n" +" //Second condition: not enough nodes in the next level for each parent to have 2 children, so the right child is invalid\n" +" //\n" +" //Third condition: must be the last node in its level\n" +" if( level < numLevels - 2 \n" +" && numNodesPerLevel[level] * 2 > numNodesPerLevel[level + 1] \n" +" && indexInLevel == numNodesPerLevel[level] - 1 )\n" +" {\n" +" //Check lower levels until we find a node without a parent\n" +" for(; rightChildLevel < numLevels - 1; ++rightChildLevel)\n" +" {\n" +" int rightChildNextLevel = rightChildLevel + 1;\n" +" \n" +" //If this branch is taken, it means that the last node in rightChildNextLevel has no parent\n" +" if( numNodesPerLevel[rightChildLevel] * 2 < numNodesPerLevel[rightChildNextLevel] )\n" +" {\n" +" //Set the node to the last node in rightChildNextLevel\n" +" rightChildLevel = rightChildNextLevel;\n" +" rightChildIndex = firstIndexOffsetPerLevel[rightChildNextLevel] + numNodesPerLevel[rightChildNextLevel] - 1;\n" +" break;\n" +" }\n" +" }\n" +" }\n" +" \n" +" int isLeftChildLeaf = (leftChildLevel >= numLevels - 1);\n" +" int isRightChildLeaf = (rightChildLevel >= numLevels - 1);\n" +" \n" +" //If left/right child is a leaf node, the index needs to be corrected\n" +" //the way the index is calculated assumes that the leaf and internal nodes are in a contiguous array,\n" +" //with leaf nodes at the end of the array; in actuality, the leaf and internal nodes are in separate arrays\n" +" {\n" +" int leafNodeLevel = numLevels - 1;\n" +" leftChildIndex = (isLeftChildLeaf) ? leftChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : leftChildIndex;\n" +" rightChildIndex = (isLeftChildLeaf) ? rightChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : rightChildIndex;\n" +" }\n" +" \n" +" //Set the negative sign bit if the node is internal\n" +" int2 childIndices;\n" +" childIndices.x = getIndexWithInternalNodeMarkerSet(isLeftChildLeaf, leftChildIndex);\n" +" childIndices.y = getIndexWithInternalNodeMarkerSet(isRightChildLeaf, rightChildIndex);\n" +" out_internalNodeChildIndices[internalNodeIndex] = childIndices;\n" +" \n" +" //Assign parent node index to children\n" +" __global int* out_leftChildParentNodeIndices = (isLeftChildLeaf) ? out_leafNodeParentNodes : out_internalNodeParentNodes;\n" +" out_leftChildParentNodeIndices[leftChildIndex] = internalNodeIndex;\n" +" \n" +" __global int* out_rightChildParentNodeIndices = (isRightChildLeaf) ? out_leafNodeParentNodes : out_internalNodeParentNodes;\n" +" out_rightChildParentNodeIndices[rightChildIndex] = internalNodeIndex;\n" +"}\n" +"__kernel void determineInternalNodeAabbs(__global int* firstIndexOffsetPerLevel,\n" +" __global int* numNodesPerLevel, \n" +" __global int2* internalNodeChildIndices,\n" +" __global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global b3AabbCL* leafNodeAabbs, \n" +" __global b3AabbCL* out_internalNodeAabbs, int numLevels, int numInternalNodes)\n" +"{\n" +" int i = get_global_id(0);\n" +" if(i >= numInternalNodes) return;\n" +" \n" +" int numInternalLevels = numLevels - 1;\n" +" \n" +" //Starting from the level next to the leaf nodes, move towards the root(level 0)\n" +" for(int level = numInternalLevels - 1; level >= 0; --level)\n" +" {\n" +" int indexInLevel = i; //Index relative to firstIndexOffsetPerLevel[level]\n" +" \n" +" int numNodesInLevel = numNodesPerLevel[level];\n" +" if(i < numNodesInLevel)\n" +" {\n" +" int internalNodeIndexGlobal = indexInLevel + firstIndexOffsetPerLevel[level];\n" +" int2 childIndicies = internalNodeChildIndices[internalNodeIndexGlobal];\n" +" \n" +" int leftChildIndex = getIndexWithInternalNodeMarkerRemoved(childIndicies.x);\n" +" int rightChildIndex = getIndexWithInternalNodeMarkerRemoved(childIndicies.y);\n" +" \n" +" int isLeftChildLeaf = isLeafNode(childIndicies.x);\n" +" int isRightChildLeaf = isLeafNode(childIndicies.y);\n" +" \n" +" int leftChildLeafIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1;\n" +" int rightChildLeafIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1;\n" +" \n" +" b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftChildLeafIndex] : out_internalNodeAabbs[leftChildIndex];\n" +" b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightChildLeafIndex] : out_internalNodeAabbs[rightChildIndex];\n" +" \n" +" b3AabbCL internalNodeAabb;\n" +" internalNodeAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min);\n" +" internalNodeAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max);\n" +" out_internalNodeAabbs[internalNodeIndexGlobal] = internalNodeAabb;\n" +" }\n" +" \n" +" barrier(CLK_GLOBAL_MEM_FENCE);\n" +" }\n" +"}\n" +"//From sap.cl\n" +"#define NEW_PAIR_MARKER -1\n" +"bool TestAabbAgainstAabb2(const b3AabbCL* aabb1, const b3AabbCL* aabb2)\n" +"{\n" +" bool overlap = true;\n" +" overlap = (aabb1->m_min.x > aabb2->m_max.x || aabb1->m_max.x < aabb2->m_min.x) ? false : overlap;\n" +" overlap = (aabb1->m_min.z > aabb2->m_max.z || aabb1->m_max.z < aabb2->m_min.z) ? false : overlap;\n" +" overlap = (aabb1->m_min.y > aabb2->m_max.y || aabb1->m_max.y < aabb2->m_min.y) ? false : overlap;\n" +" return overlap;\n" +"}\n" +"//From sap.cl\n" +"__kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, \n" +" __global int2* internalNodeChildIndices, __global b3AabbCL* internalNodeAabbs,\n" +" __global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global int* out_numPairs, __global int4* out_overlappingPairs, \n" +" int maxPairs, int numQueryAabbs)\n" +"{\n" +" int queryRigidIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" +" if(queryRigidIndex >= numQueryAabbs) return;\n" +" \n" +" queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value;\n" +" //int queryRigidIndex = get_global_id(0);\n" +" //if(queryRigidIndex >= numQueryAabbs) return;\n" +" \n" +" b3AabbCL queryAabb = rigidAabbs[queryRigidIndex];\n" +" \n" +" int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" +" \n" +" //Starting by placing only the root node index, 0, in the stack causes it to be detected as a leaf node(see isLeafNode() in loop)\n" +" int stackSize = 2;\n" +" stack[0] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].x;\n" +" stack[1] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].y;\n" +" \n" +" while(stackSize)\n" +" {\n" +" int internalOrLeafNodeIndex = stack[ stackSize - 1 ];\n" +" --stackSize;\n" +" \n" +" int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false\n" +" int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex);\n" +" \n" +" //bvhRigidIndex is not used if internal node\n" +" int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1;\n" +" \n" +" b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex];\n" +" if( queryRigidIndex != bvhRigidIndex && TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) )\n" +" {\n" +" if(isLeaf && rigidAabbs[queryRigidIndex].m_minIndices[3] < rigidAabbs[bvhRigidIndex].m_minIndices[3])\n" +" {\n" +" int4 pair;\n" +" pair.x = rigidAabbs[queryRigidIndex].m_minIndices[3];\n" +" pair.y = rigidAabbs[bvhRigidIndex].m_minIndices[3];\n" +" pair.z = NEW_PAIR_MARKER;\n" +" pair.w = NEW_PAIR_MARKER;\n" +" \n" +" int pairIndex = atomic_inc(out_numPairs);\n" +" if(pairIndex < maxPairs) out_overlappingPairs[pairIndex] = pair;\n" +" }\n" +" \n" +" if(!isLeaf) //Internal node\n" +" {\n" +" if(stackSize + 2 > B3_PLVBH_TRAVERSE_MAX_STACK_SIZE)\n" +" {\n" +" //Error\n" +" }\n" +" else\n" +" {\n" +" stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].x;\n" +" stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].y;\n" +" }\n" +" }\n" +" }\n" +" \n" +" }\n" +"}\n" +; From 7f0e361fa097d5859afbaae4d1a8e55195627af9 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Tue, 18 Feb 2014 19:59:05 -0800 Subject: [PATCH 002/116] Use merged AABB to calculate grid cell size for PLBVH. --- .../b3GpuParallelLinearBvh.h | 38 ++++++--- .../b3GpuParallelLinearBvhBroadphase.h | 8 +- .../kernels/parallelLinearBvh.cl | 34 ++++---- .../kernels/parallelLinearBvhKernels.h | 80 ++++++++++++++++--- 4 files changed, 115 insertions(+), 45 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index 10fbeb79f..58ec34ab8 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -55,6 +55,7 @@ class b3GpuParallelLinearBvh cl_program m_parallelLinearBvhProgram; + cl_kernel m_findAllNodesMergedAabbKernel; cl_kernel m_assignMortonCodesAndAabbIndiciesKernel; cl_kernel m_constructBinaryTreeKernel; cl_kernel m_determineInternalNodeAabbsKernel; @@ -78,6 +79,7 @@ class b3GpuParallelLinearBvh //1 element per leaf node b3OpenCLArray m_leafNodeParentNodes; b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key = morton code, m_value == aabb index + b3OpenCLArray m_mergedAabb; public: b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue) : @@ -91,7 +93,8 @@ public: m_internalNodeChildNodes(context, queue), m_internalNodeParentNodes(context, queue), m_leafNodeParentNodes(context, queue), - m_mortonCodesAndAabbIndicies(context, queue) + m_mortonCodesAndAabbIndicies(context, queue), + m_mergedAabb(context, queue) { const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; @@ -101,6 +104,8 @@ public: m_parallelLinearBvhProgram = b3OpenCLUtils::compileCLProgramFromString(context, device, kernelSource, &error, additionalMacros, CL_PROGRAM_PATH); b3Assert(m_parallelLinearBvhProgram); + m_findAllNodesMergedAabbKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findAllNodesMergedAabb", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_findAllNodesMergedAabbKernel); m_assignMortonCodesAndAabbIndiciesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "assignMortonCodesAndAabbIndicies", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_assignMortonCodesAndAabbIndiciesKernel); m_constructBinaryTreeKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "constructBinaryTree", &error, m_parallelLinearBvhProgram, additionalMacros ); @@ -114,6 +119,7 @@ public: virtual ~b3GpuParallelLinearBvh() { + clReleaseKernel(m_findAllNodesMergedAabbKernel); clReleaseKernel(m_assignMortonCodesAndAabbIndiciesKernel); clReleaseKernel(m_constructBinaryTreeKernel); clReleaseKernel(m_determineInternalNodeAabbsKernel); @@ -125,8 +131,7 @@ public: // fix: need to handle/test case with 2 nodes - ///@param cellsize A virtual grid of size 2^10^3 is used in the process of creating the BVH - void build(const b3OpenCLArray& worldSpaceAabbs, b3Scalar cellSize) + void build(const b3OpenCLArray& worldSpaceAabbs) { B3_PROFILE("b3ParallelLinearBvh::build()"); @@ -143,6 +148,7 @@ public: m_leafNodeParentNodes.resize(numLeaves); m_mortonCodesAndAabbIndicies.resize(numLeaves); + m_mergedAabb.resize(numLeaves); } //Determine number of levels in the binary tree( numLevels = ceil( log2(numLeaves) ) ) @@ -160,7 +166,7 @@ public: //If the number of nodes is not a power of 2(as in, can be expressed as 2^N where N is an integer), then there is 1 additional level if( ~(1 << mostSignificantBit) & numLeaves ) numLevels++; - if(1) printf("numLeaves, numLevels, mostSignificantBit: %d, %d, %d \n", numLeaves, numLevels, mostSignificantBit); + if(0) printf("numLeaves, numLevels, mostSignificantBit: %d, %d, %d \n", numLeaves, numLevels, mostSignificantBit); } //Determine number of nodes per level, use prefix sum to get offsets of each level, and send to GPU @@ -202,7 +208,7 @@ public: m_firstIndexOffsetPerLevelCpu[i] -= m_numNodesPerLevelCpu[i]; } - if(1) + if(0) { int numInternalNodes = 0; for(int i = 0; i < numLevels; ++i) @@ -225,20 +231,22 @@ public: { B3_PROFILE("Find AABB of merged nodes"); - /*b3BufferInfoCL bufferInfo[] = + m_mergedAabb.copyFromOpenCLArray(worldSpaceAabbs); //Need to make a copy since the kernel modifies the array + + b3BufferInfoCL bufferInfo[] = { - b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), - b3BufferInfoCL( m_allNodesMergedAabb.getBufferCL() ), + b3BufferInfoCL( m_mergedAabb.getBufferCL() ) //Resulting AABB is stored in m_mergedAabb[0] }; - b3LauncherCL launcher(m_queue, m_findAllNodesMergedAabb, "m_findAllNodesMergedAabb"); + b3LauncherCL launcher(m_queue, m_findAllNodesMergedAabbKernel, "m_findAllNodesMergedAabbKernel"); launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); launcher.setConst(numLeaves); launcher.launch1D(numLeaves); - clFinish(m_queue);*/ + clFinish(m_queue); } + //Insert the center of the AABBs into a virtual grid, //then convert the discrete grid coordinates into a morton code //For each element in m_mortonCodesAndAabbIndicies, set @@ -250,12 +258,12 @@ public: b3BufferInfoCL bufferInfo[] = { b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( m_mergedAabb.getBufferCL() ), b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ) }; b3LauncherCL launcher(m_queue, m_assignMortonCodesAndAabbIndiciesKernel, "m_assignMortonCodesAndAabbIndiciesKernel"); launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(cellSize); launcher.setConst(numLeaves); launcher.launch1D(numLeaves); @@ -301,7 +309,7 @@ public: launcher.launch1D(numInternalNodes); clFinish(m_queue); - if(1) + if(0) { static b3AlignedObjectArray internalNodeChildNodes; m_internalNodeChildNodes.copyToHost(internalNodeChildNodes, false); @@ -335,6 +343,12 @@ public: launcher.launch1D(numLeaves); clFinish(m_queue); + if(0) + { + b3SapAabb mergedAABB = m_mergedAabb.at(0); + printf("mergedAABBMin: %f, %f, %f \n", mergedAABB.m_minVec.x, mergedAABB.m_minVec.y, mergedAABB.m_minVec.z); + printf("mergedAABBMax: %f, %f, %f \n", mergedAABB.m_maxVec.x, mergedAABB.m_maxVec.y, mergedAABB.m_maxVec.z); + } if(0) { static b3AlignedObjectArray rigidAabbs; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h index 728215b7a..007067460 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h @@ -56,14 +56,8 @@ public: virtual void calculateOverlappingPairs(int maxPairs) { - //Detect overall min/max - { - //Not implemented - } - //Reconstruct BVH - const b3Scalar CELL_SIZE(0.1); - m_plbvh.build(m_aabbsGpu, CELL_SIZE); + m_plbvh.build(m_aabbsGpu); // m_overlappingPairsGpu.resize(maxPairs); diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index a5127c3aa..51c8ce281 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -80,8 +80,8 @@ unsigned int getMortonCode(unsigned int x, unsigned int y, unsigned int z) return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2; } -/* -__kernel void findAllNodesMergedAabb(__global b3AabbCL* worldSpaceAabbs, __global b3AabbCL* out_mergedAabb, int numAabbs) + +__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbs) { int aabbIndex = get_global_id(0); if(aabbIndex >= numAabbs) return; @@ -89,11 +89,11 @@ __kernel void findAllNodesMergedAabb(__global b3AabbCL* worldSpaceAabbs, __globa //Find the most significant bit(msb) int mostSignificantBit = 0; { - int temp = numLeaves; + int temp = numAabbs; while(temp >>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1) } - int numberOfAabbsAboveMsbSplit = numAabbs & ~( ~(0) << mostSignificantBit ); // verify + int numberOfAabbsAboveMsbSplit = numAabbs & ~( ~(0) << mostSignificantBit ); int numRemainingAabbs = (1 << mostSignificantBit); //Merge AABBs above most significant bit so that the number of remaining AABBs is a power of 2 @@ -102,8 +102,8 @@ __kernel void findAllNodesMergedAabb(__global b3AabbCL* worldSpaceAabbs, __globa { int otherAabbIndex = numRemainingAabbs + aabbIndex; - b3AabbCL aabb = worldSpaceAabbs[aabbIndex]; - b3AabbCL otherAabb = worldSpaceAabbs[otherAabbIndex]; + b3AabbCL aabb = out_mergedAabb[aabbIndex]; + b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex]; b3AabbCL mergedAabb; mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min); @@ -121,8 +121,8 @@ __kernel void findAllNodesMergedAabb(__global b3AabbCL* worldSpaceAabbs, __globa { int otherAabbIndex = aabbIndex + offset; - b3AabbCL aabb = worldSpaceAabbs[aabbIndex]; - b3AabbCL otherAabb = worldSpaceAabbs[otherAabbIndex]; + b3AabbCL aabb = out_mergedAabb[aabbIndex]; + b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex]; b3AabbCL mergedAabb; mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min); @@ -130,27 +130,29 @@ __kernel void findAllNodesMergedAabb(__global b3AabbCL* worldSpaceAabbs, __globa out_mergedAabb[aabbIndex] = mergedAabb; } - offset = offset / 2; + offset /= 2; barrier(CLK_GLOBAL_MEM_FENCE); } } -*/ -__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, - __global SortDataCL* out_mortonCodesAndAabbIndices, - b3Scalar cellSize, int numAabbs) +__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, __global b3AabbCL* mergedAabbOfAllNodes, + __global SortDataCL* out_mortonCodesAndAabbIndices, int numAabbs) { int leafNodeIndex = get_global_id(0); //Leaf node index == AABB index if(leafNodeIndex >= numAabbs) return; - b3AabbCL aabb = worldSpaceAabbs[leafNodeIndex]; + b3AabbCL mergedAabb = mergedAabbOfAllNodes[0]; + b3Vector3 gridCenter = (mergedAabb.m_min + mergedAabb.m_max) * 0.5f; + b3Vector3 gridCellSize = (mergedAabb.m_max - mergedAabb.m_min) / (float)1024; - b3Vector3 center = (aabb.m_min + aabb.m_max) * 0.5f; + b3AabbCL aabb = worldSpaceAabbs[leafNodeIndex]; + b3Vector3 aabbCenter = (aabb.m_min + aabb.m_max) * 0.5f; + b3Vector3 aabbCenterRelativeToGrid = aabbCenter - gridCenter; //Quantize into integer coordinates //floor() is needed to prevent the center cell, at (0,0,0) from being twice the size - b3Vector3 gridPosition = center / cellSize; + b3Vector3 gridPosition = aabbCenterRelativeToGrid / gridCellSize; int4 discretePosition; discretePosition.x = (int)( (gridPosition.x >= 0.0f) ? gridPosition.x : floor(gridPosition.x) ); diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index a6cabdb99..fc3273bbc 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -75,20 +75,77 @@ static const char* parallelLinearBvhCL= \ "{\n" " return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2;\n" "}\n" -"__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, \n" -" __global SortDataCL* out_mortonCodesAndAabbIndices, \n" -" b3Scalar cellSize, int numAabbs)\n" +"__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbs)\n" +"{\n" +" int aabbIndex = get_global_id(0);\n" +" if(aabbIndex >= numAabbs) return;\n" +" \n" +" //Find the most significant bit(msb)\n" +" int mostSignificantBit = 0;\n" +" {\n" +" int temp = numAabbs;\n" +" while(temp >>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1)\n" +" }\n" +" \n" +" int numberOfAabbsAboveMsbSplit = numAabbs & ~( ~(0) << mostSignificantBit );\n" +" int numRemainingAabbs = (1 << mostSignificantBit);\n" +" \n" +" //Merge AABBs above most significant bit so that the number of remaining AABBs is a power of 2\n" +" //For example, if there are 159 AABBs = 128 + 31, then merge indices [0, 30] and 128 + [0, 30]\n" +" if(aabbIndex < numberOfAabbsAboveMsbSplit)\n" +" {\n" +" int otherAabbIndex = numRemainingAabbs + aabbIndex;\n" +" \n" +" b3AabbCL aabb = out_mergedAabb[aabbIndex];\n" +" b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex];\n" +" \n" +" b3AabbCL mergedAabb;\n" +" mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min);\n" +" mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max);\n" +" out_mergedAabb[aabbIndex] = mergedAabb;\n" +" }\n" +" \n" +" barrier(CLK_GLOBAL_MEM_FENCE);\n" +" \n" +" //\n" +" int offset = numRemainingAabbs / 2;\n" +" while(offset >= 1)\n" +" {\n" +" if(aabbIndex < offset)\n" +" {\n" +" int otherAabbIndex = aabbIndex + offset;\n" +" \n" +" b3AabbCL aabb = out_mergedAabb[aabbIndex];\n" +" b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex];\n" +" \n" +" b3AabbCL mergedAabb;\n" +" mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min);\n" +" mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max);\n" +" out_mergedAabb[aabbIndex] = mergedAabb;\n" +" }\n" +" \n" +" offset /= 2;\n" +" \n" +" barrier(CLK_GLOBAL_MEM_FENCE);\n" +" }\n" +"}\n" +"__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, __global b3AabbCL* mergedAabbOfAllNodes, \n" +" __global SortDataCL* out_mortonCodesAndAabbIndices, int numAabbs)\n" "{\n" " int leafNodeIndex = get_global_id(0); //Leaf node index == AABB index\n" " if(leafNodeIndex >= numAabbs) return;\n" " \n" -" b3AabbCL aabb = worldSpaceAabbs[leafNodeIndex];\n" +" b3AabbCL mergedAabb = mergedAabbOfAllNodes[0];\n" +" b3Vector3 gridCenter = (mergedAabb.m_min + mergedAabb.m_max) * 0.5f;\n" +" b3Vector3 gridCellSize = (mergedAabb.m_max - mergedAabb.m_min) / (float)1024;\n" " \n" -" b3Vector3 center = (aabb.m_min + aabb.m_max) * 0.5f;\n" +" b3AabbCL aabb = worldSpaceAabbs[leafNodeIndex];\n" +" b3Vector3 aabbCenter = (aabb.m_min + aabb.m_max) * 0.5f;\n" +" b3Vector3 aabbCenterRelativeToGrid = aabbCenter - gridCenter;\n" " \n" " //Quantize into integer coordinates\n" " //floor() is needed to prevent the center cell, at (0,0,0) from being twice the size\n" -" b3Vector3 gridPosition = center / cellSize;\n" +" b3Vector3 gridPosition = aabbCenterRelativeToGrid / gridCellSize;\n" " \n" " int4 discretePosition;\n" " discretePosition.x = (int)( (gridPosition.x >= 0.0f) ? gridPosition.x : floor(gridPosition.x) );\n" @@ -110,7 +167,7 @@ static const char* parallelLinearBvhCL= \ " out_mortonCodesAndAabbIndices[leafNodeIndex] = mortonCodeIndexPair;\n" "}\n" "#define B3_PLVBH_TRAVERSE_MAX_STACK_SIZE 128\n" -"#define B3_PLBVH_ROOT_NODE_MARKER -1 //Used to indicate that the node has no parent \n" +"#define B3_PLBVH_ROOT_NODE_MARKER -1 //Used to indicate that the (root) node has no parent \n" "#define B3_PLBVH_ROOT_NODE_INDEX 0\n" "//For elements of internalNodeChildIndices(int2), the negative bit determines whether it is a leaf or internal node.\n" "//Positive index == leaf node, while negative index == internal node (remove negative sign to get index).\n" @@ -264,13 +321,16 @@ static const char* parallelLinearBvhCL= \ " __global int* out_numPairs, __global int4* out_overlappingPairs, \n" " int maxPairs, int numQueryAabbs)\n" "{\n" +"#define USE_SPATIALLY_COHERENT_INDICIES //mortonCodesAndAabbIndices[] contains rigid body indices sorted along the z-curve\n" +"#ifdef USE_SPATIALLY_COHERENT_INDICIES\n" " int queryRigidIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" " if(queryRigidIndex >= numQueryAabbs) return;\n" " \n" " queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value;\n" -" //int queryRigidIndex = get_global_id(0);\n" -" //if(queryRigidIndex >= numQueryAabbs) return;\n" -" \n" +"#else\n" +" int queryRigidIndex = get_global_id(0);\n" +" if(queryRigidIndex >= numQueryAabbs) return;\n" +"#endif\n" " b3AabbCL queryAabb = rigidAabbs[queryRigidIndex];\n" " \n" " int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" From e955192971e3e4644fdb94f701a00a549587c068 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Wed, 19 Feb 2014 21:49:30 -0800 Subject: [PATCH 003/116] Fix PLBVH reduction kernels, simplify nodes per level calculation. Also calculate index ranges for each internal node. --- .../b3GpuParallelLinearBvh.h | 133 ++++++++++++------ .../b3GpuParallelLinearBvhBroadphase.h | 6 +- .../kernels/parallelLinearBvh.cl | 115 +++++++-------- .../kernels/parallelLinearBvhKernels.h | 114 +++++++-------- 4 files changed, 193 insertions(+), 175 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index 58ec34ab8..f2199a3cf 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -44,10 +44,8 @@ subject to the following restrictions: ///The BVH implementation here is almost the same as [Karras 2012], but a different method is used for constructing the tree. /// - Instead of building a binary radix tree, we simply pair each node with its nearest sibling. /// This has the effect of further worsening the quality of the BVH, but the main spatial partitioning is done by the -/// Z-curve anyways, and this method should be simpler and faster during construction. Additionally, it is still possible -/// to improve the quality of the BVH by rearranging the connections between nodes. -/// - Due to the way the tree is constructed, it becomes unnecessary to use atomic_inc to get -/// the AABB for each internal node. Rather than traveling upwards from the leaf nodes, as in the paper, +/// Z-curve anyways, and this method should be simpler and faster during construction. +/// - Rather than traveling upwards towards the root from the leaf nodes, as in the paper, /// each internal node checks its child nodes to get its AABB. class b3GpuParallelLinearBvh { @@ -73,6 +71,7 @@ class b3GpuParallelLinearBvh //1 element per internal node (number_of_internal_nodes = number_of_leaves - 1); index 0 is the root node b3OpenCLArray m_internalNodeAabbs; + b3OpenCLArray m_internalNodeLeafIndexRanges; //x == min leaf index, y == max leaf index b3OpenCLArray m_internalNodeChildNodes; //x == left child, y == right child b3OpenCLArray m_internalNodeParentNodes; @@ -90,6 +89,7 @@ public: m_numNodesPerLevelGpu(context, queue), m_firstIndexOffsetPerLevelGpu(context, queue), m_internalNodeAabbs(context, queue), + m_internalNodeLeafIndexRanges(context, queue), m_internalNodeChildNodes(context, queue), m_internalNodeParentNodes(context, queue), m_leafNodeParentNodes(context, queue), @@ -128,8 +128,6 @@ public: clReleaseProgram(m_parallelLinearBvhProgram); } - - // fix: need to handle/test case with 2 nodes void build(const b3OpenCLArray& worldSpaceAabbs) { @@ -143,6 +141,7 @@ public: // { m_internalNodeAabbs.resize(numInternalNodes); + m_internalNodeLeafIndexRanges.resize(numInternalNodes); m_internalNodeChildNodes.resize(numInternalNodes); m_internalNodeParentNodes.resize(numInternalNodes); @@ -180,17 +179,20 @@ public: //Calculate number of nodes in each level; //start from the second to last level(level right next to leaf nodes) and move towards the root(level 0) - int hasRemainder = 0; + int remainder = 0; for(int levelIndex = numLevels - 2; levelIndex >= 0; --levelIndex) { int numNodesPreviousLevel = m_numNodesPerLevelCpu[levelIndex + 1]; //For first iteration this == numLeaves - - bool allNodesAllocated = ( (numNodesPreviousLevel + hasRemainder) % 2 == 0 ); - - int numNodesCurrentLevel = (allNodesAllocated) ? (numNodesPreviousLevel + hasRemainder) / 2 : numNodesPreviousLevel / 2; - m_numNodesPerLevelCpu[levelIndex] = numNodesCurrentLevel; + int numNodesCurrentLevel = numNodesPreviousLevel / 2; - hasRemainder = static_cast(!allNodesAllocated); + remainder += numNodesPreviousLevel % 2; + if(remainder == 2) + { + numNodesCurrentLevel++; + remainder = 0; + } + + m_numNodesPerLevelCpu[levelIndex] = numNodesCurrentLevel; } //Prefix sum to calculate the first index offset of each level @@ -232,17 +234,22 @@ public: B3_PROFILE("Find AABB of merged nodes"); m_mergedAabb.copyFromOpenCLArray(worldSpaceAabbs); //Need to make a copy since the kernel modifies the array - - b3BufferInfoCL bufferInfo[] = + + for(int numAabbsNeedingMerge = numLeaves; numAabbsNeedingMerge >= 2; + numAabbsNeedingMerge = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2) { - b3BufferInfoCL( m_mergedAabb.getBufferCL() ) //Resulting AABB is stored in m_mergedAabb[0] - }; + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_mergedAabb.getBufferCL() ) //Resulting AABB is stored in m_mergedAabb[0] + }; + + b3LauncherCL launcher(m_queue, m_findAllNodesMergedAabbKernel, "m_findAllNodesMergedAabbKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numAabbsNeedingMerge); + + launcher.launch1D(numAabbsNeedingMerge); + } - b3LauncherCL launcher(m_queue, m_findAllNodesMergedAabbKernel, "m_findAllNodesMergedAabbKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLeaves); - - launcher.launch1D(numLeaves); clFinish(m_queue); } @@ -315,7 +322,8 @@ public: m_internalNodeChildNodes.copyToHost(internalNodeChildNodes, false); clFinish(m_queue); - for(int i = 0; i < 256; ++i) printf("ch[%d]: %d, %d\n", i, internalNodeChildNodes[i].x, internalNodeChildNodes[i].y); + for(int i = 0; i < numInternalNodes; ++i) + printf("ch[%d]: %d, %d\n", i, internalNodeChildNodes[i].x, internalNodeChildNodes[i].y); printf("\n"); } } @@ -325,30 +333,58 @@ public: { B3_PROFILE("Set AABBs"); - b3BufferInfoCL bufferInfo[] = + //Due to the arrangement of internal nodes, each internal node corresponds + //to a contiguous range of leaf node indices. This characteristic can be used + //to optimize calculateOverlappingPairs(); checking if + //(m_internalNodeLeafIndexRanges[].y < leafNodeIndex) can be used to ensure that + //each pair is processed only once. { - b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), - b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) - }; + B3_PROFILE("Reset internal node index ranges"); + + b3Int2 invalidIndexRange; + invalidIndexRange.x = -1; //x == min + invalidIndexRange.y = -2; //y == max + + m_fill.execute( m_internalNodeLeafIndexRanges, invalidIndexRange, m_internalNodeLeafIndexRanges.size() ); + clFinish(m_queue); + } - b3LauncherCL launcher(m_queue, m_determineInternalNodeAabbsKernel, "m_determineInternalNodeAabbsKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLevels); - launcher.setConst(numInternalNodes); - - launcher.launch1D(numLeaves); + int lastInternalLevelIndex = numLevels - 2; //Last level is leaf node level + for(int level = lastInternalLevelIndex; level >= 0; --level) + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_determineInternalNodeAabbsKernel, "m_determineInternalNodeAabbsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLevels); + launcher.setConst(numInternalNodes); + launcher.setConst(level); + + launcher.launch1D(numLeaves); + } clFinish(m_queue); if(0) { - b3SapAabb mergedAABB = m_mergedAabb.at(0); - printf("mergedAABBMin: %f, %f, %f \n", mergedAABB.m_minVec.x, mergedAABB.m_minVec.y, mergedAABB.m_minVec.z); - printf("mergedAABBMax: %f, %f, %f \n", mergedAABB.m_maxVec.x, mergedAABB.m_maxVec.y, mergedAABB.m_maxVec.z); + static b3AlignedObjectArray leafIndexRanges; + m_internalNodeLeafIndexRanges.copyToHost(leafIndexRanges, false); + clFinish(m_queue); + + for(int i = 0; i < numInternalNodes; ++i) + //if(leafIndexRanges[i].x == -1 || leafIndexRanges[i].y == -1) + printf("leafIndexRanges[%d]: %d, %d\n", i, leafIndexRanges[i].x, leafIndexRanges[i].y); + printf("\n"); } + if(0) { static b3AlignedObjectArray rigidAabbs; @@ -363,12 +399,18 @@ public: actualRootAabb.m_minVec.setMin(rigidAabbs[i].m_minVec); actualRootAabb.m_maxVec.setMax(rigidAabbs[i].m_maxVec); } - printf("actualRootMin: %f, %f, %f \n", actualRootAabb.m_minVec.x, actualRootAabb.m_minVec.y, actualRootAabb.m_minVec.z); - printf("actualRootMax: %f, %f, %f \n", actualRootAabb.m_maxVec.x, actualRootAabb.m_maxVec.y, actualRootAabb.m_maxVec.z); - + b3SapAabb rootAabb = m_internalNodeAabbs.at(0); - printf("rootMin: %f, %f, %f \n", rootAabb.m_minVec.x, rootAabb.m_minVec.y, rootAabb.m_minVec.z); - printf("rootMax: %f, %f, %f \n", rootAabb.m_maxVec.x, rootAabb.m_maxVec.y, rootAabb.m_maxVec.z); + b3SapAabb mergedAABB = m_mergedAabb.at(0); + + printf("mergedAABBMin: %f, %f, %f \n", mergedAABB.m_minVec.x, mergedAABB.m_minVec.y, mergedAABB.m_minVec.z); + printf("actualRootMin: %f, %f, %f \n", actualRootAabb.m_minVec.x, actualRootAabb.m_minVec.y, actualRootAabb.m_minVec.z); + printf("kernelRootMin: %f, %f, %f \n", rootAabb.m_minVec.x, rootAabb.m_minVec.y, rootAabb.m_minVec.z); + + printf("mergedAABBMax: %f, %f, %f \n", mergedAABB.m_maxVec.x, mergedAABB.m_maxVec.y, mergedAABB.m_maxVec.z); + printf("actualRootMax: %f, %f, %f \n", actualRootAabb.m_maxVec.x, actualRootAabb.m_maxVec.y, actualRootAabb.m_maxVec.z); + printf("kernelRootMax: %f, %f, %f \n", rootAabb.m_maxVec.x, rootAabb.m_maxVec.y, rootAabb.m_maxVec.z); + printf("\n"); } } @@ -397,6 +439,7 @@ public: b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), b3BufferInfoCL( out_numPairs.getBufferCL() ), diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h index 007067460..761f4b168 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h @@ -77,11 +77,7 @@ public: virtual cl_mem getAabbBufferWS() { return m_aabbsGpu.getBufferCL(); } virtual b3OpenCLArray& getAllAabbsGPU() { return m_aabbsGpu; } - virtual b3AlignedObjectArray& getAllAabbsCPU() - { - b3Assert(0); //CPU version not implemented - return m_aabbsCpu; - } + virtual b3AlignedObjectArray& getAllAabbsCPU() { return m_aabbsCpu; } static b3GpuBroadphaseInterface* CreateFunc(cl_context context, cl_device_id device, cl_command_queue queue) { diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index 51c8ce281..dc283ac95 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -80,60 +80,32 @@ unsigned int getMortonCode(unsigned int x, unsigned int y, unsigned int z) return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2; } - -__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbs) +//Should replace with an optimized parallel reduction +__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbsNeedingMerge) { - int aabbIndex = get_global_id(0); - if(aabbIndex >= numAabbs) return; - - //Find the most significant bit(msb) - int mostSignificantBit = 0; - { - int temp = numAabbs; - while(temp >>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1) - } - - int numberOfAabbsAboveMsbSplit = numAabbs & ~( ~(0) << mostSignificantBit ); - int numRemainingAabbs = (1 << mostSignificantBit); - - //Merge AABBs above most significant bit so that the number of remaining AABBs is a power of 2 - //For example, if there are 159 AABBs = 128 + 31, then merge indices [0, 30] and 128 + [0, 30] - if(aabbIndex < numberOfAabbsAboveMsbSplit) - { - int otherAabbIndex = numRemainingAabbs + aabbIndex; - - b3AabbCL aabb = out_mergedAabb[aabbIndex]; - b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex]; - - b3AabbCL mergedAabb; - mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min); - mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max); - out_mergedAabb[aabbIndex] = mergedAabb; - } - - barrier(CLK_GLOBAL_MEM_FENCE); - + //Each time this kernel is added to the command queue, + //the number of AABBs needing to be merged is halved // - int offset = numRemainingAabbs / 2; - while(offset >= 1) - { - if(aabbIndex < offset) - { - int otherAabbIndex = aabbIndex + offset; + //Example with 159 AABBs: + // numRemainingAabbs == 159 / 2 + 159 % 2 == 80 + // numMergedAabbs == 159 - 80 == 79 + //So, indices [0, 78] are merged with [0 + 80, 78 + 80] + + int numRemainingAabbs = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2; + int numMergedAabbs = numAabbsNeedingMerge - numRemainingAabbs; + + int aabbIndex = get_global_id(0); + if(aabbIndex >= numMergedAabbs) return; + + int otherAabbIndex = aabbIndex + numRemainingAabbs; + + b3AabbCL aabb = out_mergedAabb[aabbIndex]; + b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex]; - b3AabbCL aabb = out_mergedAabb[aabbIndex]; - b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex]; - - b3AabbCL mergedAabb; - mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min); - mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max); - out_mergedAabb[aabbIndex] = mergedAabb; - } - - offset /= 2; - - barrier(CLK_GLOBAL_MEM_FENCE); - } + b3AabbCL mergedAabb; + mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min); + mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max); + out_mergedAabb[aabbIndex] = mergedAabb; } __kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, __global b3AabbCL* mergedAabbOfAllNodes, @@ -254,7 +226,7 @@ __kernel void constructBinaryTree(__global int* firstIndexOffsetPerLevel, { int leafNodeLevel = numLevels - 1; leftChildIndex = (isLeftChildLeaf) ? leftChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : leftChildIndex; - rightChildIndex = (isLeftChildLeaf) ? rightChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : rightChildIndex; + rightChildIndex = (isRightChildLeaf) ? rightChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : rightChildIndex; } //Set the negative sign bit if the node is internal @@ -276,20 +248,19 @@ __kernel void determineInternalNodeAabbs(__global int* firstIndexOffsetPerLevel, __global int2* internalNodeChildIndices, __global SortDataCL* mortonCodesAndAabbIndices, __global b3AabbCL* leafNodeAabbs, - __global b3AabbCL* out_internalNodeAabbs, int numLevels, int numInternalNodes) + __global int2* out_internalNodeLeafIndexRanges, + __global b3AabbCL* out_internalNodeAabbs, + int numLevels, int numInternalNodes, int level) { int i = get_global_id(0); if(i >= numInternalNodes) return; - int numInternalLevels = numLevels - 1; - - //Starting from the level next to the leaf nodes, move towards the root(level 0) - for(int level = numInternalLevels - 1; level >= 0; --level) + //For each node in a level, check its child nodes to determine its AABB { int indexInLevel = i; //Index relative to firstIndexOffsetPerLevel[level] int numNodesInLevel = numNodesPerLevel[level]; - if(i < numNodesInLevel) + if(indexInLevel < numNodesInLevel) { int internalNodeIndexGlobal = indexInLevel + firstIndexOffsetPerLevel[level]; int2 childIndicies = internalNodeChildIndices[internalNodeIndexGlobal]; @@ -300,19 +271,26 @@ __kernel void determineInternalNodeAabbs(__global int* firstIndexOffsetPerLevel, int isLeftChildLeaf = isLeafNode(childIndicies.x); int isRightChildLeaf = isLeafNode(childIndicies.y); + //left/RightChildLeafIndex == Rigid body indicies int leftChildLeafIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1; int rightChildLeafIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1; b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftChildLeafIndex] : out_internalNodeAabbs[leftChildIndex]; b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightChildLeafIndex] : out_internalNodeAabbs[rightChildIndex]; + // b3AabbCL internalNodeAabb; internalNodeAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min); internalNodeAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max); out_internalNodeAabbs[internalNodeIndexGlobal] = internalNodeAabb; + + //For index range, x == min and y == max; left child always has lower index + int2 leafIndexRange; + leafIndexRange.x = (isLeftChildLeaf) ? leftChildIndex : out_internalNodeLeafIndexRanges[leftChildIndex].x; + leafIndexRange.y = (isRightChildLeaf) ? rightChildIndex : out_internalNodeLeafIndexRanges[rightChildIndex].y; + + out_internalNodeLeafIndexRanges[internalNodeIndexGlobal] = leafIndexRange; } - - barrier(CLK_GLOBAL_MEM_FENCE); } } @@ -331,7 +309,9 @@ bool TestAabbAgainstAabb2(const b3AabbCL* aabb1, const b3AabbCL* aabb2) //From sap.cl __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, - __global int2* internalNodeChildIndices, __global b3AabbCL* internalNodeAabbs, + __global int2* internalNodeChildIndices, + __global b3AabbCL* internalNodeAabbs, + __global int2* internalNodeLeafIndexRanges, __global SortDataCL* mortonCodesAndAabbIndices, __global int* out_numPairs, __global int4* out_overlappingPairs, int maxPairs, int numQueryAabbs) @@ -341,7 +321,8 @@ __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, int queryRigidIndex = get_group_id(0) * get_local_size(0) + get_local_id(0); if(queryRigidIndex >= numQueryAabbs) return; - queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value; + int queryBvhNodeIndex = queryRigidIndex; + queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value; // fix queryRigidIndex naming for this branch #else int queryRigidIndex = get_global_id(0); if(queryRigidIndex >= numQueryAabbs) return; @@ -363,7 +344,15 @@ __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex); - + + //Optimization - if the node is not a leaf, check whether the highest leaf index of that node + //is less than the queried node's index to avoid testing each pair twice. + { + // fix: produces duplicate pairs + // int highestLeafIndex = (isLeaf) ? numQueryAabbs : internalNodeLeafIndexRanges[bvhNodeIndex].y; + // if(highestLeafIndex < queryBvhNodeIndex) continue; + } + //bvhRigidIndex is not used if internal node int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index fc3273bbc..6f99d51f2 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -75,59 +75,32 @@ static const char* parallelLinearBvhCL= \ "{\n" " return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2;\n" "}\n" -"__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbs)\n" +"//Should replace with an optimized parallel reduction\n" +"__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbsNeedingMerge)\n" "{\n" -" int aabbIndex = get_global_id(0);\n" -" if(aabbIndex >= numAabbs) return;\n" -" \n" -" //Find the most significant bit(msb)\n" -" int mostSignificantBit = 0;\n" -" {\n" -" int temp = numAabbs;\n" -" while(temp >>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1)\n" -" }\n" -" \n" -" int numberOfAabbsAboveMsbSplit = numAabbs & ~( ~(0) << mostSignificantBit );\n" -" int numRemainingAabbs = (1 << mostSignificantBit);\n" -" \n" -" //Merge AABBs above most significant bit so that the number of remaining AABBs is a power of 2\n" -" //For example, if there are 159 AABBs = 128 + 31, then merge indices [0, 30] and 128 + [0, 30]\n" -" if(aabbIndex < numberOfAabbsAboveMsbSplit)\n" -" {\n" -" int otherAabbIndex = numRemainingAabbs + aabbIndex;\n" -" \n" -" b3AabbCL aabb = out_mergedAabb[aabbIndex];\n" -" b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex];\n" -" \n" -" b3AabbCL mergedAabb;\n" -" mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min);\n" -" mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max);\n" -" out_mergedAabb[aabbIndex] = mergedAabb;\n" -" }\n" -" \n" -" barrier(CLK_GLOBAL_MEM_FENCE);\n" -" \n" +" //Each time this kernel is added to the command queue, \n" +" //the number of AABBs needing to be merged is halved\n" " //\n" -" int offset = numRemainingAabbs / 2;\n" -" while(offset >= 1)\n" -" {\n" -" if(aabbIndex < offset)\n" -" {\n" -" int otherAabbIndex = aabbIndex + offset;\n" +" //Example with 159 AABBs:\n" +" // numRemainingAabbs == 159 / 2 + 159 % 2 == 80\n" +" // numMergedAabbs == 159 - 80 == 79\n" +" //So, indices [0, 78] are merged with [0 + 80, 78 + 80]\n" +" \n" +" int numRemainingAabbs = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2;\n" +" int numMergedAabbs = numAabbsNeedingMerge - numRemainingAabbs;\n" +" \n" +" int aabbIndex = get_global_id(0);\n" +" if(aabbIndex >= numMergedAabbs) return;\n" +" \n" +" int otherAabbIndex = aabbIndex + numRemainingAabbs;\n" +" \n" +" b3AabbCL aabb = out_mergedAabb[aabbIndex];\n" +" b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex];\n" " \n" -" b3AabbCL aabb = out_mergedAabb[aabbIndex];\n" -" b3AabbCL otherAabb = out_mergedAabb[otherAabbIndex];\n" -" \n" -" b3AabbCL mergedAabb;\n" -" mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min);\n" -" mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max);\n" -" out_mergedAabb[aabbIndex] = mergedAabb;\n" -" }\n" -" \n" -" offset /= 2;\n" -" \n" -" barrier(CLK_GLOBAL_MEM_FENCE);\n" -" }\n" +" b3AabbCL mergedAabb;\n" +" mergedAabb.m_min = b3Min(aabb.m_min, otherAabb.m_min);\n" +" mergedAabb.m_max = b3Max(aabb.m_max, otherAabb.m_max);\n" +" out_mergedAabb[aabbIndex] = mergedAabb;\n" "}\n" "__kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabbs, __global b3AabbCL* mergedAabbOfAllNodes, \n" " __global SortDataCL* out_mortonCodesAndAabbIndices, int numAabbs)\n" @@ -244,7 +217,7 @@ static const char* parallelLinearBvhCL= \ " {\n" " int leafNodeLevel = numLevels - 1;\n" " leftChildIndex = (isLeftChildLeaf) ? leftChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : leftChildIndex;\n" -" rightChildIndex = (isLeftChildLeaf) ? rightChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : rightChildIndex;\n" +" rightChildIndex = (isRightChildLeaf) ? rightChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : rightChildIndex;\n" " }\n" " \n" " //Set the negative sign bit if the node is internal\n" @@ -265,20 +238,19 @@ static const char* parallelLinearBvhCL= \ " __global int2* internalNodeChildIndices,\n" " __global SortDataCL* mortonCodesAndAabbIndices,\n" " __global b3AabbCL* leafNodeAabbs, \n" -" __global b3AabbCL* out_internalNodeAabbs, int numLevels, int numInternalNodes)\n" +" __global int2* out_internalNodeLeafIndexRanges,\n" +" __global b3AabbCL* out_internalNodeAabbs, \n" +" int numLevels, int numInternalNodes, int level)\n" "{\n" " int i = get_global_id(0);\n" " if(i >= numInternalNodes) return;\n" " \n" -" int numInternalLevels = numLevels - 1;\n" -" \n" -" //Starting from the level next to the leaf nodes, move towards the root(level 0)\n" -" for(int level = numInternalLevels - 1; level >= 0; --level)\n" +" //For each node in a level, check its child nodes to determine its AABB\n" " {\n" " int indexInLevel = i; //Index relative to firstIndexOffsetPerLevel[level]\n" " \n" " int numNodesInLevel = numNodesPerLevel[level];\n" -" if(i < numNodesInLevel)\n" +" if(indexInLevel < numNodesInLevel)\n" " {\n" " int internalNodeIndexGlobal = indexInLevel + firstIndexOffsetPerLevel[level];\n" " int2 childIndicies = internalNodeChildIndices[internalNodeIndexGlobal];\n" @@ -289,19 +261,26 @@ static const char* parallelLinearBvhCL= \ " int isLeftChildLeaf = isLeafNode(childIndicies.x);\n" " int isRightChildLeaf = isLeafNode(childIndicies.y);\n" " \n" +" //left/RightChildLeafIndex == Rigid body indicies\n" " int leftChildLeafIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1;\n" " int rightChildLeafIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1;\n" " \n" " b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftChildLeafIndex] : out_internalNodeAabbs[leftChildIndex];\n" " b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightChildLeafIndex] : out_internalNodeAabbs[rightChildIndex];\n" " \n" +" //\n" " b3AabbCL internalNodeAabb;\n" " internalNodeAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min);\n" " internalNodeAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max);\n" " out_internalNodeAabbs[internalNodeIndexGlobal] = internalNodeAabb;\n" +" \n" +" //For index range, x == min and y == max; left child always has lower index\n" +" int2 leafIndexRange;\n" +" leafIndexRange.x = (isLeftChildLeaf) ? leftChildIndex : out_internalNodeLeafIndexRanges[leftChildIndex].x;\n" +" leafIndexRange.y = (isRightChildLeaf) ? rightChildIndex : out_internalNodeLeafIndexRanges[rightChildIndex].y;\n" +" \n" +" out_internalNodeLeafIndexRanges[internalNodeIndexGlobal] = leafIndexRange;\n" " }\n" -" \n" -" barrier(CLK_GLOBAL_MEM_FENCE);\n" " }\n" "}\n" "//From sap.cl\n" @@ -316,7 +295,9 @@ static const char* parallelLinearBvhCL= \ "}\n" "//From sap.cl\n" "__kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, \n" -" __global int2* internalNodeChildIndices, __global b3AabbCL* internalNodeAabbs,\n" +" __global int2* internalNodeChildIndices, \n" +" __global b3AabbCL* internalNodeAabbs,\n" +" __global int2* internalNodeLeafIndexRanges,\n" " __global SortDataCL* mortonCodesAndAabbIndices,\n" " __global int* out_numPairs, __global int4* out_overlappingPairs, \n" " int maxPairs, int numQueryAabbs)\n" @@ -326,7 +307,8 @@ static const char* parallelLinearBvhCL= \ " int queryRigidIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" " if(queryRigidIndex >= numQueryAabbs) return;\n" " \n" -" queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value;\n" +" int queryBvhNodeIndex = queryRigidIndex;\n" +" queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value; // fix queryRigidIndex naming for this branch\n" "#else\n" " int queryRigidIndex = get_global_id(0);\n" " if(queryRigidIndex >= numQueryAabbs) return;\n" @@ -347,7 +329,15 @@ static const char* parallelLinearBvhCL= \ " \n" " int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false\n" " int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex);\n" -" \n" +" \n" +" //Optimization - if the node is not a leaf, check whether the highest leaf index of that node\n" +" //is less than the queried node's index to avoid testing each pair twice.\n" +" {\n" +" // fix: produces duplicate pairs\n" +" // int highestLeafIndex = (isLeaf) ? numQueryAabbs : internalNodeLeafIndexRanges[bvhNodeIndex].y;\n" +" // if(highestLeafIndex < queryBvhNodeIndex) continue;\n" +" }\n" +" \n" " //bvhRigidIndex is not used if internal node\n" " int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1;\n" " \n" From e4fbd5332d64940e976500fd5d9dc5ade036eb60 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Sun, 23 Feb 2014 20:40:58 -0800 Subject: [PATCH 004/116] Accelerate GPU raycaster with PLBVH. --- .../GpuDemos/raytrace/RaytracedShadowDemo.cpp | 4 +- .../b3GpuParallelLinearBvh.h | 78 +++++++- .../b3GpuParallelLinearBvhBroadphase.h | 2 +- .../kernels/parallelLinearBvh.cl | 159 ++++++++++++++++ .../kernels/parallelLinearBvhKernels.h | 148 +++++++++++++++ src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp | 170 ++++++++++++++++-- src/Bullet3OpenCL/Raycast/b3GpuRaycast.h | 3 +- .../Raycast/kernels/rayCastKernels.cl | 100 +++++++++++ .../Raycast/kernels/rayCastKernels.h | 97 ++++++++++ .../RigidBody/b3GpuRigidBodyPipeline.cpp | 4 +- 10 files changed, 732 insertions(+), 33 deletions(-) diff --git a/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp b/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp index b114b4511..9596b34e9 100644 --- a/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp +++ b/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp @@ -308,7 +308,7 @@ void GpuRaytraceScene::renderScene2() { B3_PROFILE("cast primary rays"); //m_raycaster->castRaysHost(primaryRays, hits, this->m_data->m_np->getNumRigidBodies(), m_data->m_np->getBodiesCpu(), m_data->m_np->getNumCollidablesGpu(), m_data->m_np->getCollidablesCpu(),m_data->m_np->getInternalData()); - m_raycaster->castRays(primaryRays, hits, this->m_data->m_np->getNumRigidBodies(), m_data->m_np->getBodiesCpu(), m_data->m_np->getNumCollidablesGpu(), m_data->m_np->getCollidablesCpu(), m_data->m_np->getInternalData()); + m_raycaster->castRays(primaryRays, hits, this->m_data->m_np->getNumRigidBodies(), m_data->m_np->getBodiesCpu(), m_data->m_np->getNumCollidablesGpu(), m_data->m_np->getCollidablesCpu(), m_data->m_np->getInternalData(), m_data->m_bp); } @@ -350,7 +350,7 @@ void GpuRaytraceScene::renderScene2() { B3_PROFILE("cast shadow rays"); //m_raycaster->castRaysHost(primaryRays, hits, this->m_data->m_np->getNumRigidBodies(), m_data->m_np->getBodiesCpu(), m_data->m_np->getNumCollidablesGpu(), m_data->m_np->getCollidablesCpu()); - m_raycaster->castRays(shadowRays, shadowHits, this->m_data->m_np->getNumRigidBodies(), m_data->m_np->getBodiesCpu(), m_data->m_np->getNumCollidablesGpu(), m_data->m_np->getCollidablesCpu(), m_data->m_np->getInternalData()); + m_raycaster->castRays(shadowRays, shadowHits, this->m_data->m_np->getNumRigidBodies(), m_data->m_np->getBodiesCpu(), m_data->m_np->getNumCollidablesGpu(), m_data->m_np->getCollidablesCpu(), m_data->m_np->getInternalData(), m_data->m_bp); } { diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index f2199a3cf..84371b0e8 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -18,6 +18,7 @@ subject to the following restrictions: #include "Bullet3OpenCL/BroadphaseCollision/b3SapAabb.h" #include "Bullet3Common/shared/b3Int2.h" #include "Bullet3Common/shared/b3Int4.h" +#include "Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h" #include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" #include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" @@ -59,6 +60,7 @@ class b3GpuParallelLinearBvh cl_kernel m_determineInternalNodeAabbsKernel; cl_kernel m_plbvhCalculateOverlappingPairsKernel; + cl_kernel m_plbvhRayTraverseKernel; b3FillCL m_fill; b3RadixSort32CL m_radixSorter; @@ -79,6 +81,7 @@ class b3GpuParallelLinearBvh b3OpenCLArray m_leafNodeParentNodes; b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key = morton code, m_value == aabb index b3OpenCLArray m_mergedAabb; + b3OpenCLArray m_leafNodeAabbs; public: b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue) : @@ -94,7 +97,8 @@ public: m_internalNodeParentNodes(context, queue), m_leafNodeParentNodes(context, queue), m_mortonCodesAndAabbIndicies(context, queue), - m_mergedAabb(context, queue) + m_mergedAabb(context, queue), + m_leafNodeAabbs(context, queue) { const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; @@ -115,6 +119,8 @@ public: m_plbvhCalculateOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhCalculateOverlappingPairs", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_plbvhCalculateOverlappingPairsKernel); + m_plbvhRayTraverseKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhRayTraverse", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhRayTraverseKernel); } virtual ~b3GpuParallelLinearBvh() @@ -125,6 +131,7 @@ public: clReleaseKernel(m_determineInternalNodeAabbsKernel); clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); + clReleaseKernel(m_plbvhRayTraverseKernel); clReleaseProgram(m_parallelLinearBvhProgram); } @@ -148,8 +155,12 @@ public: m_leafNodeParentNodes.resize(numLeaves); m_mortonCodesAndAabbIndicies.resize(numLeaves); m_mergedAabb.resize(numLeaves); + m_leafNodeAabbs.resize(numLeaves); } + // + m_leafNodeAabbs.copyFromOpenCLArray(worldSpaceAabbs); + //Determine number of levels in the binary tree( numLevels = ceil( log2(numLeaves) ) ) //The number of levels is equivalent to the number of bits needed to uniquely identify each node(including both internal and leaf nodes) int numLevels = 0; @@ -168,7 +179,7 @@ public: if(0) printf("numLeaves, numLevels, mostSignificantBit: %d, %d, %d \n", numLeaves, numLevels, mostSignificantBit); } - //Determine number of nodes per level, use prefix sum to get offsets of each level, and send to GPU + //Determine number of internal nodes per level, use prefix sum to get offsets of each level, and send to GPU { B3_PROFILE("Determine number of nodes per level"); @@ -329,7 +340,7 @@ public: } //For each internal node, check children to get its AABB; start from the - //last level and move towards the root + //last level, which contains the leaves, and move towards the root { B3_PROFILE("Set AABBs"); @@ -416,10 +427,12 @@ public: } } - //Max number of pairs is out_overlappingPairs.size() - //If the number of overlapping pairs is < out_overlappingPairs.size(), the array is resized - void calculateOverlappingPairs(const b3OpenCLArray& worldSpaceAabbs, - b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs) + ///b3GpuParallelLinearBvh::build() must be called before this function. calculateOverlappingPairs() uses + ///the worldSpaceAabbs parameter of b3GpuParallelLinearBvh::build() as the query AABBs. + ///@param out_numPairs If number of pairs exceeds the max number of pairs, this is clamped to the max number. + ///@param out_overlappingPairs The size() of this array is used to determine the max number of pairs. + ///If the number of overlapping pairs is < out_overlappingPairs.size(), out_overlappingPairs is resized. + void calculateOverlappingPairs(b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs) { b3Assert( out_numPairs.size() == 1 ); @@ -431,11 +444,11 @@ public: { B3_PROFILE("PLBVH calculateOverlappingPairs"); - int numQueryAabbs = worldSpaceAabbs.size(); + int numQueryAabbs = m_leafNodeAabbs.size(); b3BufferInfoCL bufferInfo[] = { - b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), @@ -468,6 +481,53 @@ public: out_overlappingPairs.resize(numPairs); } + + ///@param out_numRigidRayPairs Array of length 1; contains the number of detected ray-rigid AABB intersections; + ///this value may be greater than out_rayRigidPairs.size() if out_rayRigidPairs is not large enough. + ///@param out_rayRigidPairs Contains an array of rays intersecting rigid AABBs; x == ray index, y == rigid body index. + ///If the size of this array is insufficient to hold all ray-rigid AABB intersections, additional intersections are discarded. + void testRaysAgainstBvhAabbs(const b3OpenCLArray& rays, + b3OpenCLArray& out_numRayRigidPairs, b3OpenCLArray& out_rayRigidPairs) + { + B3_PROFILE("PLBVH testRaysAgainstBvhAabbs()"); + + int numRays = rays.size(); + int maxRayRigidPairs = out_rayRigidPairs.size(); + + int reset = 0; + out_numRayRigidPairs.copyFromHostPointer(&reset, 1); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + + b3BufferInfoCL( rays.getBufferCL() ), + + b3BufferInfoCL( out_numRayRigidPairs.getBufferCL() ), + b3BufferInfoCL( out_rayRigidPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhRayTraverseKernel, "m_plbvhRayTraverseKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxRayRigidPairs); + launcher.setConst(numRays); + + launcher.launch1D(numRays); + clFinish(m_queue); + + + // + int numRayRigidPairs = -1; + out_numRayRigidPairs.copyToHostPointer(&numRayRigidPairs, 1); + + if(numRayRigidPairs > maxRayRigidPairs) + b3Error("Error running out of rayRigid pairs: numRayRigidPairs = %d, maxRayRigidPairs = %d.\n", numRayRigidPairs, maxRayRigidPairs); + + } }; #endif diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h index 761f4b168..c5b85f4bb 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h @@ -61,7 +61,7 @@ public: // m_overlappingPairsGpu.resize(maxPairs); - m_plbvh.calculateOverlappingPairs(m_aabbsGpu, m_tempNumPairs, m_overlappingPairsGpu); + m_plbvh.calculateOverlappingPairs(m_tempNumPairs, m_overlappingPairsGpu); } virtual void calculateOverlappingPairsHost(int maxPairs) { diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index dc283ac95..3e650c7f9 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -15,6 +15,7 @@ typedef float b3Scalar; typedef float4 b3Vector3; #define b3Max max #define b3Min min +#define b3Sqrt sqrt typedef struct { @@ -388,3 +389,161 @@ __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, } } + +//From rayCastKernels.cl +typedef struct +{ + float4 m_from; + float4 m_to; +} b3RayInfo; + +typedef struct +{ + float m_hitFraction; + int m_hitResult0; + int m_hitResult1; + int m_hitResult2; + float4 m_hitPoint; + float4 m_hitNormal; +} b3RayHit; +//From rayCastKernels.cl + +b3Vector3 b3Vector3_normalize(b3Vector3 v) +{ + b3Vector3 normal = (b3Vector3){v.x, v.y, v.z, 0.f}; + return normalize(normal); //OpenCL normalize == vector4 normalize +} +b3Scalar b3Vector3_length2(b3Vector3 v) { return v.x*v.x + v.y*v.y + v.z*v.z; } +b3Scalar b3Vector3_dot(b3Vector3 a, b3Vector3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; } + + +/** + +int rayIntersectsAabb_optimized(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalizedDirection, b3AabbCL aabb) +{ + // not functional -- need to fix + + //aabb is considered as 3 pairs of 2 planes( {x_min, x_max}, {y_min, y_max}, {z_min, z_max} ) + //t_min is the first intersection, t_max is the second intersection + b3Vector3 inverseRayDirection = (b3Vector3){1.0f, 1.0f, 1.0f, 0.0f} / rayNormalizedDirection; + int4 sign = isless( inverseRayDirection, (b3Vector3){0.0f, 0.0f, 0.0f, 0.0f} ); //isless(x,y) returns (x < y) + + //select(b, a, condition) == condition ? a : b + b3Vector3 t_min = ( select(aabb.m_min, aabb.m_max, sign) - rayFrom ) * inverseRayDirection; + b3Vector3 t_max = ( select(aabb.m_min, aabb.m_max, (int4){1,1,1,1} - sign) - rayFrom ) * inverseRayDirection; + + b3Scalar t_min_final = 0.0f; + b3Scalar t_max_final = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); + + //Must use fmin()/fmax(); if one of the parameters is NaN, then the parameter that is not NaN is returned. + //Behavior of min()/max() with NaNs is undefined. (See OpenCL Specification 1.2 [6.12.2] and [6.12.4]) + //Since the innermost fmin()/fmax() is always not NaN, this should never return NaN + t_min_final = fmax( t_min.z, fmax(t_min.y, fmax(t_min.x, t_min_final)) ); + t_max_final = fmin( t_max.z, fmin(t_max.y, fmin(t_max.x, t_max_final)) ); + + return (t_min_final <= t_max_final); +} +**/ + +void rayPlanePairTest(b3Scalar rayStart, b3Scalar rayNormalizedDirection, + b3Scalar planeMin, b3Scalar planeMax, + b3Scalar* out_t_min, b3Scalar* out_t_max) +{ + if(rayNormalizedDirection < 0.0f) + { + //max is closer, min is farther + *out_t_min = (planeMax - rayStart) / rayNormalizedDirection; + *out_t_max = (planeMin - rayStart) / rayNormalizedDirection; + } + else + { + //min is closer, max is farther + *out_t_min = (planeMin - rayStart) / rayNormalizedDirection; + *out_t_max = (planeMax - rayStart) / rayNormalizedDirection; + } +} +int rayIntersectsAabb(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalizedDirection, b3AabbCL aabb) +{ + b3Scalar t_min_x, t_min_y, t_min_z; + b3Scalar t_max_x, t_max_y, t_max_z; + + rayPlanePairTest(rayFrom.x, rayNormalizedDirection.x, aabb.m_min.x, aabb.m_max.x, &t_min_x, &t_max_x); + rayPlanePairTest(rayFrom.y, rayNormalizedDirection.y, aabb.m_min.y, aabb.m_max.y, &t_min_y, &t_max_y); + rayPlanePairTest(rayFrom.z, rayNormalizedDirection.z, aabb.m_min.z, aabb.m_max.z, &t_min_z, &t_max_z); + + b3Scalar t_min_final = 0.0f; + b3Scalar t_max_final = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); + + t_min_final = fmax( t_min_z, fmax(t_min_y, fmax(t_min_x, t_min_final)) ); + t_max_final = fmin( t_max_z, fmin(t_max_y, fmin(t_max_x, t_max_final)) ); + + return (t_min_final <= t_max_final); +} + +__kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, + __global int2* internalNodeChildIndices, + __global b3AabbCL* internalNodeAabbs, + __global int2* internalNodeLeafIndexRanges, + __global SortDataCL* mortonCodesAndAabbIndices, + + __global b3RayInfo* rays, + + __global int* out_numRayRigidPairs, + __global int2* out_rayRigidPairs, + int maxRayRigidPairs, int numRays) +{ + int rayIndex = get_global_id(0); + if(rayIndex >= numRays) return; + + b3Vector3 rayFrom = rays[rayIndex].m_from; + b3Vector3 rayTo = rays[rayIndex].m_to; + b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rays[rayIndex].m_to - rays[rayIndex].m_from); + + int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; + + //Starting by placing only the root node index, 0, in the stack causes it to be detected as a leaf node(see isLeafNode() in loop) + int stackSize = 2; + stack[0] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].x; + stack[1] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].y; + + while(stackSize) + { + int internalOrLeafNodeIndex = stack[ stackSize - 1 ]; + --stackSize; + + int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false + int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex); + + //bvhRigidIndex is not used if internal node + int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1; + + b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex]; + + if( rayIntersectsAabb(rayFrom, rayTo, rayNormalizedDirection, bvhNodeAabb) ) + { + if(isLeaf) + { + int2 rayRigidPair; + rayRigidPair.x = rayIndex; + rayRigidPair.y = rigidAabbs[bvhRigidIndex].m_minIndices[3]; + + int pairIndex = atomic_inc(out_numRayRigidPairs); + if(pairIndex < maxRayRigidPairs) out_rayRigidPairs[pairIndex] = rayRigidPair; + } + + if(!isLeaf) //Internal node + { + if(stackSize + 2 > B3_PLVBH_TRAVERSE_MAX_STACK_SIZE) + { + //Error + } + else + { + stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].x; + stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].y; + } + } + } + } +} + diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index 6f99d51f2..eb45c0975 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -15,6 +15,7 @@ static const char* parallelLinearBvhCL= \ "typedef float4 b3Vector3;\n" "#define b3Max max\n" "#define b3Min min\n" +"#define b3Sqrt sqrt\n" "typedef struct\n" "{\n" " unsigned int m_key;\n" @@ -372,4 +373,151 @@ static const char* parallelLinearBvhCL= \ " \n" " }\n" "}\n" +"//From rayCastKernels.cl\n" +"typedef struct\n" +"{\n" +" float4 m_from;\n" +" float4 m_to;\n" +"} b3RayInfo;\n" +"typedef struct\n" +"{\n" +" float m_hitFraction;\n" +" int m_hitResult0;\n" +" int m_hitResult1;\n" +" int m_hitResult2;\n" +" float4 m_hitPoint;\n" +" float4 m_hitNormal;\n" +"} b3RayHit;\n" +"//From rayCastKernels.cl\n" +"b3Vector3 b3Vector3_normalize(b3Vector3 v)\n" +"{\n" +" b3Vector3 normal = (b3Vector3){v.x, v.y, v.z, 0.f};\n" +" return normalize(normal); //OpenCL normalize == vector4 normalize\n" +"}\n" +"b3Scalar b3Vector3_length2(b3Vector3 v) { return v.x*v.x + v.y*v.y + v.z*v.z; }\n" +"b3Scalar b3Vector3_dot(b3Vector3 a, b3Vector3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; }\n" +"/**\n" +"int rayIntersectsAabb_optimized(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalizedDirection, b3AabbCL aabb)\n" +"{\n" +" // not functional -- need to fix\n" +" //aabb is considered as 3 pairs of 2 planes( {x_min, x_max}, {y_min, y_max}, {z_min, z_max} )\n" +" //t_min is the first intersection, t_max is the second intersection\n" +" b3Vector3 inverseRayDirection = (b3Vector3){1.0f, 1.0f, 1.0f, 0.0f} / rayNormalizedDirection;\n" +" int4 sign = isless( inverseRayDirection, (b3Vector3){0.0f, 0.0f, 0.0f, 0.0f} ); //isless(x,y) returns (x < y)\n" +" \n" +" //select(b, a, condition) == condition ? a : b\n" +" b3Vector3 t_min = ( select(aabb.m_min, aabb.m_max, sign) - rayFrom ) * inverseRayDirection;\n" +" b3Vector3 t_max = ( select(aabb.m_min, aabb.m_max, (int4){1,1,1,1} - sign) - rayFrom ) * inverseRayDirection;\n" +" b3Scalar t_min_final = 0.0f;\n" +" b3Scalar t_max_final = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" +" \n" +" //Must use fmin()/fmax(); if one of the parameters is NaN, then the parameter that is not NaN is returned. \n" +" //Behavior of min()/max() with NaNs is undefined. (See OpenCL Specification 1.2 [6.12.2] and [6.12.4])\n" +" //Since the innermost fmin()/fmax() is always not NaN, this should never return NaN\n" +" t_min_final = fmax( t_min.z, fmax(t_min.y, fmax(t_min.x, t_min_final)) );\n" +" t_max_final = fmin( t_max.z, fmin(t_max.y, fmin(t_max.x, t_max_final)) );\n" +" \n" +" return (t_min_final <= t_max_final);\n" +"}\n" +"**/\n" +"void rayPlanePairTest(b3Scalar rayStart, b3Scalar rayNormalizedDirection,\n" +" b3Scalar planeMin, b3Scalar planeMax, \n" +" b3Scalar* out_t_min, b3Scalar* out_t_max)\n" +"{\n" +" if(rayNormalizedDirection < 0.0f)\n" +" {\n" +" //max is closer, min is farther\n" +" *out_t_min = (planeMax - rayStart) / rayNormalizedDirection;\n" +" *out_t_max = (planeMin - rayStart) / rayNormalizedDirection;\n" +" }\n" +" else\n" +" {\n" +" //min is closer, max is farther\n" +" *out_t_min = (planeMin - rayStart) / rayNormalizedDirection;\n" +" *out_t_max = (planeMax - rayStart) / rayNormalizedDirection;\n" +" }\n" +"}\n" +"int rayIntersectsAabb(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalizedDirection, b3AabbCL aabb)\n" +"{\n" +" b3Scalar t_min_x, t_min_y, t_min_z;\n" +" b3Scalar t_max_x, t_max_y, t_max_z;\n" +" \n" +" rayPlanePairTest(rayFrom.x, rayNormalizedDirection.x, aabb.m_min.x, aabb.m_max.x, &t_min_x, &t_max_x);\n" +" rayPlanePairTest(rayFrom.y, rayNormalizedDirection.y, aabb.m_min.y, aabb.m_max.y, &t_min_y, &t_max_y);\n" +" rayPlanePairTest(rayFrom.z, rayNormalizedDirection.z, aabb.m_min.z, aabb.m_max.z, &t_min_z, &t_max_z);\n" +" \n" +" b3Scalar t_min_final = 0.0f;\n" +" b3Scalar t_max_final = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" +" \n" +" t_min_final = fmax( t_min_z, fmax(t_min_y, fmax(t_min_x, t_min_final)) );\n" +" t_max_final = fmin( t_max_z, fmin(t_max_y, fmin(t_max_x, t_max_final)) );\n" +" \n" +" return (t_min_final <= t_max_final);\n" +"}\n" +"__kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs,\n" +" __global int2* internalNodeChildIndices, \n" +" __global b3AabbCL* internalNodeAabbs,\n" +" __global int2* internalNodeLeafIndexRanges,\n" +" __global SortDataCL* mortonCodesAndAabbIndices,\n" +" \n" +" __global b3RayInfo* rays,\n" +" \n" +" __global int* out_numRayRigidPairs, \n" +" __global int2* out_rayRigidPairs,\n" +" int maxRayRigidPairs, int numRays)\n" +"{\n" +" int rayIndex = get_global_id(0);\n" +" if(rayIndex >= numRays) return;\n" +" \n" +" b3Vector3 rayFrom = rays[rayIndex].m_from;\n" +" b3Vector3 rayTo = rays[rayIndex].m_to;\n" +" b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rays[rayIndex].m_to - rays[rayIndex].m_from);\n" +" \n" +" int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" +" \n" +" //Starting by placing only the root node index, 0, in the stack causes it to be detected as a leaf node(see isLeafNode() in loop)\n" +" int stackSize = 2;\n" +" stack[0] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].x;\n" +" stack[1] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].y;\n" +" \n" +" while(stackSize)\n" +" {\n" +" int internalOrLeafNodeIndex = stack[ stackSize - 1 ];\n" +" --stackSize;\n" +" \n" +" int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false\n" +" int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex);\n" +" \n" +" //bvhRigidIndex is not used if internal node\n" +" int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1;\n" +" \n" +" b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex];\n" +" \n" +" if( rayIntersectsAabb(rayFrom, rayTo, rayNormalizedDirection, bvhNodeAabb) )\n" +" {\n" +" if(isLeaf)\n" +" {\n" +" int2 rayRigidPair;\n" +" rayRigidPair.x = rayIndex;\n" +" rayRigidPair.y = rigidAabbs[bvhRigidIndex].m_minIndices[3];\n" +" \n" +" int pairIndex = atomic_inc(out_numRayRigidPairs);\n" +" if(pairIndex < maxRayRigidPairs) out_rayRigidPairs[pairIndex] = rayRigidPair;\n" +" }\n" +" \n" +" if(!isLeaf) //Internal node\n" +" {\n" +" if(stackSize + 2 > B3_PLVBH_TRAVERSE_MAX_STACK_SIZE)\n" +" {\n" +" //Error\n" +" }\n" +" else\n" +" {\n" +" stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].x;\n" +" stack[ stackSize++ ] = internalNodeChildIndices[bvhNodeIndex].y;\n" +" }\n" +" }\n" +" }\n" +" }\n" +"}\n" ; diff --git a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp index cb57fbd5b..1ada815c7 100644 --- a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp +++ b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp @@ -8,6 +8,11 @@ #include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" #include "Bullet3OpenCL/ParallelPrimitives/b3OpenCLArray.h" #include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3FillCL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h" +#include "Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h" + #include "Bullet3OpenCL/Raycast/kernels/rayCastKernels.h" @@ -20,7 +25,24 @@ struct b3GpuRaycastInternalData cl_context m_context; cl_device_id m_device; cl_command_queue m_q; - cl_kernel m_raytraceKernel; + cl_kernel m_raytraceKernel; + cl_kernel m_raytracePairsKernel; + cl_kernel m_findRayRigidPairIndexRanges; + + b3GpuParallelLinearBvh* m_plbvh; + b3RadixSort32CL* m_radixSorter; + b3FillCL* m_fill; + + //1 element per ray + b3OpenCLArray* m_gpuRays; + b3OpenCLArray* m_gpuHitResults; + b3OpenCLArray* m_firstRayRigidPairIndexPerRay; + b3OpenCLArray* m_numRayRigidPairsPerRay; + + //1 element per (ray index, rigid index) pair + b3OpenCLArray* m_gpuNumRayRigidPairs; + b3OpenCLArray* m_gpuRayRigidPairs; + int m_test; }; @@ -31,7 +53,19 @@ b3GpuRaycast::b3GpuRaycast(cl_context ctx,cl_device_id device, cl_command_queue m_data->m_device = device; m_data->m_q = q; m_data->m_raytraceKernel = 0; + m_data->m_raytracePairsKernel = 0; + m_data->m_findRayRigidPairIndexRanges = 0; + m_data->m_plbvh = new b3GpuParallelLinearBvh(ctx, device, q); + m_data->m_radixSorter = new b3RadixSort32CL(ctx, device, q); + m_data->m_fill = new b3FillCL(ctx, device, q); + + m_data->m_gpuRays = new b3OpenCLArray(ctx, q); + m_data->m_gpuHitResults = new b3OpenCLArray(ctx, q); + m_data->m_firstRayRigidPairIndexPerRay = new b3OpenCLArray(ctx, q); + m_data->m_numRayRigidPairsPerRay = new b3OpenCLArray(ctx, q); + m_data->m_gpuNumRayRigidPairs = new b3OpenCLArray(ctx, q); + m_data->m_gpuRayRigidPairs = new b3OpenCLArray(ctx, q); { cl_int errNum=0; @@ -39,6 +73,10 @@ b3GpuRaycast::b3GpuRaycast(cl_context ctx,cl_device_id device, cl_command_queue b3Assert(errNum==CL_SUCCESS); m_data->m_raytraceKernel = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,rayCastKernelCL, "rayCastKernel",&errNum,prog); b3Assert(errNum==CL_SUCCESS); + m_data->m_raytracePairsKernel = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,rayCastKernelCL, "rayCastPairsKernel",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); + m_data->m_findRayRigidPairIndexRanges = b3OpenCLUtils::compileCLKernelFromString(m_data->m_context, m_data->m_device,rayCastKernelCL, "findRayRigidPairIndexRanges",&errNum,prog); + b3Assert(errNum==CL_SUCCESS); clReleaseProgram(prog); } @@ -48,6 +86,20 @@ b3GpuRaycast::b3GpuRaycast(cl_context ctx,cl_device_id device, cl_command_queue b3GpuRaycast::~b3GpuRaycast() { clReleaseKernel(m_data->m_raytraceKernel); + clReleaseKernel(m_data->m_raytracePairsKernel); + clReleaseKernel(m_data->m_findRayRigidPairIndexRanges); + + delete m_data->m_plbvh; + delete m_data->m_radixSorter; + delete m_data->m_fill; + + delete m_data->m_gpuRays; + delete m_data->m_gpuHitResults; + delete m_data->m_firstRayRigidPairIndexPerRay; + delete m_data->m_numRayRigidPairsPerRay; + delete m_data->m_gpuNumRayRigidPairs; + delete m_data->m_gpuRayRigidPairs; + delete m_data; } @@ -206,27 +258,32 @@ void b3GpuRaycast::castRaysHost(const b3AlignedObjectArray& rays, b3A } ///todo: add some acceleration structure (AABBs, tree etc) void b3GpuRaycast::castRays(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults, - int numBodies,const struct b3RigidBodyData* bodies, int numCollidables, const struct b3Collidable* collidables, const struct b3GpuNarrowPhaseInternalData* narrowphaseData) + int numBodies,const struct b3RigidBodyData* bodies, int numCollidables, const struct b3Collidable* collidables, + const struct b3GpuNarrowPhaseInternalData* narrowphaseData, class b3GpuBroadphaseInterface* broadphase) { - //castRaysHost(rays,hitResults,numBodies,bodies,numCollidables,collidables,narrowphaseData); B3_PROFILE("castRaysGPU"); - - b3OpenCLArray gpuRays(m_data->m_context,m_data->m_q); - b3OpenCLArray gpuHitResults(m_data->m_context,m_data->m_q); - + { B3_PROFILE("raycast copyFromHost"); - gpuRays.copyFromHost(rays); - - - gpuHitResults.resize(hitResults.size()); - gpuHitResults.copyFromHost(hitResults); + m_data->m_gpuRays->copyFromHost(rays); + m_data->m_gpuHitResults->copyFromHost(hitResults); + } - - + + int numRays = hitResults.size(); + { + m_data->m_firstRayRigidPairIndexPerRay->resize(numRays); + m_data->m_numRayRigidPairsPerRay->resize(numRays); + + m_data->m_gpuNumRayRigidPairs->resize(1); + m_data->m_gpuRayRigidPairs->resize(numRays * 16); + } + //run kernel + const bool USE_BRUTE_FORCE_RAYCAST = false; + if(USE_BRUTE_FORCE_RAYCAST) { B3_PROFILE("raycast launch1D"); @@ -234,8 +291,8 @@ void b3GpuRaycast::castRays(const b3AlignedObjectArray& rays, b3Align int numRays = rays.size(); launcher.setConst(numRays); - launcher.setBuffer(gpuRays.getBufferCL()); - launcher.setBuffer(gpuHitResults.getBufferCL()); + launcher.setBuffer(m_data->m_gpuRays->getBufferCL()); + launcher.setBuffer(m_data->m_gpuHitResults->getBufferCL()); launcher.setConst(numBodies); launcher.setBuffer(narrowphaseData->m_bodyBufferGPU->getBufferCL()); @@ -246,11 +303,90 @@ void b3GpuRaycast::castRays(const b3AlignedObjectArray& rays, b3Align launcher.launch1D(numRays); clFinish(m_data->m_q); } + else + { + //printf("broadphase->getAllAabbsGPU().size(): %d \n", broadphase->getAllAabbsGPU().size()); + m_data->m_plbvh->build( broadphase->getAllAabbsGPU() ); + + m_data->m_plbvh->testRaysAgainstBvhAabbs(*m_data->m_gpuRays, *m_data->m_gpuNumRayRigidPairs, *m_data->m_gpuRayRigidPairs); + + int numRayRigidPairs = -1; + m_data->m_gpuNumRayRigidPairs->copyToHostPointer(&numRayRigidPairs, 1); + if( numRayRigidPairs > m_data->m_gpuRayRigidPairs->size() ) + { + numRayRigidPairs = m_data->m_gpuRayRigidPairs->size(); + m_data->m_gpuNumRayRigidPairs->copyFromHostPointer(&numRayRigidPairs, 1); + } + + m_data->m_gpuRayRigidPairs->resize(numRayRigidPairs); //Radix sort needs b3OpenCLArray::size() to be correct + + //Sort ray-rigid pairs by ray index + { + B3_PROFILE("sort ray-rigid pairs"); + m_data->m_radixSorter->execute( *reinterpret_cast< b3OpenCLArray* >(m_data->m_gpuRayRigidPairs) ); + } + + //detect start,count of each ray pair + { + B3_PROFILE("detect ray-rigid pair index ranges"); + + { + B3_PROFILE("reset ray-rigid pair index ranges"); + + m_data->m_fill->execute(*m_data->m_firstRayRigidPairIndexPerRay, numRayRigidPairs, numRays); //atomic_min used to find first index + m_data->m_fill->execute(*m_data->m_numRayRigidPairsPerRay, 0, numRays); + clFinish(m_data->m_q); + } + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_data->m_gpuRayRigidPairs->getBufferCL() ), + + b3BufferInfoCL( m_data->m_firstRayRigidPairIndexPerRay->getBufferCL() ), + b3BufferInfoCL( m_data->m_numRayRigidPairsPerRay->getBufferCL() ) + }; + + b3LauncherCL launcher(m_data->m_q, m_data->m_findRayRigidPairIndexRanges, "m_findRayRigidPairIndexRanges"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numRayRigidPairs); + + launcher.launch1D(numRayRigidPairs); + clFinish(m_data->m_q); + } + + { + B3_PROFILE("ray-rigid intersection"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_data->m_gpuRays->getBufferCL() ), + b3BufferInfoCL( m_data->m_gpuHitResults->getBufferCL() ), + b3BufferInfoCL( m_data->m_firstRayRigidPairIndexPerRay->getBufferCL() ), + b3BufferInfoCL( m_data->m_numRayRigidPairsPerRay->getBufferCL() ), + + b3BufferInfoCL( narrowphaseData->m_bodyBufferGPU->getBufferCL() ), + b3BufferInfoCL( narrowphaseData->m_collidablesGPU->getBufferCL() ), + b3BufferInfoCL( narrowphaseData->m_convexFacesGPU->getBufferCL() ), + b3BufferInfoCL( narrowphaseData->m_convexPolyhedraGPU->getBufferCL() ), + + b3BufferInfoCL( m_data->m_gpuRayRigidPairs->getBufferCL() ) + }; + + b3LauncherCL launcher(m_data->m_q, m_data->m_raytracePairsKernel, "m_raytracePairsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numRays); + + launcher.launch1D(numRays); + clFinish(m_data->m_q); + } + } + + //copy results { B3_PROFILE("raycast copyToHost"); - gpuHitResults.copyToHost(hitResults); + m_data->m_gpuHitResults->copyToHost(hitResults); } } \ No newline at end of file diff --git a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.h b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.h index 8b0cbd0be..3a5cf44b7 100644 --- a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.h +++ b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.h @@ -23,8 +23,7 @@ public: void castRays(const b3AlignedObjectArray& rays, b3AlignedObjectArray& hitResults, int numBodies,const struct b3RigidBodyData* bodies, int numCollidables, const struct b3Collidable* collidables, - const struct b3GpuNarrowPhaseInternalData* narrowphaseData - ); + const struct b3GpuNarrowPhaseInternalData* narrowphaseData, class b3GpuBroadphaseInterface* broadphase); diff --git a/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.cl b/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.cl index acf0bdd32..e72d96876 100644 --- a/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.cl +++ b/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.cl @@ -337,3 +337,103 @@ __kernel void rayCastKernel( } } + + +__kernel void findRayRigidPairIndexRanges(__global int2* rayRigidPairs, + __global int* out_firstRayRigidPairIndexPerRay, + __global int* out_numRayRigidPairsPerRay, + int numRayRigidPairs) +{ + int rayRigidPairIndex = get_global_id(0); + if (rayRigidPairIndex >= numRayRigidPairs) return; + + int rayIndex = rayRigidPairs[rayRigidPairIndex].x; + + atomic_min(&out_firstRayRigidPairIndexPerRay[rayIndex], rayRigidPairIndex); + atomic_inc(&out_numRayRigidPairsPerRay[rayIndex]); +} + +__kernel void rayCastPairsKernel(const __global b3RayInfo* rays, + __global b3RayHit* hitResults, + __global int* firstRayRigidPairIndexPerRay, + __global int* numRayRigidPairsPerRay, + + __global Body* bodies, + __global Collidable* collidables, + __global const b3GpuFace* faces, + __global const ConvexPolyhedronCL* convexShapes, + + __global int2* rayRigidPairs, + int numRays) +{ + int i = get_global_id(0); + if (i >= numRays) return; + + float4 rayFrom = rays[i].m_from; + float4 rayTo = rays[i].m_to; + + hitResults[i].m_hitFraction = 1.f; + + float hitFraction = 1.f; + float4 hitPoint; + float4 hitNormal; + int hitBodyIndex = -1; + + // + for(int pair = 0; pair < numRayRigidPairsPerRay[i]; ++pair) + { + int rayRigidPairIndex = pair + firstRayRigidPairIndexPerRay[i]; + int b = rayRigidPairs[rayRigidPairIndex].y; + + if (hitResults[i].m_hitResult2 == b) continue; + + Body body = bodies[b]; + Collidable rigidCollidable = collidables[body.m_collidableIdx]; + + float4 pos = body.m_pos; + float4 orn = body.m_quat; + + if (rigidCollidable.m_shapeType == SHAPE_CONVEX_HULL) + { + float4 invPos = (float4)(0,0,0,0); + float4 invOrn = (float4)(0,0,0,0); + float4 rayFromLocal = (float4)(0,0,0,0); + float4 rayToLocal = (float4)(0,0,0,0); + invOrn = qtInvert(orn); + invPos = qtRotate(invOrn, -pos); + rayFromLocal = qtRotate( invOrn, rayFrom ) + invPos; + rayToLocal = qtRotate( invOrn, rayTo) + invPos; + rayFromLocal.w = 0.f; + rayToLocal.w = 0.f; + int numFaces = convexShapes[rigidCollidable.m_shapeIndex].m_numFaces; + int faceOffset = convexShapes[rigidCollidable.m_shapeIndex].m_faceOffset; + + if (numFaces && rayConvex(rayFromLocal, rayToLocal, numFaces, faceOffset,faces, &hitFraction, &hitNormal)) + { + hitBodyIndex = b; + hitPoint = setInterpolate3(rayFrom, rayTo, hitFraction); + } + } + + if (rigidCollidable.m_shapeType == SHAPE_SPHERE) + { + float radius = rigidCollidable.m_radius; + + if (sphere_intersect(pos, radius, rayFrom, rayTo, &hitFraction)) + { + hitBodyIndex = b; + hitPoint = setInterpolate3(rayFrom, rayTo, hitFraction); + hitNormal = (float4) (hitPoint - bodies[b].m_pos); + } + } + } + + if (hitBodyIndex >= 0) + { + hitResults[i].m_hitFraction = hitFraction; + hitResults[i].m_hitPoint = hitPoint; + hitResults[i].m_hitNormal = normalize(hitNormal); + hitResults[i].m_hitResult0 = hitBodyIndex; + } + +} diff --git a/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.h b/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.h index 159da7c17..6257909a4 100644 --- a/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.h +++ b/src/Bullet3OpenCL/Raycast/kernels/rayCastKernels.h @@ -281,4 +281,101 @@ static const char* rayCastKernelCL= \ " hitResults[i].m_hitResult0 = hitBodyIndex;\n" " }\n" "}\n" +"__kernel void findRayRigidPairIndexRanges(__global int2* rayRigidPairs, \n" +" __global int* out_firstRayRigidPairIndexPerRay,\n" +" __global int* out_numRayRigidPairsPerRay,\n" +" int numRayRigidPairs)\n" +"{\n" +" int rayRigidPairIndex = get_global_id(0);\n" +" if (rayRigidPairIndex >= numRayRigidPairs) return;\n" +" \n" +" int rayIndex = rayRigidPairs[rayRigidPairIndex].x;\n" +" \n" +" atomic_min(&out_firstRayRigidPairIndexPerRay[rayIndex], rayRigidPairIndex);\n" +" atomic_inc(&out_numRayRigidPairsPerRay[rayIndex]);\n" +"}\n" +"__kernel void rayCastPairsKernel(const __global b3RayInfo* rays, \n" +" __global b3RayHit* hitResults, \n" +" __global int* firstRayRigidPairIndexPerRay,\n" +" __global int* numRayRigidPairsPerRay,\n" +" \n" +" __global Body* bodies,\n" +" __global Collidable* collidables,\n" +" __global const b3GpuFace* faces,\n" +" __global const ConvexPolyhedronCL* convexShapes,\n" +" \n" +" __global int2* rayRigidPairs,\n" +" int numRays)\n" +"{\n" +" int i = get_global_id(0);\n" +" if (i >= numRays) return;\n" +" \n" +" float4 rayFrom = rays[i].m_from;\n" +" float4 rayTo = rays[i].m_to;\n" +" \n" +" hitResults[i].m_hitFraction = 1.f;\n" +" \n" +" float hitFraction = 1.f;\n" +" float4 hitPoint;\n" +" float4 hitNormal;\n" +" int hitBodyIndex = -1;\n" +" \n" +" //\n" +" for(int pair = 0; pair < numRayRigidPairsPerRay[i]; ++pair)\n" +" {\n" +" int rayRigidPairIndex = pair + firstRayRigidPairIndexPerRay[i];\n" +" int b = rayRigidPairs[rayRigidPairIndex].y;\n" +" \n" +" if (hitResults[i].m_hitResult2 == b) continue;\n" +" \n" +" Body body = bodies[b];\n" +" Collidable rigidCollidable = collidables[body.m_collidableIdx];\n" +" \n" +" float4 pos = body.m_pos;\n" +" float4 orn = body.m_quat;\n" +" \n" +" if (rigidCollidable.m_shapeType == SHAPE_CONVEX_HULL)\n" +" {\n" +" float4 invPos = (float4)(0,0,0,0);\n" +" float4 invOrn = (float4)(0,0,0,0);\n" +" float4 rayFromLocal = (float4)(0,0,0,0);\n" +" float4 rayToLocal = (float4)(0,0,0,0);\n" +" invOrn = qtInvert(orn);\n" +" invPos = qtRotate(invOrn, -pos);\n" +" rayFromLocal = qtRotate( invOrn, rayFrom ) + invPos;\n" +" rayToLocal = qtRotate( invOrn, rayTo) + invPos;\n" +" rayFromLocal.w = 0.f;\n" +" rayToLocal.w = 0.f;\n" +" int numFaces = convexShapes[rigidCollidable.m_shapeIndex].m_numFaces;\n" +" int faceOffset = convexShapes[rigidCollidable.m_shapeIndex].m_faceOffset;\n" +" \n" +" if (numFaces && rayConvex(rayFromLocal, rayToLocal, numFaces, faceOffset,faces, &hitFraction, &hitNormal))\n" +" {\n" +" hitBodyIndex = b;\n" +" hitPoint = setInterpolate3(rayFrom, rayTo, hitFraction);\n" +" }\n" +" }\n" +" \n" +" if (rigidCollidable.m_shapeType == SHAPE_SPHERE)\n" +" {\n" +" float radius = rigidCollidable.m_radius;\n" +" \n" +" if (sphere_intersect(pos, radius, rayFrom, rayTo, &hitFraction))\n" +" {\n" +" hitBodyIndex = b;\n" +" hitPoint = setInterpolate3(rayFrom, rayTo, hitFraction);\n" +" hitNormal = (float4) (hitPoint - bodies[b].m_pos);\n" +" }\n" +" }\n" +" }\n" +" \n" +" if (hitBodyIndex >= 0)\n" +" {\n" +" hitResults[i].m_hitFraction = hitFraction;\n" +" hitResults[i].m_hitPoint = hitPoint;\n" +" hitResults[i].m_hitNormal = normalize(hitNormal);\n" +" hitResults[i].m_hitResult0 = hitBodyIndex;\n" +" }\n" +" \n" +"}\n" ; diff --git a/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp b/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp index e1665f406..783e44306 100644 --- a/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp +++ b/src/Bullet3OpenCL/RigidBody/b3GpuRigidBodyPipeline.cpp @@ -703,6 +703,6 @@ void b3GpuRigidBodyPipeline::castRays(const b3AlignedObjectArray& ray { this->m_data->m_raycaster->castRays(rays,hitResults, getNumBodies(),this->m_data->m_narrowphase->getBodiesCpu(), - m_data->m_narrowphase->getNumCollidablesGpu(), m_data->m_narrowphase->getCollidablesCpu(), m_data->m_narrowphase->getInternalData() - ); + m_data->m_narrowphase->getNumCollidablesGpu(), m_data->m_narrowphase->getCollidablesCpu(), + m_data->m_narrowphase->getInternalData(), m_data->m_broadphaseSap); } From c782f4976c73021a9ec13a9f3977a34c07c23ab1 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Mon, 24 Feb 2014 23:50:20 -0800 Subject: [PATCH 005/116] Various minor PLBVH related changes. -Use most significant bit instead of negative for internal nodes. -Explicitly store root node index, so that it does not have to be 0. -Check the root node first in PLBVH traversal. -Fix rigid body clipping in RaytracedShadowDemo. --- .../GpuDemos/raytrace/RaytracedShadowDemo.cpp | 4 ++ .../b3GpuParallelLinearBvh.h | 16 +++++++ .../kernels/parallelLinearBvh.cl | 44 +++++++------------ .../kernels/parallelLinearBvhKernels.h | 41 ++++++----------- src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp | 2 +- 5 files changed, 49 insertions(+), 58 deletions(-) diff --git a/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp b/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp index 9596b34e9..5c75d12e0 100644 --- a/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp +++ b/Demos3/GpuDemos/raytrace/RaytracedShadowDemo.cpp @@ -187,6 +187,10 @@ void GpuRaytraceScene::renderScene() void GpuRaytraceScene::renderScene2() { + //If using the BVH to accelerate raycasting, the AABBs need to be updated or else they will + //not match the actual rigid body positions after integration. The result is that rigid bodies + //are not drawn or appear clipped, especially if they are moving quickly. + m_data->m_rigidBodyPipeline->setupGpuAabbsFull(); // GpuBoxPlaneScene::renderScene(); // return; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index 84371b0e8..29c3e14bb 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -65,6 +65,9 @@ class b3GpuParallelLinearBvh b3FillCL m_fill; b3RadixSort32CL m_radixSorter; + // + b3OpenCLArray m_rootNodeIndex; + //1 element per level in the tree b3AlignedObjectArray m_numNodesPerLevelCpu; //Level 0(m_numNodesPerLevelCpu[0]) is the root, last level contains the leaf nodes b3AlignedObjectArray m_firstIndexOffsetPerLevelCpu; //Contains the index/offset of the first node in that level @@ -89,12 +92,16 @@ public: m_fill(context, device, queue), m_radixSorter(context, device, queue), + m_rootNodeIndex(context, queue), + m_numNodesPerLevelGpu(context, queue), m_firstIndexOffsetPerLevelGpu(context, queue), + m_internalNodeAabbs(context, queue), m_internalNodeLeafIndexRanges(context, queue), m_internalNodeChildNodes(context, queue), m_internalNodeParentNodes(context, queue), + m_leafNodeParentNodes(context, queue), m_mortonCodesAndAabbIndicies(context, queue), m_mergedAabb(context, queue), @@ -147,6 +154,8 @@ public: // { + m_rootNodeIndex.resize(1); + m_internalNodeAabbs.resize(numInternalNodes); m_internalNodeLeafIndexRanges.resize(numInternalNodes); m_internalNodeChildNodes.resize(numInternalNodes); @@ -309,6 +318,9 @@ public: //Construct binary tree; find the children of each internal node, and assign parent nodes { B3_PROFILE("Construct binary tree"); + + const int ROOT_NODE_INDEX = 0x80000000; //Default root index is 0, most significant bit is set to indicate internal node + m_rootNodeIndex.copyFromHostPointer(&ROOT_NODE_INDEX, 1); b3BufferInfoCL bufferInfo[] = { @@ -450,6 +462,7 @@ public: { b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), @@ -500,6 +513,9 @@ public: b3BufferInfoCL bufferInfo[] = { b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + + + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index 3e650c7f9..40eabfd6c 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -148,17 +148,13 @@ __kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabb } #define B3_PLVBH_TRAVERSE_MAX_STACK_SIZE 128 -#define B3_PLBVH_ROOT_NODE_MARKER -1 //Used to indicate that the (root) node has no parent -#define B3_PLBVH_ROOT_NODE_INDEX 0 -//For elements of internalNodeChildIndices(int2), the negative bit determines whether it is a leaf or internal node. -//Positive index == leaf node, while negative index == internal node (remove negative sign to get index). -// -//Since the root internal node is at index 0, no internal nodes should reference it as a child, -//and so index 0 is always used to indicate a leaf node. -int isLeafNode(int index) { return (index >= 0); } -int getIndexWithInternalNodeMarkerRemoved(int index) { return (index >= 0) ? index : -index; } -int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : -index; } +//The most significant bit(0x80000000) of a int32 is used to distinguish between leaf and internal nodes. +//If it is set, then the index is for an internal node; otherwise, it is a leaf node. +//In both cases, the bit should be cleared to access the index. +int isLeafNode(int index) { return (index >> 31 == 0); } +int getIndexWithInternalNodeMarkerRemoved(int index) { return index & (~0x80000000); } +int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : (index | 0x80000000); } __kernel void constructBinaryTree(__global int* firstIndexOffsetPerLevel, __global int* numNodesPerLevel, @@ -310,9 +306,12 @@ bool TestAabbAgainstAabb2(const b3AabbCL* aabb1, const b3AabbCL* aabb2) //From sap.cl __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, + + __global int* rootNodeIndex, __global int2* internalNodeChildIndices, __global b3AabbCL* internalNodeAabbs, __global int2* internalNodeLeafIndexRanges, + __global SortDataCL* mortonCodesAndAabbIndices, __global int* out_numPairs, __global int4* out_overlappingPairs, int maxPairs, int numQueryAabbs) @@ -333,10 +332,8 @@ __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; - //Starting by placing only the root node index, 0, in the stack causes it to be detected as a leaf node(see isLeafNode() in loop) - int stackSize = 2; - stack[0] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].x; - stack[1] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].y; + int stackSize = 1; + stack[0] = *rootNodeIndex; while(stackSize) { @@ -396,16 +393,6 @@ typedef struct float4 m_from; float4 m_to; } b3RayInfo; - -typedef struct -{ - float m_hitFraction; - int m_hitResult0; - int m_hitResult1; - int m_hitResult2; - float4 m_hitPoint; - float4 m_hitNormal; -} b3RayHit; //From rayCastKernels.cl b3Vector3 b3Vector3_normalize(b3Vector3 v) @@ -481,6 +468,8 @@ int rayIntersectsAabb(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalize } __kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, + + __global int* rootNodeIndex, __global int2* internalNodeChildIndices, __global b3AabbCL* internalNodeAabbs, __global int2* internalNodeLeafIndexRanges, @@ -501,10 +490,8 @@ __kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; - //Starting by placing only the root node index, 0, in the stack causes it to be detected as a leaf node(see isLeafNode() in loop) - int stackSize = 2; - stack[0] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].x; - stack[1] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].y; + int stackSize = 1; + stack[0] = *rootNodeIndex; while(stackSize) { @@ -518,7 +505,6 @@ __kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1; b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex]; - if( rayIntersectsAabb(rayFrom, rayTo, rayNormalizedDirection, bvhNodeAabb) ) { if(isLeaf) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index eb45c0975..c83783901 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -141,16 +141,12 @@ static const char* parallelLinearBvhCL= \ " out_mortonCodesAndAabbIndices[leafNodeIndex] = mortonCodeIndexPair;\n" "}\n" "#define B3_PLVBH_TRAVERSE_MAX_STACK_SIZE 128\n" -"#define B3_PLBVH_ROOT_NODE_MARKER -1 //Used to indicate that the (root) node has no parent \n" -"#define B3_PLBVH_ROOT_NODE_INDEX 0\n" -"//For elements of internalNodeChildIndices(int2), the negative bit determines whether it is a leaf or internal node.\n" -"//Positive index == leaf node, while negative index == internal node (remove negative sign to get index).\n" -"//\n" -"//Since the root internal node is at index 0, no internal nodes should reference it as a child,\n" -"//and so index 0 is always used to indicate a leaf node.\n" -"int isLeafNode(int index) { return (index >= 0); }\n" -"int getIndexWithInternalNodeMarkerRemoved(int index) { return (index >= 0) ? index : -index; }\n" -"int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : -index; }\n" +"//The most significant bit(0x80000000) of a int32 is used to distinguish between leaf and internal nodes.\n" +"//If it is set, then the index is for an internal node; otherwise, it is a leaf node. \n" +"//In both cases, the bit should be cleared to access the index.\n" +"int isLeafNode(int index) { return (index >> 31 == 0); }\n" +"int getIndexWithInternalNodeMarkerRemoved(int index) { return index & (~0x80000000); }\n" +"int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : (index | 0x80000000); }\n" "__kernel void constructBinaryTree(__global int* firstIndexOffsetPerLevel,\n" " __global int* numNodesPerLevel,\n" " __global int2* out_internalNodeChildIndices, \n" @@ -296,9 +292,11 @@ static const char* parallelLinearBvhCL= \ "}\n" "//From sap.cl\n" "__kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, \n" +" __global int* rootNodeIndex, \n" " __global int2* internalNodeChildIndices, \n" " __global b3AabbCL* internalNodeAabbs,\n" " __global int2* internalNodeLeafIndexRanges,\n" +" \n" " __global SortDataCL* mortonCodesAndAabbIndices,\n" " __global int* out_numPairs, __global int4* out_overlappingPairs, \n" " int maxPairs, int numQueryAabbs)\n" @@ -318,10 +316,8 @@ static const char* parallelLinearBvhCL= \ " \n" " int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" " \n" -" //Starting by placing only the root node index, 0, in the stack causes it to be detected as a leaf node(see isLeafNode() in loop)\n" -" int stackSize = 2;\n" -" stack[0] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].x;\n" -" stack[1] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].y;\n" +" int stackSize = 1;\n" +" stack[0] = *rootNodeIndex;\n" " \n" " while(stackSize)\n" " {\n" @@ -379,15 +375,6 @@ static const char* parallelLinearBvhCL= \ " float4 m_from;\n" " float4 m_to;\n" "} b3RayInfo;\n" -"typedef struct\n" -"{\n" -" float m_hitFraction;\n" -" int m_hitResult0;\n" -" int m_hitResult1;\n" -" int m_hitResult2;\n" -" float4 m_hitPoint;\n" -" float4 m_hitNormal;\n" -"} b3RayHit;\n" "//From rayCastKernels.cl\n" "b3Vector3 b3Vector3_normalize(b3Vector3 v)\n" "{\n" @@ -455,6 +442,7 @@ static const char* parallelLinearBvhCL= \ " return (t_min_final <= t_max_final);\n" "}\n" "__kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs,\n" +" __global int* rootNodeIndex, \n" " __global int2* internalNodeChildIndices, \n" " __global b3AabbCL* internalNodeAabbs,\n" " __global int2* internalNodeLeafIndexRanges,\n" @@ -475,10 +463,8 @@ static const char* parallelLinearBvhCL= \ " \n" " int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" " \n" -" //Starting by placing only the root node index, 0, in the stack causes it to be detected as a leaf node(see isLeafNode() in loop)\n" -" int stackSize = 2;\n" -" stack[0] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].x;\n" -" stack[1] = internalNodeChildIndices[B3_PLBVH_ROOT_NODE_INDEX].y;\n" +" int stackSize = 1;\n" +" stack[0] = *rootNodeIndex;\n" " \n" " while(stackSize)\n" " {\n" @@ -492,7 +478,6 @@ static const char* parallelLinearBvhCL= \ " int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1;\n" " \n" " b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex];\n" -" \n" " if( rayIntersectsAabb(rayFrom, rayTo, rayNormalizedDirection, bvhNodeAabb) )\n" " {\n" " if(isLeaf)\n" diff --git a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp index 1ada815c7..686a7f835 100644 --- a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp +++ b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp @@ -41,7 +41,7 @@ struct b3GpuRaycastInternalData //1 element per (ray index, rigid index) pair b3OpenCLArray* m_gpuNumRayRigidPairs; - b3OpenCLArray* m_gpuRayRigidPairs; + b3OpenCLArray* m_gpuRayRigidPairs; //x == ray index, y == rigid index int m_test; }; From fe12ad9c9b67fa39a17a1d6e94a3788222876461 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Wed, 26 Feb 2014 14:56:43 -0800 Subject: [PATCH 006/116] Fix PLBVH with 0/1 nodes, fix optimized ray-AABB intersect. --- .../b3GpuParallelLinearBvh.h | 92 ++++--------------- .../kernels/parallelLinearBvh.cl | 81 ++++++---------- .../kernels/parallelLinearBvhKernels.h | 74 +++++---------- 3 files changed, 69 insertions(+), 178 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index 29c3e14bb..81d455044 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -107,6 +107,9 @@ public: m_mergedAabb(context, queue), m_leafNodeAabbs(context, queue) { + m_rootNodeIndex.resize(1); + + // const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; const char* kernelSource = parallelLinearBvhCL; //parallelLinearBvhCL.h @@ -150,12 +153,18 @@ public: int numLeaves = worldSpaceAabbs.size(); //Number of leaves in the BVH == Number of rigid body AABBs int numInternalNodes = numLeaves - 1; - if(numLeaves < 2) return; - + // + m_leafNodeAabbs.copyFromOpenCLArray(worldSpaceAabbs); + + if(numLeaves < 2) + { + int rootNodeIndex = numLeaves - 1; + m_rootNodeIndex.copyFromHostPointer(&rootNodeIndex, 1); + return; + } + // { - m_rootNodeIndex.resize(1); - m_internalNodeAabbs.resize(numInternalNodes); m_internalNodeLeafIndexRanges.resize(numInternalNodes); m_internalNodeChildNodes.resize(numInternalNodes); @@ -164,12 +173,8 @@ public: m_leafNodeParentNodes.resize(numLeaves); m_mortonCodesAndAabbIndicies.resize(numLeaves); m_mergedAabb.resize(numLeaves); - m_leafNodeAabbs.resize(numLeaves); } - // - m_leafNodeAabbs.copyFromOpenCLArray(worldSpaceAabbs); - //Determine number of levels in the binary tree( numLevels = ceil( log2(numLeaves) ) ) //The number of levels is equivalent to the number of bits needed to uniquely identify each node(including both internal and leaf nodes) int numLevels = 0; @@ -184,8 +189,6 @@ public: //If the number of nodes is not a power of 2(as in, can be expressed as 2^N where N is an integer), then there is 1 additional level if( ~(1 << mostSignificantBit) & numLeaves ) numLevels++; - - if(0) printf("numLeaves, numLevels, mostSignificantBit: %d, %d, %d \n", numLeaves, numLevels, mostSignificantBit); } //Determine number of internal nodes per level, use prefix sum to get offsets of each level, and send to GPU @@ -230,18 +233,6 @@ public: m_firstIndexOffsetPerLevelCpu[i] -= m_numNodesPerLevelCpu[i]; } - if(0) - { - int numInternalNodes = 0; - for(int i = 0; i < numLevels; ++i) - if(i < numLevels - 1) numInternalNodes += m_numNodesPerLevelCpu[i]; - printf("numInternalNodes: %d\n", numInternalNodes); - - for(int i = 0; i < numLevels; ++i) - printf("numNodes, offset[%d]: %d, %d \n", i, m_numNodesPerLevelCpu[i], m_firstIndexOffsetPerLevelCpu[i]); - printf("\n"); - } - //Copy to GPU m_numNodesPerLevelGpu.copyFromHost(m_numNodesPerLevelCpu, false); m_firstIndexOffsetPerLevelGpu.copyFromHost(m_firstIndexOffsetPerLevelCpu, false); @@ -338,17 +329,6 @@ public: launcher.launch1D(numInternalNodes); clFinish(m_queue); - - if(0) - { - static b3AlignedObjectArray internalNodeChildNodes; - m_internalNodeChildNodes.copyToHost(internalNodeChildNodes, false); - clFinish(m_queue); - - for(int i = 0; i < numInternalNodes; ++i) - printf("ch[%d]: %d, %d\n", i, internalNodeChildNodes[i].x, internalNodeChildNodes[i].y); - printf("\n"); - } } //For each internal node, check children to get its AABB; start from the @@ -395,47 +375,6 @@ public: launcher.launch1D(numLeaves); } clFinish(m_queue); - - if(0) - { - static b3AlignedObjectArray leafIndexRanges; - m_internalNodeLeafIndexRanges.copyToHost(leafIndexRanges, false); - clFinish(m_queue); - - for(int i = 0; i < numInternalNodes; ++i) - //if(leafIndexRanges[i].x == -1 || leafIndexRanges[i].y == -1) - printf("leafIndexRanges[%d]: %d, %d\n", i, leafIndexRanges[i].x, leafIndexRanges[i].y); - printf("\n"); - } - - if(0) - { - static b3AlignedObjectArray rigidAabbs; - worldSpaceAabbs.copyToHost(rigidAabbs, false); - clFinish(m_queue); - - b3SapAabb actualRootAabb; - actualRootAabb.m_minVec = b3MakeVector3(B3_LARGE_FLOAT, B3_LARGE_FLOAT, B3_LARGE_FLOAT); - actualRootAabb.m_maxVec = b3MakeVector3(-B3_LARGE_FLOAT, -B3_LARGE_FLOAT, -B3_LARGE_FLOAT); - for(int i = 0; i < rigidAabbs.size(); ++i) - { - actualRootAabb.m_minVec.setMin(rigidAabbs[i].m_minVec); - actualRootAabb.m_maxVec.setMax(rigidAabbs[i].m_maxVec); - } - - b3SapAabb rootAabb = m_internalNodeAabbs.at(0); - b3SapAabb mergedAABB = m_mergedAabb.at(0); - - printf("mergedAABBMin: %f, %f, %f \n", mergedAABB.m_minVec.x, mergedAABB.m_minVec.y, mergedAABB.m_minVec.z); - printf("actualRootMin: %f, %f, %f \n", actualRootAabb.m_minVec.x, actualRootAabb.m_minVec.y, actualRootAabb.m_minVec.z); - printf("kernelRootMin: %f, %f, %f \n", rootAabb.m_minVec.x, rootAabb.m_minVec.y, rootAabb.m_minVec.z); - - printf("mergedAABBMax: %f, %f, %f \n", mergedAABB.m_maxVec.x, mergedAABB.m_maxVec.y, mergedAABB.m_maxVec.z); - printf("actualRootMax: %f, %f, %f \n", actualRootAabb.m_maxVec.x, actualRootAabb.m_maxVec.y, actualRootAabb.m_maxVec.z); - printf("kernelRootMax: %f, %f, %f \n", rootAabb.m_maxVec.x, rootAabb.m_maxVec.y, rootAabb.m_maxVec.z); - - printf("\n"); - } } } @@ -453,6 +392,8 @@ public: int reset = 0; out_numPairs.copyFromHostPointer(&reset, 1); + if( m_leafNodeAabbs.size() < 2 ) return; + { B3_PROFILE("PLBVH calculateOverlappingPairs"); @@ -510,11 +451,12 @@ public: int reset = 0; out_numRayRigidPairs.copyFromHostPointer(&reset, 1); + if( m_leafNodeAabbs.size() < 1 ) return; + b3BufferInfoCL bufferInfo[] = { b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), - b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index 40eabfd6c..3b634328a 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -403,69 +403,39 @@ b3Vector3 b3Vector3_normalize(b3Vector3 v) b3Scalar b3Vector3_length2(b3Vector3 v) { return v.x*v.x + v.y*v.y + v.z*v.z; } b3Scalar b3Vector3_dot(b3Vector3 a, b3Vector3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; } - -/** - -int rayIntersectsAabb_optimized(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalizedDirection, b3AabbCL aabb) +int rayIntersectsAabb(b3Vector3 rayOrigin, b3Scalar rayLength, b3Vector3 rayNormalizedDirection, b3AabbCL aabb) { - // not functional -- need to fix - - //aabb is considered as 3 pairs of 2 planes( {x_min, x_max}, {y_min, y_max}, {z_min, z_max} ) - //t_min is the first intersection, t_max is the second intersection - b3Vector3 inverseRayDirection = (b3Vector3){1.0f, 1.0f, 1.0f, 0.0f} / rayNormalizedDirection; - int4 sign = isless( inverseRayDirection, (b3Vector3){0.0f, 0.0f, 0.0f, 0.0f} ); //isless(x,y) returns (x < y) + //AABB is considered as 3 pairs of 2 planes( {x_min, x_max}, {y_min, y_max}, {z_min, z_max} ). + //t_min is the point of intersection with the closer plane, t_max is the point of intersection with the farther plane. + // + //if (rayNormalizedDirection.x < 0.0f), then max.x will be the near plane + //and min.x will be the far plane; otherwise, it is reversed. + // + //In order for there to be a collision, the t_min and t_max of each pair must overlap. + //This can be tested for by selecting the highest t_min and lowest t_max and comparing them. - //select(b, a, condition) == condition ? a : b - b3Vector3 t_min = ( select(aabb.m_min, aabb.m_max, sign) - rayFrom ) * inverseRayDirection; - b3Vector3 t_max = ( select(aabb.m_min, aabb.m_max, (int4){1,1,1,1} - sign) - rayFrom ) * inverseRayDirection; + int4 isNegative = isless( rayNormalizedDirection, (b3Vector3){0.0f, 0.0f, 0.0f, 0.0f} ); //isless(x,y) returns (x < y) + + //When using vector types, the select() function checks the most signficant bit, + //but isless() sets the least significant bit. + isNegative <<= 31; + //select(b, a, condition) == condition ? a : b + //When using select() with vector types, (condition[i]) is true if its most significant bit is 1 + b3Vector3 t_min = ( select(aabb.m_min, aabb.m_max, isNegative) - rayOrigin ) / rayNormalizedDirection; + b3Vector3 t_max = ( select(aabb.m_max, aabb.m_min, isNegative) - rayOrigin ) / rayNormalizedDirection; + b3Scalar t_min_final = 0.0f; - b3Scalar t_max_final = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); + b3Scalar t_max_final = rayLength; //Must use fmin()/fmax(); if one of the parameters is NaN, then the parameter that is not NaN is returned. //Behavior of min()/max() with NaNs is undefined. (See OpenCL Specification 1.2 [6.12.2] and [6.12.4]) - //Since the innermost fmin()/fmax() is always not NaN, this should never return NaN + //Since the innermost fmin()/fmax() is always not NaN, this should never return NaN. t_min_final = fmax( t_min.z, fmax(t_min.y, fmax(t_min.x, t_min_final)) ); t_max_final = fmin( t_max.z, fmin(t_max.y, fmin(t_max.x, t_max_final)) ); return (t_min_final <= t_max_final); } -**/ - -void rayPlanePairTest(b3Scalar rayStart, b3Scalar rayNormalizedDirection, - b3Scalar planeMin, b3Scalar planeMax, - b3Scalar* out_t_min, b3Scalar* out_t_max) -{ - if(rayNormalizedDirection < 0.0f) - { - //max is closer, min is farther - *out_t_min = (planeMax - rayStart) / rayNormalizedDirection; - *out_t_max = (planeMin - rayStart) / rayNormalizedDirection; - } - else - { - //min is closer, max is farther - *out_t_min = (planeMin - rayStart) / rayNormalizedDirection; - *out_t_max = (planeMax - rayStart) / rayNormalizedDirection; - } -} -int rayIntersectsAabb(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalizedDirection, b3AabbCL aabb) -{ - b3Scalar t_min_x, t_min_y, t_min_z; - b3Scalar t_max_x, t_max_y, t_max_z; - - rayPlanePairTest(rayFrom.x, rayNormalizedDirection.x, aabb.m_min.x, aabb.m_max.x, &t_min_x, &t_max_x); - rayPlanePairTest(rayFrom.y, rayNormalizedDirection.y, aabb.m_min.y, aabb.m_max.y, &t_min_y, &t_max_y); - rayPlanePairTest(rayFrom.z, rayNormalizedDirection.z, aabb.m_min.z, aabb.m_max.z, &t_min_z, &t_max_z); - - b3Scalar t_min_final = 0.0f; - b3Scalar t_max_final = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); - - t_min_final = fmax( t_min_z, fmax(t_min_y, fmax(t_min_x, t_min_final)) ); - t_max_final = fmin( t_max_z, fmin(t_max_y, fmin(t_max_x, t_max_final)) ); - - return (t_min_final <= t_max_final); -} __kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, @@ -484,10 +454,13 @@ __kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, int rayIndex = get_global_id(0); if(rayIndex >= numRays) return; + // b3Vector3 rayFrom = rays[rayIndex].m_from; b3Vector3 rayTo = rays[rayIndex].m_to; - b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rays[rayIndex].m_to - rays[rayIndex].m_from); - + b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom); + b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); + + // int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; int stackSize = 1; @@ -505,7 +478,7 @@ __kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1; b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex]; - if( rayIntersectsAabb(rayFrom, rayTo, rayNormalizedDirection, bvhNodeAabb) ) + if( rayIntersectsAabb(rayFrom, rayLength, rayNormalizedDirection, bvhNodeAabb) ) { if(isLeaf) { diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index c83783901..b894e2a11 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -383,64 +383,38 @@ static const char* parallelLinearBvhCL= \ "}\n" "b3Scalar b3Vector3_length2(b3Vector3 v) { return v.x*v.x + v.y*v.y + v.z*v.z; }\n" "b3Scalar b3Vector3_dot(b3Vector3 a, b3Vector3 b) { return a.x*b.x + a.y*b.y + a.z*b.z; }\n" -"/**\n" -"int rayIntersectsAabb_optimized(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalizedDirection, b3AabbCL aabb)\n" +"int rayIntersectsAabb(b3Vector3 rayOrigin, b3Scalar rayLength, b3Vector3 rayNormalizedDirection, b3AabbCL aabb)\n" "{\n" -" // not functional -- need to fix\n" -" //aabb is considered as 3 pairs of 2 planes( {x_min, x_max}, {y_min, y_max}, {z_min, z_max} )\n" -" //t_min is the first intersection, t_max is the second intersection\n" -" b3Vector3 inverseRayDirection = (b3Vector3){1.0f, 1.0f, 1.0f, 0.0f} / rayNormalizedDirection;\n" -" int4 sign = isless( inverseRayDirection, (b3Vector3){0.0f, 0.0f, 0.0f, 0.0f} ); //isless(x,y) returns (x < y)\n" +" //AABB is considered as 3 pairs of 2 planes( {x_min, x_max}, {y_min, y_max}, {z_min, z_max} ).\n" +" //t_min is the point of intersection with the closer plane, t_max is the point of intersection with the farther plane.\n" +" //\n" +" //if (rayNormalizedDirection.x < 0.0f), then max.x will be the near plane \n" +" //and min.x will be the far plane; otherwise, it is reversed.\n" +" //\n" +" //In order for there to be a collision, the t_min and t_max of each pair must overlap.\n" +" //This can be tested for by selecting the highest t_min and lowest t_max and comparing them.\n" " \n" +" int4 isNegative = isless( rayNormalizedDirection, (b3Vector3){0.0f, 0.0f, 0.0f, 0.0f} ); //isless(x,y) returns (x < y)\n" +" \n" +" //When using vector types, the select() function checks the most signficant bit, \n" +" //but isless() sets the least significant bit.\n" +" isNegative <<= 31;\n" " //select(b, a, condition) == condition ? a : b\n" -" b3Vector3 t_min = ( select(aabb.m_min, aabb.m_max, sign) - rayFrom ) * inverseRayDirection;\n" -" b3Vector3 t_max = ( select(aabb.m_min, aabb.m_max, (int4){1,1,1,1} - sign) - rayFrom ) * inverseRayDirection;\n" +" //When using select() with vector types, (condition[i]) is true if its most significant bit is 1\n" +" b3Vector3 t_min = ( select(aabb.m_min, aabb.m_max, isNegative) - rayOrigin ) / rayNormalizedDirection;\n" +" b3Vector3 t_max = ( select(aabb.m_max, aabb.m_min, isNegative) - rayOrigin ) / rayNormalizedDirection;\n" +" \n" " b3Scalar t_min_final = 0.0f;\n" -" b3Scalar t_max_final = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" +" b3Scalar t_max_final = rayLength;\n" " \n" " //Must use fmin()/fmax(); if one of the parameters is NaN, then the parameter that is not NaN is returned. \n" " //Behavior of min()/max() with NaNs is undefined. (See OpenCL Specification 1.2 [6.12.2] and [6.12.4])\n" -" //Since the innermost fmin()/fmax() is always not NaN, this should never return NaN\n" +" //Since the innermost fmin()/fmax() is always not NaN, this should never return NaN.\n" " t_min_final = fmax( t_min.z, fmax(t_min.y, fmax(t_min.x, t_min_final)) );\n" " t_max_final = fmin( t_max.z, fmin(t_max.y, fmin(t_max.x, t_max_final)) );\n" " \n" " return (t_min_final <= t_max_final);\n" "}\n" -"**/\n" -"void rayPlanePairTest(b3Scalar rayStart, b3Scalar rayNormalizedDirection,\n" -" b3Scalar planeMin, b3Scalar planeMax, \n" -" b3Scalar* out_t_min, b3Scalar* out_t_max)\n" -"{\n" -" if(rayNormalizedDirection < 0.0f)\n" -" {\n" -" //max is closer, min is farther\n" -" *out_t_min = (planeMax - rayStart) / rayNormalizedDirection;\n" -" *out_t_max = (planeMin - rayStart) / rayNormalizedDirection;\n" -" }\n" -" else\n" -" {\n" -" //min is closer, max is farther\n" -" *out_t_min = (planeMin - rayStart) / rayNormalizedDirection;\n" -" *out_t_max = (planeMax - rayStart) / rayNormalizedDirection;\n" -" }\n" -"}\n" -"int rayIntersectsAabb(b3Vector3 rayFrom, b3Vector3 rayTo, b3Vector3 rayNormalizedDirection, b3AabbCL aabb)\n" -"{\n" -" b3Scalar t_min_x, t_min_y, t_min_z;\n" -" b3Scalar t_max_x, t_max_y, t_max_z;\n" -" \n" -" rayPlanePairTest(rayFrom.x, rayNormalizedDirection.x, aabb.m_min.x, aabb.m_max.x, &t_min_x, &t_max_x);\n" -" rayPlanePairTest(rayFrom.y, rayNormalizedDirection.y, aabb.m_min.y, aabb.m_max.y, &t_min_y, &t_max_y);\n" -" rayPlanePairTest(rayFrom.z, rayNormalizedDirection.z, aabb.m_min.z, aabb.m_max.z, &t_min_z, &t_max_z);\n" -" \n" -" b3Scalar t_min_final = 0.0f;\n" -" b3Scalar t_max_final = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" -" \n" -" t_min_final = fmax( t_min_z, fmax(t_min_y, fmax(t_min_x, t_min_final)) );\n" -" t_max_final = fmin( t_max_z, fmin(t_max_y, fmin(t_max_x, t_max_final)) );\n" -" \n" -" return (t_min_final <= t_max_final);\n" -"}\n" "__kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs,\n" " __global int* rootNodeIndex, \n" " __global int2* internalNodeChildIndices, \n" @@ -457,10 +431,12 @@ static const char* parallelLinearBvhCL= \ " int rayIndex = get_global_id(0);\n" " if(rayIndex >= numRays) return;\n" " \n" +" //\n" " b3Vector3 rayFrom = rays[rayIndex].m_from;\n" " b3Vector3 rayTo = rays[rayIndex].m_to;\n" -" b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rays[rayIndex].m_to - rays[rayIndex].m_from);\n" -" \n" +" b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom);\n" +" b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" +" //\n" " int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" " \n" " int stackSize = 1;\n" @@ -478,7 +454,7 @@ static const char* parallelLinearBvhCL= \ " int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1;\n" " \n" " b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex];\n" -" if( rayIntersectsAabb(rayFrom, rayTo, rayNormalizedDirection, bvhNodeAabb) )\n" +" if( rayIntersectsAabb(rayFrom, rayLength, rayNormalizedDirection, bvhNodeAabb) )\n" " {\n" " if(isLeaf)\n" " {\n" From 28da87dfc77f9f50e826aa4c7f8a7314ed3f07f3 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Wed, 26 Feb 2014 15:20:12 -0800 Subject: [PATCH 007/116] Split PLBVH files into .h/.cpp. Also move PLBVH binary tree construction into separate function. --- .../b3GpuParallelLinearBvh.cpp | 425 ++++++++++++++++++ .../b3GpuParallelLinearBvh.h | 401 +---------------- .../b3GpuParallelLinearBvhBroadphase.cpp | 52 +++ .../b3GpuParallelLinearBvhBroadphase.h | 40 +- 4 files changed, 495 insertions(+), 423 deletions(-) create mode 100644 src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp create mode 100644 src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp new file mode 100644 index 000000000..c6169ee8e --- /dev/null +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -0,0 +1,425 @@ +/* +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +//Initial Author Jackson Lee, 2014 + +#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" + +#include "b3GpuParallelLinearBvh.h" + +b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue) : + m_queue(queue), + m_fill(context, device, queue), + m_radixSorter(context, device, queue), + + m_rootNodeIndex(context, queue), + + m_numNodesPerLevelGpu(context, queue), + m_firstIndexOffsetPerLevelGpu(context, queue), + + m_internalNodeAabbs(context, queue), + m_internalNodeLeafIndexRanges(context, queue), + m_internalNodeChildNodes(context, queue), + m_internalNodeParentNodes(context, queue), + + m_leafNodeParentNodes(context, queue), + m_mortonCodesAndAabbIndicies(context, queue), + m_mergedAabb(context, queue), + m_leafNodeAabbs(context, queue) +{ + m_rootNodeIndex.resize(1); + + // + const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; + + const char* kernelSource = parallelLinearBvhCL; //parallelLinearBvhCL.h + cl_int error; + char* additionalMacros = 0; + m_parallelLinearBvhProgram = b3OpenCLUtils::compileCLProgramFromString(context, device, kernelSource, &error, additionalMacros, CL_PROGRAM_PATH); + b3Assert(m_parallelLinearBvhProgram); + + m_findAllNodesMergedAabbKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findAllNodesMergedAabb", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_findAllNodesMergedAabbKernel); + m_assignMortonCodesAndAabbIndiciesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "assignMortonCodesAndAabbIndicies", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_assignMortonCodesAndAabbIndiciesKernel); + + m_constructBinaryTreeKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "constructBinaryTree", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_constructBinaryTreeKernel); + m_determineInternalNodeAabbsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "determineInternalNodeAabbs", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_determineInternalNodeAabbsKernel); + + m_plbvhCalculateOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhCalculateOverlappingPairs", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhCalculateOverlappingPairsKernel); + m_plbvhRayTraverseKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhRayTraverse", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhRayTraverseKernel); +} + +b3GpuParallelLinearBvh::~b3GpuParallelLinearBvh() +{ + clReleaseKernel(m_findAllNodesMergedAabbKernel); + clReleaseKernel(m_assignMortonCodesAndAabbIndiciesKernel); + clReleaseKernel(m_constructBinaryTreeKernel); + clReleaseKernel(m_determineInternalNodeAabbsKernel); + + clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); + clReleaseKernel(m_plbvhRayTraverseKernel); + + clReleaseProgram(m_parallelLinearBvhProgram); +} + +void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAabbs) +{ + B3_PROFILE("b3ParallelLinearBvh::build()"); + + m_leafNodeAabbs.copyFromOpenCLArray(worldSpaceAabbs); + + // + int numLeaves = m_leafNodeAabbs.size(); //Number of leaves in the BVH == Number of rigid body AABBs + int numInternalNodes = numLeaves - 1; + + if(numLeaves < 2) + { + int rootNodeIndex = numLeaves - 1; + m_rootNodeIndex.copyFromHostPointer(&rootNodeIndex, 1); + return; + } + + // + { + m_internalNodeAabbs.resize(numInternalNodes); + m_internalNodeLeafIndexRanges.resize(numInternalNodes); + m_internalNodeChildNodes.resize(numInternalNodes); + m_internalNodeParentNodes.resize(numInternalNodes); + + m_leafNodeParentNodes.resize(numLeaves); + m_mortonCodesAndAabbIndicies.resize(numLeaves); + m_mergedAabb.resize(numLeaves); + } + + //Find the AABB of all input AABBs; this is used to define the size of + //each cell in the virtual grid(2^10 cells in each dimension). + { + B3_PROFILE("Find AABB of merged nodes"); + + m_mergedAabb.copyFromOpenCLArray(worldSpaceAabbs); //Need to make a copy since the kernel modifies the array + + for(int numAabbsNeedingMerge = numLeaves; numAabbsNeedingMerge >= 2; + numAabbsNeedingMerge = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2) + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_mergedAabb.getBufferCL() ) //Resulting AABB is stored in m_mergedAabb[0] + }; + + b3LauncherCL launcher(m_queue, m_findAllNodesMergedAabbKernel, "m_findAllNodesMergedAabbKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numAabbsNeedingMerge); + + launcher.launch1D(numAabbsNeedingMerge); + } + + clFinish(m_queue); + } + + + //Insert the center of the AABBs into a virtual grid, + //then convert the discrete grid coordinates into a morton code + //For each element in m_mortonCodesAndAabbIndicies, set + // m_key == morton code (value to sort by) + // m_value = AABB index + { + B3_PROFILE("Assign morton codes"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_mergedAabb.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_assignMortonCodesAndAabbIndiciesKernel, "m_assignMortonCodesAndAabbIndiciesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLeaves); + + launcher.launch1D(numLeaves); + clFinish(m_queue); + } + + // + { + B3_PROFILE("Sort leaves by morton codes"); + + m_radixSorter.execute(m_mortonCodesAndAabbIndicies); + clFinish(m_queue); + } + + //Optional; only element at m_internalNodeParentNodes[0], the root node, needs to be set here + //as the parent indices of other nodes are overwritten during m_constructBinaryTreeKernel + { + B3_PROFILE("Reset parent node indices"); + + m_fill.execute( m_internalNodeParentNodes, B3_PLBVH_ROOT_NODE_MARKER, m_internalNodeParentNodes.size() ); + m_fill.execute( m_leafNodeParentNodes, B3_PLBVH_ROOT_NODE_MARKER, m_leafNodeParentNodes.size() ); + clFinish(m_queue); + } + + constructSimpleBinaryTree(); +} + +void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs) +{ + b3Assert( out_numPairs.size() == 1 ); + + int maxPairs = out_overlappingPairs.size(); + + int reset = 0; + out_numPairs.copyFromHostPointer(&reset, 1); + + if( m_leafNodeAabbs.size() < 2 ) return; + + { + B3_PROFILE("PLBVH calculateOverlappingPairs"); + + int numQueryAabbs = m_leafNodeAabbs.size(); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + + b3BufferInfoCL( out_numPairs.getBufferCL() ), + b3BufferInfoCL( out_overlappingPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhCalculateOverlappingPairsKernel, "m_plbvhCalculateOverlappingPairsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxPairs); + launcher.setConst(numQueryAabbs); + + launcher.launch1D(numQueryAabbs); + clFinish(m_queue); + } + + + // + int numPairs = -1; + out_numPairs.copyToHostPointer(&numPairs, 1); + if(numPairs > maxPairs) + { + b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); + numPairs = maxPairs; + out_numPairs.copyFromHostPointer(&maxPairs, 1); + } + + out_overlappingPairs.resize(numPairs); +} + + +void b3GpuParallelLinearBvh::testRaysAgainstBvhAabbs(const b3OpenCLArray& rays, + b3OpenCLArray& out_numRayRigidPairs, b3OpenCLArray& out_rayRigidPairs) +{ + B3_PROFILE("PLBVH testRaysAgainstBvhAabbs()"); + + int numRays = rays.size(); + int maxRayRigidPairs = out_rayRigidPairs.size(); + + int reset = 0; + out_numRayRigidPairs.copyFromHostPointer(&reset, 1); + + if( m_leafNodeAabbs.size() < 1 ) return; + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + + b3BufferInfoCL( rays.getBufferCL() ), + + b3BufferInfoCL( out_numRayRigidPairs.getBufferCL() ), + b3BufferInfoCL( out_rayRigidPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhRayTraverseKernel, "m_plbvhRayTraverseKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxRayRigidPairs); + launcher.setConst(numRays); + + launcher.launch1D(numRays); + clFinish(m_queue); + + + // + int numRayRigidPairs = -1; + out_numRayRigidPairs.copyToHostPointer(&numRayRigidPairs, 1); + + if(numRayRigidPairs > maxRayRigidPairs) + b3Error("Error running out of rayRigid pairs: numRayRigidPairs = %d, maxRayRigidPairs = %d.\n", numRayRigidPairs, maxRayRigidPairs); + +} + +void b3GpuParallelLinearBvh::constructSimpleBinaryTree() +{ + int numLeaves = m_leafNodeAabbs.size(); //Number of leaves in the BVH == Number of rigid body AABBs + int numInternalNodes = numLeaves - 1; + + //Determine number of levels in the binary tree( numLevels = ceil( log2(numLeaves) ) ) + //The number of levels is equivalent to the number of bits needed to uniquely identify each node(including both internal and leaf nodes) + int numLevels = 0; + { + //Find the most significant bit(msb) + int mostSignificantBit = 0; + { + int temp = numLeaves; + while(temp >>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1) + } + numLevels = mostSignificantBit + 1; + + //If the number of nodes is not a power of 2(as in, can be expressed as 2^N where N is an integer), then there is 1 additional level + if( ~(1 << mostSignificantBit) & numLeaves ) numLevels++; + } + + //Determine number of internal nodes per level, use prefix sum to get offsets of each level, and send to GPU + { + B3_PROFILE("Determine number of nodes per level"); + + m_numNodesPerLevelCpu.resize(numLevels); + + //The last level contains the leaf nodes; number of leaves is already known + if(numLevels - 1 >= 0) m_numNodesPerLevelCpu[numLevels - 1] = numLeaves; + + //Calculate number of nodes in each level; + //start from the second to last level(level right next to leaf nodes) and move towards the root(level 0) + int remainder = 0; + for(int levelIndex = numLevels - 2; levelIndex >= 0; --levelIndex) + { + int numNodesPreviousLevel = m_numNodesPerLevelCpu[levelIndex + 1]; //For first iteration this == numLeaves + int numNodesCurrentLevel = numNodesPreviousLevel / 2; + + remainder += numNodesPreviousLevel % 2; + if(remainder == 2) + { + numNodesCurrentLevel++; + remainder = 0; + } + + m_numNodesPerLevelCpu[levelIndex] = numNodesCurrentLevel; + } + + //Prefix sum to calculate the first index offset of each level + { + m_firstIndexOffsetPerLevelCpu = m_numNodesPerLevelCpu; + + //Perform inclusive scan + for(int i = 1; i < m_firstIndexOffsetPerLevelCpu.size(); ++i) + m_firstIndexOffsetPerLevelCpu[i] += m_firstIndexOffsetPerLevelCpu[i - 1]; + + //Convert inclusive scan to exclusive scan to get the offsets + //This is equivalent to shifting each element in m_firstIndexOffsetPerLevelCpu[] by 1 to the right, + //and setting the first element to 0 + for(int i = 0; i < m_firstIndexOffsetPerLevelCpu.size(); ++i) + m_firstIndexOffsetPerLevelCpu[i] -= m_numNodesPerLevelCpu[i]; + } + + //Copy to GPU + m_numNodesPerLevelGpu.copyFromHost(m_numNodesPerLevelCpu, false); + m_firstIndexOffsetPerLevelGpu.copyFromHost(m_firstIndexOffsetPerLevelCpu, false); + clFinish(m_queue); + } + + //Construct binary tree; find the children of each internal node, and assign parent nodes + { + B3_PROFILE("Construct binary tree"); + + const int ROOT_NODE_INDEX = 0x80000000; //Default root index is 0, most significant bit is set to indicate internal node + m_rootNodeIndex.copyFromHostPointer(&ROOT_NODE_INDEX, 1); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_leafNodeParentNodes.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_constructBinaryTreeKernel, "m_constructBinaryTreeKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLevels); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } + + //For each internal node, check children to get its AABB; start from the + //last level, which contains the leaves, and move towards the root + { + B3_PROFILE("Set AABBs"); + + //Due to the arrangement of internal nodes, each internal node corresponds + //to a contiguous range of leaf node indices. This characteristic can be used + //to optimize calculateOverlappingPairs(); checking if + //(m_internalNodeLeafIndexRanges[].y < leafNodeIndex) can be used to ensure that + //each pair is processed only once. + { + B3_PROFILE("Reset internal node index ranges"); + + b3Int2 invalidIndexRange; + invalidIndexRange.x = -1; //x == min + invalidIndexRange.y = -2; //y == max + + m_fill.execute( m_internalNodeLeafIndexRanges, invalidIndexRange, m_internalNodeLeafIndexRanges.size() ); + clFinish(m_queue); + } + + int lastInternalLevelIndex = numLevels - 2; //Last level is leaf node level + for(int level = lastInternalLevelIndex; level >= 0; --level) + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_determineInternalNodeAabbsKernel, "m_determineInternalNodeAabbsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLevels); + launcher.setConst(numInternalNodes); + launcher.setConst(level); + + launcher.launch1D(numLeaves); + } + clFinish(m_queue); + } +} + + +void b3GpuParallelLinearBvh::constructRadixBinaryTree() +{ +} + + \ No newline at end of file diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index 81d455044..89c6cedb7 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -20,8 +20,6 @@ subject to the following restrictions: #include "Bullet3Common/shared/b3Int4.h" #include "Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h" -#include "Bullet3OpenCL/Initialize/b3OpenCLUtils.h" -#include "Bullet3OpenCL/ParallelPrimitives/b3LauncherCL.h" #include "Bullet3OpenCL/ParallelPrimitives/b3FillCL.h" #include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" @@ -56,9 +54,12 @@ class b3GpuParallelLinearBvh cl_kernel m_findAllNodesMergedAabbKernel; cl_kernel m_assignMortonCodesAndAabbIndiciesKernel; + + //Binary tree construction kernels cl_kernel m_constructBinaryTreeKernel; cl_kernel m_determineInternalNodeAabbsKernel; + //Traversal kernels cl_kernel m_plbvhCalculateOverlappingPairsKernel; cl_kernel m_plbvhRayTraverseKernel; @@ -87,405 +88,29 @@ class b3GpuParallelLinearBvh b3OpenCLArray m_leafNodeAabbs; public: - b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue) : - m_queue(queue), - m_fill(context, device, queue), - m_radixSorter(context, device, queue), - - m_rootNodeIndex(context, queue), - - m_numNodesPerLevelGpu(context, queue), - m_firstIndexOffsetPerLevelGpu(context, queue), - - m_internalNodeAabbs(context, queue), - m_internalNodeLeafIndexRanges(context, queue), - m_internalNodeChildNodes(context, queue), - m_internalNodeParentNodes(context, queue), - - m_leafNodeParentNodes(context, queue), - m_mortonCodesAndAabbIndicies(context, queue), - m_mergedAabb(context, queue), - m_leafNodeAabbs(context, queue) - { - m_rootNodeIndex.resize(1); + b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue); + virtual ~b3GpuParallelLinearBvh(); - // - const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; - - const char* kernelSource = parallelLinearBvhCL; //parallelLinearBvhCL.h - cl_int error; - char* additionalMacros = 0; - m_parallelLinearBvhProgram = b3OpenCLUtils::compileCLProgramFromString(context, device, kernelSource, &error, additionalMacros, CL_PROGRAM_PATH); - b3Assert(m_parallelLinearBvhProgram); - - m_findAllNodesMergedAabbKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findAllNodesMergedAabb", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_findAllNodesMergedAabbKernel); - m_assignMortonCodesAndAabbIndiciesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "assignMortonCodesAndAabbIndicies", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_assignMortonCodesAndAabbIndiciesKernel); - m_constructBinaryTreeKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "constructBinaryTree", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_constructBinaryTreeKernel); - m_determineInternalNodeAabbsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "determineInternalNodeAabbs", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_determineInternalNodeAabbsKernel); - - m_plbvhCalculateOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhCalculateOverlappingPairs", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_plbvhCalculateOverlappingPairsKernel); - m_plbvhRayTraverseKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhRayTraverse", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_plbvhRayTraverseKernel); - } - - virtual ~b3GpuParallelLinearBvh() - { - clReleaseKernel(m_findAllNodesMergedAabbKernel); - clReleaseKernel(m_assignMortonCodesAndAabbIndiciesKernel); - clReleaseKernel(m_constructBinaryTreeKernel); - clReleaseKernel(m_determineInternalNodeAabbsKernel); - - clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); - clReleaseKernel(m_plbvhRayTraverseKernel); - - clReleaseProgram(m_parallelLinearBvhProgram); - } - - void build(const b3OpenCLArray& worldSpaceAabbs) - { - B3_PROFILE("b3ParallelLinearBvh::build()"); - - int numLeaves = worldSpaceAabbs.size(); //Number of leaves in the BVH == Number of rigid body AABBs - int numInternalNodes = numLeaves - 1; - - // - m_leafNodeAabbs.copyFromOpenCLArray(worldSpaceAabbs); - - if(numLeaves < 2) - { - int rootNodeIndex = numLeaves - 1; - m_rootNodeIndex.copyFromHostPointer(&rootNodeIndex, 1); - return; - } - - // - { - m_internalNodeAabbs.resize(numInternalNodes); - m_internalNodeLeafIndexRanges.resize(numInternalNodes); - m_internalNodeChildNodes.resize(numInternalNodes); - m_internalNodeParentNodes.resize(numInternalNodes); - - m_leafNodeParentNodes.resize(numLeaves); - m_mortonCodesAndAabbIndicies.resize(numLeaves); - m_mergedAabb.resize(numLeaves); - } - - //Determine number of levels in the binary tree( numLevels = ceil( log2(numLeaves) ) ) - //The number of levels is equivalent to the number of bits needed to uniquely identify each node(including both internal and leaf nodes) - int numLevels = 0; - { - //Find the most significant bit(msb) - int mostSignificantBit = 0; - { - int temp = numLeaves; - while(temp >>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1) - } - numLevels = mostSignificantBit + 1; - - //If the number of nodes is not a power of 2(as in, can be expressed as 2^N where N is an integer), then there is 1 additional level - if( ~(1 << mostSignificantBit) & numLeaves ) numLevels++; - } - - //Determine number of internal nodes per level, use prefix sum to get offsets of each level, and send to GPU - { - B3_PROFILE("Determine number of nodes per level"); - - m_numNodesPerLevelCpu.resize(numLevels); - - //The last level contains the leaf nodes; number of leaves is already known - if(numLevels - 1 >= 0) m_numNodesPerLevelCpu[numLevels - 1] = numLeaves; - - //Calculate number of nodes in each level; - //start from the second to last level(level right next to leaf nodes) and move towards the root(level 0) - int remainder = 0; - for(int levelIndex = numLevels - 2; levelIndex >= 0; --levelIndex) - { - int numNodesPreviousLevel = m_numNodesPerLevelCpu[levelIndex + 1]; //For first iteration this == numLeaves - int numNodesCurrentLevel = numNodesPreviousLevel / 2; - - remainder += numNodesPreviousLevel % 2; - if(remainder == 2) - { - numNodesCurrentLevel++; - remainder = 0; - } - - m_numNodesPerLevelCpu[levelIndex] = numNodesCurrentLevel; - } - - //Prefix sum to calculate the first index offset of each level - { - m_firstIndexOffsetPerLevelCpu = m_numNodesPerLevelCpu; - - //Perform inclusive scan - for(int i = 1; i < m_firstIndexOffsetPerLevelCpu.size(); ++i) - m_firstIndexOffsetPerLevelCpu[i] += m_firstIndexOffsetPerLevelCpu[i - 1]; - - //Convert inclusive scan to exclusive scan to get the offsets - //This is equivalent to shifting each element in m_firstIndexOffsetPerLevelCpu[] by 1 to the right, - //and setting the first element to 0 - for(int i = 0; i < m_firstIndexOffsetPerLevelCpu.size(); ++i) - m_firstIndexOffsetPerLevelCpu[i] -= m_numNodesPerLevelCpu[i]; - } - - //Copy to GPU - m_numNodesPerLevelGpu.copyFromHost(m_numNodesPerLevelCpu, false); - m_firstIndexOffsetPerLevelGpu.copyFromHost(m_firstIndexOffsetPerLevelCpu, false); - clFinish(m_queue); - } - - //Find the AABB of all input AABBs; this is used to define the size of - //each cell in the virtual grid(2^10 cells in each dimension). - { - B3_PROFILE("Find AABB of merged nodes"); - - m_mergedAabb.copyFromOpenCLArray(worldSpaceAabbs); //Need to make a copy since the kernel modifies the array - - for(int numAabbsNeedingMerge = numLeaves; numAabbsNeedingMerge >= 2; - numAabbsNeedingMerge = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2) - { - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_mergedAabb.getBufferCL() ) //Resulting AABB is stored in m_mergedAabb[0] - }; - - b3LauncherCL launcher(m_queue, m_findAllNodesMergedAabbKernel, "m_findAllNodesMergedAabbKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numAabbsNeedingMerge); - - launcher.launch1D(numAabbsNeedingMerge); - } - - clFinish(m_queue); - } - - - //Insert the center of the AABBs into a virtual grid, - //then convert the discrete grid coordinates into a morton code - //For each element in m_mortonCodesAndAabbIndicies, set - // m_key == morton code (value to sort by) - // m_value = AABB index - { - B3_PROFILE("Assign morton codes"); - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), - b3BufferInfoCL( m_mergedAabb.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_assignMortonCodesAndAabbIndiciesKernel, "m_assignMortonCodesAndAabbIndiciesKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLeaves); - - launcher.launch1D(numLeaves); - clFinish(m_queue); - } - - // - { - B3_PROFILE("Sort leaves by morton codes"); - - m_radixSorter.execute(m_mortonCodesAndAabbIndicies); - clFinish(m_queue); - } - - //Optional; only element at m_internalNodeParentNodes[0], the root node, needs to be set here - //as the parent indices of other nodes are overwritten during m_constructBinaryTreeKernel - { - B3_PROFILE("Reset parent node indices"); - - m_fill.execute( m_internalNodeParentNodes, B3_PLBVH_ROOT_NODE_MARKER, m_internalNodeParentNodes.size() ); - m_fill.execute( m_leafNodeParentNodes, B3_PLBVH_ROOT_NODE_MARKER, m_leafNodeParentNodes.size() ); - clFinish(m_queue); - } - - //Construct binary tree; find the children of each internal node, and assign parent nodes - { - B3_PROFILE("Construct binary tree"); - - const int ROOT_NODE_INDEX = 0x80000000; //Default root index is 0, most significant bit is set to indicate internal node - m_rootNodeIndex.copyFromHostPointer(&ROOT_NODE_INDEX, 1); - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), - b3BufferInfoCL( m_leafNodeParentNodes.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_constructBinaryTreeKernel, "m_constructBinaryTreeKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLevels); - launcher.setConst(numInternalNodes); - - launcher.launch1D(numInternalNodes); - clFinish(m_queue); - } - - //For each internal node, check children to get its AABB; start from the - //last level, which contains the leaves, and move towards the root - { - B3_PROFILE("Set AABBs"); - - //Due to the arrangement of internal nodes, each internal node corresponds - //to a contiguous range of leaf node indices. This characteristic can be used - //to optimize calculateOverlappingPairs(); checking if - //(m_internalNodeLeafIndexRanges[].y < leafNodeIndex) can be used to ensure that - //each pair is processed only once. - { - B3_PROFILE("Reset internal node index ranges"); - - b3Int2 invalidIndexRange; - invalidIndexRange.x = -1; //x == min - invalidIndexRange.y = -2; //y == max - - m_fill.execute( m_internalNodeLeafIndexRanges, invalidIndexRange, m_internalNodeLeafIndexRanges.size() ); - clFinish(m_queue); - } - - int lastInternalLevelIndex = numLevels - 2; //Last level is leaf node level - for(int level = lastInternalLevelIndex; level >= 0; --level) - { - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), - b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), - b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_determineInternalNodeAabbsKernel, "m_determineInternalNodeAabbsKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLevels); - launcher.setConst(numInternalNodes); - launcher.setConst(level); - - launcher.launch1D(numLeaves); - } - clFinish(m_queue); - } - } + void build(const b3OpenCLArray& worldSpaceAabbs); ///b3GpuParallelLinearBvh::build() must be called before this function. calculateOverlappingPairs() uses ///the worldSpaceAabbs parameter of b3GpuParallelLinearBvh::build() as the query AABBs. ///@param out_numPairs If number of pairs exceeds the max number of pairs, this is clamped to the max number. ///@param out_overlappingPairs The size() of this array is used to determine the max number of pairs. ///If the number of overlapping pairs is < out_overlappingPairs.size(), out_overlappingPairs is resized. - void calculateOverlappingPairs(b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs) - { - b3Assert( out_numPairs.size() == 1 ); - - int maxPairs = out_overlappingPairs.size(); - - int reset = 0; - out_numPairs.copyFromHostPointer(&reset, 1); - - if( m_leafNodeAabbs.size() < 2 ) return; - - { - B3_PROFILE("PLBVH calculateOverlappingPairs"); - - int numQueryAabbs = m_leafNodeAabbs.size(); - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), - - b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), - b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - - b3BufferInfoCL( out_numPairs.getBufferCL() ), - b3BufferInfoCL( out_overlappingPairs.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_plbvhCalculateOverlappingPairsKernel, "m_plbvhCalculateOverlappingPairsKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(maxPairs); - launcher.setConst(numQueryAabbs); - - launcher.launch1D(numQueryAabbs); - clFinish(m_queue); - } - - - // - int numPairs = -1; - out_numPairs.copyToHostPointer(&numPairs, 1); - if(numPairs > maxPairs) - { - b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); - numPairs = maxPairs; - out_numPairs.copyFromHostPointer(&maxPairs, 1); - } - - out_overlappingPairs.resize(numPairs); - } + void calculateOverlappingPairs(b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs); ///@param out_numRigidRayPairs Array of length 1; contains the number of detected ray-rigid AABB intersections; ///this value may be greater than out_rayRigidPairs.size() if out_rayRigidPairs is not large enough. ///@param out_rayRigidPairs Contains an array of rays intersecting rigid AABBs; x == ray index, y == rigid body index. ///If the size of this array is insufficient to hold all ray-rigid AABB intersections, additional intersections are discarded. void testRaysAgainstBvhAabbs(const b3OpenCLArray& rays, - b3OpenCLArray& out_numRayRigidPairs, b3OpenCLArray& out_rayRigidPairs) - { - B3_PROFILE("PLBVH testRaysAgainstBvhAabbs()"); - - int numRays = rays.size(); - int maxRayRigidPairs = out_rayRigidPairs.size(); - - int reset = 0; - out_numRayRigidPairs.copyFromHostPointer(&reset, 1); - - if( m_leafNodeAabbs.size() < 1 ) return; - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), - - b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), - b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - - b3BufferInfoCL( rays.getBufferCL() ), - - b3BufferInfoCL( out_numRayRigidPairs.getBufferCL() ), - b3BufferInfoCL( out_rayRigidPairs.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_plbvhRayTraverseKernel, "m_plbvhRayTraverseKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(maxRayRigidPairs); - launcher.setConst(numRays); - - launcher.launch1D(numRays); - clFinish(m_queue); - - - // - int numRayRigidPairs = -1; - out_numRayRigidPairs.copyToHostPointer(&numRayRigidPairs, 1); - - if(numRayRigidPairs > maxRayRigidPairs) - b3Error("Error running out of rayRigid pairs: numRayRigidPairs = %d, maxRayRigidPairs = %d.\n", numRayRigidPairs, maxRayRigidPairs); - - } + b3OpenCLArray& out_numRayRigidPairs, b3OpenCLArray& out_rayRigidPairs); + +private: + void constructSimpleBinaryTree(); + + void constructRadixBinaryTree(); }; #endif diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp new file mode 100644 index 000000000..6d7293e2c --- /dev/null +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp @@ -0,0 +1,52 @@ +/* +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ +//Initial Author Jackson Lee, 2014 + +#include "b3GpuParallelLinearBvhBroadphase.h" + +b3GpuParallelLinearBvhBroadphase::b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue) : + m_plbvh(context, device, queue), + + m_overlappingPairsGpu(context, queue), + m_aabbsGpu(context, queue), + m_tempNumPairs(context, queue) +{ + m_tempNumPairs.resize(1); +} + +void b3GpuParallelLinearBvhBroadphase::createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) +{ + b3SapAabb aabb; + aabb.m_minVec = aabbMin; + aabb.m_maxVec = aabbMax; + aabb.m_minIndices[3] = userPtr; + + m_aabbsCpu.push_back(aabb); +} +void b3GpuParallelLinearBvhBroadphase::createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) +{ + b3Assert(0); //Not implemented +} + +void b3GpuParallelLinearBvhBroadphase::calculateOverlappingPairs(int maxPairs) +{ + //Reconstruct BVH + m_plbvh.build(m_aabbsGpu); + + // + m_overlappingPairsGpu.resize(maxPairs); + m_plbvh.calculateOverlappingPairs(m_tempNumPairs, m_overlappingPairsGpu); +} +void b3GpuParallelLinearBvhBroadphase::calculateOverlappingPairsHost(int maxPairs) +{ + b3Assert(0); //CPU version not implemented +} diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h index c5b85f4bb..2280b48ce 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h @@ -29,44 +29,14 @@ class b3GpuParallelLinearBvhBroadphase : public b3GpuBroadphaseInterface b3AlignedObjectArray m_aabbsCpu; public: - b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue) : - m_plbvh(context, device, queue), - - m_overlappingPairsGpu(context, queue), - m_aabbsGpu(context, queue), - m_tempNumPairs(context, queue) - { - m_tempNumPairs.resize(1); - } + b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue); virtual ~b3GpuParallelLinearBvhBroadphase() {} - virtual void createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) - { - b3SapAabb aabb; - aabb.m_minVec = aabbMin; - aabb.m_maxVec = aabbMax; - aabb.m_minIndices[3] = userPtr; - - m_aabbsCpu.push_back(aabb); - } - virtual void createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) - { - b3Assert(0); //Not implemented - } + virtual void createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask); + virtual void createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask); - virtual void calculateOverlappingPairs(int maxPairs) - { - //Reconstruct BVH - m_plbvh.build(m_aabbsGpu); - - // - m_overlappingPairsGpu.resize(maxPairs); - m_plbvh.calculateOverlappingPairs(m_tempNumPairs, m_overlappingPairsGpu); - } - virtual void calculateOverlappingPairsHost(int maxPairs) - { - b3Assert(0); //CPU version not implemented - } + virtual void calculateOverlappingPairs(int maxPairs); + virtual void calculateOverlappingPairsHost(int maxPairs); //call writeAabbsToGpu after done making all changes (createProxy etc) virtual void writeAabbsToGpu() { m_aabbsGpu.copyFromHost(m_aabbsCpu); } From 4dcd52c0904be63695c28a429ace46c8f50ed927 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Wed, 26 Feb 2014 15:38:59 -0800 Subject: [PATCH 008/116] Add only small AABBs to PLBVH, add large AABB support. --- .../b3GpuBroadphaseInterface.h | 3 + .../b3GpuGridBroadphase.cpp | 12 +- .../BroadphaseCollision/b3GpuGridBroadphase.h | 3 + .../b3GpuParallelLinearBvh.cpp | 179 ++++++++++++++---- .../b3GpuParallelLinearBvh.h | 16 +- .../b3GpuParallelLinearBvhBroadphase.cpp | 40 +++- .../b3GpuParallelLinearBvhBroadphase.h | 11 +- .../b3GpuSapBroadphase.cpp | 9 + .../BroadphaseCollision/b3GpuSapBroadphase.h | 2 + .../kernels/parallelLinearBvh.cl | 61 ++++++ .../kernels/parallelLinearBvhKernels.h | 57 ++++++ src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp | 3 +- 12 files changed, 350 insertions(+), 46 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h index 3598ffb56..bcbf09a4f 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h @@ -34,6 +34,9 @@ public: virtual b3OpenCLArray& getAllAabbsGPU()=0; virtual b3AlignedObjectArray& getAllAabbsCPU()=0; + + virtual b3OpenCLArray& getSmallAabbIndicesGPU() = 0; + virtual b3OpenCLArray& getLargeAabbIndicesGPU() = 0; }; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp index f5308ecf4..1e707f364 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp @@ -366,4 +366,14 @@ b3OpenCLArray& b3GpuGridBroadphase::getAllAabbsGPU() b3AlignedObjectArray& b3GpuGridBroadphase::getAllAabbsCPU() { return m_allAabbsCPU1; -} \ No newline at end of file +} + +b3OpenCLArray& b3GpuGridBroadphase::getSmallAabbIndicesGPU() +{ + return m_smallAabbsMappingGPU; +} +b3OpenCLArray& b3GpuGridBroadphase::getLargeAabbIndicesGPU() +{ + return m_largeAabbsMappingGPU; +} + diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h index 4dd5c3a3c..c2c66ce7c 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h @@ -78,6 +78,9 @@ public: virtual b3OpenCLArray& getAllAabbsGPU(); virtual b3AlignedObjectArray& getAllAabbsCPU(); + + virtual b3OpenCLArray& getSmallAabbIndicesGPU(); + virtual b3OpenCLArray& getLargeAabbIndicesGPU(); }; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp index c6169ee8e..dd5557360 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -34,7 +34,9 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_leafNodeParentNodes(context, queue), m_mortonCodesAndAabbIndicies(context, queue), m_mergedAabb(context, queue), - m_leafNodeAabbs(context, queue) + m_leafNodeAabbs(context, queue), + + m_largeAabbs(context, queue) { m_rootNodeIndex.resize(1); @@ -47,6 +49,8 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_parallelLinearBvhProgram = b3OpenCLUtils::compileCLProgramFromString(context, device, kernelSource, &error, additionalMacros, CL_PROGRAM_PATH); b3Assert(m_parallelLinearBvhProgram); + m_separateAabbsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "separateAabbs", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_separateAabbsKernel); m_findAllNodesMergedAabbKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findAllNodesMergedAabb", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_findAllNodesMergedAabbKernel); m_assignMortonCodesAndAabbIndiciesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "assignMortonCodesAndAabbIndicies", &error, m_parallelLinearBvhProgram, additionalMacros ); @@ -61,10 +65,15 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id b3Assert(m_plbvhCalculateOverlappingPairsKernel); m_plbvhRayTraverseKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhRayTraverse", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_plbvhRayTraverseKernel); + m_plbvhLargeAabbAabbTestKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhLargeAabbAabbTest", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhLargeAabbAabbTestKernel); + m_plbvhLargeAabbRayTestKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhLargeAabbRayTest", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_plbvhLargeAabbRayTestKernel); } b3GpuParallelLinearBvh::~b3GpuParallelLinearBvh() { + clReleaseKernel(m_separateAabbsKernel); clReleaseKernel(m_findAllNodesMergedAabbKernel); clReleaseKernel(m_assignMortonCodesAndAabbIndiciesKernel); clReleaseKernel(m_constructBinaryTreeKernel); @@ -72,18 +81,68 @@ b3GpuParallelLinearBvh::~b3GpuParallelLinearBvh() clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); clReleaseKernel(m_plbvhRayTraverseKernel); + clReleaseKernel(m_plbvhLargeAabbAabbTestKernel); + clReleaseKernel(m_plbvhLargeAabbRayTestKernel); clReleaseProgram(m_parallelLinearBvhProgram); } -void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAabbs) +void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAabbs, const b3OpenCLArray& smallAabbIndices, + const b3OpenCLArray& largeAabbIndices) { B3_PROFILE("b3ParallelLinearBvh::build()"); - m_leafNodeAabbs.copyFromOpenCLArray(worldSpaceAabbs); + int numLargeAabbs = largeAabbIndices.size(); + int numSmallAabbs = smallAabbIndices.size(); + + //Since all AABBs(both large and small) are input as a contiguous array, + //with 2 additional arrays used to indicate the indices of large and small AABBs, + //it is necessary to separate the AABBs so that the large AABBs will not degrade the quality of the BVH. + { + B3_PROFILE("Separate large and small AABBs"); + + m_largeAabbs.resize(numLargeAabbs); + m_leafNodeAabbs.resize(numSmallAabbs); + + //Write large AABBs into m_largeAabbs + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( largeAabbIndices.getBufferCL() ), + + b3BufferInfoCL( m_largeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_separateAabbsKernel, "m_separateAabbsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLargeAabbs); + + launcher.launch1D(numLargeAabbs); + } + + //Write small AABBs into m_leafNodeAabbs + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( worldSpaceAabbs.getBufferCL() ), + b3BufferInfoCL( smallAabbIndices.getBufferCL() ), + + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_separateAabbsKernel, "m_separateAabbsKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numSmallAabbs); + + launcher.launch1D(numSmallAabbs); + } + + clFinish(m_queue); + } // - int numLeaves = m_leafNodeAabbs.size(); //Number of leaves in the BVH == Number of rigid body AABBs + int numLeaves = numSmallAabbs; //Number of leaves in the BVH == Number of rigid bodies with small AABBs int numInternalNodes = numLeaves - 1; if(numLeaves < 2) @@ -105,12 +164,14 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab m_mergedAabb.resize(numLeaves); } + + //Find the AABB of all input AABBs; this is used to define the size of //each cell in the virtual grid(2^10 cells in each dimension). { B3_PROFILE("Find AABB of merged nodes"); - m_mergedAabb.copyFromOpenCLArray(worldSpaceAabbs); //Need to make a copy since the kernel modifies the array + m_mergedAabb.copyFromOpenCLArray(m_leafNodeAabbs); //Need to make a copy since the kernel modifies the array for(int numAabbsNeedingMerge = numLeaves; numAabbsNeedingMerge >= 2; numAabbsNeedingMerge = numAabbsNeedingMerge / 2 + numAabbsNeedingMerge % 2) @@ -172,6 +233,7 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab clFinish(m_queue); } + // constructSimpleBinaryTree(); } @@ -184,10 +246,10 @@ void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_n int reset = 0; out_numPairs.copyFromHostPointer(&reset, 1); - if( m_leafNodeAabbs.size() < 2 ) return; - + // + if( m_leafNodeAabbs.size() > 1 ) { - B3_PROFILE("PLBVH calculateOverlappingPairs"); + B3_PROFILE("PLBVH small-small AABB test"); int numQueryAabbs = m_leafNodeAabbs.size(); @@ -214,6 +276,32 @@ void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_n clFinish(m_queue); } + int numLargeAabbRigids = m_largeAabbs.size(); + if( numLargeAabbRigids > 0 && m_leafNodeAabbs.size() > 0 ) + { + B3_PROFILE("PLBVH large-small AABB test"); + + int numQueryAabbs = m_leafNodeAabbs.size(); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_largeAabbs.getBufferCL() ), + + b3BufferInfoCL( out_numPairs.getBufferCL() ), + b3BufferInfoCL( out_overlappingPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhLargeAabbAabbTestKernel, "m_plbvhLargeAabbAabbTestKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxPairs); + launcher.setConst(numLargeAabbRigids); + launcher.setConst(numQueryAabbs); + + launcher.launch1D(numQueryAabbs); + clFinish(m_queue); + } + // int numPairs = -1; @@ -240,32 +328,59 @@ void b3GpuParallelLinearBvh::testRaysAgainstBvhAabbs(const b3OpenCLArray 0 ) { - b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), - - b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), - b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - - b3BufferInfoCL( rays.getBufferCL() ), - - b3BufferInfoCL( out_numRayRigidPairs.getBufferCL() ), - b3BufferInfoCL( out_rayRigidPairs.getBufferCL() ) - }; + B3_PROFILE("PLBVH ray test small AABB"); - b3LauncherCL launcher(m_queue, m_plbvhRayTraverseKernel, "m_plbvhRayTraverseKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(maxRayRigidPairs); - launcher.setConst(numRays); - - launcher.launch1D(numRays); - clFinish(m_queue); + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + + b3BufferInfoCL( rays.getBufferCL() ), + + b3BufferInfoCL( out_numRayRigidPairs.getBufferCL() ), + b3BufferInfoCL( out_rayRigidPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhRayTraverseKernel, "m_plbvhRayTraverseKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxRayRigidPairs); + launcher.setConst(numRays); + + launcher.launch1D(numRays); + clFinish(m_queue); + } + int numLargeAabbRigids = m_largeAabbs.size(); + if(numLargeAabbRigids > 0) + { + B3_PROFILE("PLBVH ray test large AABB"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_largeAabbs.getBufferCL() ), + b3BufferInfoCL( rays.getBufferCL() ), + + b3BufferInfoCL( out_numRayRigidPairs.getBufferCL() ), + b3BufferInfoCL( out_rayRigidPairs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_plbvhLargeAabbRayTestKernel, "m_plbvhLargeAabbRayTestKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLargeAabbRigids); + launcher.setConst(maxRayRigidPairs); + launcher.setConst(numRays); + + launcher.launch1D(numRays); + clFinish(m_queue); + } // int numRayRigidPairs = -1; @@ -278,7 +393,7 @@ void b3GpuParallelLinearBvh::testRaysAgainstBvhAabbs(const b3OpenCLArray m_numNodesPerLevelGpu; b3OpenCLArray m_firstIndexOffsetPerLevelGpu; - //1 element per internal node (number_of_internal_nodes = number_of_leaves - 1); index 0 is the root node + //1 element per internal node (number_of_internal_nodes = number_of_leaves - 1) b3OpenCLArray m_internalNodeAabbs; b3OpenCLArray m_internalNodeLeafIndexRanges; //x == min leaf index, y == max leaf index b3OpenCLArray m_internalNodeChildNodes; //x == left child, y == right child b3OpenCLArray m_internalNodeParentNodes; - //1 element per leaf node + //1 element per leaf node (leaf nodes only include small AABBs) b3OpenCLArray m_leafNodeParentNodes; b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key = morton code, m_value == aabb index b3OpenCLArray m_mergedAabb; - b3OpenCLArray m_leafNodeAabbs; + b3OpenCLArray m_leafNodeAabbs; //Contains only small AABBs + + //1 element per large AABB + b3OpenCLArray m_largeAabbs; //Not stored in the BVH public: b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue); virtual ~b3GpuParallelLinearBvh(); - void build(const b3OpenCLArray& worldSpaceAabbs); + void build(const b3OpenCLArray& worldSpaceAabbs, const b3OpenCLArray& smallAabbIndices, + const b3OpenCLArray& largeAabbIndices); ///b3GpuParallelLinearBvh::build() must be called before this function. calculateOverlappingPairs() uses ///the worldSpaceAabbs parameter of b3GpuParallelLinearBvh::build() as the query AABBs. diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp index 6d7293e2c..b48c2c1de 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp @@ -16,37 +16,67 @@ subject to the following restrictions: b3GpuParallelLinearBvhBroadphase::b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue) : m_plbvh(context, device, queue), + m_numOverlappingPairs(context, queue), m_overlappingPairsGpu(context, queue), + m_aabbsGpu(context, queue), - m_tempNumPairs(context, queue) + m_smallAabbsMappingGpu(context, queue), + m_largeAabbsMappingGpu(context, queue) { - m_tempNumPairs.resize(1); + m_numOverlappingPairs.resize(1); } void b3GpuParallelLinearBvhBroadphase::createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) { + int newAabbIndex = m_aabbsCpu.size(); + b3SapAabb aabb; aabb.m_minVec = aabbMin; aabb.m_maxVec = aabbMax; + aabb.m_minIndices[3] = userPtr; + aabb.m_signedMaxIndices[3] = newAabbIndex; + + m_smallAabbsMappingCpu.push_back(newAabbIndex); m_aabbsCpu.push_back(aabb); } void b3GpuParallelLinearBvhBroadphase::createLargeProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) { - b3Assert(0); //Not implemented + int newAabbIndex = m_aabbsCpu.size(); + + b3SapAabb aabb; + aabb.m_minVec = aabbMin; + aabb.m_maxVec = aabbMax; + + aabb.m_minIndices[3] = userPtr; + aabb.m_signedMaxIndices[3] = newAabbIndex; + + m_largeAabbsMappingCpu.push_back(newAabbIndex); + + m_aabbsCpu.push_back(aabb); } void b3GpuParallelLinearBvhBroadphase::calculateOverlappingPairs(int maxPairs) { //Reconstruct BVH - m_plbvh.build(m_aabbsGpu); + m_plbvh.build(m_aabbsGpu, m_smallAabbsMappingGpu, m_largeAabbsMappingGpu); // m_overlappingPairsGpu.resize(maxPairs); - m_plbvh.calculateOverlappingPairs(m_tempNumPairs, m_overlappingPairsGpu); + m_plbvh.calculateOverlappingPairs(m_numOverlappingPairs, m_overlappingPairsGpu); } void b3GpuParallelLinearBvhBroadphase::calculateOverlappingPairsHost(int maxPairs) { b3Assert(0); //CPU version not implemented } + +void b3GpuParallelLinearBvhBroadphase::writeAabbsToGpu() +{ + m_aabbsGpu.copyFromHost(m_aabbsCpu); + m_smallAabbsMappingGpu.copyFromHost(m_smallAabbsMappingCpu); + m_largeAabbsMappingGpu.copyFromHost(m_largeAabbsMappingCpu); +} + + + diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h index 2280b48ce..9155bc1a7 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h @@ -22,11 +22,16 @@ class b3GpuParallelLinearBvhBroadphase : public b3GpuBroadphaseInterface { b3GpuParallelLinearBvh m_plbvh; + b3OpenCLArray m_numOverlappingPairs; b3OpenCLArray m_overlappingPairsGpu; + b3OpenCLArray m_aabbsGpu; - b3OpenCLArray m_tempNumPairs; + b3OpenCLArray m_smallAabbsMappingGpu; + b3OpenCLArray m_largeAabbsMappingGpu; b3AlignedObjectArray m_aabbsCpu; + b3AlignedObjectArray m_smallAabbsMappingCpu; + b3AlignedObjectArray m_largeAabbsMappingCpu; public: b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue); @@ -39,13 +44,15 @@ public: virtual void calculateOverlappingPairsHost(int maxPairs); //call writeAabbsToGpu after done making all changes (createProxy etc) - virtual void writeAabbsToGpu() { m_aabbsGpu.copyFromHost(m_aabbsCpu); } + virtual void writeAabbsToGpu(); virtual int getNumOverlap() { return m_overlappingPairsGpu.size(); } virtual cl_mem getOverlappingPairBuffer() { return m_overlappingPairsGpu.getBufferCL(); } virtual cl_mem getAabbBufferWS() { return m_aabbsGpu.getBufferCL(); } virtual b3OpenCLArray& getAllAabbsGPU() { return m_aabbsGpu; } + virtual b3OpenCLArray& getSmallAabbIndicesGPU() { return m_smallAabbsMappingGpu; } + virtual b3OpenCLArray& getLargeAabbIndicesGPU() { return m_largeAabbsMappingGpu; } virtual b3AlignedObjectArray& getAllAabbsCPU() { return m_aabbsCpu; } diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp index 529951af0..5ab7bf0db 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp @@ -1307,3 +1307,12 @@ cl_mem b3GpuSapBroadphase::getOverlappingPairBuffer() { return m_overlappingPairs.getBufferCL(); } + +b3OpenCLArray& b3GpuSapBroadphase::getSmallAabbIndicesGPU() +{ + return m_smallAabbsMappingGPU; +} +b3OpenCLArray& b3GpuSapBroadphase::getLargeAabbIndicesGPU() +{ + return m_largeAabbsMappingGPU; +} diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h index 2d3d39367..7cbf6c7fc 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h @@ -143,6 +143,8 @@ public: virtual int getNumOverlap(); virtual cl_mem getOverlappingPairBuffer(); + virtual b3OpenCLArray& getSmallAabbIndicesGPU(); + virtual b3OpenCLArray& getLargeAabbIndicesGPU(); }; #endif //B3_GPU_SAP_BROADPHASE_H \ No newline at end of file diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index 3b634328a..e2380145e 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -81,6 +81,15 @@ unsigned int getMortonCode(unsigned int x, unsigned int y, unsigned int z) return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2; } +__kernel void separateAabbs(__global b3AabbCL* unseparatedAabbs, __global int* aabbIndices, __global b3AabbCL* out_aabbs, int numAabbsToSeparate) +{ + int separatedAabbIndex = get_global_id(0); + if(separatedAabbIndex >= numAabbsToSeparate) return; + + int unseparatedAabbIndex = aabbIndices[separatedAabbIndex]; + out_aabbs[separatedAabbIndex] = unseparatedAabbs[unseparatedAabbIndex]; +} + //Should replace with an optimized parallel reduction __kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbsNeedingMerge) { @@ -506,3 +515,55 @@ __kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, } } +__kernel void plbvhLargeAabbAabbTest(__global b3AabbCL* smallAabbs, __global b3AabbCL* largeAabbs, + __global int* out_numPairs, __global int4* out_overlappingPairs, + int maxPairs, int numLargeAabbRigids, int numSmallAabbRigids) +{ + int smallAabbIndex = get_global_id(0); + if(smallAabbIndex >= numSmallAabbRigids) return; + + b3AabbCL smallAabb = smallAabbs[smallAabbIndex]; + for(int i = 0; i < numLargeAabbRigids; ++i) + { + b3AabbCL largeAabb = largeAabbs[i]; + if( TestAabbAgainstAabb2(&smallAabb, &largeAabb) ) + { + int4 pair; + pair.x = smallAabb.m_minIndices[3]; + pair.y = largeAabb.m_minIndices[3]; + pair.z = NEW_PAIR_MARKER; + pair.w = NEW_PAIR_MARKER; + + int pairIndex = atomic_inc(out_numPairs); + if(pairIndex < maxPairs) out_overlappingPairs[pairIndex] = pair; + } + } +} +__kernel void plbvhLargeAabbRayTest(__global b3AabbCL* largeRigidAabbs, __global b3RayInfo* rays, + __global int* out_numRayRigidPairs, __global int2* out_rayRigidPairs, + int numLargeAabbRigids, int maxRayRigidPairs, int numRays) +{ + int rayIndex = get_global_id(0); + if(rayIndex >= numRays) return; + + b3Vector3 rayFrom = rays[rayIndex].m_from; + b3Vector3 rayTo = rays[rayIndex].m_to; + b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom); + b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); + + for(int i = 0; i < numLargeAabbRigids; ++i) + { + b3AabbCL rigidAabb = largeRigidAabbs[i]; + if( rayIntersectsAabb(rayFrom, rayLength, rayNormalizedDirection, rigidAabb) ) + { + int2 rayRigidPair; + rayRigidPair.x = rayIndex; + rayRigidPair.y = rigidAabb.m_minIndices[3]; + + int pairIndex = atomic_inc(out_numRayRigidPairs); + if(pairIndex < maxRayRigidPairs) out_rayRigidPairs[pairIndex] = rayRigidPair; + } + } +} + + diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index b894e2a11..cfb477d03 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -76,6 +76,13 @@ static const char* parallelLinearBvhCL= \ "{\n" " return interleaveBits(x) << 0 | interleaveBits(y) << 1 | interleaveBits(z) << 2;\n" "}\n" +"__kernel void separateAabbs(__global b3AabbCL* unseparatedAabbs, __global int* aabbIndices, __global b3AabbCL* out_aabbs, int numAabbsToSeparate)\n" +"{\n" +" int separatedAabbIndex = get_global_id(0);\n" +" if(separatedAabbIndex >= numAabbsToSeparate) return;\n" +" int unseparatedAabbIndex = aabbIndices[separatedAabbIndex];\n" +" out_aabbs[separatedAabbIndex] = unseparatedAabbs[unseparatedAabbIndex];\n" +"}\n" "//Should replace with an optimized parallel reduction\n" "__kernel void findAllNodesMergedAabb(__global b3AabbCL* out_mergedAabb, int numAabbsNeedingMerge)\n" "{\n" @@ -481,4 +488,54 @@ static const char* parallelLinearBvhCL= \ " }\n" " }\n" "}\n" +"__kernel void plbvhLargeAabbAabbTest(__global b3AabbCL* smallAabbs, __global b3AabbCL* largeAabbs, \n" +" __global int* out_numPairs, __global int4* out_overlappingPairs, \n" +" int maxPairs, int numLargeAabbRigids, int numSmallAabbRigids)\n" +"{\n" +" int smallAabbIndex = get_global_id(0);\n" +" if(smallAabbIndex >= numSmallAabbRigids) return;\n" +" \n" +" b3AabbCL smallAabb = smallAabbs[smallAabbIndex];\n" +" for(int i = 0; i < numLargeAabbRigids; ++i)\n" +" {\n" +" b3AabbCL largeAabb = largeAabbs[i];\n" +" if( TestAabbAgainstAabb2(&smallAabb, &largeAabb) )\n" +" {\n" +" int4 pair;\n" +" pair.x = smallAabb.m_minIndices[3];\n" +" pair.y = largeAabb.m_minIndices[3];\n" +" pair.z = NEW_PAIR_MARKER;\n" +" pair.w = NEW_PAIR_MARKER;\n" +" \n" +" int pairIndex = atomic_inc(out_numPairs);\n" +" if(pairIndex < maxPairs) out_overlappingPairs[pairIndex] = pair;\n" +" }\n" +" }\n" +"}\n" +"__kernel void plbvhLargeAabbRayTest(__global b3AabbCL* largeRigidAabbs, __global b3RayInfo* rays,\n" +" __global int* out_numRayRigidPairs, __global int2* out_rayRigidPairs,\n" +" int numLargeAabbRigids, int maxRayRigidPairs, int numRays)\n" +"{\n" +" int rayIndex = get_global_id(0);\n" +" if(rayIndex >= numRays) return;\n" +" \n" +" b3Vector3 rayFrom = rays[rayIndex].m_from;\n" +" b3Vector3 rayTo = rays[rayIndex].m_to;\n" +" b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom);\n" +" b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" +" \n" +" for(int i = 0; i < numLargeAabbRigids; ++i)\n" +" {\n" +" b3AabbCL rigidAabb = largeRigidAabbs[i];\n" +" if( rayIntersectsAabb(rayFrom, rayLength, rayNormalizedDirection, rigidAabb) )\n" +" {\n" +" int2 rayRigidPair;\n" +" rayRigidPair.x = rayIndex;\n" +" rayRigidPair.y = rigidAabb.m_minIndices[3];\n" +" \n" +" int pairIndex = atomic_inc(out_numRayRigidPairs);\n" +" if(pairIndex < maxRayRigidPairs) out_rayRigidPairs[pairIndex] = rayRigidPair;\n" +" }\n" +" }\n" +"}\n" ; diff --git a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp index 686a7f835..294a20f74 100644 --- a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp +++ b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp @@ -305,8 +305,7 @@ void b3GpuRaycast::castRays(const b3AlignedObjectArray& rays, b3Align } else { - //printf("broadphase->getAllAabbsGPU().size(): %d \n", broadphase->getAllAabbsGPU().size()); - m_data->m_plbvh->build( broadphase->getAllAabbsGPU() ); + m_data->m_plbvh->build( broadphase->getAllAabbsGPU(), broadphase->getSmallAabbIndicesGPU(), broadphase->getLargeAabbIndicesGPU() ); m_data->m_plbvh->testRaysAgainstBvhAabbs(*m_data->m_gpuRays, *m_data->m_gpuNumRayRigidPairs, *m_data->m_gpuRayRigidPairs); From f19f85368517ff08a4f329710a1710f547c545d2 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Mon, 3 Mar 2014 14:33:53 -0800 Subject: [PATCH 009/116] Draft PLBVH construction using binary radix tree. --- .../b3GpuParallelLinearBvh.cpp | 158 +++++++++++++- .../b3GpuParallelLinearBvh.h | 17 +- .../kernels/parallelLinearBvh.cl | 203 +++++++++++++++++- .../kernels/parallelLinearBvhKernels.h | 192 +++++++++++++++++ 4 files changed, 564 insertions(+), 6 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp index dd5557360..c5e8a89e1 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -31,6 +31,13 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_internalNodeChildNodes(context, queue), m_internalNodeParentNodes(context, queue), + m_maxCommonPrefix(context, queue), + m_commonPrefixes(context, queue), + m_leftInternalNodePointers(context, queue), + m_rightInternalNodePointers(context, queue), + m_internalNodeLeftChildNodes(context, queue), + m_internalNodeRightChildNodes(context, queue), + m_leafNodeParentNodes(context, queue), m_mortonCodesAndAabbIndicies(context, queue), m_mergedAabb(context, queue), @@ -39,6 +46,7 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_largeAabbs(context, queue) { m_rootNodeIndex.resize(1); + m_maxCommonPrefix.resize(1); // const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; @@ -61,6 +69,17 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_determineInternalNodeAabbsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "determineInternalNodeAabbs", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_determineInternalNodeAabbsKernel); + m_computePrefixAndInitPointersKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "computePrefixAndInitPointers", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_computePrefixAndInitPointersKernel); + m_correctDuplicatePrefixesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "correctDuplicatePrefixes", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_correctDuplicatePrefixesKernel); + m_buildBinaryRadixTreeLeafNodesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeLeafNodes", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_buildBinaryRadixTreeLeafNodesKernel); + m_buildBinaryRadixTreeInternalNodesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeInternalNodes", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_buildBinaryRadixTreeInternalNodesKernel); + m_convertChildNodeFormatKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "convertChildNodeFormat", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_convertChildNodeFormatKernel); + m_plbvhCalculateOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhCalculateOverlappingPairs", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_plbvhCalculateOverlappingPairsKernel); m_plbvhRayTraverseKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhRayTraverse", &error, m_parallelLinearBvhProgram, additionalMacros ); @@ -76,9 +95,16 @@ b3GpuParallelLinearBvh::~b3GpuParallelLinearBvh() clReleaseKernel(m_separateAabbsKernel); clReleaseKernel(m_findAllNodesMergedAabbKernel); clReleaseKernel(m_assignMortonCodesAndAabbIndiciesKernel); + clReleaseKernel(m_constructBinaryTreeKernel); clReleaseKernel(m_determineInternalNodeAabbsKernel); + clReleaseKernel(m_computePrefixAndInitPointersKernel); + clReleaseKernel(m_correctDuplicatePrefixesKernel); + clReleaseKernel(m_buildBinaryRadixTreeLeafNodesKernel); + clReleaseKernel(m_buildBinaryRadixTreeInternalNodesKernel); + clReleaseKernel(m_convertChildNodeFormatKernel); + clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); clReleaseKernel(m_plbvhRayTraverseKernel); clReleaseKernel(m_plbvhLargeAabbAabbTestKernel); @@ -159,6 +185,12 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab m_internalNodeChildNodes.resize(numInternalNodes); m_internalNodeParentNodes.resize(numInternalNodes); + m_commonPrefixes.resize(numInternalNodes); + m_leftInternalNodePointers.resize(numInternalNodes); + m_rightInternalNodePointers.resize(numInternalNodes); + m_internalNodeLeftChildNodes.resize(numInternalNodes); + m_internalNodeRightChildNodes.resize(numInternalNodes); + m_leafNodeParentNodes.resize(numLeaves); m_mortonCodesAndAabbIndicies.resize(numLeaves); m_mergedAabb.resize(numLeaves); @@ -166,7 +198,7 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab - //Find the AABB of all input AABBs; this is used to define the size of + //Find the merged AABB of all small AABBs; this is used to define the size of //each cell in the virtual grid(2^10 cells in each dimension). { B3_PROFILE("Find AABB of merged nodes"); @@ -196,7 +228,7 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab //then convert the discrete grid coordinates into a morton code //For each element in m_mortonCodesAndAabbIndicies, set // m_key == morton code (value to sort by) - // m_value = AABB index + // m_value == small AABB index { B3_PROFILE("Assign morton codes"); @@ -234,7 +266,8 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab } // - constructSimpleBinaryTree(); + //constructSimpleBinaryTree(); + constructRadixBinaryTree(); } void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs) @@ -393,6 +426,8 @@ void b3GpuParallelLinearBvh::testRaysAgainstBvhAabbs(const b3OpenCLArray= -1; --processedCommonPrefix) + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeftChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeRightChildNodes.getBufferCL() ), + b3BufferInfoCL( m_leftInternalNodePointers.getBufferCL() ), + b3BufferInfoCL( m_rightInternalNodePointers.getBufferCL() ), + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeInternalNodesKernel, "m_buildBinaryRadixTreeInternalNodesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(processedCommonPrefix); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + } + + clFinish(m_queue); + } + + { + B3_PROFILE("m_convertChildNodeFormatKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_internalNodeLeftChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeRightChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_convertChildNodeFormatKernel, "m_convertChildNodeFormatKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } } \ No newline at end of file diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index a8c7f111a..559786cbb 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -56,10 +56,17 @@ class b3GpuParallelLinearBvh cl_kernel m_findAllNodesMergedAabbKernel; cl_kernel m_assignMortonCodesAndAabbIndiciesKernel; - //Binary tree construction kernels + //Simple binary tree construction kernels cl_kernel m_constructBinaryTreeKernel; cl_kernel m_determineInternalNodeAabbsKernel; + //Radix binary tree construction kernels + cl_kernel m_computePrefixAndInitPointersKernel; + cl_kernel m_correctDuplicatePrefixesKernel; + cl_kernel m_buildBinaryRadixTreeLeafNodesKernel; + cl_kernel m_buildBinaryRadixTreeInternalNodesKernel; + cl_kernel m_convertChildNodeFormatKernel; + //Traversal kernels cl_kernel m_plbvhCalculateOverlappingPairsKernel; cl_kernel m_plbvhRayTraverseKernel; @@ -85,6 +92,14 @@ class b3GpuParallelLinearBvh b3OpenCLArray m_internalNodeChildNodes; //x == left child, y == right child b3OpenCLArray m_internalNodeParentNodes; + //1 element per internal node; for radix binary tree construction + b3OpenCLArray m_maxCommonPrefix; + b3OpenCLArray m_commonPrefixes; + b3OpenCLArray m_leftInternalNodePointers; //Linked list + b3OpenCLArray m_rightInternalNodePointers; //Linked list + b3OpenCLArray m_internalNodeLeftChildNodes; + b3OpenCLArray m_internalNodeRightChildNodes; + //1 element per leaf node (leaf nodes only include small AABBs) b3OpenCLArray m_leafNodeParentNodes; b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key = morton code, m_value == aabb index diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index e2380145e..3bcd4f351 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -468,7 +468,7 @@ __kernel void plbvhRayTraverse(__global b3AabbCL* rigidAabbs, b3Vector3 rayTo = rays[rayIndex].m_to; b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom); b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) ); - + // int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; @@ -567,3 +567,204 @@ __kernel void plbvhLargeAabbRayTest(__global b3AabbCL* largeRigidAabbs, __global } + +#define B3_PLBVH_LINKED_LIST_INVALID_NODE -1 + +int longestCommonPrefix(int i, int j) { return clz(i ^ j); } + +__kernel void computePrefixAndInitPointers(__global SortDataCL* mortonCodesAndAabbIndices, + __global int* out_commonPrefixes, + __global int* out_leftInternalNodePointers, + __global int* out_rightInternalNodePointers, + int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if (internalNodeIndex >= numInternalNodes) return; + + //Compute common prefix + { + //Here, (internalNodeIndex + 1) is never out of bounds since it is a leaf node index, + //and the number of internal nodes is always numLeafNodes - 1 + int leftLeafMortonCode = mortonCodesAndAabbIndices[internalNodeIndex].m_key; + int rightLeafMortonCode = mortonCodesAndAabbIndices[internalNodeIndex + 1].m_key; + + out_commonPrefixes[internalNodeIndex] = longestCommonPrefix(leftLeafMortonCode, rightLeafMortonCode); + } + + //Assign neighbor pointers of this node + { + int leftInternalIndex = internalNodeIndex - 1; + int rightInternalIndex = internalNodeIndex + 1; + + out_leftInternalNodePointers[internalNodeIndex] = (leftInternalIndex >= 0) ? leftInternalIndex : B3_PLBVH_LINKED_LIST_INVALID_NODE; + out_rightInternalNodePointers[internalNodeIndex] = (rightInternalIndex < numInternalNodes) ? rightInternalIndex : B3_PLBVH_LINKED_LIST_INVALID_NODE; + } +} + +__kernel void correctDuplicatePrefixes(__global int* commonPrefixes, __global int* out_maxCommonPrefix, int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if (internalNodeIndex >= numInternalNodes) return; + + int commonPrefix = commonPrefixes[internalNodeIndex]; + + //Linear search to find the size of the subtree + int firstSubTreeIndex = internalNodeIndex; + int lastSubTreeIndex = internalNodeIndex; + + while(firstSubTreeIndex - 1 >= 0 && commonPrefix == commonPrefixes[firstSubTreeIndex - 1]) --firstSubTreeIndex; + while(lastSubTreeIndex + 1 < numInternalNodes && commonPrefix == commonPrefixes[lastSubTreeIndex + 1]) ++lastSubTreeIndex; + + //Fix duplicate common prefixes by incrementing them so that a subtree is formed. + //Recursively divide the tree until the position of the split is this node's index. + //Every time this node is not the split node, increment the common prefix. + int isCurrentSplitNode = false; + int correctedCommonPrefix = commonPrefix; + + while(!isCurrentSplitNode) + { + int numInternalNodesInSubTree = lastSubTreeIndex - firstSubTreeIndex + 1; + int splitNodeIndex = firstSubTreeIndex + numInternalNodesInSubTree / 2; + + if(internalNodeIndex > splitNodeIndex) firstSubTreeIndex = splitNodeIndex + 1; + else if(internalNodeIndex < splitNodeIndex) lastSubTreeIndex = splitNodeIndex - 1; + //else if(internalNodeIndex == splitNodeIndex) break; + + isCurrentSplitNode = (internalNodeIndex == splitNodeIndex); + if(!isCurrentSplitNode) correctedCommonPrefix++; + } + + commonPrefixes[internalNodeIndex] = correctedCommonPrefix; + atomic_max(out_maxCommonPrefix, correctedCommonPrefix); +} + +//Set so that it is always greater than the actual common prefixes, and never selected as a parent node. +//If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve. +//Duplicates common prefixes increase the highest common prefix by N, where 2^N is the number of duplicate nodes. +#define B3_PLBVH_INVALID_COMMON_PREFIX 128 + +__kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixes, __global int* out_leftChildNodes, + __global int* out_rightChildNodes, int numLeafNodes) +{ + int leafNodeIndex = get_global_id(0); + if (leafNodeIndex >= numLeafNodes) return; + + int numInternalNodes = numLeafNodes - 1; + + int leftSplitIndex = leafNodeIndex - 1; + int rightSplitIndex = leafNodeIndex; + + int leftCommonPrefix = (leftSplitIndex >= 0) ? commonPrefixes[leftSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + int rightCommonPrefix = (rightSplitIndex < numInternalNodes) ? commonPrefixes[rightSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + + //Parent node is the highest adjacent common prefix that is lower than the node's common prefix + //Leaf nodes are considered as having the highest common prefix + int isLeftHigherCommonPrefix = (leftCommonPrefix > rightCommonPrefix); + + //Handle cases for the edge nodes; the first and last node + //For leaf nodes, leftCommonPrefix and rightCommonPrefix should never both be B3_PLBVH_INVALID_COMMON_PREFIX + if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = false; + if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true; + + int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftSplitIndex : rightSplitIndex; + + //If the left node is the parent, then this node is its right child and vice versa + __global int* out_childNode = (isLeftHigherCommonPrefix) ? out_rightChildNodes : out_leftChildNodes; + + int isLeaf = 1; + out_childNode[parentNodeIndex] = getIndexWithInternalNodeMarkerSet(isLeaf, leafNodeIndex); +} + +__kernel void buildBinaryRadixTreeInternalNodes(__global int* commonPrefixes, __global SortDataCL* mortonCodesAndAabbIndices, + __global int* leftChildNodes, __global int* rightChildNodes, + __global int* leftNeighborPointers, __global int* rightNeighborPointers, + __global b3AabbCL* leafNodeAabbs, __global b3AabbCL* internalNodeAabbs, + __global int* out_rootNodeIndex, + int processedCommonPrefix, int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if (internalNodeIndex >= numInternalNodes) return; + + int commonPrefix = commonPrefixes[internalNodeIndex]; + if (commonPrefix == processedCommonPrefix) + { + //Check neighbors and compare the common prefix to select the parent node + int leftNodeIndex = leftNeighborPointers[internalNodeIndex]; + int rightNodeIndex = rightNeighborPointers[internalNodeIndex]; + + int leftCommonPrefix = (leftNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) ? commonPrefixes[leftNodeIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + int rightCommonPrefix = (rightNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) ? commonPrefixes[rightNodeIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + + //Parent node is the highest common prefix that is lower than the node's common prefix + //Since the nodes with lower common prefixes are removed, that condition does not have to be tested for, + //and we only need to pick the node with the higher prefix. + int isLeftHigherCommonPrefix = (leftCommonPrefix > rightCommonPrefix); + + // + if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = false; + else if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true; + + int isRootNode = false; + if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX && rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isRootNode = true; + + int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftNodeIndex : rightNodeIndex; + + //If the left node is the parent, then this node is its right child and vice versa + __global int* out_childNode = (isLeftHigherCommonPrefix) ? rightChildNodes : leftChildNodes; + + int isLeaf = 0; + if(!isRootNode) out_childNode[parentNodeIndex] = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex); + + if(isRootNode) *out_rootNodeIndex = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex); + + //Remove this node from the linked list, + //so that the left and right nodes point at each other instead of this node + if(leftNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) rightNeighborPointers[leftNodeIndex] = rightNodeIndex; + if(rightNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) leftNeighborPointers[rightNodeIndex] = leftNodeIndex; + + //For debug + leftNeighborPointers[internalNodeIndex] = -2; + rightNeighborPointers[internalNodeIndex] = -2; + } + + //Processing occurs from highest common prefix to lowest common prefix + //Nodes in the previously processed level have their children set, so we merge their child AABBs here + if (commonPrefix == processedCommonPrefix + 1) + { + int leftChildIndex = leftChildNodes[internalNodeIndex]; + int rightChildIndex = rightChildNodes[internalNodeIndex]; + + int isLeftChildLeaf = isLeafNode(leftChildIndex); + int isRightChildLeaf = isLeafNode(rightChildIndex); + + leftChildIndex = getIndexWithInternalNodeMarkerRemoved(leftChildIndex); + rightChildIndex = getIndexWithInternalNodeMarkerRemoved(rightChildIndex); + + //leftRigidIndex/rightRigidIndex is not used if internal node + int leftRigidIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1; + int rightRigidIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1; + + b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftRigidIndex] : internalNodeAabbs[leftChildIndex]; + b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightRigidIndex] : internalNodeAabbs[rightChildIndex]; + + b3AabbCL mergedAabb; + mergedAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min); + mergedAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max); + internalNodeAabbs[internalNodeIndex] = mergedAabb; + } +} + +__kernel void convertChildNodeFormat(__global int* leftChildNodes, __global int* rightChildNodes, + __global int2* out_childNodes, int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if (internalNodeIndex >= numInternalNodes) return; + + int2 childNodesIndices; + childNodesIndices.x = leftChildNodes[internalNodeIndex]; + childNodesIndices.y = rightChildNodes[internalNodeIndex]; + + out_childNodes[internalNodeIndex] = childNodesIndices; +} + + diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index cfb477d03..1a1437d10 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -443,6 +443,7 @@ static const char* parallelLinearBvhCL= \ " b3Vector3 rayTo = rays[rayIndex].m_to;\n" " b3Vector3 rayNormalizedDirection = b3Vector3_normalize(rayTo - rayFrom);\n" " b3Scalar rayLength = b3Sqrt( b3Vector3_length2(rayTo - rayFrom) );\n" +" \n" " //\n" " int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" " \n" @@ -538,4 +539,195 @@ static const char* parallelLinearBvhCL= \ " }\n" " }\n" "}\n" +"#define B3_PLBVH_LINKED_LIST_INVALID_NODE -1\n" +"int longestCommonPrefix(int i, int j) { return clz(i ^ j); }\n" +"__kernel void computePrefixAndInitPointers(__global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global int* out_commonPrefixes,\n" +" __global int* out_leftInternalNodePointers, \n" +" __global int* out_rightInternalNodePointers,\n" +" int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if (internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" //Compute common prefix\n" +" {\n" +" //Here, (internalNodeIndex + 1) is never out of bounds since it is a leaf node index,\n" +" //and the number of internal nodes is always numLeafNodes - 1\n" +" int leftLeafMortonCode = mortonCodesAndAabbIndices[internalNodeIndex].m_key;\n" +" int rightLeafMortonCode = mortonCodesAndAabbIndices[internalNodeIndex + 1].m_key;\n" +" \n" +" out_commonPrefixes[internalNodeIndex] = longestCommonPrefix(leftLeafMortonCode, rightLeafMortonCode);\n" +" }\n" +" \n" +" //Assign neighbor pointers of this node\n" +" {\n" +" int leftInternalIndex = internalNodeIndex - 1;\n" +" int rightInternalIndex = internalNodeIndex + 1;\n" +" \n" +" out_leftInternalNodePointers[internalNodeIndex] = (leftInternalIndex >= 0) ? leftInternalIndex : B3_PLBVH_LINKED_LIST_INVALID_NODE;\n" +" out_rightInternalNodePointers[internalNodeIndex] = (rightInternalIndex < numInternalNodes) ? rightInternalIndex : B3_PLBVH_LINKED_LIST_INVALID_NODE;\n" +" }\n" +"}\n" +"__kernel void correctDuplicatePrefixes(__global int* commonPrefixes, __global int* out_maxCommonPrefix, int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if (internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" int commonPrefix = commonPrefixes[internalNodeIndex];\n" +" \n" +" //Linear search to find the size of the subtree\n" +" int firstSubTreeIndex = internalNodeIndex;\n" +" int lastSubTreeIndex = internalNodeIndex;\n" +" \n" +" while(firstSubTreeIndex - 1 >= 0 && commonPrefix == commonPrefixes[firstSubTreeIndex - 1]) --firstSubTreeIndex;\n" +" while(lastSubTreeIndex + 1 < numInternalNodes && commonPrefix == commonPrefixes[lastSubTreeIndex + 1]) ++lastSubTreeIndex;\n" +" \n" +" //Fix duplicate common prefixes by incrementing them so that a subtree is formed.\n" +" //Recursively divide the tree until the position of the split is this node's index.\n" +" //Every time this node is not the split node, increment the common prefix.\n" +" int isCurrentSplitNode = false;\n" +" int correctedCommonPrefix = commonPrefix;\n" +" \n" +" while(!isCurrentSplitNode)\n" +" {\n" +" int numInternalNodesInSubTree = lastSubTreeIndex - firstSubTreeIndex + 1;\n" +" int splitNodeIndex = firstSubTreeIndex + numInternalNodesInSubTree / 2;\n" +" \n" +" if(internalNodeIndex > splitNodeIndex) firstSubTreeIndex = splitNodeIndex + 1;\n" +" else if(internalNodeIndex < splitNodeIndex) lastSubTreeIndex = splitNodeIndex - 1;\n" +" //else if(internalNodeIndex == splitNodeIndex) break;\n" +" \n" +" isCurrentSplitNode = (internalNodeIndex == splitNodeIndex);\n" +" if(!isCurrentSplitNode) correctedCommonPrefix++;\n" +" }\n" +" \n" +" commonPrefixes[internalNodeIndex] = correctedCommonPrefix;\n" +" atomic_max(out_maxCommonPrefix, correctedCommonPrefix);\n" +"}\n" +"//Set so that it is always greater than the actual common prefixes, and never selected as a parent node.\n" +"//If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve.\n" +"//Duplicates common prefixes increase the highest common prefix by N, where 2^N is the number of duplicate nodes.\n" +"#define B3_PLBVH_INVALID_COMMON_PREFIX 128\n" +"__kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixes, __global int* out_leftChildNodes, \n" +" __global int* out_rightChildNodes, int numLeafNodes)\n" +"{\n" +" int leafNodeIndex = get_global_id(0);\n" +" if (leafNodeIndex >= numLeafNodes) return;\n" +" \n" +" int numInternalNodes = numLeafNodes - 1;\n" +" \n" +" int leftSplitIndex = leafNodeIndex - 1;\n" +" int rightSplitIndex = leafNodeIndex;\n" +" \n" +" int leftCommonPrefix = (leftSplitIndex >= 0) ? commonPrefixes[leftSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" int rightCommonPrefix = (rightSplitIndex < numInternalNodes) ? commonPrefixes[rightSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" \n" +" //Parent node is the highest adjacent common prefix that is lower than the node's common prefix\n" +" //Leaf nodes are considered as having the highest common prefix\n" +" int isLeftHigherCommonPrefix = (leftCommonPrefix > rightCommonPrefix);\n" +" \n" +" //Handle cases for the edge nodes; the first and last node\n" +" //For leaf nodes, leftCommonPrefix and rightCommonPrefix should never both be B3_PLBVH_INVALID_COMMON_PREFIX\n" +" if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = false;\n" +" if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true;\n" +" \n" +" int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftSplitIndex : rightSplitIndex;\n" +" \n" +" //If the left node is the parent, then this node is its right child and vice versa\n" +" __global int* out_childNode = (isLeftHigherCommonPrefix) ? out_rightChildNodes : out_leftChildNodes;\n" +" \n" +" int isLeaf = 1;\n" +" out_childNode[parentNodeIndex] = getIndexWithInternalNodeMarkerSet(isLeaf, leafNodeIndex);\n" +"}\n" +"__kernel void buildBinaryRadixTreeInternalNodes(__global int* commonPrefixes, __global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global int* leftChildNodes, __global int* rightChildNodes,\n" +" __global int* leftNeighborPointers, __global int* rightNeighborPointers,\n" +" __global b3AabbCL* leafNodeAabbs, __global b3AabbCL* internalNodeAabbs,\n" +" __global int* out_rootNodeIndex,\n" +" int processedCommonPrefix, int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if (internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" int commonPrefix = commonPrefixes[internalNodeIndex];\n" +" if (commonPrefix == processedCommonPrefix)\n" +" {\n" +" //Check neighbors and compare the common prefix to select the parent node\n" +" int leftNodeIndex = leftNeighborPointers[internalNodeIndex];\n" +" int rightNodeIndex = rightNeighborPointers[internalNodeIndex];\n" +" \n" +" int leftCommonPrefix = (leftNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) ? commonPrefixes[leftNodeIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" int rightCommonPrefix = (rightNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) ? commonPrefixes[rightNodeIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" \n" +" //Parent node is the highest common prefix that is lower than the node's common prefix\n" +" //Since the nodes with lower common prefixes are removed, that condition does not have to be tested for,\n" +" //and we only need to pick the node with the higher prefix.\n" +" int isLeftHigherCommonPrefix = (leftCommonPrefix > rightCommonPrefix);\n" +" \n" +" //\n" +" if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = false;\n" +" else if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true;\n" +" \n" +" int isRootNode = false;\n" +" if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX && rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isRootNode = true;\n" +" \n" +" int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftNodeIndex : rightNodeIndex;\n" +" \n" +" //If the left node is the parent, then this node is its right child and vice versa\n" +" __global int* out_childNode = (isLeftHigherCommonPrefix) ? rightChildNodes : leftChildNodes;\n" +" \n" +" int isLeaf = 0;\n" +" if(!isRootNode) out_childNode[parentNodeIndex] = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex);\n" +" \n" +" if(isRootNode) *out_rootNodeIndex = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex);\n" +" \n" +" //Remove this node from the linked list, \n" +" //so that the left and right nodes point at each other instead of this node\n" +" if(leftNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) rightNeighborPointers[leftNodeIndex] = rightNodeIndex;\n" +" if(rightNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) leftNeighborPointers[rightNodeIndex] = leftNodeIndex;\n" +" \n" +" //For debug\n" +" leftNeighborPointers[internalNodeIndex] = -2;\n" +" rightNeighborPointers[internalNodeIndex] = -2;\n" +" }\n" +" \n" +" //Processing occurs from highest common prefix to lowest common prefix\n" +" //Nodes in the previously processed level have their children set, so we merge their child AABBs here\n" +" if (commonPrefix == processedCommonPrefix + 1)\n" +" {\n" +" int leftChildIndex = leftChildNodes[internalNodeIndex];\n" +" int rightChildIndex = rightChildNodes[internalNodeIndex];\n" +" \n" +" int isLeftChildLeaf = isLeafNode(leftChildIndex);\n" +" int isRightChildLeaf = isLeafNode(rightChildIndex);\n" +" \n" +" leftChildIndex = getIndexWithInternalNodeMarkerRemoved(leftChildIndex);\n" +" rightChildIndex = getIndexWithInternalNodeMarkerRemoved(rightChildIndex);\n" +" \n" +" //leftRigidIndex/rightRigidIndex is not used if internal node\n" +" int leftRigidIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1;\n" +" int rightRigidIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1;\n" +" \n" +" b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftRigidIndex] : internalNodeAabbs[leftChildIndex];\n" +" b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightRigidIndex] : internalNodeAabbs[rightChildIndex];\n" +" \n" +" b3AabbCL mergedAabb;\n" +" mergedAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min);\n" +" mergedAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max);\n" +" internalNodeAabbs[internalNodeIndex] = mergedAabb;\n" +" }\n" +"}\n" +"__kernel void convertChildNodeFormat(__global int* leftChildNodes, __global int* rightChildNodes, \n" +" __global int2* out_childNodes, int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if (internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" int2 childNodesIndices;\n" +" childNodesIndices.x = leftChildNodes[internalNodeIndex];\n" +" childNodesIndices.y = rightChildNodes[internalNodeIndex];\n" +" \n" +" out_childNodes[internalNodeIndex] = childNodesIndices;\n" +"}\n" ; From 038364ccdd70e1f87a42bd36cfb898f4e499b59b Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Mon, 10 Mar 2014 15:33:47 -0700 Subject: [PATCH 010/116] Merge various commits into a single commit. Commits after: 2014-03-03 Draft PLBVH construction using binary radix tree. f19f85368517ff08a4f329710a1710f547c545d2 Are merged into a single commit; this includes: 03-10 Remove single launch build AABB kernel. 03-10 Add kernels for setting PLBVH AABBs using distance from root. 03-10 Use faster morton code, remove convertChildNodeFormat kernel. 03-09 Add duplicate morton code handling to binary radix construct. 03-09 Remove slower PLBVH constructors. 03-08 Add binary radix tree construct using binary search. 03-06 Remove slowest PLBVH constructor, fix implicit construct AABB. 03-04 Test various optimizations for PLBVH binary radix tree construct. --- .../b3GpuParallelLinearBvh.cpp | 448 ++++++-------- .../b3GpuParallelLinearBvh.h | 67 +- .../kernels/parallelLinearBvh.cl | 582 +++++++++--------- .../kernels/parallelLinearBvhKernels.h | 552 ++++++++--------- 4 files changed, 760 insertions(+), 889 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp index c5e8a89e1..fa1bc8db0 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -18,25 +18,24 @@ subject to the following restrictions: b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue) : m_queue(queue), - m_fill(context, device, queue), m_radixSorter(context, device, queue), m_rootNodeIndex(context, queue), - - m_numNodesPerLevelGpu(context, queue), - m_firstIndexOffsetPerLevelGpu(context, queue), + m_maxDistanceFromRoot(context, queue), m_internalNodeAabbs(context, queue), m_internalNodeLeafIndexRanges(context, queue), m_internalNodeChildNodes(context, queue), m_internalNodeParentNodes(context, queue), - m_maxCommonPrefix(context, queue), m_commonPrefixes(context, queue), - m_leftInternalNodePointers(context, queue), - m_rightInternalNodePointers(context, queue), - m_internalNodeLeftChildNodes(context, queue), - m_internalNodeRightChildNodes(context, queue), + m_commonPrefixLengths(context, queue), + m_childNodeCount(context, queue), + m_distanceFromRoot(context, queue), + m_TEMP_leftLowerPrefix(context, queue), + m_TEMP_rightLowerPrefix(context, queue), + m_TEMP_leftSharedPrefixLength(context, queue), + m_TEMP_rightSharedPrefixLength(context, queue), m_leafNodeParentNodes(context, queue), m_mortonCodesAndAabbIndicies(context, queue), @@ -46,8 +45,8 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_largeAabbs(context, queue) { m_rootNodeIndex.resize(1); - m_maxCommonPrefix.resize(1); - + m_maxDistanceFromRoot.resize(1); + // const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; @@ -64,21 +63,16 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_assignMortonCodesAndAabbIndiciesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "assignMortonCodesAndAabbIndicies", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_assignMortonCodesAndAabbIndiciesKernel); - m_constructBinaryTreeKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "constructBinaryTree", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_constructBinaryTreeKernel); - m_determineInternalNodeAabbsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "determineInternalNodeAabbs", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_determineInternalNodeAabbsKernel); - - m_computePrefixAndInitPointersKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "computePrefixAndInitPointers", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_computePrefixAndInitPointersKernel); - m_correctDuplicatePrefixesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "correctDuplicatePrefixes", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_correctDuplicatePrefixesKernel); + m_computeAdjacentPairCommonPrefixKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "computeAdjacentPairCommonPrefix", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_computeAdjacentPairCommonPrefixKernel); m_buildBinaryRadixTreeLeafNodesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeLeafNodes", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_buildBinaryRadixTreeLeafNodesKernel); m_buildBinaryRadixTreeInternalNodesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeInternalNodes", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_buildBinaryRadixTreeInternalNodesKernel); - m_convertChildNodeFormatKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "convertChildNodeFormat", &error, m_parallelLinearBvhProgram, additionalMacros ); - b3Assert(m_convertChildNodeFormatKernel); + m_findDistanceFromRootKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findDistanceFromRoot", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_findDistanceFromRootKernel); + m_buildBinaryRadixTreeAabbsRecursiveKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeAabbsRecursive", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_buildBinaryRadixTreeAabbsRecursiveKernel); m_plbvhCalculateOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhCalculateOverlappingPairs", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_plbvhCalculateOverlappingPairsKernel); @@ -96,14 +90,11 @@ b3GpuParallelLinearBvh::~b3GpuParallelLinearBvh() clReleaseKernel(m_findAllNodesMergedAabbKernel); clReleaseKernel(m_assignMortonCodesAndAabbIndiciesKernel); - clReleaseKernel(m_constructBinaryTreeKernel); - clReleaseKernel(m_determineInternalNodeAabbsKernel); - - clReleaseKernel(m_computePrefixAndInitPointersKernel); - clReleaseKernel(m_correctDuplicatePrefixesKernel); + clReleaseKernel(m_computeAdjacentPairCommonPrefixKernel); clReleaseKernel(m_buildBinaryRadixTreeLeafNodesKernel); clReleaseKernel(m_buildBinaryRadixTreeInternalNodesKernel); - clReleaseKernel(m_convertChildNodeFormatKernel); + clReleaseKernel(m_findDistanceFromRootKernel); + clReleaseKernel(m_buildBinaryRadixTreeAabbsRecursiveKernel); clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); clReleaseKernel(m_plbvhRayTraverseKernel); @@ -186,18 +177,19 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab m_internalNodeParentNodes.resize(numInternalNodes); m_commonPrefixes.resize(numInternalNodes); - m_leftInternalNodePointers.resize(numInternalNodes); - m_rightInternalNodePointers.resize(numInternalNodes); - m_internalNodeLeftChildNodes.resize(numInternalNodes); - m_internalNodeRightChildNodes.resize(numInternalNodes); + m_commonPrefixLengths.resize(numInternalNodes); + m_childNodeCount.resize(numInternalNodes); + m_distanceFromRoot.resize(numInternalNodes); + m_TEMP_leftLowerPrefix.resize(numInternalNodes); + m_TEMP_rightLowerPrefix.resize(numInternalNodes); + m_TEMP_leftSharedPrefixLength.resize(numInternalNodes); + m_TEMP_rightSharedPrefixLength.resize(numInternalNodes); m_leafNodeParentNodes.resize(numLeaves); m_mortonCodesAndAabbIndicies.resize(numLeaves); m_mergedAabb.resize(numLeaves); } - - //Find the merged AABB of all small AABBs; this is used to define the size of //each cell in the virtual grid(2^10 cells in each dimension). { @@ -255,18 +247,7 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab clFinish(m_queue); } - //Optional; only element at m_internalNodeParentNodes[0], the root node, needs to be set here - //as the parent indices of other nodes are overwritten during m_constructBinaryTreeKernel - { - B3_PROFILE("Reset parent node indices"); - - m_fill.execute( m_internalNodeParentNodes, B3_PLBVH_ROOT_NODE_MARKER, m_internalNodeParentNodes.size() ); - m_fill.execute( m_leafNodeParentNodes, B3_PLBVH_ROOT_NODE_MARKER, m_leafNodeParentNodes.size() ); - clFinish(m_queue); - } - // - //constructSimpleBinaryTree(); constructRadixBinaryTree(); } @@ -424,148 +405,11 @@ void b3GpuParallelLinearBvh::testRaysAgainstBvhAabbs(const b3OpenCLArray>= 1) mostSignificantBit++; //Start counting from 0 (0 and 1 have msb 0, 2 has msb 1) - } - numLevels = mostSignificantBit + 1; - - //If the number of nodes is not a power of 2(as in, can be expressed as 2^N where N is an integer), then there is 1 additional level - if( ~(1 << mostSignificantBit) & numLeaves ) numLevels++; - } - - //Determine number of internal nodes per level, use prefix sum to get offsets of each level, and send to GPU - { - B3_PROFILE("Determine number of nodes per level"); - - m_numNodesPerLevelCpu.resize(numLevels); - - //The last level contains the leaf nodes; number of leaves is already known - if(numLevels - 1 >= 0) m_numNodesPerLevelCpu[numLevels - 1] = numLeaves; - - //Calculate number of nodes in each level; - //start from the second to last level(level right next to leaf nodes) and move towards the root(level 0) - int remainder = 0; - for(int levelIndex = numLevels - 2; levelIndex >= 0; --levelIndex) - { - int numNodesPreviousLevel = m_numNodesPerLevelCpu[levelIndex + 1]; //For first iteration this == numLeaves - int numNodesCurrentLevel = numNodesPreviousLevel / 2; - - remainder += numNodesPreviousLevel % 2; - if(remainder == 2) - { - numNodesCurrentLevel++; - remainder = 0; - } - - m_numNodesPerLevelCpu[levelIndex] = numNodesCurrentLevel; - } - - //Prefix sum to calculate the first index offset of each level - { - m_firstIndexOffsetPerLevelCpu = m_numNodesPerLevelCpu; - - //Perform inclusive scan - for(int i = 1; i < m_firstIndexOffsetPerLevelCpu.size(); ++i) - m_firstIndexOffsetPerLevelCpu[i] += m_firstIndexOffsetPerLevelCpu[i - 1]; - - //Convert inclusive scan to exclusive scan to get the offsets - //This is equivalent to shifting each element in m_firstIndexOffsetPerLevelCpu[] by 1 to the right, - //and setting the first element to 0 - for(int i = 0; i < m_firstIndexOffsetPerLevelCpu.size(); ++i) - m_firstIndexOffsetPerLevelCpu[i] -= m_numNodesPerLevelCpu[i]; - } - - //Copy to GPU - m_numNodesPerLevelGpu.copyFromHost(m_numNodesPerLevelCpu, false); - m_firstIndexOffsetPerLevelGpu.copyFromHost(m_firstIndexOffsetPerLevelCpu, false); - clFinish(m_queue); - } - - //Construct binary tree; find the children of each internal node, and assign parent nodes - { - B3_PROFILE("Construct binary tree"); - - const int ROOT_NODE_INDEX = 0x80000000; //Default root index is 0, most significant bit is set to indicate internal node - m_rootNodeIndex.copyFromHostPointer(&ROOT_NODE_INDEX, 1); - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), - b3BufferInfoCL( m_leafNodeParentNodes.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_constructBinaryTreeKernel, "m_constructBinaryTreeKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLevels); - launcher.setConst(numInternalNodes); - - launcher.launch1D(numInternalNodes); - clFinish(m_queue); - } - - //For each internal node, check children to get its AABB; start from the - //last level, which contains the leaves, and move towards the root - { - B3_PROFILE("Set AABBs"); - - //Due to the arrangement of internal nodes, each internal node corresponds - //to a contiguous range of leaf node indices. This characteristic can be used - //to optimize calculateOverlappingPairs(); checking if - //(m_internalNodeLeafIndexRanges[].y < leafNodeIndex) can be used to ensure that - //each pair is processed only once. - { - B3_PROFILE("Reset internal node index ranges"); - - b3Int2 invalidIndexRange; - invalidIndexRange.x = -1; //x == min - invalidIndexRange.y = -2; //y == max - - m_fill.execute( m_internalNodeLeafIndexRanges, invalidIndexRange, m_internalNodeLeafIndexRanges.size() ); - clFinish(m_queue); - } - - int lastInternalLevelIndex = numLevels - 2; //Last level is leaf node level - for(int level = lastInternalLevelIndex; level >= 0; --level) - { - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_firstIndexOffsetPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_numNodesPerLevelGpu.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), - b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), - b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_determineInternalNodeAabbsKernel, "m_determineInternalNodeAabbsKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLevels); - launcher.setConst(numInternalNodes); - launcher.setConst(level); - - launcher.launch1D(numLeaves); - } - clFinish(m_queue); - } -} +// remove +#include +int isLeafNode(int index) { return (index >> 31 == 0); } +int getIndexWithInternalNodeMarkerRemoved(int index) { return index & (~0x80000000); } +int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : (index | 0x80000000); } void b3GpuParallelLinearBvh::constructRadixBinaryTree() { @@ -576,17 +420,16 @@ void b3GpuParallelLinearBvh::constructRadixBinaryTree() //For each internal node, compute common prefix and set pointers to left and right internal nodes { - B3_PROFILE("m_computePrefixAndInitPointersKernel"); + B3_PROFILE("m_computeAdjacentPairCommonPrefixKernel"); b3BufferInfoCL bufferInfo[] = { b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), - b3BufferInfoCL( m_leftInternalNodePointers.getBufferCL() ), - b3BufferInfoCL( m_rightInternalNodePointers.getBufferCL() ) + b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ) }; - b3LauncherCL launcher(m_queue, m_computePrefixAndInitPointersKernel, "m_computePrefixAndInitPointersKernel"); + b3LauncherCL launcher(m_queue, m_computeAdjacentPairCommonPrefixKernel, "m_computeAdjacentPairCommonPrefixKernel"); launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); launcher.setConst(numInternalNodes); @@ -594,96 +437,185 @@ void b3GpuParallelLinearBvh::constructRadixBinaryTree() clFinish(m_queue); } - //Increase the common prefixes so that there are no adjacent duplicates for each internal node { - B3_PROFILE("m_correctDuplicatePrefixesKernel"); - - int reset = 0; - m_maxCommonPrefix.copyFromHostPointer(&reset, 1); - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), - b3BufferInfoCL( m_maxCommonPrefix.getBufferCL() ), - }; - - b3LauncherCL launcher(m_queue, m_correctDuplicatePrefixesKernel, "m_correctDuplicatePrefixesKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numInternalNodes); - - launcher.launch1D(numInternalNodes); + static b3AlignedObjectArray prefixLengths; + m_commonPrefixLengths.copyToHost(prefixLengths); clFinish(m_queue); + + for(int i = 1; i < prefixLengths.size(); ++i) + if( prefixLengths[i - 1] == prefixLengths[i] ) + for(;;) printf("duplicate prefix[%d]: %d\n", i, prefixLengths[i]); } - //For each leaf node, find parent nodes and assign child node indices { - B3_PROFILE("m_buildBinaryRadixTreeLeafNodesKernel"); - - b3BufferInfoCL bufferInfo[] = + //For each leaf node, find parent nodes and assign child node indices { - b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeLeftChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeRightChildNodes.getBufferCL() ) - }; + B3_PROFILE("m_buildBinaryRadixTreeLeafNodesKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ), + b3BufferInfoCL( m_leafNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeLeafNodesKernel, "m_buildBinaryRadixTreeLeafNodesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLeaves); + + launcher.launch1D(numLeaves); + clFinish(m_queue); + } - b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeLeafNodesKernel, "m_buildBinaryRadixTreeLeafNodesKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLeaves); - - launcher.launch1D(numLeaves); - clFinish(m_queue); - } - - //For each internal node, find parent nodes and assign child node indices - { - B3_PROFILE("m_buildBinaryRadixTreeInternalNodesKernel"); - - int maxCommonPrefix = -1; - m_maxCommonPrefix.copyToHostPointer(&maxCommonPrefix, 1); - - //-1 so that the root sets its AABB - for(int processedCommonPrefix = maxCommonPrefix; processedCommonPrefix >= -1; --processedCommonPrefix) + //For each internal node, find parent nodes and assign child node indices { + B3_PROFILE("m_buildBinaryRadixTreeInternalNodesKernel"); + b3BufferInfoCL bufferInfo[] = { b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - b3BufferInfoCL( m_internalNodeLeftChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeRightChildNodes.getBufferCL() ), - b3BufferInfoCL( m_leftInternalNodePointers.getBufferCL() ), - b3BufferInfoCL( m_rightInternalNodePointers.getBufferCL() ), - b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), - b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ), - b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ) + b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_TEMP_leftLowerPrefix.getBufferCL() ), + b3BufferInfoCL( m_TEMP_rightLowerPrefix.getBufferCL() ), + b3BufferInfoCL( m_TEMP_leftSharedPrefixLength.getBufferCL() ), + b3BufferInfoCL( m_TEMP_rightSharedPrefixLength.getBufferCL() ) }; b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeInternalNodesKernel, "m_buildBinaryRadixTreeInternalNodesKernel"); launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(processedCommonPrefix); launcher.setConst(numInternalNodes); launcher.launch1D(numInternalNodes); + clFinish(m_queue); } - clFinish(m_queue); - } - - { - B3_PROFILE("m_convertChildNodeFormatKernel"); - - b3BufferInfoCL bufferInfo[] = + if(0) { - b3BufferInfoCL( m_internalNodeLeftChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeRightChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ) - }; + static b3AlignedObjectArray mortonCodesAndAabbIndices; + + static b3AlignedObjectArray child; + static b3AlignedObjectArray commonPrefixes; + static b3AlignedObjectArray commonPrefixLengths; + static b3AlignedObjectArray tempLeftLowerPrefixIndex; + static b3AlignedObjectArray tempRightLowerPrefixIndex; + static b3AlignedObjectArray tempLeftLowerPrefixSPL; + static b3AlignedObjectArray tempRightLowerPrefixSPL; + static b3AlignedObjectArray internalParent; + + m_mortonCodesAndAabbIndicies.copyToHost(mortonCodesAndAabbIndices); + + m_internalNodeChildNodes.copyToHost(child); + m_commonPrefixes.copyToHost(commonPrefixes); + m_commonPrefixLengths.copyToHost(commonPrefixLengths); + m_TEMP_leftLowerPrefix.copyToHost(tempLeftLowerPrefixIndex); + m_TEMP_rightLowerPrefix.copyToHost(tempRightLowerPrefixIndex); + m_TEMP_leftSharedPrefixLength.copyToHost(tempLeftLowerPrefixSPL); + m_TEMP_rightSharedPrefixLength.copyToHost(tempRightLowerPrefixSPL); + m_internalNodeParentNodes.copyToHost(internalParent); + + int rootNode = -1; + m_rootNodeIndex.copyToHostPointer(&rootNode, 1); + clFinish(m_queue); + + printf( "rootNode: %d\n", getIndexWithInternalNodeMarkerRemoved(rootNode) ); + + for(int i = 0; i < numInternalNodes; ++i) + { + b3Int2 childNodes = child[i]; + + printf("childNodes[%d]:", i); + printf( " %d", getIndexWithInternalNodeMarkerRemoved(childNodes.x) ); + if( !isLeafNode(childNodes.x) ) printf("i"); + printf( ", %d", getIndexWithInternalNodeMarkerRemoved(childNodes.y) ); + if( !isLeafNode(childNodes.y) ) printf("i"); + printf(" (lr: %d, %d)", tempLeftLowerPrefixIndex[i], tempRightLowerPrefixIndex[i]); + printf(" (spl: %d, %d)", tempLeftLowerPrefixSPL[i], tempRightLowerPrefixSPL[i]); + printf(" (prefix: %d)", commonPrefixLengths[i]); + printf(" (par: %d)", internalParent[i]); + printf("\n"); + } + printf("\n"); + + for(int i = 0; i < numInternalNodes; ++i) + { + int hi = static_cast(commonPrefixes[i] >> 32); + int lo = static_cast(commonPrefixes[i]); + + printf("commonPrefix[%d]: %x, %d, len %d \n", i, hi, lo, commonPrefixLengths[i]); + } + printf("\n"); + + for(int i = 0; i < numLeaves; ++i) + { + printf("z-curve[%d]: %x \n", i, mortonCodesAndAabbIndices[i].m_key); + } + printf("\n"); + + + std::cout << std::endl; + for(;;); + } - b3LauncherCL launcher(m_queue, m_convertChildNodeFormatKernel, "m_convertChildNodeFormatKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numInternalNodes); + //Find the number of nodes seperating each internal node and the root node + //so that the AABBs can be set using the next kernel + { + B3_PROFILE("m_findDistanceFromRootKernel"); - launcher.launch1D(numInternalNodes); - clFinish(m_queue); + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_maxDistanceFromRoot.getBufferCL() ), + b3BufferInfoCL( m_distanceFromRoot.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_findDistanceFromRootKernel, "m_findDistanceFromRootKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } + + //Starting from the nodes nearest to the leaf nodes, recursively move up + //the tree to set the AABBs of each internal node; each internal node + //checks its children and merges their AABBs + { + B3_PROFILE("m_buildBinaryRadixTreeAabbsRecursiveKernel"); + + int maxDistanceFromRoot = -1; + { + B3_PROFILE("copy maxDistanceFromRoot to CPU"); + m_maxDistanceFromRoot.copyToHostPointer(&maxDistanceFromRoot, 1); + clFinish(m_queue); + } + + for(int distanceFromRoot = maxDistanceFromRoot; distanceFromRoot >= 0; --distanceFromRoot) + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_distanceFromRoot.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeAabbsRecursiveKernel, "m_buildBinaryRadixTreeAabbsRecursiveKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxDistanceFromRoot); + launcher.setConst(distanceFromRoot); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + } + + clFinish(m_queue); + } + } } diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index 559786cbb..4d5467481 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -22,10 +22,11 @@ subject to the following restrictions: #include "Bullet3OpenCL/ParallelPrimitives/b3FillCL.h" #include "Bullet3OpenCL/ParallelPrimitives/b3RadixSort32CL.h" +#include "Bullet3OpenCL/ParallelPrimitives/b3PrefixScanCL.h" #include "Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h" -#define B3_PLBVH_ROOT_NODE_MARKER -1 //Syncronize with parallelLinearBvh.cl +#define b3Int64 cl_long ///@brief GPU Parallel Linearized Bounding Volume Heirarchy(LBVH) that is reconstructed every frame ///@remarks @@ -36,16 +37,13 @@ subject to the following restrictions: ///The basic algorithm for building the BVH as presented in [Lauterbach et al. 2009] consists of 4 stages: /// - [fully parallel] Assign morton codes for each AABB using its center (after quantizing the AABB centers into a virtual grid) /// - [fully parallel] Sort morton codes -/// - [somewhat parallel] Build radix binary tree (assign parent/child pointers for internal nodes of the BVH) +/// - [somewhat parallel] Build binary radix tree (assign parent/child pointers for internal nodes of the BVH) /// - [somewhat parallel] Set internal node AABBs ///@par ///[Karras 2012] improves on the algorithm by introducing fully parallel methods for the last 2 stages. -///The BVH implementation here is almost the same as [Karras 2012], but a different method is used for constructing the tree. -/// - Instead of building a binary radix tree, we simply pair each node with its nearest sibling. -/// This has the effect of further worsening the quality of the BVH, but the main spatial partitioning is done by the -/// Z-curve anyways, and this method should be simpler and faster during construction. -/// - Rather than traveling upwards towards the root from the leaf nodes, as in the paper, -/// each internal node checks its child nodes to get its AABB. +///The BVH implementation here shares many concepts with [Karras 2012], but a different method is used for constructing the tree. +///Instead of searching for the child nodes of each internal node, we search for the parent node of each node. +///Additionally, a non-atomic traversal that starts from the leaf nodes and moves towards the root node is used to set the AABBs. class b3GpuParallelLinearBvh { cl_command_queue m_queue; @@ -56,58 +54,49 @@ class b3GpuParallelLinearBvh cl_kernel m_findAllNodesMergedAabbKernel; cl_kernel m_assignMortonCodesAndAabbIndiciesKernel; - //Simple binary tree construction kernels - cl_kernel m_constructBinaryTreeKernel; - cl_kernel m_determineInternalNodeAabbsKernel; - - //Radix binary tree construction kernels - cl_kernel m_computePrefixAndInitPointersKernel; - cl_kernel m_correctDuplicatePrefixesKernel; + //Binary radix tree construction kernels + cl_kernel m_computeAdjacentPairCommonPrefixKernel; cl_kernel m_buildBinaryRadixTreeLeafNodesKernel; cl_kernel m_buildBinaryRadixTreeInternalNodesKernel; - cl_kernel m_convertChildNodeFormatKernel; + cl_kernel m_findDistanceFromRootKernel; + cl_kernel m_buildBinaryRadixTreeAabbsRecursiveKernel; //Traversal kernels cl_kernel m_plbvhCalculateOverlappingPairsKernel; cl_kernel m_plbvhRayTraverseKernel; - cl_kernel m_plbvhLargeAabbAabbTestKernel; cl_kernel m_plbvhLargeAabbRayTestKernel; - - b3FillCL m_fill; + b3RadixSort32CL m_radixSorter; - // + //1 element b3OpenCLArray m_rootNodeIndex; + b3OpenCLArray m_maxDistanceFromRoot; - //1 element per level in the tree - b3AlignedObjectArray m_numNodesPerLevelCpu; //Level 0(m_numNodesPerLevelCpu[0]) is the root, last level contains the leaf nodes - b3AlignedObjectArray m_firstIndexOffsetPerLevelCpu; //Contains the index/offset of the first node in that level - b3OpenCLArray m_numNodesPerLevelGpu; - b3OpenCLArray m_firstIndexOffsetPerLevelGpu; - - //1 element per internal node (number_of_internal_nodes = number_of_leaves - 1) + //1 element per internal node (number_of_internal_nodes == number_of_leaves - 1) b3OpenCLArray m_internalNodeAabbs; b3OpenCLArray m_internalNodeLeafIndexRanges; //x == min leaf index, y == max leaf index b3OpenCLArray m_internalNodeChildNodes; //x == left child, y == right child b3OpenCLArray m_internalNodeParentNodes; - //1 element per internal node; for radix binary tree construction - b3OpenCLArray m_maxCommonPrefix; - b3OpenCLArray m_commonPrefixes; - b3OpenCLArray m_leftInternalNodePointers; //Linked list - b3OpenCLArray m_rightInternalNodePointers; //Linked list - b3OpenCLArray m_internalNodeLeftChildNodes; - b3OpenCLArray m_internalNodeRightChildNodes; + //1 element per internal node; for binary radix tree construction + b3OpenCLArray m_commonPrefixes; + b3OpenCLArray m_commonPrefixLengths; + b3OpenCLArray m_childNodeCount; + b3OpenCLArray m_distanceFromRoot; + b3OpenCLArray m_TEMP_leftLowerPrefix; + b3OpenCLArray m_TEMP_rightLowerPrefix; + b3OpenCLArray m_TEMP_leftSharedPrefixLength; + b3OpenCLArray m_TEMP_rightSharedPrefixLength; //1 element per leaf node (leaf nodes only include small AABBs) b3OpenCLArray m_leafNodeParentNodes; - b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key = morton code, m_value == aabb index - b3OpenCLArray m_mergedAabb; + b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key == morton code, m_value == aabb index + b3OpenCLArray m_mergedAabb; //m_mergedAabb[0] contains the merged AABB of all leaf nodes b3OpenCLArray m_leafNodeAabbs; //Contains only small AABBs - //1 element per large AABB - b3OpenCLArray m_largeAabbs; //Not stored in the BVH + //1 element per large AABB, which is not stored in the BVH + b3OpenCLArray m_largeAabbs; public: b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue); @@ -131,8 +120,6 @@ public: b3OpenCLArray& out_numRayRigidPairs, b3OpenCLArray& out_rayRigidPairs); private: - void constructSimpleBinaryTree(); - void constructRadixBinaryTree(); }; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index 3bcd4f351..2c17f8623 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -45,34 +45,29 @@ unsigned int interleaveBits(unsigned int x) //........ ........ ......12 3456789A //x //....1..2 ..3..4.. 5..6..7. .8..9..A //x after interleaving bits - //........ ....1234 56789A12 3456789A //x |= (x << 10) - //........ ....1111 1....... ...11111 //0x 00 0F 80 1F - //........ ....1234 5....... ...6789A //x = ( x | (x << 10) ) & 0x000F801F; + //......12 3456789A ......12 3456789A //x ^ (x << 16) + //11111111 ........ ........ 11111111 //0x FF 00 00 FF + //......12 ........ ........ 3456789A //x = (x ^ (x << 16)) & 0xFF0000FF; - //.......1 23451234 5.....67 89A6789A //x |= (x << 5) - //.......1 1.....11 1.....11 .....111 //0x 01 83 83 07 - //.......1 2.....34 5.....67 .....89A //x = ( x | (x << 5) ) & 0x01838307; + //......12 ........ 3456789A 3456789A //x ^ (x << 8) + //......11 ........ 1111.... ....1111 //0x 03 00 F0 0F + //......12 ........ 3456.... ....789A //x = (x ^ (x << 8)) & 0x0300F00F; - //....12.1 2..34534 5..67.67 ..89A89A //x |= (x << 3) - //....1... 1..1...1 1..1...1 ..1...11 //0x 08 91 91 23 - //....1... 2..3...4 5..6...7 ..8...9A //x = ( x | (x << 3) ) & 0x08919123; + //..12..12 ....3456 3456.... 789A789A //x ^ (x << 4) + //......11 ....11.. ..11.... 11....11 //0x 03 0C 30 C3 + //......12 ....34.. ..56.... 78....9A //x = (x ^ (x << 4)) & 0x030C30C3; - //...11..2 2.33..4N 5.66..77 .88..9NA //x |= (x << 1) ( N indicates overlapping bits, first overlap is bit {4,5} second is {9,A} ) - //....1..1 ..1...1. 1..1..1. .1...1.1 //0x 09 22 92 45 - //....1..2 ..3...4. 5..6..7. .8...9.A //x = ( x | (x << 1) ) & 0x09229245; - - //...11.22 .33..445 5.66.77. 88..99AA //x |= (x << 1) - //....1..1 ..1..1.. 1..1..1. .1..1..1 //0x 09 34 92 29 - //....1..2 ..3..4.. 5..6..7. .8..9..A //x = ( x | (x << 1) ) & 0x09349229; + //....1212 ..3434.. 5656..78 78..9A9A //x ^ (x << 2) + //....1..1 ..1..1.. 1..1..1. .1..1..1 //0x 09 24 92 49 + //....1..2 ..3..4.. 5..6..7. .8..9..A //x = (x ^ (x << 2)) & 0x09249249; //........ ........ ......11 11111111 //0x000003FF x &= 0x000003FF; //Clear all bits above bit 10 - x = ( x | (x << 10) ) & 0x000F801F; - x = ( x | (x << 5) ) & 0x01838307; - x = ( x | (x << 3) ) & 0x08919123; - x = ( x | (x << 1) ) & 0x09229245; - x = ( x | (x << 1) ) & 0x09349229; + x = (x ^ (x << 16)) & 0xFF0000FF; + x = (x ^ (x << 8)) & 0x0300F00F; + x = (x ^ (x << 4)) & 0x030C30C3; + x = (x ^ (x << 2)) & 0x09249249; return x; } @@ -160,147 +155,11 @@ __kernel void assignMortonCodesAndAabbIndicies(__global b3AabbCL* worldSpaceAabb //The most significant bit(0x80000000) of a int32 is used to distinguish between leaf and internal nodes. //If it is set, then the index is for an internal node; otherwise, it is a leaf node. -//In both cases, the bit should be cleared to access the index. +//In both cases, the bit should be cleared to access the actual node index. int isLeafNode(int index) { return (index >> 31 == 0); } int getIndexWithInternalNodeMarkerRemoved(int index) { return index & (~0x80000000); } int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : (index | 0x80000000); } -__kernel void constructBinaryTree(__global int* firstIndexOffsetPerLevel, - __global int* numNodesPerLevel, - __global int2* out_internalNodeChildIndices, - __global int* out_internalNodeParentNodes, - __global int* out_leafNodeParentNodes, - int numLevels, int numInternalNodes) -{ - int internalNodeIndex = get_global_id(0); - if(internalNodeIndex >= numInternalNodes) return; - - //Find the level that this node is in, using linear search(could replace with binary search) - int level = 0; - int numInternalLevels = numLevels - 1; //All levels except the last are internal nodes - for(; level < numInternalLevels; ++level) - { - if( firstIndexOffsetPerLevel[level] <= internalNodeIndex && internalNodeIndex < firstIndexOffsetPerLevel[level + 1]) break; - } - - //Check lower levels to find child nodes - //Left child is always in the next level, but the same does not apply to the right child - int indexInLevel = internalNodeIndex - firstIndexOffsetPerLevel[level]; - int firstIndexInNextLevel = firstIndexOffsetPerLevel[level + 1]; //Should never be out of bounds(see for loop above) - - int leftChildLevel = level + 1; - int leftChildIndex = firstIndexInNextLevel + indexInLevel * 2; - - int rightChildLevel = level + 1; - int rightChildIndex = leftChildIndex + 1; - - //Under certain conditions, the right child index as calculated above is invalid; need to find the correct index - // - //First condition: must be at least 2 levels apart from the leaf node level; - //if the current level is right next to the leaf node level, then the right child - //will never be invalid due to the way the nodes are allocated (also avoid a out-of-bounds memory access) - // - //Second condition: not enough nodes in the next level for each parent to have 2 children, so the right child is invalid - // - //Third condition: must be the last node in its level - if( level < numLevels - 2 - && numNodesPerLevel[level] * 2 > numNodesPerLevel[level + 1] - && indexInLevel == numNodesPerLevel[level] - 1 ) - { - //Check lower levels until we find a node without a parent - for(; rightChildLevel < numLevels - 1; ++rightChildLevel) - { - int rightChildNextLevel = rightChildLevel + 1; - - //If this branch is taken, it means that the last node in rightChildNextLevel has no parent - if( numNodesPerLevel[rightChildLevel] * 2 < numNodesPerLevel[rightChildNextLevel] ) - { - //Set the node to the last node in rightChildNextLevel - rightChildLevel = rightChildNextLevel; - rightChildIndex = firstIndexOffsetPerLevel[rightChildNextLevel] + numNodesPerLevel[rightChildNextLevel] - 1; - break; - } - } - } - - int isLeftChildLeaf = (leftChildLevel >= numLevels - 1); - int isRightChildLeaf = (rightChildLevel >= numLevels - 1); - - //If left/right child is a leaf node, the index needs to be corrected - //the way the index is calculated assumes that the leaf and internal nodes are in a contiguous array, - //with leaf nodes at the end of the array; in actuality, the leaf and internal nodes are in separate arrays - { - int leafNodeLevel = numLevels - 1; - leftChildIndex = (isLeftChildLeaf) ? leftChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : leftChildIndex; - rightChildIndex = (isRightChildLeaf) ? rightChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : rightChildIndex; - } - - //Set the negative sign bit if the node is internal - int2 childIndices; - childIndices.x = getIndexWithInternalNodeMarkerSet(isLeftChildLeaf, leftChildIndex); - childIndices.y = getIndexWithInternalNodeMarkerSet(isRightChildLeaf, rightChildIndex); - out_internalNodeChildIndices[internalNodeIndex] = childIndices; - - //Assign parent node index to children - __global int* out_leftChildParentNodeIndices = (isLeftChildLeaf) ? out_leafNodeParentNodes : out_internalNodeParentNodes; - out_leftChildParentNodeIndices[leftChildIndex] = internalNodeIndex; - - __global int* out_rightChildParentNodeIndices = (isRightChildLeaf) ? out_leafNodeParentNodes : out_internalNodeParentNodes; - out_rightChildParentNodeIndices[rightChildIndex] = internalNodeIndex; -} - -__kernel void determineInternalNodeAabbs(__global int* firstIndexOffsetPerLevel, - __global int* numNodesPerLevel, - __global int2* internalNodeChildIndices, - __global SortDataCL* mortonCodesAndAabbIndices, - __global b3AabbCL* leafNodeAabbs, - __global int2* out_internalNodeLeafIndexRanges, - __global b3AabbCL* out_internalNodeAabbs, - int numLevels, int numInternalNodes, int level) -{ - int i = get_global_id(0); - if(i >= numInternalNodes) return; - - //For each node in a level, check its child nodes to determine its AABB - { - int indexInLevel = i; //Index relative to firstIndexOffsetPerLevel[level] - - int numNodesInLevel = numNodesPerLevel[level]; - if(indexInLevel < numNodesInLevel) - { - int internalNodeIndexGlobal = indexInLevel + firstIndexOffsetPerLevel[level]; - int2 childIndicies = internalNodeChildIndices[internalNodeIndexGlobal]; - - int leftChildIndex = getIndexWithInternalNodeMarkerRemoved(childIndicies.x); - int rightChildIndex = getIndexWithInternalNodeMarkerRemoved(childIndicies.y); - - int isLeftChildLeaf = isLeafNode(childIndicies.x); - int isRightChildLeaf = isLeafNode(childIndicies.y); - - //left/RightChildLeafIndex == Rigid body indicies - int leftChildLeafIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1; - int rightChildLeafIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1; - - b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftChildLeafIndex] : out_internalNodeAabbs[leftChildIndex]; - b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightChildLeafIndex] : out_internalNodeAabbs[rightChildIndex]; - - // - b3AabbCL internalNodeAabb; - internalNodeAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min); - internalNodeAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max); - out_internalNodeAabbs[internalNodeIndexGlobal] = internalNodeAabb; - - //For index range, x == min and y == max; left child always has lower index - int2 leafIndexRange; - leafIndexRange.x = (isLeftChildLeaf) ? leftChildIndex : out_internalNodeLeafIndexRanges[leftChildIndex].x; - leafIndexRange.y = (isRightChildLeaf) ? rightChildIndex : out_internalNodeLeafIndexRanges[rightChildIndex].y; - - out_internalNodeLeafIndexRanges[internalNodeIndexGlobal] = leafIndexRange; - } - } -} - - //From sap.cl #define NEW_PAIR_MARKER -1 @@ -567,84 +426,65 @@ __kernel void plbvhLargeAabbRayTest(__global b3AabbCL* largeRigidAabbs, __global } - -#define B3_PLBVH_LINKED_LIST_INVALID_NODE -1 - -int longestCommonPrefix(int i, int j) { return clz(i ^ j); } - -__kernel void computePrefixAndInitPointers(__global SortDataCL* mortonCodesAndAabbIndices, - __global int* out_commonPrefixes, - __global int* out_leftInternalNodePointers, - __global int* out_rightInternalNodePointers, - int numInternalNodes) -{ - int internalNodeIndex = get_global_id(0); - if (internalNodeIndex >= numInternalNodes) return; - - //Compute common prefix - { - //Here, (internalNodeIndex + 1) is never out of bounds since it is a leaf node index, - //and the number of internal nodes is always numLeafNodes - 1 - int leftLeafMortonCode = mortonCodesAndAabbIndices[internalNodeIndex].m_key; - int rightLeafMortonCode = mortonCodesAndAabbIndices[internalNodeIndex + 1].m_key; - - out_commonPrefixes[internalNodeIndex] = longestCommonPrefix(leftLeafMortonCode, rightLeafMortonCode); - } - - //Assign neighbor pointers of this node - { - int leftInternalIndex = internalNodeIndex - 1; - int rightInternalIndex = internalNodeIndex + 1; - - out_leftInternalNodePointers[internalNodeIndex] = (leftInternalIndex >= 0) ? leftInternalIndex : B3_PLBVH_LINKED_LIST_INVALID_NODE; - out_rightInternalNodePointers[internalNodeIndex] = (rightInternalIndex < numInternalNodes) ? rightInternalIndex : B3_PLBVH_LINKED_LIST_INVALID_NODE; - } -} - -__kernel void correctDuplicatePrefixes(__global int* commonPrefixes, __global int* out_maxCommonPrefix, int numInternalNodes) -{ - int internalNodeIndex = get_global_id(0); - if (internalNodeIndex >= numInternalNodes) return; - - int commonPrefix = commonPrefixes[internalNodeIndex]; - - //Linear search to find the size of the subtree - int firstSubTreeIndex = internalNodeIndex; - int lastSubTreeIndex = internalNodeIndex; - - while(firstSubTreeIndex - 1 >= 0 && commonPrefix == commonPrefixes[firstSubTreeIndex - 1]) --firstSubTreeIndex; - while(lastSubTreeIndex + 1 < numInternalNodes && commonPrefix == commonPrefixes[lastSubTreeIndex + 1]) ++lastSubTreeIndex; - - //Fix duplicate common prefixes by incrementing them so that a subtree is formed. - //Recursively divide the tree until the position of the split is this node's index. - //Every time this node is not the split node, increment the common prefix. - int isCurrentSplitNode = false; - int correctedCommonPrefix = commonPrefix; - - while(!isCurrentSplitNode) - { - int numInternalNodesInSubTree = lastSubTreeIndex - firstSubTreeIndex + 1; - int splitNodeIndex = firstSubTreeIndex + numInternalNodesInSubTree / 2; - - if(internalNodeIndex > splitNodeIndex) firstSubTreeIndex = splitNodeIndex + 1; - else if(internalNodeIndex < splitNodeIndex) lastSubTreeIndex = splitNodeIndex - 1; - //else if(internalNodeIndex == splitNodeIndex) break; - - isCurrentSplitNode = (internalNodeIndex == splitNodeIndex); - if(!isCurrentSplitNode) correctedCommonPrefix++; - } - - commonPrefixes[internalNodeIndex] = correctedCommonPrefix; - atomic_max(out_maxCommonPrefix, correctedCommonPrefix); -} - //Set so that it is always greater than the actual common prefixes, and never selected as a parent node. //If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve. //Duplicates common prefixes increase the highest common prefix by N, where 2^N is the number of duplicate nodes. #define B3_PLBVH_INVALID_COMMON_PREFIX 128 -__kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixes, __global int* out_leftChildNodes, - __global int* out_rightChildNodes, int numLeafNodes) +#define B3_PLBVH_ROOT_NODE_MARKER -1 + +#define b3Int64 long + +int computeCommonPrefixLength(b3Int64 i, b3Int64 j) { return (int)clz(i ^ j); } +b3Int64 computeCommonPrefix(b3Int64 i, b3Int64 j) +{ + //This function only needs to return (i & j) in order for the algorithm to work, + //but it may help with debugging to mask out the lower bits. + + b3Int64 commonPrefixLength = (b3Int64)computeCommonPrefixLength(i, j); + + b3Int64 sharedBits = i & j; + b3Int64 bitmask = ((b3Int64)(~0)) << (64 - commonPrefixLength); //Set all bits after the common prefix to 0 + + return sharedBits & bitmask; +} +int getSharedPrefixLength(b3Int64 prefixA, int prefixLengthA, b3Int64 prefixB, int prefixLengthB) +{ + return b3Min( computeCommonPrefixLength(prefixA, prefixB), b3Min(prefixLengthA, prefixLengthB) ); +} + +__kernel void computeAdjacentPairCommonPrefix(__global SortDataCL* mortonCodesAndAabbIndices, + __global b3Int64* out_commonPrefixes, + __global int* out_commonPrefixLengths, + int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if (internalNodeIndex >= numInternalNodes) return; + + //Here, (internalNodeIndex + 1) is never out of bounds since it is a leaf node index, + //and the number of internal nodes is always numLeafNodes - 1 + int leftLeafIndex = internalNodeIndex; + int rightLeafIndex = internalNodeIndex + 1; + + int leftLeafMortonCode = mortonCodesAndAabbIndices[leftLeafIndex].m_key; + int rightLeafMortonCode = mortonCodesAndAabbIndices[rightLeafIndex].m_key; + + //Binary radix tree construction algorithm does not work if there are duplicate morton codes. + //Append the index of each leaf node to each morton code so that there are no duplicates. + //The algorithm also requires that the morton codes are sorted in ascending order; this requirement + //is also satisfied with this method, as (leftLeafIndex < rightLeafIndex) is always true. + // + //upsample(a, b) == ( ((b3Int64)a) << 32) | b + b3Int64 nonduplicateLeftMortonCode = upsample(leftLeafMortonCode, leftLeafIndex); + b3Int64 nonduplicateRightMortonCode = upsample(rightLeafMortonCode, rightLeafIndex); + + out_commonPrefixes[internalNodeIndex] = computeCommonPrefix(nonduplicateLeftMortonCode, nonduplicateRightMortonCode); + out_commonPrefixLengths[internalNodeIndex] = computeCommonPrefixLength(nonduplicateLeftMortonCode, nonduplicateRightMortonCode); +} + + +__kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixLengths, __global int* out_leafNodeParentNodes, + __global int2* out_childNodes, int numLeafNodes) { int leafNodeIndex = get_global_id(0); if (leafNodeIndex >= numLeafNodes) return; @@ -654,8 +494,8 @@ __kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixes, __glob int leftSplitIndex = leafNodeIndex - 1; int rightSplitIndex = leafNodeIndex; - int leftCommonPrefix = (leftSplitIndex >= 0) ? commonPrefixes[leftSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; - int rightCommonPrefix = (rightSplitIndex < numInternalNodes) ? commonPrefixes[rightSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + int leftCommonPrefix = (leftSplitIndex >= 0) ? commonPrefixLengths[leftSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + int rightCommonPrefix = (rightSplitIndex < numInternalNodes) ? commonPrefixLengths[rightSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; //Parent node is the highest adjacent common prefix that is lower than the node's common prefix //Leaf nodes are considered as having the highest common prefix @@ -667,72 +507,223 @@ __kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixes, __glob if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true; int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftSplitIndex : rightSplitIndex; + out_leafNodeParentNodes[leafNodeIndex] = parentNodeIndex; - //If the left node is the parent, then this node is its right child and vice versa - __global int* out_childNode = (isLeftHigherCommonPrefix) ? out_rightChildNodes : out_leftChildNodes; + int isRightChild = (isLeftHigherCommonPrefix); //If the left node is the parent, then this node is its right child and vice versa + //out_childNodesAsInt[0] == int2.x == left child + //out_childNodesAsInt[1] == int2.y == right child int isLeaf = 1; - out_childNode[parentNodeIndex] = getIndexWithInternalNodeMarkerSet(isLeaf, leafNodeIndex); + __global int* out_childNodesAsInt = (__global int*)(&out_childNodes[parentNodeIndex]); + out_childNodesAsInt[isRightChild] = getIndexWithInternalNodeMarkerSet(isLeaf, leafNodeIndex); } -__kernel void buildBinaryRadixTreeInternalNodes(__global int* commonPrefixes, __global SortDataCL* mortonCodesAndAabbIndices, - __global int* leftChildNodes, __global int* rightChildNodes, - __global int* leftNeighborPointers, __global int* rightNeighborPointers, - __global b3AabbCL* leafNodeAabbs, __global b3AabbCL* internalNodeAabbs, - __global int* out_rootNodeIndex, - int processedCommonPrefix, int numInternalNodes) +__kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes, __global int* commonPrefixLengths, + __global int2* out_childNodes, + __global int* out_internalNodeParentNodes, __global int* out_rootNodeIndex, + __global int* TEMP_out_leftLowerPrefix, __global int* TEMP_out_rightLowerPrefix, + __global int* TEMP_spl_left, __global int* TEMP_spl_right, + int numInternalNodes) { - int internalNodeIndex = get_global_id(0); - if (internalNodeIndex >= numInternalNodes) return; + int internalNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0); + if(internalNodeIndex >= numInternalNodes) return; - int commonPrefix = commonPrefixes[internalNodeIndex]; - if (commonPrefix == processedCommonPrefix) + b3Int64 nodePrefix = commonPrefixes[internalNodeIndex]; + int nodePrefixLength = commonPrefixLengths[internalNodeIndex]; + +//#define USE_LINEAR_SEARCH +#ifdef USE_LINEAR_SEARCH + int leftIndex = -1; + int rightIndex = -1; + + for(int i = internalNodeIndex - 1; i >= 0; --i) { - //Check neighbors and compare the common prefix to select the parent node - int leftNodeIndex = leftNeighborPointers[internalNodeIndex]; - int rightNodeIndex = rightNeighborPointers[internalNodeIndex]; - - int leftCommonPrefix = (leftNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) ? commonPrefixes[leftNodeIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; - int rightCommonPrefix = (rightNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) ? commonPrefixes[rightNodeIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; - - //Parent node is the highest common prefix that is lower than the node's common prefix - //Since the nodes with lower common prefixes are removed, that condition does not have to be tested for, - //and we only need to pick the node with the higher prefix. - int isLeftHigherCommonPrefix = (leftCommonPrefix > rightCommonPrefix); - - // - if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = false; - else if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true; - - int isRootNode = false; - if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX && rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isRootNode = true; - - int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftNodeIndex : rightNodeIndex; - - //If the left node is the parent, then this node is its right child and vice versa - __global int* out_childNode = (isLeftHigherCommonPrefix) ? rightChildNodes : leftChildNodes; - - int isLeaf = 0; - if(!isRootNode) out_childNode[parentNodeIndex] = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex); - - if(isRootNode) *out_rootNodeIndex = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex); - - //Remove this node from the linked list, - //so that the left and right nodes point at each other instead of this node - if(leftNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) rightNeighborPointers[leftNodeIndex] = rightNodeIndex; - if(rightNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) leftNeighborPointers[rightNodeIndex] = leftNodeIndex; - - //For debug - leftNeighborPointers[internalNodeIndex] = -2; - rightNeighborPointers[internalNodeIndex] = -2; + int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]); + if(nodeLeftSharedPrefixLength < nodePrefixLength) + { + leftIndex = i; + break; + } } - //Processing occurs from highest common prefix to lowest common prefix - //Nodes in the previously processed level have their children set, so we merge their child AABBs here - if (commonPrefix == processedCommonPrefix + 1) + for(int i = internalNodeIndex + 1; i < numInternalNodes; ++i) { - int leftChildIndex = leftChildNodes[internalNodeIndex]; - int rightChildIndex = rightChildNodes[internalNodeIndex]; + int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]); + if(nodeRightSharedPrefixLength < nodePrefixLength) + { + rightIndex = i; + break; + } + } + +#else //Use binary search + + //Find nearest element to left with a lower common prefix + int leftIndex = -1; + { + int lower = 0; + int upper = internalNodeIndex - 1; + + while(lower <= upper) + { + int mid = (lower + upper) / 2; + b3Int64 midPrefix = commonPrefixes[mid]; + int midPrefixLength = commonPrefixLengths[mid]; + + int nodeMidSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, midPrefix, midPrefixLength); + if(nodeMidSharedPrefixLength < nodePrefixLength) + { + int right = mid + 1; + if(right < internalNodeIndex) + { + b3Int64 rightPrefix = commonPrefixes[right]; + int rightPrefixLength = commonPrefixLengths[right]; + + int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, rightPrefix, rightPrefixLength); + if(nodeRightSharedPrefixLength < nodePrefixLength) + { + lower = right; + leftIndex = right; + } + else + { + leftIndex = mid; + break; + } + } + else + { + leftIndex = mid; + break; + } + } + else upper = mid - 1; + } + } + + //Find nearest element to right with a lower common prefix + int rightIndex = -1; + { + int lower = internalNodeIndex + 1; + int upper = numInternalNodes - 1; + + while(lower <= upper) + { + int mid = (lower + upper) / 2; + b3Int64 midPrefix = commonPrefixes[mid]; + int midPrefixLength = commonPrefixLengths[mid]; + + int nodeMidSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, midPrefix, midPrefixLength); + if(nodeMidSharedPrefixLength < nodePrefixLength) + { + int left = mid - 1; + if(left > internalNodeIndex) + { + b3Int64 leftPrefix = commonPrefixes[left]; + int leftPrefixLength = commonPrefixLengths[left]; + + int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, leftPrefix, leftPrefixLength); + if(nodeLeftSharedPrefixLength < nodePrefixLength) + { + upper = left; + rightIndex = left; + } + else + { + rightIndex = mid; + break; + } + } + else + { + rightIndex = mid; + break; + } + } + else lower = mid + 1; + } + } +#endif + + TEMP_out_leftLowerPrefix[internalNodeIndex] = leftIndex; + TEMP_out_rightLowerPrefix[internalNodeIndex] = rightIndex; + TEMP_spl_left[internalNodeIndex] = (leftIndex != -1) ? getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[leftIndex], commonPrefixLengths[leftIndex]) : -1; + TEMP_spl_right[internalNodeIndex] = (rightIndex != -1) ? getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[rightIndex], commonPrefixLengths[rightIndex]) : -1; + + //Select parent + { + int leftPrefixLength = (leftIndex != -1) ? commonPrefixLengths[leftIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + int rightPrefixLength = (rightIndex != -1) ? commonPrefixLengths[rightIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; + + int isLeftHigherPrefixLength = (leftPrefixLength > rightPrefixLength); + + if(leftPrefixLength == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherPrefixLength = false; + else if(rightPrefixLength == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherPrefixLength = true; + + int parentNodeIndex = (isLeftHigherPrefixLength) ? leftIndex : rightIndex; + + int isRootNode = (leftIndex == -1 && rightIndex == -1); + out_internalNodeParentNodes[internalNodeIndex] = (!isRootNode) ? parentNodeIndex : B3_PLBVH_ROOT_NODE_MARKER; + + int isLeaf = 0; + if(!isRootNode) + { + int isRightChild = (isLeftHigherPrefixLength); //If the left node is the parent, then this node is its right child and vice versa + + //out_childNodesAsInt[0] == int2.x == left child + //out_childNodesAsInt[1] == int2.y == right child + __global int* out_childNodesAsInt = (__global int*)(&out_childNodes[parentNodeIndex]); + out_childNodesAsInt[isRightChild] = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex); + } + else *out_rootNodeIndex = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex); + } +} + +__kernel void findDistanceFromRoot(__global int* rootNodeIndex, __global int* internalNodeParentNodes, + __global int* out_maxDistanceFromRoot, __global int* out_distanceFromRoot, int numInternalNodes) +{ + if( get_global_id(0) == 0 ) atomic_xchg(out_maxDistanceFromRoot, 0); + + int internalNodeIndex = get_global_id(0); + if(internalNodeIndex >= numInternalNodes) return; + + // + int distanceFromRoot = 0; + { + int parentIndex = internalNodeParentNodes[internalNodeIndex]; + while(parentIndex != B3_PLBVH_ROOT_NODE_MARKER) + { + parentIndex = internalNodeParentNodes[parentIndex]; + ++distanceFromRoot; + } + } + out_distanceFromRoot[internalNodeIndex] = distanceFromRoot; + + // + __local int localMaxDistanceFromRoot; + if( get_local_id(0) == 0 ) localMaxDistanceFromRoot = 0; + barrier(CLK_LOCAL_MEM_FENCE); + + atomic_max(&localMaxDistanceFromRoot, distanceFromRoot); + barrier(CLK_LOCAL_MEM_FENCE); + + if( get_local_id(0) == 0 ) atomic_max(out_maxDistanceFromRoot, localMaxDistanceFromRoot); +} + +__kernel void buildBinaryRadixTreeAabbsRecursive(__global int* distanceFromRoot, __global SortDataCL* mortonCodesAndAabbIndices, + __global int2* childNodes, + __global b3AabbCL* leafNodeAabbs, __global b3AabbCL* internalNodeAabbs, + int maxDistanceFromRoot, int processedDistance, int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if(internalNodeIndex >= numInternalNodes) return; + + int distance = distanceFromRoot[internalNodeIndex]; + + if(distance == processedDistance) + { + int leftChildIndex = childNodes[internalNodeIndex].x; + int rightChildIndex = childNodes[internalNodeIndex].y; int isLeftChildLeaf = isLeafNode(leftChildIndex); int isRightChildLeaf = isLeafNode(rightChildIndex); @@ -753,18 +744,3 @@ __kernel void buildBinaryRadixTreeInternalNodes(__global int* commonPrefixes, __ internalNodeAabbs[internalNodeIndex] = mergedAabb; } } - -__kernel void convertChildNodeFormat(__global int* leftChildNodes, __global int* rightChildNodes, - __global int2* out_childNodes, int numInternalNodes) -{ - int internalNodeIndex = get_global_id(0); - if (internalNodeIndex >= numInternalNodes) return; - - int2 childNodesIndices; - childNodesIndices.x = leftChildNodes[internalNodeIndex]; - childNodesIndices.y = rightChildNodes[internalNodeIndex]; - - out_childNodes[internalNodeIndex] = childNodesIndices; -} - - diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index 1a1437d10..46848b1aa 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -41,34 +41,29 @@ static const char* parallelLinearBvhCL= \ " //........ ........ ......12 3456789A //x\n" " //....1..2 ..3..4.. 5..6..7. .8..9..A //x after interleaving bits\n" " \n" -" //........ ....1234 56789A12 3456789A //x |= (x << 10)\n" -" //........ ....1111 1....... ...11111 //0x 00 0F 80 1F\n" -" //........ ....1234 5....... ...6789A //x = ( x | (x << 10) ) & 0x000F801F; \n" +" //......12 3456789A ......12 3456789A //x ^ (x << 16)\n" +" //11111111 ........ ........ 11111111 //0x FF 00 00 FF\n" +" //......12 ........ ........ 3456789A //x = (x ^ (x << 16)) & 0xFF0000FF;\n" " \n" -" //.......1 23451234 5.....67 89A6789A //x |= (x << 5)\n" -" //.......1 1.....11 1.....11 .....111 //0x 01 83 83 07\n" -" //.......1 2.....34 5.....67 .....89A //x = ( x | (x << 5) ) & 0x01838307;\n" +" //......12 ........ 3456789A 3456789A //x ^ (x << 8)\n" +" //......11 ........ 1111.... ....1111 //0x 03 00 F0 0F\n" +" //......12 ........ 3456.... ....789A //x = (x ^ (x << 8)) & 0x0300F00F;\n" " \n" -" //....12.1 2..34534 5..67.67 ..89A89A //x |= (x << 3)\n" -" //....1... 1..1...1 1..1...1 ..1...11 //0x 08 91 91 23\n" -" //....1... 2..3...4 5..6...7 ..8...9A //x = ( x | (x << 3) ) & 0x08919123;\n" +" //..12..12 ....3456 3456.... 789A789A //x ^ (x << 4)\n" +" //......11 ....11.. ..11.... 11....11 //0x 03 0C 30 C3\n" +" //......12 ....34.. ..56.... 78....9A //x = (x ^ (x << 4)) & 0x030C30C3;\n" " \n" -" //...11..2 2.33..4N 5.66..77 .88..9NA //x |= (x << 1) ( N indicates overlapping bits, first overlap is bit {4,5} second is {9,A} )\n" -" //....1..1 ..1...1. 1..1..1. .1...1.1 //0x 09 22 92 45\n" -" //....1..2 ..3...4. 5..6..7. .8...9.A //x = ( x | (x << 1) ) & 0x09229245;\n" -" \n" -" //...11.22 .33..445 5.66.77. 88..99AA //x |= (x << 1)\n" -" //....1..1 ..1..1.. 1..1..1. .1..1..1 //0x 09 34 92 29\n" -" //....1..2 ..3..4.. 5..6..7. .8..9..A //x = ( x | (x << 1) ) & 0x09349229;\n" +" //....1212 ..3434.. 5656..78 78..9A9A //x ^ (x << 2)\n" +" //....1..1 ..1..1.. 1..1..1. .1..1..1 //0x 09 24 92 49\n" +" //....1..2 ..3..4.. 5..6..7. .8..9..A //x = (x ^ (x << 2)) & 0x09249249;\n" " \n" " //........ ........ ......11 11111111 //0x000003FF\n" " x &= 0x000003FF; //Clear all bits above bit 10\n" " \n" -" x = ( x | (x << 10) ) & 0x000F801F;\n" -" x = ( x | (x << 5) ) & 0x01838307;\n" -" x = ( x | (x << 3) ) & 0x08919123;\n" -" x = ( x | (x << 1) ) & 0x09229245;\n" -" x = ( x | (x << 1) ) & 0x09349229;\n" +" x = (x ^ (x << 16)) & 0xFF0000FF;\n" +" x = (x ^ (x << 8)) & 0x0300F00F;\n" +" x = (x ^ (x << 4)) & 0x030C30C3;\n" +" x = (x ^ (x << 2)) & 0x09249249;\n" " \n" " return x;\n" "}\n" @@ -150,143 +145,10 @@ static const char* parallelLinearBvhCL= \ "#define B3_PLVBH_TRAVERSE_MAX_STACK_SIZE 128\n" "//The most significant bit(0x80000000) of a int32 is used to distinguish between leaf and internal nodes.\n" "//If it is set, then the index is for an internal node; otherwise, it is a leaf node. \n" -"//In both cases, the bit should be cleared to access the index.\n" +"//In both cases, the bit should be cleared to access the actual node index.\n" "int isLeafNode(int index) { return (index >> 31 == 0); }\n" "int getIndexWithInternalNodeMarkerRemoved(int index) { return index & (~0x80000000); }\n" "int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : (index | 0x80000000); }\n" -"__kernel void constructBinaryTree(__global int* firstIndexOffsetPerLevel,\n" -" __global int* numNodesPerLevel,\n" -" __global int2* out_internalNodeChildIndices, \n" -" __global int* out_internalNodeParentNodes, \n" -" __global int* out_leafNodeParentNodes, \n" -" int numLevels, int numInternalNodes)\n" -"{\n" -" int internalNodeIndex = get_global_id(0);\n" -" if(internalNodeIndex >= numInternalNodes) return;\n" -" \n" -" //Find the level that this node is in, using linear search(could replace with binary search)\n" -" int level = 0;\n" -" int numInternalLevels = numLevels - 1; //All levels except the last are internal nodes\n" -" for(; level < numInternalLevels; ++level)\n" -" {\n" -" if( firstIndexOffsetPerLevel[level] <= internalNodeIndex && internalNodeIndex < firstIndexOffsetPerLevel[level + 1]) break;\n" -" }\n" -" \n" -" //Check lower levels to find child nodes\n" -" //Left child is always in the next level, but the same does not apply to the right child\n" -" int indexInLevel = internalNodeIndex - firstIndexOffsetPerLevel[level];\n" -" int firstIndexInNextLevel = firstIndexOffsetPerLevel[level + 1]; //Should never be out of bounds(see for loop above)\n" -" \n" -" int leftChildLevel = level + 1;\n" -" int leftChildIndex = firstIndexInNextLevel + indexInLevel * 2;\n" -" \n" -" int rightChildLevel = level + 1;\n" -" int rightChildIndex = leftChildIndex + 1;\n" -" \n" -" //Under certain conditions, the right child index as calculated above is invalid; need to find the correct index\n" -" //\n" -" //First condition: must be at least 2 levels apart from the leaf node level;\n" -" //if the current level is right next to the leaf node level, then the right child\n" -" //will never be invalid due to the way the nodes are allocated (also avoid a out-of-bounds memory access)\n" -" //\n" -" //Second condition: not enough nodes in the next level for each parent to have 2 children, so the right child is invalid\n" -" //\n" -" //Third condition: must be the last node in its level\n" -" if( level < numLevels - 2 \n" -" && numNodesPerLevel[level] * 2 > numNodesPerLevel[level + 1] \n" -" && indexInLevel == numNodesPerLevel[level] - 1 )\n" -" {\n" -" //Check lower levels until we find a node without a parent\n" -" for(; rightChildLevel < numLevels - 1; ++rightChildLevel)\n" -" {\n" -" int rightChildNextLevel = rightChildLevel + 1;\n" -" \n" -" //If this branch is taken, it means that the last node in rightChildNextLevel has no parent\n" -" if( numNodesPerLevel[rightChildLevel] * 2 < numNodesPerLevel[rightChildNextLevel] )\n" -" {\n" -" //Set the node to the last node in rightChildNextLevel\n" -" rightChildLevel = rightChildNextLevel;\n" -" rightChildIndex = firstIndexOffsetPerLevel[rightChildNextLevel] + numNodesPerLevel[rightChildNextLevel] - 1;\n" -" break;\n" -" }\n" -" }\n" -" }\n" -" \n" -" int isLeftChildLeaf = (leftChildLevel >= numLevels - 1);\n" -" int isRightChildLeaf = (rightChildLevel >= numLevels - 1);\n" -" \n" -" //If left/right child is a leaf node, the index needs to be corrected\n" -" //the way the index is calculated assumes that the leaf and internal nodes are in a contiguous array,\n" -" //with leaf nodes at the end of the array; in actuality, the leaf and internal nodes are in separate arrays\n" -" {\n" -" int leafNodeLevel = numLevels - 1;\n" -" leftChildIndex = (isLeftChildLeaf) ? leftChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : leftChildIndex;\n" -" rightChildIndex = (isRightChildLeaf) ? rightChildIndex - firstIndexOffsetPerLevel[leafNodeLevel] : rightChildIndex;\n" -" }\n" -" \n" -" //Set the negative sign bit if the node is internal\n" -" int2 childIndices;\n" -" childIndices.x = getIndexWithInternalNodeMarkerSet(isLeftChildLeaf, leftChildIndex);\n" -" childIndices.y = getIndexWithInternalNodeMarkerSet(isRightChildLeaf, rightChildIndex);\n" -" out_internalNodeChildIndices[internalNodeIndex] = childIndices;\n" -" \n" -" //Assign parent node index to children\n" -" __global int* out_leftChildParentNodeIndices = (isLeftChildLeaf) ? out_leafNodeParentNodes : out_internalNodeParentNodes;\n" -" out_leftChildParentNodeIndices[leftChildIndex] = internalNodeIndex;\n" -" \n" -" __global int* out_rightChildParentNodeIndices = (isRightChildLeaf) ? out_leafNodeParentNodes : out_internalNodeParentNodes;\n" -" out_rightChildParentNodeIndices[rightChildIndex] = internalNodeIndex;\n" -"}\n" -"__kernel void determineInternalNodeAabbs(__global int* firstIndexOffsetPerLevel,\n" -" __global int* numNodesPerLevel, \n" -" __global int2* internalNodeChildIndices,\n" -" __global SortDataCL* mortonCodesAndAabbIndices,\n" -" __global b3AabbCL* leafNodeAabbs, \n" -" __global int2* out_internalNodeLeafIndexRanges,\n" -" __global b3AabbCL* out_internalNodeAabbs, \n" -" int numLevels, int numInternalNodes, int level)\n" -"{\n" -" int i = get_global_id(0);\n" -" if(i >= numInternalNodes) return;\n" -" \n" -" //For each node in a level, check its child nodes to determine its AABB\n" -" {\n" -" int indexInLevel = i; //Index relative to firstIndexOffsetPerLevel[level]\n" -" \n" -" int numNodesInLevel = numNodesPerLevel[level];\n" -" if(indexInLevel < numNodesInLevel)\n" -" {\n" -" int internalNodeIndexGlobal = indexInLevel + firstIndexOffsetPerLevel[level];\n" -" int2 childIndicies = internalNodeChildIndices[internalNodeIndexGlobal];\n" -" \n" -" int leftChildIndex = getIndexWithInternalNodeMarkerRemoved(childIndicies.x);\n" -" int rightChildIndex = getIndexWithInternalNodeMarkerRemoved(childIndicies.y);\n" -" \n" -" int isLeftChildLeaf = isLeafNode(childIndicies.x);\n" -" int isRightChildLeaf = isLeafNode(childIndicies.y);\n" -" \n" -" //left/RightChildLeafIndex == Rigid body indicies\n" -" int leftChildLeafIndex = (isLeftChildLeaf) ? mortonCodesAndAabbIndices[leftChildIndex].m_value : -1;\n" -" int rightChildLeafIndex = (isRightChildLeaf) ? mortonCodesAndAabbIndices[rightChildIndex].m_value : -1;\n" -" \n" -" b3AabbCL leftChildAabb = (isLeftChildLeaf) ? leafNodeAabbs[leftChildLeafIndex] : out_internalNodeAabbs[leftChildIndex];\n" -" b3AabbCL rightChildAabb = (isRightChildLeaf) ? leafNodeAabbs[rightChildLeafIndex] : out_internalNodeAabbs[rightChildIndex];\n" -" \n" -" //\n" -" b3AabbCL internalNodeAabb;\n" -" internalNodeAabb.m_min = b3Min(leftChildAabb.m_min, rightChildAabb.m_min);\n" -" internalNodeAabb.m_max = b3Max(leftChildAabb.m_max, rightChildAabb.m_max);\n" -" out_internalNodeAabbs[internalNodeIndexGlobal] = internalNodeAabb;\n" -" \n" -" //For index range, x == min and y == max; left child always has lower index\n" -" int2 leafIndexRange;\n" -" leafIndexRange.x = (isLeftChildLeaf) ? leftChildIndex : out_internalNodeLeafIndexRanges[leftChildIndex].x;\n" -" leafIndexRange.y = (isRightChildLeaf) ? rightChildIndex : out_internalNodeLeafIndexRanges[rightChildIndex].y;\n" -" \n" -" out_internalNodeLeafIndexRanges[internalNodeIndexGlobal] = leafIndexRange;\n" -" }\n" -" }\n" -"}\n" "//From sap.cl\n" "#define NEW_PAIR_MARKER -1\n" "bool TestAabbAgainstAabb2(const b3AabbCL* aabb1, const b3AabbCL* aabb2)\n" @@ -539,78 +401,57 @@ static const char* parallelLinearBvhCL= \ " }\n" " }\n" "}\n" -"#define B3_PLBVH_LINKED_LIST_INVALID_NODE -1\n" -"int longestCommonPrefix(int i, int j) { return clz(i ^ j); }\n" -"__kernel void computePrefixAndInitPointers(__global SortDataCL* mortonCodesAndAabbIndices,\n" -" __global int* out_commonPrefixes,\n" -" __global int* out_leftInternalNodePointers, \n" -" __global int* out_rightInternalNodePointers,\n" +"//Set so that it is always greater than the actual common prefixes, and never selected as a parent node.\n" +"//If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve.\n" +"//Duplicates common prefixes increase the highest common prefix by N, where 2^N is the number of duplicate nodes.\n" +"#define B3_PLBVH_INVALID_COMMON_PREFIX 128\n" +"#define B3_PLBVH_ROOT_NODE_MARKER -1\n" +"#define b3Int64 long\n" +"int computeCommonPrefixLength(b3Int64 i, b3Int64 j) { return (int)clz(i ^ j); }\n" +"b3Int64 computeCommonPrefix(b3Int64 i, b3Int64 j) \n" +"{\n" +" //This function only needs to return (i & j) in order for the algorithm to work,\n" +" //but it may help with debugging to mask out the lower bits.\n" +" b3Int64 commonPrefixLength = (b3Int64)computeCommonPrefixLength(i, j);\n" +" b3Int64 sharedBits = i & j;\n" +" b3Int64 bitmask = ((b3Int64)(~0)) << (64 - commonPrefixLength); //Set all bits after the common prefix to 0\n" +" \n" +" return sharedBits & bitmask;\n" +"}\n" +"int getSharedPrefixLength(b3Int64 prefixA, int prefixLengthA, b3Int64 prefixB, int prefixLengthB)\n" +"{\n" +" return b3Min( computeCommonPrefixLength(prefixA, prefixB), b3Min(prefixLengthA, prefixLengthB) );\n" +"}\n" +"__kernel void computeAdjacentPairCommonPrefix(__global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global b3Int64* out_commonPrefixes,\n" +" __global int* out_commonPrefixLengths,\n" " int numInternalNodes)\n" "{\n" " int internalNodeIndex = get_global_id(0);\n" " if (internalNodeIndex >= numInternalNodes) return;\n" " \n" -" //Compute common prefix\n" -" {\n" -" //Here, (internalNodeIndex + 1) is never out of bounds since it is a leaf node index,\n" -" //and the number of internal nodes is always numLeafNodes - 1\n" -" int leftLeafMortonCode = mortonCodesAndAabbIndices[internalNodeIndex].m_key;\n" -" int rightLeafMortonCode = mortonCodesAndAabbIndices[internalNodeIndex + 1].m_key;\n" +" //Here, (internalNodeIndex + 1) is never out of bounds since it is a leaf node index,\n" +" //and the number of internal nodes is always numLeafNodes - 1\n" +" int leftLeafIndex = internalNodeIndex;\n" +" int rightLeafIndex = internalNodeIndex + 1;\n" " \n" -" out_commonPrefixes[internalNodeIndex] = longestCommonPrefix(leftLeafMortonCode, rightLeafMortonCode);\n" -" }\n" +" int leftLeafMortonCode = mortonCodesAndAabbIndices[leftLeafIndex].m_key;\n" +" int rightLeafMortonCode = mortonCodesAndAabbIndices[rightLeafIndex].m_key;\n" " \n" -" //Assign neighbor pointers of this node\n" -" {\n" -" int leftInternalIndex = internalNodeIndex - 1;\n" -" int rightInternalIndex = internalNodeIndex + 1;\n" -" \n" -" out_leftInternalNodePointers[internalNodeIndex] = (leftInternalIndex >= 0) ? leftInternalIndex : B3_PLBVH_LINKED_LIST_INVALID_NODE;\n" -" out_rightInternalNodePointers[internalNodeIndex] = (rightInternalIndex < numInternalNodes) ? rightInternalIndex : B3_PLBVH_LINKED_LIST_INVALID_NODE;\n" -" }\n" +" //Binary radix tree construction algorithm does not work if there are duplicate morton codes.\n" +" //Append the index of each leaf node to each morton code so that there are no duplicates.\n" +" //The algorithm also requires that the morton codes are sorted in ascending order; this requirement\n" +" //is also satisfied with this method, as (leftLeafIndex < rightLeafIndex) is always true.\n" +" //\n" +" //upsample(a, b) == ( ((b3Int64)a) << 32) | b\n" +" b3Int64 nonduplicateLeftMortonCode = upsample(leftLeafMortonCode, leftLeafIndex);\n" +" b3Int64 nonduplicateRightMortonCode = upsample(rightLeafMortonCode, rightLeafIndex);\n" +" \n" +" out_commonPrefixes[internalNodeIndex] = computeCommonPrefix(nonduplicateLeftMortonCode, nonduplicateRightMortonCode);\n" +" out_commonPrefixLengths[internalNodeIndex] = computeCommonPrefixLength(nonduplicateLeftMortonCode, nonduplicateRightMortonCode);\n" "}\n" -"__kernel void correctDuplicatePrefixes(__global int* commonPrefixes, __global int* out_maxCommonPrefix, int numInternalNodes)\n" -"{\n" -" int internalNodeIndex = get_global_id(0);\n" -" if (internalNodeIndex >= numInternalNodes) return;\n" -" \n" -" int commonPrefix = commonPrefixes[internalNodeIndex];\n" -" \n" -" //Linear search to find the size of the subtree\n" -" int firstSubTreeIndex = internalNodeIndex;\n" -" int lastSubTreeIndex = internalNodeIndex;\n" -" \n" -" while(firstSubTreeIndex - 1 >= 0 && commonPrefix == commonPrefixes[firstSubTreeIndex - 1]) --firstSubTreeIndex;\n" -" while(lastSubTreeIndex + 1 < numInternalNodes && commonPrefix == commonPrefixes[lastSubTreeIndex + 1]) ++lastSubTreeIndex;\n" -" \n" -" //Fix duplicate common prefixes by incrementing them so that a subtree is formed.\n" -" //Recursively divide the tree until the position of the split is this node's index.\n" -" //Every time this node is not the split node, increment the common prefix.\n" -" int isCurrentSplitNode = false;\n" -" int correctedCommonPrefix = commonPrefix;\n" -" \n" -" while(!isCurrentSplitNode)\n" -" {\n" -" int numInternalNodesInSubTree = lastSubTreeIndex - firstSubTreeIndex + 1;\n" -" int splitNodeIndex = firstSubTreeIndex + numInternalNodesInSubTree / 2;\n" -" \n" -" if(internalNodeIndex > splitNodeIndex) firstSubTreeIndex = splitNodeIndex + 1;\n" -" else if(internalNodeIndex < splitNodeIndex) lastSubTreeIndex = splitNodeIndex - 1;\n" -" //else if(internalNodeIndex == splitNodeIndex) break;\n" -" \n" -" isCurrentSplitNode = (internalNodeIndex == splitNodeIndex);\n" -" if(!isCurrentSplitNode) correctedCommonPrefix++;\n" -" }\n" -" \n" -" commonPrefixes[internalNodeIndex] = correctedCommonPrefix;\n" -" atomic_max(out_maxCommonPrefix, correctedCommonPrefix);\n" -"}\n" -"//Set so that it is always greater than the actual common prefixes, and never selected as a parent node.\n" -"//If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve.\n" -"//Duplicates common prefixes increase the highest common prefix by N, where 2^N is the number of duplicate nodes.\n" -"#define B3_PLBVH_INVALID_COMMON_PREFIX 128\n" -"__kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixes, __global int* out_leftChildNodes, \n" -" __global int* out_rightChildNodes, int numLeafNodes)\n" +"__kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixLengths, __global int* out_leafNodeParentNodes,\n" +" __global int2* out_childNodes, int numLeafNodes)\n" "{\n" " int leafNodeIndex = get_global_id(0);\n" " if (leafNodeIndex >= numLeafNodes) return;\n" @@ -620,8 +461,8 @@ static const char* parallelLinearBvhCL= \ " int leftSplitIndex = leafNodeIndex - 1;\n" " int rightSplitIndex = leafNodeIndex;\n" " \n" -" int leftCommonPrefix = (leftSplitIndex >= 0) ? commonPrefixes[leftSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" -" int rightCommonPrefix = (rightSplitIndex < numInternalNodes) ? commonPrefixes[rightSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" int leftCommonPrefix = (leftSplitIndex >= 0) ? commonPrefixLengths[leftSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" int rightCommonPrefix = (rightSplitIndex < numInternalNodes) ? commonPrefixLengths[rightSplitIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" " \n" " //Parent node is the highest adjacent common prefix that is lower than the node's common prefix\n" " //Leaf nodes are considered as having the highest common prefix\n" @@ -633,71 +474,218 @@ static const char* parallelLinearBvhCL= \ " if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true;\n" " \n" " int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftSplitIndex : rightSplitIndex;\n" +" out_leafNodeParentNodes[leafNodeIndex] = parentNodeIndex;\n" " \n" -" //If the left node is the parent, then this node is its right child and vice versa\n" -" __global int* out_childNode = (isLeftHigherCommonPrefix) ? out_rightChildNodes : out_leftChildNodes;\n" +" int isRightChild = (isLeftHigherCommonPrefix); //If the left node is the parent, then this node is its right child and vice versa\n" " \n" +" //out_childNodesAsInt[0] == int2.x == left child\n" +" //out_childNodesAsInt[1] == int2.y == right child\n" " int isLeaf = 1;\n" -" out_childNode[parentNodeIndex] = getIndexWithInternalNodeMarkerSet(isLeaf, leafNodeIndex);\n" +" __global int* out_childNodesAsInt = (__global int*)(&out_childNodes[parentNodeIndex]);\n" +" out_childNodesAsInt[isRightChild] = getIndexWithInternalNodeMarkerSet(isLeaf, leafNodeIndex);\n" "}\n" -"__kernel void buildBinaryRadixTreeInternalNodes(__global int* commonPrefixes, __global SortDataCL* mortonCodesAndAabbIndices,\n" -" __global int* leftChildNodes, __global int* rightChildNodes,\n" -" __global int* leftNeighborPointers, __global int* rightNeighborPointers,\n" -" __global b3AabbCL* leafNodeAabbs, __global b3AabbCL* internalNodeAabbs,\n" -" __global int* out_rootNodeIndex,\n" -" int processedCommonPrefix, int numInternalNodes)\n" +"__kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes, __global int* commonPrefixLengths,\n" +" __global int2* out_childNodes,\n" +" __global int* out_internalNodeParentNodes, __global int* out_rootNodeIndex,\n" +" __global int* TEMP_out_leftLowerPrefix, __global int* TEMP_out_rightLowerPrefix,\n" +" __global int* TEMP_spl_left, __global int* TEMP_spl_right,\n" +" int numInternalNodes)\n" "{\n" -" int internalNodeIndex = get_global_id(0);\n" -" if (internalNodeIndex >= numInternalNodes) return;\n" +" int internalNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" " \n" -" int commonPrefix = commonPrefixes[internalNodeIndex];\n" -" if (commonPrefix == processedCommonPrefix)\n" +" b3Int64 nodePrefix = commonPrefixes[internalNodeIndex];\n" +" int nodePrefixLength = commonPrefixLengths[internalNodeIndex];\n" +" \n" +"//#define USE_LINEAR_SEARCH\n" +"#ifdef USE_LINEAR_SEARCH\n" +" int leftIndex = -1;\n" +" int rightIndex = -1;\n" +" \n" +" for(int i = internalNodeIndex - 1; i >= 0; --i)\n" " {\n" -" //Check neighbors and compare the common prefix to select the parent node\n" -" int leftNodeIndex = leftNeighborPointers[internalNodeIndex];\n" -" int rightNodeIndex = rightNeighborPointers[internalNodeIndex];\n" -" \n" -" int leftCommonPrefix = (leftNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) ? commonPrefixes[leftNodeIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" -" int rightCommonPrefix = (rightNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) ? commonPrefixes[rightNodeIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" -" \n" -" //Parent node is the highest common prefix that is lower than the node's common prefix\n" -" //Since the nodes with lower common prefixes are removed, that condition does not have to be tested for,\n" -" //and we only need to pick the node with the higher prefix.\n" -" int isLeftHigherCommonPrefix = (leftCommonPrefix > rightCommonPrefix);\n" -" \n" -" //\n" -" if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = false;\n" -" else if(rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherCommonPrefix = true;\n" -" \n" -" int isRootNode = false;\n" -" if(leftCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX && rightCommonPrefix == B3_PLBVH_INVALID_COMMON_PREFIX) isRootNode = true;\n" -" \n" -" int parentNodeIndex = (isLeftHigherCommonPrefix) ? leftNodeIndex : rightNodeIndex;\n" -" \n" -" //If the left node is the parent, then this node is its right child and vice versa\n" -" __global int* out_childNode = (isLeftHigherCommonPrefix) ? rightChildNodes : leftChildNodes;\n" -" \n" -" int isLeaf = 0;\n" -" if(!isRootNode) out_childNode[parentNodeIndex] = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex);\n" -" \n" -" if(isRootNode) *out_rootNodeIndex = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex);\n" -" \n" -" //Remove this node from the linked list, \n" -" //so that the left and right nodes point at each other instead of this node\n" -" if(leftNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) rightNeighborPointers[leftNodeIndex] = rightNodeIndex;\n" -" if(rightNodeIndex != B3_PLBVH_LINKED_LIST_INVALID_NODE) leftNeighborPointers[rightNodeIndex] = leftNodeIndex;\n" -" \n" -" //For debug\n" -" leftNeighborPointers[internalNodeIndex] = -2;\n" -" rightNeighborPointers[internalNodeIndex] = -2;\n" +" int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]);\n" +" if(nodeLeftSharedPrefixLength < nodePrefixLength)\n" +" {\n" +" leftIndex = i;\n" +" break;\n" +" }\n" " }\n" " \n" -" //Processing occurs from highest common prefix to lowest common prefix\n" -" //Nodes in the previously processed level have their children set, so we merge their child AABBs here\n" -" if (commonPrefix == processedCommonPrefix + 1)\n" +" for(int i = internalNodeIndex + 1; i < numInternalNodes; ++i)\n" " {\n" -" int leftChildIndex = leftChildNodes[internalNodeIndex];\n" -" int rightChildIndex = rightChildNodes[internalNodeIndex];\n" +" int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]);\n" +" if(nodeRightSharedPrefixLength < nodePrefixLength)\n" +" {\n" +" rightIndex = i;\n" +" break;\n" +" }\n" +" }\n" +" \n" +"#else //Use binary search\n" +" //Find nearest element to left with a lower common prefix\n" +" int leftIndex = -1;\n" +" {\n" +" int lower = 0;\n" +" int upper = internalNodeIndex - 1;\n" +" \n" +" while(lower <= upper)\n" +" {\n" +" int mid = (lower + upper) / 2;\n" +" b3Int64 midPrefix = commonPrefixes[mid];\n" +" int midPrefixLength = commonPrefixLengths[mid];\n" +" \n" +" int nodeMidSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, midPrefix, midPrefixLength);\n" +" if(nodeMidSharedPrefixLength < nodePrefixLength) \n" +" {\n" +" int right = mid + 1;\n" +" if(right < internalNodeIndex)\n" +" {\n" +" b3Int64 rightPrefix = commonPrefixes[right];\n" +" int rightPrefixLength = commonPrefixLengths[right];\n" +" \n" +" int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, rightPrefix, rightPrefixLength);\n" +" if(nodeRightSharedPrefixLength < nodePrefixLength) \n" +" {\n" +" lower = right;\n" +" leftIndex = right;\n" +" }\n" +" else \n" +" {\n" +" leftIndex = mid;\n" +" break;\n" +" }\n" +" }\n" +" else \n" +" {\n" +" leftIndex = mid;\n" +" break;\n" +" }\n" +" }\n" +" else upper = mid - 1;\n" +" }\n" +" }\n" +" \n" +" //Find nearest element to right with a lower common prefix\n" +" int rightIndex = -1;\n" +" {\n" +" int lower = internalNodeIndex + 1;\n" +" int upper = numInternalNodes - 1;\n" +" \n" +" while(lower <= upper)\n" +" {\n" +" int mid = (lower + upper) / 2;\n" +" b3Int64 midPrefix = commonPrefixes[mid];\n" +" int midPrefixLength = commonPrefixLengths[mid];\n" +" \n" +" int nodeMidSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, midPrefix, midPrefixLength);\n" +" if(nodeMidSharedPrefixLength < nodePrefixLength) \n" +" {\n" +" int left = mid - 1;\n" +" if(left > internalNodeIndex)\n" +" {\n" +" b3Int64 leftPrefix = commonPrefixes[left];\n" +" int leftPrefixLength = commonPrefixLengths[left];\n" +" \n" +" int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, leftPrefix, leftPrefixLength);\n" +" if(nodeLeftSharedPrefixLength < nodePrefixLength) \n" +" {\n" +" upper = left;\n" +" rightIndex = left;\n" +" }\n" +" else \n" +" {\n" +" rightIndex = mid;\n" +" break;\n" +" }\n" +" }\n" +" else \n" +" {\n" +" rightIndex = mid;\n" +" break;\n" +" }\n" +" }\n" +" else lower = mid + 1;\n" +" }\n" +" }\n" +"#endif\n" +" \n" +" TEMP_out_leftLowerPrefix[internalNodeIndex] = leftIndex;\n" +" TEMP_out_rightLowerPrefix[internalNodeIndex] = rightIndex;\n" +" TEMP_spl_left[internalNodeIndex] = (leftIndex != -1) ? getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[leftIndex], commonPrefixLengths[leftIndex]) : -1;\n" +" TEMP_spl_right[internalNodeIndex] = (rightIndex != -1) ? getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[rightIndex], commonPrefixLengths[rightIndex]) : -1;\n" +" \n" +" //Select parent\n" +" {\n" +" int leftPrefixLength = (leftIndex != -1) ? commonPrefixLengths[leftIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" int rightPrefixLength = (rightIndex != -1) ? commonPrefixLengths[rightIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" +" \n" +" int isLeftHigherPrefixLength = (leftPrefixLength > rightPrefixLength);\n" +" \n" +" if(leftPrefixLength == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherPrefixLength = false;\n" +" else if(rightPrefixLength == B3_PLBVH_INVALID_COMMON_PREFIX) isLeftHigherPrefixLength = true;\n" +" \n" +" int parentNodeIndex = (isLeftHigherPrefixLength) ? leftIndex : rightIndex;\n" +" \n" +" int isRootNode = (leftIndex == -1 && rightIndex == -1);\n" +" out_internalNodeParentNodes[internalNodeIndex] = (!isRootNode) ? parentNodeIndex : B3_PLBVH_ROOT_NODE_MARKER;\n" +" \n" +" int isLeaf = 0;\n" +" if(!isRootNode)\n" +" {\n" +" int isRightChild = (isLeftHigherPrefixLength); //If the left node is the parent, then this node is its right child and vice versa\n" +" \n" +" //out_childNodesAsInt[0] == int2.x == left child\n" +" //out_childNodesAsInt[1] == int2.y == right child\n" +" __global int* out_childNodesAsInt = (__global int*)(&out_childNodes[parentNodeIndex]);\n" +" out_childNodesAsInt[isRightChild] = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex);\n" +" }\n" +" else *out_rootNodeIndex = getIndexWithInternalNodeMarkerSet(isLeaf, internalNodeIndex);\n" +" }\n" +"}\n" +"__kernel void findDistanceFromRoot(__global int* rootNodeIndex, __global int* internalNodeParentNodes,\n" +" __global int* out_maxDistanceFromRoot, __global int* out_distanceFromRoot, int numInternalNodes)\n" +"{\n" +" if( get_global_id(0) == 0 ) atomic_xchg(out_maxDistanceFromRoot, 0);\n" +" int internalNodeIndex = get_global_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" //\n" +" int distanceFromRoot = 0;\n" +" {\n" +" int parentIndex = internalNodeParentNodes[internalNodeIndex];\n" +" while(parentIndex != B3_PLBVH_ROOT_NODE_MARKER)\n" +" {\n" +" parentIndex = internalNodeParentNodes[parentIndex];\n" +" ++distanceFromRoot;\n" +" }\n" +" }\n" +" out_distanceFromRoot[internalNodeIndex] = distanceFromRoot;\n" +" \n" +" //\n" +" __local int localMaxDistanceFromRoot;\n" +" if( get_local_id(0) == 0 ) localMaxDistanceFromRoot = 0;\n" +" barrier(CLK_LOCAL_MEM_FENCE);\n" +" \n" +" atomic_max(&localMaxDistanceFromRoot, distanceFromRoot);\n" +" barrier(CLK_LOCAL_MEM_FENCE);\n" +" \n" +" if( get_local_id(0) == 0 ) atomic_max(out_maxDistanceFromRoot, localMaxDistanceFromRoot);\n" +"}\n" +"__kernel void buildBinaryRadixTreeAabbsRecursive(__global int* distanceFromRoot, __global SortDataCL* mortonCodesAndAabbIndices,\n" +" __global int2* childNodes,\n" +" __global b3AabbCL* leafNodeAabbs, __global b3AabbCL* internalNodeAabbs,\n" +" int maxDistanceFromRoot, int processedDistance, int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" int distance = distanceFromRoot[internalNodeIndex];\n" +" \n" +" if(distance == processedDistance)\n" +" {\n" +" int leftChildIndex = childNodes[internalNodeIndex].x;\n" +" int rightChildIndex = childNodes[internalNodeIndex].y;\n" " \n" " int isLeftChildLeaf = isLeafNode(leftChildIndex);\n" " int isRightChildLeaf = isLeafNode(rightChildIndex);\n" @@ -718,16 +706,4 @@ static const char* parallelLinearBvhCL= \ " internalNodeAabbs[internalNodeIndex] = mergedAabb;\n" " }\n" "}\n" -"__kernel void convertChildNodeFormat(__global int* leftChildNodes, __global int* rightChildNodes, \n" -" __global int2* out_childNodes, int numInternalNodes)\n" -"{\n" -" int internalNodeIndex = get_global_id(0);\n" -" if (internalNodeIndex >= numInternalNodes) return;\n" -" \n" -" int2 childNodesIndices;\n" -" childNodesIndices.x = leftChildNodes[internalNodeIndex];\n" -" childNodesIndices.y = rightChildNodes[internalNodeIndex];\n" -" \n" -" out_childNodes[internalNodeIndex] = childNodesIndices;\n" -"}\n" ; From db02ced6068d87791a847795f97b522f903c9816 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Tue, 11 Mar 2014 14:13:09 -0700 Subject: [PATCH 011/116] Clean up PLBVH construction, add comments. --- .../b3GpuParallelLinearBvh.cpp | 285 ++++++------------ .../b3GpuParallelLinearBvh.h | 19 +- .../kernels/parallelLinearBvh.cl | 11 +- .../kernels/parallelLinearBvhKernels.h | 10 +- 4 files changed, 111 insertions(+), 214 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp index fa1bc8db0..40a73658f 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -30,12 +30,7 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_commonPrefixes(context, queue), m_commonPrefixLengths(context, queue), - m_childNodeCount(context, queue), m_distanceFromRoot(context, queue), - m_TEMP_leftLowerPrefix(context, queue), - m_TEMP_rightLowerPrefix(context, queue), - m_TEMP_leftSharedPrefixLength(context, queue), - m_TEMP_rightSharedPrefixLength(context, queue), m_leafNodeParentNodes(context, queue), m_mortonCodesAndAabbIndicies(context, queue), @@ -164,6 +159,8 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab if(numLeaves < 2) { + //Number of leaf nodes is checked in calculateOverlappingPairs() and testRaysAgainstBvhAabbs(), + //so it does not matter if numLeaves == 0 and rootNodeIndex == -1 int rootNodeIndex = numLeaves - 1; m_rootNodeIndex.copyFromHostPointer(&rootNodeIndex, 1); return; @@ -178,12 +175,7 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab m_commonPrefixes.resize(numInternalNodes); m_commonPrefixLengths.resize(numInternalNodes); - m_childNodeCount.resize(numInternalNodes); m_distanceFromRoot.resize(numInternalNodes); - m_TEMP_leftLowerPrefix.resize(numInternalNodes); - m_TEMP_rightLowerPrefix.resize(numInternalNodes); - m_TEMP_leftSharedPrefixLength.resize(numInternalNodes); - m_TEMP_rightSharedPrefixLength.resize(numInternalNodes); m_leafNodeParentNodes.resize(numLeaves); m_mortonCodesAndAabbIndicies.resize(numLeaves); @@ -191,7 +183,7 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab } //Find the merged AABB of all small AABBs; this is used to define the size of - //each cell in the virtual grid(2^10 cells in each dimension). + //each cell in the virtual grid for the next kernel(2^10 cells in each dimension). { B3_PROFILE("Find AABB of merged nodes"); @@ -215,7 +207,6 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab clFinish(m_queue); } - //Insert the center of the AABBs into a virtual grid, //then convert the discrete grid coordinates into a morton code //For each element in m_mortonCodesAndAabbIndicies, set @@ -405,12 +396,6 @@ void b3GpuParallelLinearBvh::testRaysAgainstBvhAabbs(const b3OpenCLArray -int isLeafNode(int index) { return (index >> 31 == 0); } -int getIndexWithInternalNodeMarkerRemoved(int index) { return index & (~0x80000000); } -int getIndexWithInternalNodeMarkerSet(int isLeaf, int index) { return (isLeaf) ? index : (index | 0x80000000); } - void b3GpuParallelLinearBvh::constructRadixBinaryTree() { B3_PROFILE("b3GpuParallelLinearBvh::constructRadixBinaryTree()"); @@ -418,7 +403,9 @@ void b3GpuParallelLinearBvh::constructRadixBinaryTree() int numLeaves = m_leafNodeAabbs.size(); int numInternalNodes = numLeaves - 1; - //For each internal node, compute common prefix and set pointers to left and right internal nodes + //Each internal node is placed in between 2 leaf nodes. + //By using this arrangement and computing the common prefix between + //these 2 adjacent leaf nodes, it is possible to quickly construct a binary radix tree. { B3_PROFILE("m_computeAdjacentPairCommonPrefixKernel"); @@ -437,185 +424,107 @@ void b3GpuParallelLinearBvh::constructRadixBinaryTree() clFinish(m_queue); } + //For each leaf node, select its parent node by + //comparing the 2 nearest internal nodes and assign child node indices { - static b3AlignedObjectArray prefixLengths; - m_commonPrefixLengths.copyToHost(prefixLengths); - clFinish(m_queue); + B3_PROFILE("m_buildBinaryRadixTreeLeafNodesKernel"); - for(int i = 1; i < prefixLengths.size(); ++i) - if( prefixLengths[i - 1] == prefixLengths[i] ) - for(;;) printf("duplicate prefix[%d]: %d\n", i, prefixLengths[i]); + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ), + b3BufferInfoCL( m_leafNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeLeafNodesKernel, "m_buildBinaryRadixTreeLeafNodesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numLeaves); + + launcher.launch1D(numLeaves); + clFinish(m_queue); } + //For each internal node, perform 2 binary searches among the other internal nodes + //to its left and right to find its potential parent nodes and assign child node indices { - //For each leaf node, find parent nodes and assign child node indices - { - B3_PROFILE("m_buildBinaryRadixTreeLeafNodesKernel"); - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ), - b3BufferInfoCL( m_leafNodeParentNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeLeafNodesKernel, "m_buildBinaryRadixTreeLeafNodesKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numLeaves); - - launcher.launch1D(numLeaves); - clFinish(m_queue); - } + B3_PROFILE("m_buildBinaryRadixTreeInternalNodesKernel"); - //For each internal node, find parent nodes and assign child node indices + b3BufferInfoCL bufferInfo[] = { - B3_PROFILE("m_buildBinaryRadixTreeInternalNodesKernel"); - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), - b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), - b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), - b3BufferInfoCL( m_TEMP_leftLowerPrefix.getBufferCL() ), - b3BufferInfoCL( m_TEMP_rightLowerPrefix.getBufferCL() ), - b3BufferInfoCL( m_TEMP_leftSharedPrefixLength.getBufferCL() ), - b3BufferInfoCL( m_TEMP_rightSharedPrefixLength.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeInternalNodesKernel, "m_buildBinaryRadixTreeInternalNodesKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numInternalNodes); - - launcher.launch1D(numInternalNodes); - clFinish(m_queue); - } + b3BufferInfoCL( m_commonPrefixes.getBufferCL() ), + b3BufferInfoCL( m_commonPrefixLengths.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ) + }; - if(0) - { - static b3AlignedObjectArray mortonCodesAndAabbIndices; - - static b3AlignedObjectArray child; - static b3AlignedObjectArray commonPrefixes; - static b3AlignedObjectArray commonPrefixLengths; - static b3AlignedObjectArray tempLeftLowerPrefixIndex; - static b3AlignedObjectArray tempRightLowerPrefixIndex; - static b3AlignedObjectArray tempLeftLowerPrefixSPL; - static b3AlignedObjectArray tempRightLowerPrefixSPL; - static b3AlignedObjectArray internalParent; - - m_mortonCodesAndAabbIndicies.copyToHost(mortonCodesAndAabbIndices); - - m_internalNodeChildNodes.copyToHost(child); - m_commonPrefixes.copyToHost(commonPrefixes); - m_commonPrefixLengths.copyToHost(commonPrefixLengths); - m_TEMP_leftLowerPrefix.copyToHost(tempLeftLowerPrefixIndex); - m_TEMP_rightLowerPrefix.copyToHost(tempRightLowerPrefixIndex); - m_TEMP_leftSharedPrefixLength.copyToHost(tempLeftLowerPrefixSPL); - m_TEMP_rightSharedPrefixLength.copyToHost(tempRightLowerPrefixSPL); - m_internalNodeParentNodes.copyToHost(internalParent); - - int rootNode = -1; - m_rootNodeIndex.copyToHostPointer(&rootNode, 1); - clFinish(m_queue); - - printf( "rootNode: %d\n", getIndexWithInternalNodeMarkerRemoved(rootNode) ); - - for(int i = 0; i < numInternalNodes; ++i) - { - b3Int2 childNodes = child[i]; - - printf("childNodes[%d]:", i); - printf( " %d", getIndexWithInternalNodeMarkerRemoved(childNodes.x) ); - if( !isLeafNode(childNodes.x) ) printf("i"); - printf( ", %d", getIndexWithInternalNodeMarkerRemoved(childNodes.y) ); - if( !isLeafNode(childNodes.y) ) printf("i"); - printf(" (lr: %d, %d)", tempLeftLowerPrefixIndex[i], tempRightLowerPrefixIndex[i]); - printf(" (spl: %d, %d)", tempLeftLowerPrefixSPL[i], tempRightLowerPrefixSPL[i]); - printf(" (prefix: %d)", commonPrefixLengths[i]); - printf(" (par: %d)", internalParent[i]); - printf("\n"); - } - printf("\n"); - - for(int i = 0; i < numInternalNodes; ++i) - { - int hi = static_cast(commonPrefixes[i] >> 32); - int lo = static_cast(commonPrefixes[i]); - - printf("commonPrefix[%d]: %x, %d, len %d \n", i, hi, lo, commonPrefixLengths[i]); - } - printf("\n"); - - for(int i = 0; i < numLeaves; ++i) - { - printf("z-curve[%d]: %x \n", i, mortonCodesAndAabbIndices[i].m_key); - } - printf("\n"); - - - std::cout << std::endl; - for(;;); - } + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeInternalNodesKernel, "m_buildBinaryRadixTreeInternalNodesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); - //Find the number of nodes seperating each internal node and the root node - //so that the AABBs can be set using the next kernel - { - B3_PROFILE("m_findDistanceFromRootKernel"); - - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), - b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), - b3BufferInfoCL( m_maxDistanceFromRoot.getBufferCL() ), - b3BufferInfoCL( m_distanceFromRoot.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_findDistanceFromRootKernel, "m_findDistanceFromRootKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(numInternalNodes); - - launcher.launch1D(numInternalNodes); - clFinish(m_queue); - } - - //Starting from the nodes nearest to the leaf nodes, recursively move up - //the tree to set the AABBs of each internal node; each internal node - //checks its children and merges their AABBs - { - B3_PROFILE("m_buildBinaryRadixTreeAabbsRecursiveKernel"); - - int maxDistanceFromRoot = -1; - { - B3_PROFILE("copy maxDistanceFromRoot to CPU"); - m_maxDistanceFromRoot.copyToHostPointer(&maxDistanceFromRoot, 1); - clFinish(m_queue); - } - - for(int distanceFromRoot = maxDistanceFromRoot; distanceFromRoot >= 0; --distanceFromRoot) - { - b3BufferInfoCL bufferInfo[] = - { - b3BufferInfoCL( m_distanceFromRoot.getBufferCL() ), - b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), - b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), - b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) - }; - - b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeAabbsRecursiveKernel, "m_buildBinaryRadixTreeAabbsRecursiveKernel"); - launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); - launcher.setConst(maxDistanceFromRoot); - launcher.setConst(distanceFromRoot); - launcher.setConst(numInternalNodes); - - launcher.launch1D(numInternalNodes); - } - - clFinish(m_queue); - } + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } + //Find the number of nodes seperating each internal node and the root node + //so that the AABBs can be set using the next kernel. + //Also determine the maximum number of nodes separating an internal node and the root node. + { + B3_PROFILE("m_findDistanceFromRootKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_rootNodeIndex.getBufferCL() ), + b3BufferInfoCL( m_internalNodeParentNodes.getBufferCL() ), + b3BufferInfoCL( m_maxDistanceFromRoot.getBufferCL() ), + b3BufferInfoCL( m_distanceFromRoot.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_findDistanceFromRootKernel, "m_findDistanceFromRootKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } + + //Starting from the internal nodes nearest to the leaf nodes, recursively move up + //the tree towards the root to set the AABBs of each internal node; each internal node + //checks its children and merges their AABBs + { + B3_PROFILE("m_buildBinaryRadixTreeAabbsRecursiveKernel"); + + int maxDistanceFromRoot = -1; + { + B3_PROFILE("copy maxDistanceFromRoot to CPU"); + m_maxDistanceFromRoot.copyToHostPointer(&maxDistanceFromRoot, 1); + clFinish(m_queue); + } + + for(int distanceFromRoot = maxDistanceFromRoot; distanceFromRoot >= 0; --distanceFromRoot) + { + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_distanceFromRoot.getBufferCL() ), + b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), + b3BufferInfoCL( m_internalNodeAabbs.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_buildBinaryRadixTreeAabbsRecursiveKernel, "m_buildBinaryRadixTreeAabbsRecursiveKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(maxDistanceFromRoot); + launcher.setConst(distanceFromRoot); + launcher.setConst(numInternalNodes); + + //It may seem inefficent to launch a thread for each internal node when a + //much smaller number of nodes is actually processed, but this is actually + //faster than determining the exact nodes that are ready to merge their child AABBs. + launcher.launch1D(numInternalNodes); + } + + clFinish(m_queue); } } diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index 4d5467481..7aabd71f9 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -70,28 +70,23 @@ class b3GpuParallelLinearBvh b3RadixSort32CL m_radixSorter; //1 element - b3OpenCLArray m_rootNodeIndex; - b3OpenCLArray m_maxDistanceFromRoot; + b3OpenCLArray m_rootNodeIndex; //Most significant bit(0x80000000) is set to indicate internal node + b3OpenCLArray m_maxDistanceFromRoot; //Max number of internal nodes between an internal node and the root node //1 element per internal node (number_of_internal_nodes == number_of_leaves - 1) b3OpenCLArray m_internalNodeAabbs; b3OpenCLArray m_internalNodeLeafIndexRanges; //x == min leaf index, y == max leaf index - b3OpenCLArray m_internalNodeChildNodes; //x == left child, y == right child - b3OpenCLArray m_internalNodeParentNodes; + b3OpenCLArray m_internalNodeChildNodes; //x == left child, y == right child; msb(0x80000000) is set to indicate internal node + b3OpenCLArray m_internalNodeParentNodes; //For parent node index, msb(0x80000000) is not set since it is always internal //1 element per internal node; for binary radix tree construction b3OpenCLArray m_commonPrefixes; b3OpenCLArray m_commonPrefixLengths; - b3OpenCLArray m_childNodeCount; - b3OpenCLArray m_distanceFromRoot; - b3OpenCLArray m_TEMP_leftLowerPrefix; - b3OpenCLArray m_TEMP_rightLowerPrefix; - b3OpenCLArray m_TEMP_leftSharedPrefixLength; - b3OpenCLArray m_TEMP_rightSharedPrefixLength; + b3OpenCLArray m_distanceFromRoot; //Number of internal nodes between this node and the root //1 element per leaf node (leaf nodes only include small AABBs) - b3OpenCLArray m_leafNodeParentNodes; - b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key == morton code, m_value == aabb index + b3OpenCLArray m_leafNodeParentNodes; //For parent node index, msb(0x80000000) is not set since it is always internal + b3OpenCLArray m_mortonCodesAndAabbIndicies; //m_key == morton code, m_value == aabb index in m_leafNodeAabbs b3OpenCLArray m_mergedAabb; //m_mergedAabb[0] contains the merged AABB of all leaf nodes b3OpenCLArray m_leafNodeAabbs; //Contains only small AABBs diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index 2c17f8623..b28c5ab56 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -448,6 +448,8 @@ b3Int64 computeCommonPrefix(b3Int64 i, b3Int64 j) return sharedBits & bitmask; } + +//Same as computeCommonPrefixLength(), but allows for prefixes with different lengths int getSharedPrefixLength(b3Int64 prefixA, int prefixLengthA, b3Int64 prefixB, int prefixLengthB) { return b3Min( computeCommonPrefixLength(prefixA, prefixB), b3Min(prefixLengthA, prefixLengthB) ); @@ -521,8 +523,6 @@ __kernel void buildBinaryRadixTreeLeafNodes(__global int* commonPrefixLengths, _ __kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes, __global int* commonPrefixLengths, __global int2* out_childNodes, __global int* out_internalNodeParentNodes, __global int* out_rootNodeIndex, - __global int* TEMP_out_leftLowerPrefix, __global int* TEMP_out_rightLowerPrefix, - __global int* TEMP_spl_left, __global int* TEMP_spl_right, int numInternalNodes) { int internalNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0); @@ -536,6 +536,7 @@ __kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes int leftIndex = -1; int rightIndex = -1; + //Find nearest element to left with a lower common prefix for(int i = internalNodeIndex - 1; i >= 0; --i) { int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]); @@ -546,6 +547,7 @@ __kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes } } + //Find nearest element to right with a lower common prefix for(int i = internalNodeIndex + 1; i < numInternalNodes; ++i) { int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]); @@ -645,11 +647,6 @@ __kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes } #endif - TEMP_out_leftLowerPrefix[internalNodeIndex] = leftIndex; - TEMP_out_rightLowerPrefix[internalNodeIndex] = rightIndex; - TEMP_spl_left[internalNodeIndex] = (leftIndex != -1) ? getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[leftIndex], commonPrefixLengths[leftIndex]) : -1; - TEMP_spl_right[internalNodeIndex] = (rightIndex != -1) ? getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[rightIndex], commonPrefixLengths[rightIndex]) : -1; - //Select parent { int leftPrefixLength = (leftIndex != -1) ? commonPrefixLengths[leftIndex] : B3_PLBVH_INVALID_COMMON_PREFIX; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index 46848b1aa..731423098 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -418,6 +418,7 @@ static const char* parallelLinearBvhCL= \ " \n" " return sharedBits & bitmask;\n" "}\n" +"//Same as computeCommonPrefixLength(), but allows for prefixes with different lengths\n" "int getSharedPrefixLength(b3Int64 prefixA, int prefixLengthA, b3Int64 prefixB, int prefixLengthB)\n" "{\n" " return b3Min( computeCommonPrefixLength(prefixA, prefixB), b3Min(prefixLengthA, prefixLengthB) );\n" @@ -487,8 +488,6 @@ static const char* parallelLinearBvhCL= \ "__kernel void buildBinaryRadixTreeInternalNodes(__global b3Int64* commonPrefixes, __global int* commonPrefixLengths,\n" " __global int2* out_childNodes,\n" " __global int* out_internalNodeParentNodes, __global int* out_rootNodeIndex,\n" -" __global int* TEMP_out_leftLowerPrefix, __global int* TEMP_out_rightLowerPrefix,\n" -" __global int* TEMP_spl_left, __global int* TEMP_spl_right,\n" " int numInternalNodes)\n" "{\n" " int internalNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" @@ -502,6 +501,7 @@ static const char* parallelLinearBvhCL= \ " int leftIndex = -1;\n" " int rightIndex = -1;\n" " \n" +" //Find nearest element to left with a lower common prefix\n" " for(int i = internalNodeIndex - 1; i >= 0; --i)\n" " {\n" " int nodeLeftSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]);\n" @@ -512,6 +512,7 @@ static const char* parallelLinearBvhCL= \ " }\n" " }\n" " \n" +" //Find nearest element to right with a lower common prefix\n" " for(int i = internalNodeIndex + 1; i < numInternalNodes; ++i)\n" " {\n" " int nodeRightSharedPrefixLength = getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[i], commonPrefixLengths[i]);\n" @@ -610,11 +611,6 @@ static const char* parallelLinearBvhCL= \ " }\n" "#endif\n" " \n" -" TEMP_out_leftLowerPrefix[internalNodeIndex] = leftIndex;\n" -" TEMP_out_rightLowerPrefix[internalNodeIndex] = rightIndex;\n" -" TEMP_spl_left[internalNodeIndex] = (leftIndex != -1) ? getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[leftIndex], commonPrefixLengths[leftIndex]) : -1;\n" -" TEMP_spl_right[internalNodeIndex] = (rightIndex != -1) ? getSharedPrefixLength(nodePrefix, nodePrefixLength, commonPrefixes[rightIndex], commonPrefixLengths[rightIndex]) : -1;\n" -" \n" " //Select parent\n" " {\n" " int leftPrefixLength = (leftIndex != -1) ? commonPrefixLengths[leftIndex] : B3_PLBVH_INVALID_COMMON_PREFIX;\n" From 1b85dad6b4cfa7cd44e5ec212133536de7e6a3c2 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Tue, 11 Mar 2014 17:43:29 -0700 Subject: [PATCH 012/116] Fix PLBVH raycast when only 1 small AABB is added to the tree. --- .../BroadphaseCollision/b3GpuParallelLinearBvh.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp index 40a73658f..0593fc136 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -163,6 +163,20 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab //so it does not matter if numLeaves == 0 and rootNodeIndex == -1 int rootNodeIndex = numLeaves - 1; m_rootNodeIndex.copyFromHostPointer(&rootNodeIndex, 1); + + //Since the AABBs need to be rearranged(sorted) for the BVH construction algorithm, + //m_mortonCodesAndAabbIndicies.m_value is used to map a sorted AABB index to the unsorted AABB index + //instead of directly moving the AABBs. It needs to be set for the ray cast traversal kernel to work. + //( m_mortonCodesAndAabbIndicies[].m_value == unsorted index == index of m_leafNodeAabbs ) + if(numLeaves == 1) + { + b3SortData leaf; + leaf.m_value = 0; //1 leaf so index is always 0; leaf.m_key does not need to be set + + m_mortonCodesAndAabbIndicies.resize(1); + m_mortonCodesAndAabbIndicies.copyFromHostPointer(&leaf, 1); + } + return; } From bb0102d79b6feb7baed06dbd98c0b2527eb35aab Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Thu, 13 Mar 2014 13:52:49 -0700 Subject: [PATCH 013/116] Add PLBVH documentation/slides. --- docs/b3GpuParallelLinearBvh.pdf | Bin 0 -> 398973 bytes .../b3GpuParallelLinearBvh.h | 4 +++- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 docs/b3GpuParallelLinearBvh.pdf diff --git a/docs/b3GpuParallelLinearBvh.pdf b/docs/b3GpuParallelLinearBvh.pdf new file mode 100644 index 0000000000000000000000000000000000000000..55327bff9d7edd324e67536ee4328a87075d998b GIT binary patch literal 398973 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ξ)}Z#X2-~x&Ona=$&KVc9s?ue1xsOa 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

aaA`z(vK;5jD+7U}v;>oRF zdYl0&CoC!tgn(V7IKKHk=6Z~4rw0lEYE6VKIHmWNdXYrp4c4q}Sbl z=(IrLK;rY{5Ed|mA(hE?8?Z130ayF(+Q2MBt;&#*4~8LiN6VyU6%_(Z-D?Q+JBH37 z;8;b{?v#oobHY^HKfUxgspR+0pXnU&3it~yi$;B=&Y{_NZ+!evxP@2;>!A#87TMX^ zj(>jJL63zRiHlhs{e3Dt>qGRLFRE{#nVm(pMn>VA{RrxaJF*F(z7AZ?2A4-z4K62v zL*7x67f#Su*xj)=q4^Hs6w`Z1y%TUYvlpwPVo_wvW*hq{6v!I&lEJn2EVB;Ky6(pZ z*6(PPl$HY59jrDp5HDXABwKi$ys7quYPoybm1Jy7S6un_ZQ3DtPamRr?Z0*S5ikvE zYg4^gpFPiyKM4@Y77*Udj)IyIp*9lq7;D?YO#Pwza6pQYnT387LV1IQ4Dnga;aBw{A4+75P6?-RF}{2O36A}CH&@s#;IP?l z@h`*U<04-{NZ{`yqrvwGPx%-pj07m2b(Yhp3nJ1a_`&Oh1Q&<%3X=rOUIwO!(P* zTUs06|ISEsMCc?Bjt%T|HLOpe5)QPtvkKO~xW!aur~zV}4&7CeDt?!+P{uPi{oy=Z z=Xelr8WCb!P(Ba~5Iv%&H}QtE`g!rclL{RXCG*p8PAz4yJ@iNLH_@uPvt9vDT;QKK z*6&zYSb)QP{qn^F;1V=L#37XsxK9so#*g7;w`e168=Bi_J4+gV2w$Lu1FyPxFLt%j z8EC%TW&%{{V|(i{Jpu1q*7v$rDYvI5`CAjeS)7%l#ZC(P8uesOV(&U2yCJUyY9po0&*OF{Y=_8 zAqAkzZoOC>v|%^f&Pc|1y#UPW4jVChxiI={iIkSiH=(W+&oJK(eOuQ5#a^^B0qy()V z#+J=}{cR)dCU*8L7vPl4p@z4>HSp)pfdP#RCj~7|QbbkXug6G?|7XL063Bdtzb9}1 zbl^_Vi-xW8>|+>|&Wrqtg#kth^X|Fe7*F~;3?Pwk<%;}OpHqOo14+gJar#WhdJXOF zangJsJ0(uS&kYdF`IH$DB|SR4Tb>qP&)dGi6Vx=Fl_fB7=g;7wJ9aY5)>cGZzLCDT z%6craN3k>e{Mw0+q5v^3DSJ-g2po`xx@lL~8hMBhe_A_$bNUpPs1vEg4XE}DNb;kn zPdnD}K+gd@pM$Rg0$s2^NJL^MFu2W+0#E7(k%f%h~iKMJlgqYa0}kl!LoeW zF95M~3S4zoo`Yrpc;mx|=U%KIX-l<>JVg1*53vhAL1S=eMge%H{7F7g*#MaM1Xgii zz+OvyNXl~tqhsAgDij{pe0V)QQR(YcAfxzDjgQ+7akzRN1n52OHOk&W|! z48cp?ZT+bQ0=%@GOR%-X2DF-7xx`+;&XzDgH@CDK)pO$G4UjT|`P+K4f>0s^It-se z#WvbtHI(DvQ?bHGPzYjgfF~mU1z>wU>Os(yeUqFXTcZik+cX|*hKm$1;{Z|hxQC98 z4%|RNFcw1#qmNU@imtq>*eSDMWldOqaQh42jS!L#cGn0z z;to<$@ZY_XBe~)YYJuphY#SIGa}a+uGpyA>`paW+J@up?f)mihrN+iS1GT3dcMJ@K zDcBW~_SHMr}iS@_;Ihq1Oa`%2bIq*sc_OCjxDR!Pp{l{ z8||kW-@e`WURqGDzG7}wX??WaEM6uokMgzb{Pu~D?i6qZmX)*;ovbp3r|msP#r9nv zfHPp-5)I$h5t6&d?hpIGW&7Y=pm2`hZhkQxuyZwBupjs;BrJTF z8uziX62ND~^I#n|4BgF$rR5rIF=u?{ft9pq@OTZ_voiFLWC>^!y3}UyaRvBtl z2h+Buq!fNgNvZkX9nXCVz~-=Ma5Ok>qbZo|4(+&lLSMo+k3>CqT~xKK(mE<err>8#_{zZ0ywCtieH+i}H13{zKJFv;4phWXl$3PzA}X_& z3lw9cxv~8qI1*a}oDC~xUR8g98_tY{egu^bf2E|Q>4{pR4TBaIQC>2tiOD9QvoJO> z@ynv)x2bc$LMwhP@Em?KOzW~$Q13W1^XMANOhTIdj4k?fd%Llz`NI-;>mfJzIbP;l3|8PJ=S3RD$1CB=;b0Oja3xh z^z%l)VrH!Q(#k$g$`ovfy$CM88;wE6(?xJh*Q>n+?6xtVqtTxKjV+nHGQ} zY(S;xD68^g0ID+mMDjWQGAF1%BYke3JLqfl^#Y6fw0SlIwMNpI8|spJkm<81Dh`dn@)hyJ;A0x>(pSV#WW&;?7+-4-ZFJxb6s$Z5nZKFQqwbi-@|! zE*1ny76S8|R{ht^di(ksom>uOrLRyx&>=J|uC)LxVBg?i;^!>$Msdp?Sp6g&<1y?u zn%nO+j`1!tpSXDna`j{GuHLKHkYpTsGh}fpdV-Z%o3vkRK+EzAB`&$zyZe{O{x?95 z%vI&Wzx;LCfAE)bw*gAsz#uc_M}uVcMPX?d>j)(EZJZ?61HcvnL0%b>i%r)A$7qXu&W>+sS|PjhR9Q)R&cuZ zDb|p%o!o}KLqp!{wfHCX2zEG8a$VqLB*AkU(i)oDtr%>I#c)VHzLka7$>)`jty&WqAy$9y(4(%y?+*ZE9N3Fsqwg(d zM0vN)T%ST2UuZKG(rTw1(HZoIgHl&=KOsqpM!UWIN8fV3^b@?9PRPRT1VWrACouP} zDW=v!G+P9~Erod(N8x5+WnbWhtsI+g0p)JS`hE6cD-~y51)Luo0?bqVj+uq6ld0?Qx$f+Wp|7|C z+j2-f_NgFpUSE}*;z+nc(gJfXiAn3|LqzGODf+s9`wKXxQWbz34{`+W^&1fVz(KqB zM#_iZZ?Vz0TV`;V%`nic#vA5H#bU9Jqh*_so%g{2ZbX+lJ^ubB-OuazwXj)K&Mk1j zX)$!$pRx5K;=WCt<#fzC+Oam*S5lPq#4G`b)y3A^|H3k$ehC9<@&zrFGVEufqrzPK z=OR2-28y;HX(fZ&ay@zyAc5^Q86bxlDrNwAzUazJeL9C`Z(N8O8F{GfIS)7pn*eB) zp{Ylf~@X zwZGOc&ozx)vt~bjjmDKOBVng(e#t3)EjAnh2EODMVz>+ay^BeSC}3Q!TP=q-r04oNiOJCq=uI5NhPC|E3a724yU3n zVYo0oZnsA61643Q~Ex7$JEpx*Dcq72=(ODoh<4ByYzzEpZ7(n)RfeA>vXt}Po%s?v)r*IGZ2j{%%dnoavxLws5N*D8?FClsJo`w6 zE5C|7NIrwwwgD3{&(5Dc{`xxK#GRWjbuDlP+s^` zV}|W|-x5d)m;7kETmo=b2>Gk>@}hx|dv?wfy_Gn=UAMi1@G@S;_15WTFmF)t?^mpj z2Dimoi@T8KwC29v9RMrRio)S=?J2(^EbiO^sI*jX`$Z#`i4mysun44J8XK=~mn0o-ZfRH$^FC{ogu zKF4&Jw&@RoT83OvTJY+cS z@}PAd^l`t}ugIV9>?z7XH+2fzDFMys)^h&d)pdORr3>rcvZiLY62mc!c^h^#YX(%ZwETFzEJeE1n!LAN6ZOq5ld`jXd`qn9g^b%AcVNO#gi=Ze2Ed{) zL&(G(>L99gFcEnX-m!%J1rUm}7RP2#uG#-cjwMIXIkU8MVd074z3dT?ZYRMY3A2Tv z2FPxXi(Ry0lDVK@WZaS5B_r^#sf>SiPHt|-3j6xyS6Q{SwMbMg zep1FP;hxUGGR`dtaoxJF_q9G9Hx(4lZ-*vfj6k-5gHbTU!O!>^$t!K z9~l?`UZZPHUY-Zm;*=!wwN4C*TNa830J*q}NKs*}Xmw74+bqT30UXG*F$M0rjV=69 z9q}faPE;Sqqo&tP&{U6vzSdi}ZULsKaS%YA#mbeXKK28iMm?e1d2ypsW9?z%^acTq zKuDJx*EVW=@whWbM!Y#@8n@TaoWgq|!Igf54$L0v={!i35}_d<3KwY`L^-3}6`VZ3 zk6l|(o<{0-g^j4r2Srvv_J+!ffTCRGVGjT>+Q-+F+$6=S@8^}2xX*XQJIs!anRbAIMB8C6djAe8aE}uWK5$H!^!lC>w=fj^;%kT zhu4_lm_o7Ya!tUzX>UXDTgQRDb8ydXtnAP9ov!b+b81B&7sUK^Jh*8~q&BZ(Wl9Vb zB?ILsg{e1MiUeZ#ex>uozw6efxDn`8dOzII6ruzq?1(H1V{=SP;I~o;@4Fz62o_P+1fp z*^9ly?ms%ld}&Kv=as+41^Jq5V`vn20*&2evVt;bLkJ4!GpwLowf~g(sW>t}?s?a` zU3c&70qMVv9cf3}4PJuREq)A>1qjf|fFV|Ql%Dkm{R;s+KALD*vDFY{95%dgpw$YVF#kBt%4sx&>@iMHumw4@?jp)9J|6J zxdY#bs;p`7T(d z{r`W#MJc&-&oS9YgsqEF?|wTsR(FP~taM!Dz1*`GduIY#kSg%AZR}ig0p%w*4 z^&vm+X1G0@g!xxwq~eJeFuBI+J1jOChCCo1Go+$AGd%=Jv zq5#TjJ;gJGq~Ij{XDh5$Jb7@&+&KF4Mm>e&ufp#ig# zgp?^EAR%SiZ&cypLJEF^I9_d#)a&}Aoo$i#b8B5&2TCOmn;!jU+4d+WsIp7*Q-Qj> zsu#tha&~y$;)Y@W;R`I+{JIfR-88*HA&kC07{`XyJ|nng{W&-?TV$wQi2W>1@%ANU z5vk37<4PayI(v+B_gm5aUhU8uT5hkl{R;?gny+cU*&*P}yc|v3W>Y~c%1wXN@9ymT zc24GZuW$SGrd;G=j#G9^xp^M@HzMzi+xpxYBU8(5v61V4x5n!t=|`mkK;@%Ionk*F z-aHhbJW=NA6B7|4sgPEwcFfw#eUYE@(wR7)eF^FDDC9Uxy$RM_e_2>bUN zDR$r7RY@ZekKt+TZuBF`;FysAEhhoT{4Z6Rj-!7q0eSC#26VaxsMBlfCilpYD*8h8 z<-^8)N$uWg#h?v0}ak@Rmy9v;s_{%c#;)mOC*&5VN4f(Z2iD z7G^KtEUyqM-c$e6F=(WJ;Okh@%y2uJcFpy-cnMiKKXt-A3qZ7{PTSFG)HADW_wqYu z)^>2_#06+2k1O?`EmkgBYe1d4_ZpUT{d>5f-NdX*103))c~207Z|}=G&J@u* zYaN&U4pQ!@bo;(X$Os~;ro^(2acR$OB;Pi(;E8eH6TIvUYAXvVr?{B~A&@3@y!b|( zxz9v!{+Mw#{8ipP!A*lxr(5+h4f{`bX$NhiZ@gM2y>wV`^C48O z=~Jrv5cNxS>%rmx1=jB=#UJo1miE&;NVadkU3H~XR;8R2s2y+e!hYecA_96X#W*KH z3UJka{=A_pJmMIeW(K((y)_S5>oIQ8?8Pb-!q7-P0dpKi5xs z8g;CN&>g?PhRW%Vodhk1S!A%r3k&>BWy`4eiXa`6>-tjt9>A~ntZ;s4#9riqXO*NY~Sk6FMZ&S@kuB7_QgL@t+ugKM=+03~g z;M-8Drrx_upvf_S-QGZxphd9V@q4M62ijyoVn_#jSJv_6a84nm>p0?-f*sLz?kxA< zPHS}=!UR_2)g1Z@R7)+1*h@}WAtGa(vL=nhByvD;9-`ZfuKx0IP7JK0{0b9)ztfX> zu*!x2!!FXZYS<5o=sjy+oUSWfUG%>^a`xe=37r=92#qCeruEBHsHKz3v(|GJ%PT86 zBkyJGX)N0KxGQFM`$(}622hJNf7af~$^QxJO%oV6V70}7fv1+~(GV(()W?Hcv^dZ5 zwejhgBA}2rcAyM?*C=slL@%3SeoG6t1AWzp5AtV^OFBB`)?=&d9kk|Ake^q3yWRJ` z=&DOqm)AiAC){k_jz3`ZE5P=Ouw|UOLgFigX;T;Ug zR{soefvxHu8X6iy+tTrIU4uUO;qTTSsW(6YxvU5l=M_C=&mn|TNwFViNW;w`yOqL| zAQ?wZ1{iXU$Vz-QNf#L`7=!at zP-R?#Nl8Q_&Ryim?;L@$Fw;Fs%G_~94|kHn(hQ~s+~fS9=Uy(UX*&Rz47cu?VT6Yj zaoU@mRJoKs*?Z}3Q=G@(opij1zfn;EU19H_l~m?Q8tBsWZwW-&nw=Psz^SB{2? z18N*7lCmH2$jtbi4f0|gzHn36kz=r!pYGBn`=?K1d(`P-P6wZ~oM9jhpAS5KtqCEc zz3)13z_U=-JGpbmrcth-gy4Qz%%u|-`PF3U<26m9&-gMm7C&?2MM($K^B46rd8I)P zQ5?8V*3CB{?wv^huF+~ZPF0x@;?g0feveFYp!ia<3{Q0Wo=st8|@+v7uYL~Q9UwFLCoRXxZK*Drj1n(EJacbZV0Bj%}{q+(pN_{k1Cij-2jN{c6`EqLzyW|ECSqFl(o9t+Akz5YQn zZ$XqXS4Cc~lVe`t!0d{q;(L4F)HMLNIWGI&C5;w=DDHiGy!EbZmo*NN1c~D`vM^8` zuWq-Ya2Y+u>tVr`({pz3OV%6h_K@0nO9vD`xf#s&28H39m&(&9@S=j3{X;tZ<3tdl zm?j1R(#v;*(p^x~a)5@(TD#{uU<}QXt9o7&XjKYXcdC04N+c=3z|ckzGL!BI%!8tn z@G_ctM^-$-zNVLoxCg>8Yj~nhWi5)6BKk8gBXasZ)#=UaJhV^bzP`*-#?s@*M<2p5 z@?pWCHTH+}+kD_P}*2+HHr?}AzF!;gsXVEswLCWUId zNTIP9*hiqF((zubLeuh!%O~M!NlC^5a6`p zy(G?f&kq!;Iw-2qKvyTH*NEtDu%|yqNr{QLXoIIvN2{qPYV(!qXQSq$OSwfn@tSdF z#UY6{Yq~e957#_;bEnkNC0zE?5uag4J8qDH)gc>tN;-j8sJ$S7-VqmCLO67;KN;ujFnzs7ze050o|? zKOKG=6#rA*_;zUC!pjwleAyrE`|ygZTpg_0Kz&JXM&c82{?u8jsSk~@(FRBB}r*yjCUmY!X_VKA4$hEJn z{+bkCpIU(R)Ge^rl7JZL%QR_nuJ`zF#tVkke(cs<{~>OsFr`eaz~kh2$x+lcSD1O# zGq2r%qZSt+QJXf%Be(q~FKDetm0oZ3hHbp$4OjG9k%?pz*Mm7N3Z4vIrceS)?|=Q& zAngsp4? zd(Uq39*6Jspr$t^sM~SIUcrKpsH@LMh-}9QKH5R>sk+;Q%8<#6zs}ULS1-J`e_C5b z8|jc|-3Ayb?%NNi8YL;R7Mz}-po}4{Sp+x{^zh){#TaIN7?1UVQoLAfa~H~aVfRNA zYzxpYNW@7hY=FAgt`F;TcDRqlfr@CwU;0lOk|%2Ya%^KS~;Gv|1r`NtlD|n70@0e{HGZ&p+z<=VDlmtcL=&gA=Q&n#4)t07kHB`(O+HZ zb@)y))y8Yk8nr&Yr|(4mKBlkGiPBd1_w?EiE}&`fkn*u-+SqlW9ai&?7O%t+h)F=} zImlEb@Rn=hn2LaH9PO!k8x1A@&nr8IMF}B&p62#^mwOUB28&3cY8N97H(?LNiBk4j zB-fUpb!EyAiyFR5G3Veqr?9xY*nh84>;$iUkj~x$I$D_V=PC1Wdv@>-f zOkbtsJi$k34YM(azIxVl~q-2r+($pH&`Y4lUWINgOb79`_hDYjPf%D}^LG zBq0*1i1Vbj`&=hLvOy;gq4MpRzpfD(TL7A?lr&&Q+q|hc-5P%o>@630SVS@L-DCg z=)uhUXq!>N>wqxlTud~APEbE>tR7B{eq#1gs4 zu3`lDvHzU=%il>z` z>bI_L@vL=9)N@^MkLq-nxCy_Db@TS$Vt20CNNr^ogGew{RLjv8rU}n%DN+lkQkG6e zZEU);$lQ)6ap94N>f1gO6g>T8*Iq%bB6T^^tYDFRb3b$LaU#O`EaVS9QHJQZ)&ncR z^KM-FrEvzg>d&noJ6BY$+3b;@T&&kFWyR>f(t0;OBO{nML67{ zda6<`m5@f)h0+dK$LIph`u5FCO}Y1~2-(#18iAxN2HkCI?L=Mu=~3&{G39|nZU{HZ zN1)NWx($ITROKsbBPi6SN#}QD^3O9EQ~-Wl5G6pU41bXUWCAu%`J4!wtS1bHX`4`T zrXCFg+rW2xJeicD^!!Ej>v!`z>yx}JtFIulKkmeXETC9 z%4;lcx+$1<_MbJi6b2K3Hltdi(bVp(ljg3o7EKxGRHk;+F{`QL)g!v7*4q1n z!(L0b7SP@!uLn>oxpV0JrFTj-cW`cJwN@V+Srw%qW~1txc4y09VQ_BBvPwoX`Z23O zdi}3TMU3)7eg!$Ry>`yH`*u~|d(z40h>-|^02G;b_uJ8`iIh9LN6D~X`3K@D^j>)L zAnyQbI4oR8|h_FN?Y`=KbK9tGA1)Jt)|Q62wty1r#To-Wky<&LyjWKN%@+tU@L06 zj5?OL6Y(1?Ej((@56LGnnA&|YPj7M}cH7v9;4^P6a_RD;)52s8QATItun|8cg#Fna6T9qqiBbV~b;H zRz0wgr=Xs)m!ImlYhYAZ@^>zzalDot30Wc#+7D50$sZ0Ndkk`^cw20zD0{-#Fc|J< z+ehJ;s(i{TeGfWkEUrppb#;$HIETL$66$B37n9h9;+uQbmiX+mi(<_|G=y>bv6Unw z_(;oDXOirVd2+N!E#x6iM#LQX(S>J4WkgI{J5y5*P|Z-ctXuPdx{vx0(O zqk0jQK;gep9?zp&@#L_|Y?reTA2k(-gvZ!;^$KewMbJ4K5r=2Yz{K|vGb)b$JVzKJ z5P(hGeEf23qb4gA5o95~^7M(X>O}}kjO0T8Qdqrq@-sjCytN^3?#TKjWjs{+G&^2D z1hS%~d{TX1g9ki912@53TLA|KC`BQ}80Y@rTy57^$xTjh#(IFN);8U zRF^yYO$u@C=ue!LfJk(Yjr;AeMqZ;WLH~C|Xb;c92u;6pRTNwnyG$A)TkiQ{tfcZd z4&mlJs|TCFs%xiFmGNxC#))cN`$yC1ry)km+Wuj}!o7&CFprhr)81jFBhr?B3=y$E z?YRZ?FlWvX#K-z4sb-5(?T1Qhyt+8YgmruW?){S}sn(Z#OkoZ5bl?ERntN6YdPH zAL8WNQ0+6WQH6q`exn=cEzc*1>YojG!qTxg7wb9n*k2{Fh}_Ev#L-C4-P>UiWygqW%cwB&_mc3)Yof0XjwmsMCv71XR!x5&CEp{B>31hjn~S7nQqZ$TD3E$Do_9aWFbE$`B`sZ!n9 zG-*RMmACK-x1N^$NG9U#$64fPR%_xx^M(Ytxg7l)#+HfC?(%n30H$3`b_Dx%d*7A| z{@7v-6429oAn^;a1k@lKq5@nNQXk5hT1_c&!L~$`xG1y3)S?8^uEnG;Wi-1UCzq|K zLLIZ2e)*Pq);x&x6*$FO@uaVTq?-8yZK#94hi(gt%)VUm>{+940|lH}5CGp|>_fl^ zKI`ld`1Y^ShYCI!k6;wzSIkL-(Mi}+fw>_hYI_DzqSx{q=LA{AM4~Ixkvl zlEgJL!_wk4-53PY@CB_KC40)?eq)(pSwiP)rRy!Y_3neNxLK9Kqt6i1G)pjx$M}Ts zz{k>57VVZ1{~Ukrg2kw>{xGMNt50F(zFSjc&iPHaf4X410^u}Lg;={jFlm1H#Tl(R zQz|aDrKthSk4GRVopD#iAe-5_@POq%e)O}s%LD~i+V%4k7AZ3a4R0M09=IEz1UXgU zVV4e(#Jc5?NS}gtP~Gj*NgE_HuQdUPAoK6rblGcC_~!r6&#VH5w>NvZ7!^)(5Qac@r_#1IbYSLk^-UKbCTg%2@2?;R@T(lhzxgncZI7QH zGTM&Pj^ZKB)Z%puY&2ndcNTUY*M6E5TzSpu^jT#He~f>yO6!HtX{?k+#x|z-$z8vH zHeXF=pg%zUNqI{fh*l#xJaIEvR1pS*bqA1y=RXuA%& zZ$ml$)AL|AY7#ulWlmqE=`8>`RQX?jjt(U#n12zULtDc)-J`%9jy#J2!o#|m{3Ewg zteY}+Y&HdomFi6%kVtWwtRsUE&Q~)g2R=x7^B*agia_8?>0~VPd(!a(O#k%{&OXn> z{`XIFmD^AU9v%LVnP71zzDgW;^B-de@smdZ;1v;=Q`n!yP9iBEUST|N;XejAhvs`= zao|J@V)P#c6@aib>>YgmhBU_ZNA++w351cAGH0Kls_Fb{CnW;M0nzjS9=-BiSU&YU z5JmO0BT&!1)XR{+bSqCvcnYz{&sXn4$A%2mzazcy6;5P7<7h z9=QC3xO1vr*4+GauBW}`RZHrnj}Wk^#t+*_W0;pfFd0?uOMS^aK~+!7Jy}=lAJg_& z0`DA@15C8{!j6R`O@TUDu*h)Gx$Q}!1P5(+^G6BBEqezKlq|MzI*a;U@UhOXTK+Pk zb|r$+wiqSq0DtOy@E&R*>@MoKY)}<6?Zr?WVCH z4g=l^gldj#P5C4_XK$mAV;#vRhr87OaB6zxr}%t8%>dnjNb;^T)naHPt=h$I*V-=S zB_X5{R-b;IHTc|CeRTZ`OTjHZ>n-E3WJ0V=$v32T9^(Nneu$CKckg_+xYls| z|KEQ(jm3o^3wY#9POaapn~gM^o`nw9K|NQ*=AbWw=>59B{ut;+>HDvFpUs?C&U*0X zCCLF^_gKir$=G^Z?3ZYP$6wE_%?JceRJ~-9pt7^u%6L4&k*%+^wTs&k_?6sWXurC- z0%C)NSV!Y0w<3O(8zA?W#$z7M?X}8~ymBbmu%`ybN0K3Nu!O!wJ37@?W0Bq0t9IU1 zX5_^qAE}ibsDfrI@08A*S5`Fypb9PnxKfis9 z;X$_AcB0W0BK5>HqJ{Sw6Oq<{2F}d{i~#;L?!mt&?*{znDFvdvJvbixcfU5|;m1f0 zWzm&>T|60L2t?D(NG|x3y`oK;7%~Wzd4yPx_@w*)`Fmtx9-FGo6)@=E9j}V`?{+v`h5G)Zm9I#qNA_Fs=}t0VIe4J84RxP^50ZEd=44;@*xW6PCYP&N zxA^OAD4S@+=zEEz!IY&^@dGa5B-2kPKvV@7iv{fkncq#G&adBWw0Cy!RW;YhsRU1O ziQcH7Xbjl4qnbghM(BTijjHU|6uHrr*{}lPqaqFG4VuZ>Ed~@jKngyMGeR0F#Dn-ic6kTlRyH?m6Ex>E*v+eUr?IUBpsBY8~ z#-$PKg~$Yw=~pmZk3Ul?$|w2H?MlV@R7DOOPWpPyLz9Et*RHy0YQw}0=?RsJ1q%K4 zW(TGo7{OG%2=0O23*bGW-j3CrN>J3nj4=F!uaQT}zGMz<6%>ug#l4rRrJ09g1O>dM zENw=vpMlrau>s;|rF&nSyZzhGJ)AP$*V7n8E~}ODU}d{?3-SN&zZ@eFz7HF*a6Jsc zM~u6+=5K5w?I)$GxAnSc7N8<%bV>kowVcb5KuX!p|D4v!$_V_?av6)_*KFS4%=+(^ zAT<_|t$u%!>C@`fdm1M45Okf$7xdNU>kqrYza`ajjIo-}Cn`yGB$iOwTK&AD;z}?-b&RqR&GN1Dpe=rLCl#!r- z3Bc5$DeUHcO>Is$hpeAOls$%FHvddo98xa-ACsn8fa@|uKaGDZKzTHx>0Q+RwhtPQ zjz%CgOe7(AZzBVgb!d=uBElp^!dQ(_8F&Z#Cd_!qkP#u7j5ytDQ5^k!#ra(aN@e2A zFWfsTzV3N68(Mpy_aF**3IA;i|3Caxr-IVLSWsKEMDXVLw2)tK=_2>j>i;<3#%%<2 zz3@a@lC(D&`m#Em4fns;d-HgxyZ3*5TC}OOD}_oW6{83-Mx`jlgk(u3WZ$z6W~NOl zF_na5rpT6%kljRS$S~RWk#+21th4!@*J!!#_kDkU-_P&+$M5m@F8$HN%$(O*u5+F1 zJg?_rq562wMD#VV9hB1q?uN7fUHD+{DI2%h$Mg{OPc53-rzX7BZ1m?emvY+L{xZ#A zzi|)8^S0ybwu45F_{qdYgC6Blf4u)GZ0SCb`0+>B=gVlhgnbhkj{#aR0ouEk=7{_7 z%|_b!FJ<^PwL7;;TTG7rzxOYP4y&n+XLWxW6Fb<$*l2@Rb+z3~hj~*(^GhhSRBW2_ zu9GyN=g2>Dy1&S=!oU<;bZw3Fk3+~0A7Sq<=uI#ciTJ&vQHNZ>9?$gn5p{=ga7#@+ zv#lBgYgF&r$f<1~$awY?_U!$GWZHs>plsO++w%3<9Hx7;e4-)$pxRiDrQz1Oo9YK` z%*g9_BD{xzZ%UY(1qTK(qqc$!hS;Z!NK){m@i|`@Go0ik^Q-M1&JMio)|m@mvgu&K zwoTpP4#YENkneX8)!e4*O#)VE*1YGh)9u7!j$;DNqzCq_=|UB!KCA|7ij&1y{oa_l~o+PeWtKkag_T2YwEr z8jz&iyEd|Ftw46be#}^RMb3jB$3rg;e~u z2mGLZ9-M+qBacPP{UjGb8ksb%DCx7w0EUquEekuesblUKUBi4@_9DXZs9$S!Ce+8?`mfkd2;e;MtL2UmQm|xXJxx1HLkcf$Y!+7MK&cH1rDm z8vGZDU7eVy%VVh=$BakP?(JU+6QVgUTB(Eo5HjRL+3WZGDOM56lU`%E=e&7TkqB<9X}i|BG_} zf1%cujU7He*Z!mxGn*U$`4GUcY)oZ5s{a>pAMRw)G7JZVXy@OWVK3(JGKxNR4jx_Eu|g3s{9{YvAH>ruw4grDq!gDtQHCc-eKhAwLXqrU9zXenG%QY(`a@EgDeO^QxX%kwNRu{4jXH9n+>pmUcx?=VDqP2yaSG)_1 z$!;IDsNT|KHa%t-bLz34BkKK%M{d_1_`Vh+B_8(cpC96lXp`mqS_vCR1L-IvVxE)1 z=Bm%f-bUhZy!y!5n0fl?*vCZj)Iek(&QfxGS0Oi_&AR!5g8Jc_=dC2*CtNv-pCq^6 za%k)zi>;x~;PZwG*^^htW_V#MWlyXwUhNld-9#_lMk4gdj(xXv{$ipsHoShHTuHIf z?R^n6*E+*X@5PA|`GQ}gA{lQ8p-)!i%U)+a?5|G1`oSE=V}N#juzjXbhfU~`e| z+Pgas*7kp~nX$VyaawLd1^#`9cJ8;2o~gmKf-`QuQoJMQlNIaqjulV z@4=Sor=LD|3785ziRmymt)@t4Roh!h))v9;jCrB;R?*go=_C=-eRRI=jQsH)Gsd74 zrYu%js?k}zEXL}=%~lCFYO3q-_Zj^Ny}`0+*}ZoIvf}S8vRtdbd)%nz-bJAbyU&~4 z%3^4jsOPR(oA3J^;93Eo$ktNSt2CH;V%)d4;A``<%-tsY#zSi! zcs;asS{dHO+%~CQmwa-gC0yiS%*Nh*lE#&r>g#-;J^ikm`NUCmugQfsl?NiXzHiJh zs&;7>+^cvJ9~?GSPEJIXpEA$1GC#Y!VcbPZTIAvG21k8ApKbdXYqx0{)K3lMtn+?h zxV&gD)ojq}+{2N6vrr3_#fmH9EXKbuHX2?~@)2LE)CoVjcNJ&nu7fP!XXRRV9i3P2 z!!_!C+b=EY^v!Nxb8;!NL~%Fa^&w@N-S}&NqwVTs{k!#Tx_|2ajHL(&Q~Rg<(a))RU#6)I|eKcBC3)e3W)- zc0dXa^`48mndO-MRQqkxG1Jz8eLTJQIdpBu4V7D~s|qT|iv7}--ffe#xw}}ne~Y^L zsoWU^<-!WB{uU9pI4Nu!D{PrA`n+jtz!j?pF#(rO_wCe*D$$BU7`LN|Jq-`Be@d0|D~brn*;Z3-$bUh%1K`2sbRM$NzMc%unxKQbJA@Pko#ll!La9Yqhs|DLA`WmD3@ z(4s5r67G9kmsNa-cqrPVNc>*0dG!i^3X*_Saa*Zntrm<9XP;ZTWM^^VSo9BfWo`y( zYx)#+fSkERFL~F>Q^jo`wAYt(N?oiOUThb=ZRp}&7q|C)UCfBl9dn^WxG1#Wy1NVJ8sGz zxw%AC-6#9q`8?y?$wkdqjM7eoVKYdV!wmIWk5V6I+>3TPy5Z94jve`(hF%YIm$09U z23hf}$^y=czHSXm{-&^Q=tJ#!xi^KH=Z&15^9Kyha~|I@Nn04P!5*iQ zG?cFoF11cTzKP{68F4uA?BCP~(hf+CdGD79P;& zvrgtVR&YbRYhWimEPGS|e#Xkq#@1u!QAGv#Njnes3s%?FU7TE9oUNQab}Ieea}^;? zT=g%TE?nKk(dD|ntGT5W{FIfKou!qY=E+rm-HJ!rwQU^@abw(=R_BV*TFPLE%8Klj zy(f-e`&PYkoz-={vw=IGE3Ig`Ehig%MrCLBiLa<-nkaF_Y1LfkqfLsQIj*`Dq0h5+ zUS0ZSr)N;;M`PJJ95R)iQVbe{{NZINidCO*{%je8nJVNtJizriQcU8S|G_tLFC_h)-Ti%e1BV`lGi@eTujLASN_eGVKYtpuoKT3k#axrb zdX$hMYgR=nms6S)UQN0ylEf9pl&KS^CstG`z8+L3R+ac1!|$Vg|Avv3ru=`)L;pYWYL&cit0Wu*b56|jNNMj{RtF750N#(_KvsT2A zug=QXT}wqn%{TW!T?r)Nop_C$#-c`W|Ek{=v!afuaLso}15Mj0^SN?CeV5LGc=A0( z3so7~{Z~wk7G+BJGEU@BNH|G2v0if>f2Q{p;+iW%B7f|0#(T1E=C)I7kD$ZD$7Zbi z*1x5t*KmyAArGlx%m;&=S%NAXGYTWh{CP$L%%`J6axdrH>$`mBFgH!GOQj}-W$?EO z++1*GKT@BTxngckBV9zX4H{v2n3DmoKr4kj`q{p^3g_*WD7oJ)5bFLku$Cprmds~n zaA(xGTGx>Hx04tx_|&$qoLmjJ0#3nkAiukG^lFPI!*q1S-rCVv6`#1<`>)hPl{e4m z){fz#E>lPP5+c(oDrWrTn2GfaBS+rbOXAN+w`8X@mUB;Y3J(R$anhR@QiXLk`o7N~<0V{#&fq(b)V*#@yY*g}Q}(kOFe|@nvFRZ1mp-=~4_A>_Lk;90 z)g#p!_x~1XK$+mf=Yq@*KPGdn*}zUML(jy=&*!i8>H4XerXZ=LAm%&HraMWBi-+MF zzN7>Xw0IwFYNF1_r{FDNXESeiUiDjjFJT2=j*La7#CEIuV!R*Bw93?u)QD+zL?7k| zJ|H*2*u6Wyqy{azrgp_C@3MSC_mM3D+j@6+Kc3sO&zxiR9G`%;juGiAZ3#Qfy(4ov zXw*8$ngbH@h5emgcY}q^QzwdGBGf_?ydr!hKJsoM1k5$4U}>N4;s!)^XpmNF3>V>^ zmLe6Hy0LXpkEXvQp14PUaEM#)6@l@zzB{>VqfCX7hj_-`ZC0X$$G9idwCLy5`{9uo zMfT+`RKHPXL4KrH?2N!b1gIO>0q*IrGXhov-^Wf96@HqDdo#k;4I+g>&VAEfTH+)> z8)Spdjmk|eIPuz|ay2cipE7H6b)!N%J}a6OwLR8*wo+{vOT{}JvK(hOG0sj(-IqLU zCs^bqf{%>!J||v2U?d+^$=RQG_<#;QefO2MNA;NEkl7sReMR0$II|Vbp!ICqG0xlV z_B~j2-!2?u(sG2VhW#AEz58^|r7L|vBKZm~OI3Nl+w3FNJgKp)9N}VK>SxKt_a)Qe zl31U+T%~=!kr>k5Q>2!-ic2&x3nlLDdptmzCv~$QkxX+ zS-*0@v`Wy?PwB_7*}9Q$$T72Caufx>)a($Xoc?G*EhYDm^8SPC6Z|R;Y0#-o4 zd~gjbNS2vcX;=wWIrCwXR3E$mMFDPt=hr^*u77}%SjbUye5e!aC=*4zQi-7w8ZY24Ez9Ya2T9{!Ib z4avvYvvdyUM<_gs#XBuO?0lH%@m>IQzk1NSVtZdHZ_pcmkCdpul_rb^KBrC{RK^&d zq(>!Fh`RWz8--*<8D$*jF_pa|j;~&qIE}c;; ztQhgqi=Ju!AyQ#P#}50s4OGR|%)o2B&-q_zFSL#PG@hp>y80+)DBSq^216YwnIa&f zzTU@gXb+f-+qZ9j`lL=6`ZS?05Lo3Cswp*|SV zt?f&g-Wgb}NQgCyBfqO1?(bjWcXr5@@;m~UR)gL_soJ}pte(+Gc7>aGbP^K#s>ga~ z6Xlb*h9{s_>jyKsI2b=aHiy&J&3ea?7rViKR(pH`tc0pr(s=ZVF-U`u`&zkq01UoBaJwO0K-K>Nip zOBvhsK-X-{3tp&&+PE%k-Fj^J#AKL_xA)BC36@j#UxJ*3G(<+TqjL1%|FAwr zSC@r@!@0lIhq{fSwq%mYcq~@>38kW!(uhz|QJJUBvqS1i0FJuaFLadOmk1jtr;)xs z4d_|KLSMkM@wEfh)sF{`fcJcDn()cx%syv)|Ne1OxV5!)HwGH<7+lG$k`JqxrlfA$&mwn4!kogra*S!)6W}EKfnR z@IGE)A%a(LgU8SJ_a_D;T&j>>$MzQaU|T9`jj=$G^fdIrsts|2pgQ@S>no>)8yg$D z$9=+LU)K#v+~eKqti2GLi_1lSl@)o7?aF&3{ijo1=9ju;TMTAPWK?j3lKv}b-Q zIDMZ(v;MFl^Oq)ZAM%vfPC!=&LV+H}YK0*k}Z&xq+i0Gme;ubmCB-Z1m2*B^!0{)fb7rHjkgY zA+$`yD&U=^P$Owqf8%1v10w1P(b<*x+Oo7z+=Pgx+nGvIx&CkmuDz**Nt(~{eKCLV zia5G)rrA*;TE}yu?&Sy0>mYrKhXqY+}ZuF!+_XaV&UB<$7``qJj^U@*nWpGT(i?fg4l zb+9rk3+`ym7)AkmWK`FXb}3se_{Dtl*a&K`J(KZlqONFZfe9A2bZ_Cx_l$FAN#50M zN4osAv5g5%2IO;z3cy2qmzaW1amL&GLyhRw_0dLp?FM^b+=k`HFVsZs^rM$fvae2K zGYZZ%uvieVZ&8Rmza=Pu&8-K5+qNZZD!G1y#y8x>FNY*f1A&_nMGW_Ccq??{l<2CW{9ZlA2wxEtfnsVpa4wa-OJ)qKv2^Y;LX~jqoad8i*D%2MC}ak z9AXIAPuaDWmzRUXvF&4NK$qr#BN!k=O;kv?Rr)ed+lM6Jo@OE?8*Ci}*x&$Srz_(2O_3w-aZ zX0d=XUN>0lMU0J&<#Msnh})pU&PQqBC7r#!aXMnK{qY~>ccaM8&dv=D4Q)`TfX09c zsdC5RiV6!;LT$c*`Ag|b^1T*)70mi+C!nzONM4D@wh-@2$wHXBr&Ewlj3nPxQdz7s z048KVPZ)gcd24FXx=mTYfA=*U*g&_R+68o?KH)YZEVUFkIgorVG3BqjeZdVa*}2~y z+U`lW(q@j9QLaR){KMP%ngKv2AySj^cTQW?ruYpRn zR_RY|*lG{P@w7nu8`z3`!1PaB9RKZ>d%c_2YbE9NfO{X@Y#JSgKB^Fo(Ib0prVvDF zwXmf*98*(MM<=JF5t2>7KnB>X5-l8`ODce%b1^MtmwlX4CWl2PVA00#$77!?w!y-8&N@EOT9G4 zt&-3Au{ws_)ZVVDs_JwA6&Dc5TYTJLK>HEcb)2sM+;znLCj&rj8WT;ZXCtH31TGus zXjN4RRG~d%+;c8z54D%V4YqwoTD(REal0RWAQ}^^gsT5l+qa>y=xey=j*9Jl31Y(? zhBV7;syFV#JTC!_`G8OJ*nR35$rpn#!yQ-&vh@6BM#1VhfHA^}9nFKfmpECOa|>~F z3twDuiYKO1h?BxyROvo1roPbh7|7Fz^BL;T=P>3sV<4sM}%Uf%7iV4qK@Txvzien1J2$TfI)N31Yq{DC+ZiMSv zY|8JD8)^T0&L&&ePP=P7jtkk@v2%_#|J8@5)$y?6Eox+8kZYV{*f^<_74GxM>&R;5 z3RJpmxVX2ujM`}U$E$NvFB{OADT8|p2H>#C{Zwv#zU<7{q_8#^uA6Y*#KI~YxsCz? zd^IH;mil7i9+-!;k~VU_p! z<=4`U_@% zIN44f8y? z3R2!H?I}w4(z< z?Ij*kD}^RTAfKaT78Ln==nLCUh<7{~zC^h8qlzEbp(a^x>FC)j;@))$M(?KF3bwd| z|EsUM-93W$>Nujd>OB(X@oxUW7HjMdA-c~ddu*F7$)dP{GHyZz|DV3WWbn6t(Xk!C z3in@~H#kIPDTx(~gNk!vk)^j%2;Er`w^Il~Fa~Y(a-ZgjhUGWbPNPdp-U4bwKM|Gw zXh`mQ&KCEwDXGohIdkC73mY5Cc-5kR7VEyAlKE&z|G>w&jP6FSx3Hll$CtCyEX*4y zSUBh&)UREQlwK3NU5yDBLBGH~yp@&O6qV&h;xOeV{AR%nutRCTLYAIPrGfo#V8Cu1 zdomT31UgpHdmSOBLO=GA1^ZUaOE!v_dPTNfH6^v>I@UBb4E(PppoA~V%{9J!*}cI1 z#?+#hx4DMtvP0cGDgTHmH%;t=08{aBhi!LENqXj0q$@gtR|Aa2VY?Sv9VL|n8uJBQ zHszN4>;yE_J`TpxvU_mwYcJ6p40XldCDMKU*#~H-)VYibJIY&GFw~{|p)y!3Uo5sA zdWa(Wvwv3WK>q@c;k}NHL~ORk!tOzn&;%x-ce^8Y$AVO-8!AoHXOWO(BAATwYwwK? znT~FQ3j6$^yU+pAPAo!e9R#ywiC_QwsowpcK`#aY;xlsNG0804;VM%d2S;dVH{JtC z0)R=8K8*gxBUSg~^^9R*ru%;zD=7qmU~D7RMHQ>@xe`I=S3?Kz1nBf(Tia>l=)vBQhjqI$|}QcR7C&= z^ZbT}ImMEX8-PW7qZ2IrmM`g(iC=r)kHKKJU1hE>opzifyaBrw?9*xdqRe2+D;G9% z1z=ZmpsJ!tB=D-)ndrq!BKLFJCk|q-15G zCT@Zzls}rTH;5$GdBkHAV6d0(`5eh7ASfcZ7CJvScR)qp?lpuMJiG#Y2fMJ%khhrs zNIG?)&i;>l5M%}F+ykBv78d5$bA%=MatYtKO-3(PFFCRVwsk-B6?L=j=8Dy@t1m&9 z*Sf|iT+GVIaQE_R@CK4T5LIbiJCHfH=?0@8eqo^)l~*xb%F;XvX$AK*p z{eJw^MIeHol?Da|E?>SJoAB|`@YtBRsOS_V->*;$?_ypZKr$D@R&S~md%5JTZ6c5Y zO!mTgzZ+|T{jv?zJzR3b`JqN^k;K(AIyySQooeNeEtU++JAuEc zr6dVk7`^k`l$7?iHqhGb6TdpJ9r)R~ra(RZ^3|kp;vIgc!E7r2(#4y_N@{8ybUI&c z!hl5DBhK#&Duq;Yb(P)f1-Weh+oM3FDDp;sdg0 z7fK(qs^KUAu;)X#0RYv@8;C;zFx^((Bh5Vkc3{eCwE>KoxLB!k)Zu^3>ij;_J!W(KPwr`i&?)ATgw^|!kmKI3`Df|0R9?P zkC+q=e#wviBs$^2zycv+ePAEd^*4RMPA^>u**US*#U6vQV8kFd_*C_IVNXEo1S0JI zCmshQ*FOsOCyBpy9dt$rlUMGJ#TFJ7rG^5IwdZW?zcp`znUJBJ$CicK@hL=8Ng7yT zP-L*~gIdq}a&`O(u?df7&@jR#&hHB?wRrU(LgKfiTmcFawZJThoZySR{4#m8l7?pm zWor^5@dcif#^Xcwer*5Q@^AnGeo(y4(jS{e<9;M}a9>dn_EYx>iZd_oan^AebbwYh!5_xSxSWr_=qBGcN&? zUy7l=b4h+K`YZ)CX?BTqB^owVTRG89hk6q?f*JwBv$LB^YDZ6A7C+j>Jxw>U&Thg8 zqDIh$oJh~@X{XJ3G&8Kglh1mQ<;Vy+pEY`m`a2 z@I5H}(=+NFM6#97=O#r1m6DcL%VG!NhGMPn zaZATTgT2Nzb=L5ddnH|@h(18vU$EQ*GCqE-Hu<04h$K~X2eVU91zOe}=3YCv)57); z(O+dLL_Z_G%F5du6X<$JpX3Z?c_0Rd?J}@;g=RULm6^$r=W$1!2V<>Ya!<3?PUFRK zysQy%bTn=qx2(-pq1)?NW=BepcX;ff`)G5&9-v5)M-a39LAS)3xmijY+K8w*T@NEe zy700}Y|NNyq!+d5$`;kz6%L9*_d_J9REeW?N~!2+ZtyK!E}I*0W!VJ%`hXH@Y-(F6 zvfcUGJlzpr?T0nOO-wXtd-!%cN|es%n>Qpx_1cv3VrGCEa)G01f)zpIyu7>s1F_6d z{3vlsxY}RE7hOgTj3sR9j!}GS+Sf!uwe);;E}5$|J zq}MbO=PFP2Zcz`eU~Lv1Gj#Pan`vbfbSvl4fQ<^T&#mB{OaU4Za_(F)p(F{VSV21g zSxJ#*o_qwDj^IOTOWKji+idaXLa9OIImE=UMtMAvbzQ!7pG^WRb{duXz;?Kk>ad9)eldq8Nht#H6f|acPN#W;H zcGu?YUX%NakoL&@i{= zofm_j=h%2`3Fv?3A?U@aw4(QB+3=p-N|TyG);)E`Q{QP$M!uQ$Ec!~lDzKeVHDTMJ z`G&mitxyG_yC&uvdeRJ1qZV$!RqSh)U@=SnJx9JC?P1Da9ydQLb`J-S&&&}>)VNxd z^XRkwwWh3~Zb{OLCP9r&@QFE7+Ks6Yn?fH_Dl7RV6Ab)#{lBhs+ zcMyi+7sO!w?U34lMDwbBj;`#)ibn`ho`#C!f z2iIPw8SH~k@8TN1$h4u`stNB`wYgZ|_#SFwlznuj(X4x{X8eM_9d{60)X58r8J$6| znsP%6)@EKb>aNKN~fW%)A3DRb0;4r;9%*b3_|3$zRYcm+tV=aR~=^3I4Q zu{<(31_=765 zvpRVE;81B`x31o31%4zElieD0qg7H~`U&>KXVpq<*U-t}ju^Q*`7E4gE}&VLV-_f4 zC=do^MaiP-dAl=Nk0f6OGc`RgKxjZ9HqIR0WH`XdTk;FYST>wULWBT}xC_9rov644 zp!UPFNl2uIaW-T55*3^r)>ZwlXtIirCiTQvK^ouCv&zGrMQYsA*6Q__;v4T3*+qDZ z-F_wX6Dj@#LGB(NAP|_g0JmO3a4R59f?3htPzc^EG;Xrc7u~W9QyEHk`cEKQ*>~9e zw47xfABXPwhL*p@E9o8wxg;Ggu#Pl;D{?-!g)4;R_LQvUH?|)FngH8T{{wOHK`uz) zfH1NZA0vNtcXf63@k#s}VB6o5o0HSj(o(~3?@>ZCghG>^N{-!ubxr9mqbZUJN__nUChiR0P(o0)8Uj z-`oMb;d8$nG$jx(wz07Rp7Tk_M}$25+j3AW=X8hEjSJttS2P0OZ{#FXObXQ`?$M-@Welg&H7M%D$Ex)L?t@B>G^UzxlS53(AdUvJ4=fMVz3}01zH|n2@aJ>D4Th~2U-)2yT>7W*-<~w533w2A zi$|NZmcZ@?s0x28{6*tj-OB&Y3JPQdK|S9_0D<@Sz&~Ba?>~@1d+e{l$kG<&QGAy# z^v0aH#Dg%kc9hSelwcfhj8>yRib9UD5paxue>hHEO`*Djxm*eeeSYC3*WKLGv$E>F zSM3Cel?$SKRBCZJ^8Bw-Nx_<%x zLQ4Sp4wA7tkeR2OTQyYOFR?uUx5R-L`a&IvSr~KIT5;ZV`@RUqF4{{bP&2@d4E!`3 z_CzZ07BCy3miSkf#E)v%FXsnouk99{=T#5JCWUJdizZCX%s}i7O5T7h&96r)xrIBk zSc!ITkgM;O@C_CUjTyXR3V#9Fn-pm26D-9tUPQ#5mZZ7<@p=ai(yFVgdAy>Z7W!97 zR#5yx(k$c}gF?l{#hsn6{s)ElC4&9*fGBjx!^Coy}jTbq&f${uRKcVhU}pm*cYld{b5F;d$*NFXmk%G zkV5b;PGG?XD8mG%k8&8KR?JOLf6yTUrtz1#t<@$Dc-Z?ss8)=;3~-tmcFG`QepLZP z%upaJ+Z|z(ZghU%Mi43d!>lAkAtJe_uVJy=Qem{mobuf?$XF^@LDT^SbV>WwU+Zr~ zW2k4F%pa+=_kcvXN)E3ygN7W+ zVNB#N4DkqRoi?CC6iBq0>1mIN)xvzif3f2Fx=*J^VzzW7RE)@BE{V_o5Ssr1-d`NY z4kFJ6krO>0wCrjKL=21rC*Lf8{?(ObIDf`w=GZ4x(H>MdhAMZixBQe?03vxt7$go? z9$?oN#0CYEcwHkPcO#igtqwKB))mg>&N(PdT+Gt6UdDw0K)1tZHVIdMV&F~c-8gma z0oD{?ON!&lqAMw7wPm+dBhS}dE*0nYYl1WukfetY*tUT>0+PdNWx3=P8OWad5IbTd zepGr&_}RdbOa2oYVg_SL$~ttmk0$o^T*_zr14J-m+p!s8b1>$|o7q8PfB~2SX>*#^ zpPYj@EI-L$HB2|b-fRE0L{Yy|g3y6rk!14$qv*(`Rn{5MEgvr5b60`HpQgLgw@UmU zB1$m_g4Ng=YC(#^@PZ#D7U@6ok-Xl+wX4J3R|qrGRYRKJ?{&@|V?a)Q$k0YdF$!;Y z6R-)_eSCaeU0;UUqQVACxB4v`Z0JzVs#dZ_=7A} zaS1?{z3Gk%H+!E>!cI5iSqb=wBBWX0eU~**=f(1AT6h`94t$VHTz(Sj9p;GQKpmhO zlP4j6N1H-IN7y+{-t;u}B}V#8KuSrqbDh-i?n7-vh0V}&qW4hdCr6LfM#{-u!!>^7 ztO_3!X;O)5w{jEnJ6Ct>wEkpGW0ziDx1_X@MQOTXe12Gsuz}0bL!u$8S{|IS845pF zng^xjO{J%&n;%i*PS%2J7FMQ!{J!$GLz@&u1`q<|!ta_R^^#49$S4m${$?7mAXX_p znAZiAPP2o2=Edm)dDS?*s~t7sszf`An#vhOZnR0%7K!JS=lG@&iSf-7)HBt=7)no* zBBR^gbLNGN)nOs2+0>ie8^0WUG-n{-CtmyQG&!cmK}x3GtwD412hBw9n0JtV?C-0& zbV~U$+0<-oXP@QG9=B~B^Sl}DJ~eKwT8f8)iP~VdHnD3&-8%M_LdQ{X5A8b=QTzG5(Wucn(^Qc;#*dm?>(e+`wE&_Ai#8D z$(ts>1NF1NrmpyQu4(7QLuji2oNRG&#PRp)Bfcov67*`;9nv)5=~aYfpV=a^@8TF0(@)%$TrhFme;DU((>=yJAWYcvX%Sz>S?WC&~y zpRU*~bVgC+v;Uz-2pNeUmQSdpd&Z;YOPhMq^CJpkFSGN^j@x3|*g>*G>cpI%D{P$C zHCyhzLnA4J(1%^~YO;JpQaFzBt}^IpQ8mtcCy&qqTCOPr8P*Bc!FG9iq_N9LnSG}^ z%WWvEKWEh5NZG#3K^`ogf=GhE6N=RxQ*oDxob1g4nBi7qjO0w2iWC z%Qj{M(%c1GmsyS8p*FY0HKq)cpsR((bv1QH&-MGRi+fz7*ixQ?y*qjF16V2V<*)M+ z3(j59MBgg&9~n(6jq{jpc6>5Rc6bOaT%*%5)%}j#32Wq*Gh*QYAQY5$(=TmeNGTn| zz^7Kq{%$lY%fNq|b~Av2N#uJnlES3@8sRr(-Ou=4eHhu>lEmBZnRuR4KEe>zmAIOw zq3XLEyFT!9e%HW@@!S42B*BYcBMqPV+>KAgKgRhC1Z1?M&)MP43I0K864PUP?At_W zceB0I{6UGx%e#1inSOjC=i#FvU^NWU*!uL8{Z*kDyE@&@{QW5nk{=OatRNVe0;P;Z zC87y9YGMyIuMkqf`sj#*)@EOnGbY9*vlAX^`+$rnU)=U9h044i)ECoAqyo59K7;Dl zd4F{>;#FY+Ch~rTtE7%l)C|LwQy(cr=&(%|b)nRVY7Xe7cY&FyTY8jlF;?V)*pE<# zcF>qGz$WJ7tw(z76i{)z-5-Iea0V1M1qddMd=Dvc#qY-QI235JZ^N)syjK&Z1w{K)qV+R;0y0D2MD#YC+!t!MD%AghEjq?fSrK zdZN6gkUu|S2e_SGC|f@4B--?FM$Q2&|BC!gd{TIHfu?~DuAPJePhv9*F!TTOZxqBr zg0eDZSupP;{u?@HfzSc&LC;EQ8bH^5eerzkF8QSK!P*$4{U6l%v&G<9G1$FQSY9X8FXQ=w%t`$sK-pF9ZtSEu`T>{Ljxv7Gl`R3x=zJ z8KFZw5&NH`z_@7Xi%&q*)k0U9-wQhmT9-1R6Gc#uMKBXAL9ngg8Sqe!ssymw1pKfwr6$~KJ;*Bne?J9oV=QoG zfkO+NNRa9v!WG!TkKi^#!FJdg;QLGbDaj{1z}JZ?{B&r*VJy1=Lh3MBTu$O5(}jF6 z5Qhg}34I+wheGJEkEQ&~Q{xV)msRqw;x_|t zAADP<4Fybr@0$pD{jeK?!2bvN*a#&hevlnj2e=1;M$Gb`KSlgzTVNLyK?Yt0$f|f5 z!h8s%@ewdSroVZCpFO$N-4Fiyev7wQ=EH{%;Ap^t2t7fHI#6qD!VP8C1yCSoYp@1Z z^CRqSS{fRS2K3Rd$9tE8zhoj5W9k5}0&;br>=&3UY*KiC7DQ0G@jt%|nThM{0;df8 z{PH0p2zG(Ou5nF=!r^Cs769%4Vm-j`FGIlRUz7*29 zfF~069;2%sI|f(?s5p>Gfbkh>Obvf36T1tJyZ+`7!0$kmH-df>2tVg&f&BoP6|kJt zMOxruXprHzFr!O8dak)J_$!G6Jiisj5`5aV#}fPr6z!&-|5+e@SV)eHoR+AVnAnaT zKc9P-ovlcsfwUjH_*_|OkTU~H@nz!)uDT2jT~L6lun6Utx@$*_4{d?CFvCD0JR2ep z`Kw0=MEs>9l=Z|XjQDvSgFWNwKNWv(*ItjYA!d~lor zBuU6_UG>Mx-TJza?!OSoPr{Bn^KIeZtVtq5Ag~DV09)g^^4f_yVlIEU3TPQ_ya;i% zn;5^c9=g~3@rI#wdh091CwKii1~U#4LZGw7P@)2KJnuxW)a;-P*vV;VUN8DNardCI zw!1m6@%BHgS|ViC&OT%i{YF(f=Bj|#Wrmxxsx{_Jq35TXnR$Bm#9Hzm~2X7uOn!G>lSt9$?GgA%mQgo>3y>BY-P5DEW_e@_#Cd4Lc!3xn2j{jz-^?OERm%M&DL@*4 znOMf;bE~F9X`S#k6vE08Yn&L|+45+cf44 za*)nx;|OfWylIh;yUl}~*Kuw;L^!w&XemCCxm-O79rTIR*6#DY_->`W=dV6QHa{3s zXhR&F7N$3X!y3RfE;l7sjubXh++MSTw9xsFQV7pASb`NE+p^}{WRf3t#}29*P|E$p z<6ni$k0|4$AoR*mtVuH zekZ<8GtjlC-Kif#$AF_$CfK*V*N=f$f=x6vD5;_pz)_qrjw3mZbx{PsXF#kKxifV1 zF{~6Ch-=y^^9P>WHZfFKZZ1gU$*C%(?qv)`EXRLY@<6>M7?>ReDVJhNFu-hZ^)zs$s9YZS4;)*bFXPa4dCR{kpe6^x{Hi?qsH?3b0x6_#oczg^8{=d*%eICV zAgU`eXAWmw_Xi%C3a;jMR1$7?E6C>Gip>b}Xl~g1)$HBlw|Sejg^mtPRmjv2ph6r2 z#pYGMXoB1i$a-}4q+3qT&Ib2)#9eOb>}zgqt?;)&_OQU-N+;txK5V8Tm=6JrbP4Ch zT-`*?xyB9>HuLG^a0;RjqIKXTRrTvCj+LK_ya|_6LfsIn7}H(j(zl1mNg(^ExQpz- zK7TP+`&qvi3v-ezA77KdFpfxczZ^JWyRsX#UG!aeIEB6;>uNRoY8>Q8P*Cx#`|UA> zhuc$f;3rGBm)EE~T?=}j{M~aiC$SK)d;qw(PF#G@d4lN64G5n~cPb5n7x}QKM-qs> z2M#YcN+*}8tbNC3<*aT+M<{c^{TZYCP>NH)C_NV29$e230w?}OvGcp#wj}jyu+QGa zp2JW2#EZ@k?;P*(vUf6hXe;KxGgk@uY*;2IaaysDdtxMtIi8#62mGFhz)k+IXyYrp zHcKq!+t3c8ggH?9V<+v}5h*43 zg%wj$&Ifmc6>9xvUG%;89iWr7=m@6v8yDd z>3v0Co0i}<;8*w+=v!ocHLdPaj3?Yy*1>8SNZFVf*9e`*|8Qb3LQoONZH5-UE@RJT zkALQ7J$*Jh8>M-+*+nwt`h#~hc?N~*eHUWYIzWsPs5DXQFrsXuBfhig(y2=WaB9!% zs}pT*Skt=$aNaCoK4-d7=Gu^c8~T*8gS^N9{79OZ#b2n3WP`rgF2xp%CnuldMcgre z=}O!SnWSM&X$-~c7}9*e{K~ZR{f2U=6IE+lUp71VZ%W%~pgDkUvwD0+=qQW1WjWS1E@P0kv<36S);^E_ywWt}c-X3W4IWiBO=D0SHl8sKPYWqK5s8-Ags%LXb zh-c#`gDD?|{vY<_8qEap6{IZJ%5~YzVG?t@i*MLcUgPw zwbpg5wf7w&e6UPrt4yvM;s!MKFy>LfC*x>{QSZRipNp)9#EN{2=XHW!W8|6X)PQny1KFvu|LKwfJCYsrMg1uTC~Jaz1n-%6s}aBN{@)6>LK zZG<*4fg*qf5xt)d)tNmuuNgQVepBt5&?ZR1)0=e?Yb>h#q@NitG2W|rGQR`A0S?*X z;$QleM_b9@%V!W8d8B4wotINyZx?%Lvq>hO6RNcuK;}=o!-8nOrec|4r?)7@#1`9l z#cDAq7S!?MDEphzt)F`%_iw^n6;~S$=sI)PC7^Ps%J)X&Js=i=BMlf9zSAILO~tu7 z;SKP!*XoOXHe6LWHUKsdbZUPgib5XcHk^4+;XfMNOz+Brg>JEnr4`zJnyUvvQP@BA z=$Dw*WhbDbza>&bq>JHs9z>qxUtb#awxnrO0t|75`MCjo&EVdU}fu~#JLG1dB*D-?#KyYC-ke*S)U zyF|C)@Dq8NK(gq!)qxH;Oe;7Y&aN{zXgAi88WMS#QbRVNf**scD59+;T~9vk`o;dV zld+3^p+^ehkaF;9>{YSQuz7AYLVDZGgS}IL zm0r#hJE^l^%*Uu9gTJN4yWK-iypbCAS1dKULw0kXbo}?vmM^0^{0$-{>$ZbEY6xL9 zII?g_MQ^$KTVIUzL0{kkgD-7b21sAI^YbJxMZGx>7!9{#FcjaP+i!!)yhK`lV@qm} z0;%p&Ft=L#SC(%>iDK-V7d1;ee4j={7A)|LTi+md(~;5Z{HstoEkXHq13~fEl9Nhx zTKw#xgZ)Cc*AYtDrkh>gcTgsx1$2S)r8!Tbv(Uc2R*=Vb?5&QrdCjv`jp%j)Rm3gG z1GvS%5lH6{n0wD_ygOT7heV0ng3b(&qQQ4po{LSCqwk@uP{5hH7n@ll&t=Nv(%(5s%E~M@n;}nq>et4Dv;Qt{k!ic+)f4hv z{Yam!|NK9-0O$m@B>k_Mjo-#fP{|WB_$so#A+Odr=H2`i%J?HTCMG63TLX&N)&@I# z=ehhm$5`!-e9{vI+HxrHtM?d^{rBhKl8CE?W5qH+uHTHx5{V=d2(AA*>Q#XUk9!{i zpbP#L8FPD*3WDlgMmb-THMjNU=WfOXErA3L0feup4v_DZpCK5lc>%wgsCJ(*Lkem< z#!~G7NX}4|lQgAr7GcKcSI%0X(gH$|0M6g?RAI=G@C;Sp7uucWXCr3JfVWMSTtGjP zOF4Vu{YeB0JsR>VvEB}VD`@QH9B}FdWCtgjo?t>|z%3wLR3L}oGtieON*ka7z%90} z2&w*O{Lv0M$`~USUe1xx zGgXi{=({?`(}2Dv>Qlgz>#vFl1Y0C>;)m0Tm+K1h{WL}qd@Vis5$C;fgg#^B%$^vK zWSkJp#6g@fVN4uIfjUzt@Y06= zz_kuJF);)F;iHfIg{Fpakx$$;P>v5Ac zNng_pz$`V8Ncs8sV>X9EGi^G7S-IfO6wJ5n*WI(HgGwFW_PDP%nC)13yc`w1>A|Rc zg=<0L)WLzqWd4We@`GfDARGOi_eUPn!2JUO6=iU)oRWevHE+JQAw5R1jTg`RJcvO0 z3442A?_M2JeH$>@yC3mX=hZ_8o))K;eNHj!Ic_d z>tZmNW!xAxnl=Y9@~YHV@E+F9x&rbRXTF)~BU*27FQ3&J9}0@6*nWcIQ3+`jY`p!T zcH@V-aq}=i+NvmUlvGsUAS*Q>E8B(G1r=^w04GaKu75MRy|Ey@wH{yif-06pV1*Hn zK&oKIcLs~)YGXsl)@Y~>q|4~TzqAEpq?=tR&l!RmipM}qFDJw_jco8A`GRbi2txYv zqZVwuA2>`OzJ-(yDwNlR2>S*P)mK~xhb6$ZAzF_gu=j)TGU*Bvc2&VmDbNp`_Mq+& z)%E@P09Qhf2j@TP>C`u7Eh>?#hO5d+#2_}40`5o%GB$rvd9rJ<+FfuJP%SfMmwCcX z8;jJ={bRAZH*}qben0g00?1XM%>L%B(or6AUQ$DyTv!693NmItt;$)R-OilG z8xZ2G_XKxI>}Bt6O85Elk|V(VINCCyVQGIHOY}q!F)HCgB^YZ^CEaZod+V#5H)~Y* zj5gtyfh#2%>*Ak-Xp_ANI!5e_a7kum4)c$VzN?}{;i`hW|5Un-s97@lSXde_(Jpm~ z{SIq3yd?lnalbVWbK77r`Via(Rs-abSR@|F#1eI?_C6RKOnxAl##HU6pJya0XwB}I2nhXyRTbc5roxI)hXrz`4R zLm{@mW}4)H;)mrCeN`6%Q}fp!T>#Mue_x!1a72wM!7tv1%aHb?U zxHH3~R39s&VO^0tFa4uL`XD!yulV@m!SW5kwXXTKVDUjP1b_}i&@~EROB^0QaLvIj zYs()t3U=riA}v~C;+oj{yy9MeX1{7)&mZVJ`WnZt*-=_w5_DB@sl~Kw>H*$=yo#8s zgxg_zqmKP+oA}Ay?V{yjw#HWmg0kT$FG5C_n=I>Bc_}rz|7>HDP##!Ta+l>V2em!( zvvY$RHnd&9(EBnKi6h+#*n&fDjUE_|?D#3DAOg7otVa?!8#Pq}vHtVYDhl{kiNeUA zX%&30#MjhKT>J{+PK;9X75e%HkjoBN62BadVtM!tj@%vyxw7H80Kj;K1MfjzbpRm8 z&`_yk=jOz@Thgs4feDC13pCf(VIfDiJGLq_{a)HTS4nN#+y$ z`0$dREG68F;TPL|^A9k3Wv34rJNUc2Wop77t9lr(+7UT z6ZAo}(5I)I`FA}fWh7gci1RCAN4)!)>j_H_E_E2fpktsLU>sGUI*97dMWGo+2|R5R zr;RP(#zlMTp3CSHl7o8qAk|(wwb2BsXG1Lnn2lO|%j#5@mv}@#l|XvVW_Eosf?~?$ z1;>)Fc_a^}T=>~EuzSzW6T=G!&+*{I7ivGMW7tXA!Y3x))-uORKohzHx=Im= z9+FAL{cKxFzyrmoLB@WSWPQg|!pYhP_mmIS^*OC@w*;dLl$E13FAQ8v`;F9s3!X$`X*pSqNvB&V(2VT?xp?# z6Ht|+Zv1L#kz{+7e{l&vg}4D@cWqt!V{V_CBbik&IBxffmHL%`Adj;Ln`r7TyMd{0 zjGV1((%#5N*VXC|5F0lorf;fWs=6JV$b#+{38J!;e|D-(`xc`DGn{Z1_(XB`?_ zt_3?TIwjX1+9WRjdt97v_D4J>Uu)XIA9s*EbwMXo%^{0dy_^@ugcQ@%~om*3+fx~6*C4rSt zIpaHIn`eJ&EIz(e{n@wesHR*VZqk|(zmG{T{Kt6=hXQZs_@NM-q!(n-cL#UHt@u;`SD|_HTFjL@ zAAtOa=`Zn7eUbWEa#yZ|@b=f;Ij^qdp?m*9O<6C0S=KxdWgI1;;#1A5RAVEXRA?cB z4HpE_-Z1^gXT#KT1iN7xS5^(a?o{{2E~-Mt2tSVm=5-8tZ0)+Dlc5u~B5}3e$JfU~ z^8F&smm$6Cj;0rQI{A(TH@Ed8*R<(y{^vc=sv&?#2Id1;m!4EfvXhNN2%e!-V)+)>?V+4w)3lT0zARZ;}k`9NMO$ama_u zq2@kEfa!H6F}<8(z(S$pAK;S5<^HRobI6c^gc=)yK|Db+;0ZoX@&xiHGKgYWs|hFu zrAdkbdZ&sw5fVbDo}nh7&D?|hI^>;d9Nc>*KPNLrWT~j{S%pKH}|eP zQ_06_?(i`mr~Cxx`CZ1Ne!M3RDud4}c0~IB^B8V$aHrKptTyp0vdum-EyjRlPdtGv^+0P->VxWZD)JS!I$aActO79{BL4_3vDlSC3XX`FK7o z%-)`LCLkqmLzoe9&Xx$3gXaw%wOD%1(PzD=JnDRGn~;3uuut#ITO55{WKBff!P%C` z*m=Qk3?J#;{2}0%nzD^c?gp>eu?aq~XRhb9b!!9uY1&UgE>WEKYt-RqkAoGfO+Tzq z&UkXUT>Zg|f%e7A%W_Mj9=1HC-_bk2f4N=3-t+gGmI;$jkPK6oSkv{R8yasPSB#!D zXT_mz#gmo_zjunoWhDOHHpk1qAAaJ5U%u1)r#~`He?5KRzzv6o^B>2$93;ixSu&jQ z;a7$pp*Zo?I?{RF_hrxKq&T$lJ8kxrnaw=++vnL!Zms>nN!q&cw_kr-_g1Yfq%tV* zU350nIel(yUfaoVh1dG`mv6XWi$1Yv-@S6Rtp`%HmwKJu|96OMbM%YD_Dv_1cALIW zX?$MXblxtY?pVlK6`{}e`(aCd-k-Q4x$vC&o#zUzb(!nhOaESyRNkPp3%>7m#mYY( z;qx97X1|^%>1O`=PUH1~g7D>S#p0|Vio4fsVeVWu^Wk#G)d@P!ZR$M&Km0;8e*Ba1 zCe=%72MGuE{ULc^m0a`5#Hl*N8pe2M@tdn9>P&>~>^0TLuke^>ODugwkGd4wmC_F# z_qa3L>B1`Tx%L$`9P66eSq11H`pa%6r={nu=}uuiOA%e9L>fER-E4W*Mw|0MCmpW0 zI`?6&F)*tYEe7Q6_epOz1%rhtJ^Xj5`jYpQ(VQwGgF8ytT?XupP z;h6&WdolZwzn-F9uN_R?fPCd_rn}IZC0wl~c)lY3fp>(@oe%f2kN&v%z{ld)b31JE zSJb>^Z}%y1w!0Wzb}MrAkJuG9y8L|{8->RCPWW@b8m=peO`5gm-RuKfjQ+8Ie!!eN zkjAp!rlnnUn<#7!Yna=;vQyn6V`esefr1eG5}V`uQ@7tHBkNi{gwu8&f-Gh0d{A-ZYfNzS5=es6L!^DCUIYeJyWdlj=Ym+IFWnXa(gB zHplOFXMIFi>vhp>?%e~+-p*eC-g5VaoK0(%_oyG~BIaH&VW~EU9h&tWvodBZEn1v$eHPvhwvF>OLUEbf3MY`r#Ovwfv7c1=sf_ zGqx=1$|mO?sCYtnb)l)&{m=4eH%Mi3Dmv!7njBYtVe@lg2c^61jI7*f&FIp(ThR;t z-*-BNX&eM0k zD@sT{VuO#4L1|J27Nw6u5qhmT8u&rm?C@n8MAgb7}W9HS}`Kj19M30d(& z*6M9@-alONZ@45$B{JoU&Z zhW%=e=LZXcD*E!^{*^PX&r&yj?SPc_WaDLfn}RO(jR@=6e%Qfy@F>B{5*dw+Oeu{! zf_W_Ei3JYcF`uZiVlj;pwq~eHtYBZA_?}eg*>~`bT8Ih17>`AmA7EqIKdiqhInNnz zNXs2eg5}I(1&P)@bwY=Ubp;vk=L*krs(VAisx1%PxV%d^tkHU!KHue#8S?zb=)>?x z^e*A~R{hBTyPw$gF#N&MY?iM8Z|lPf)UG8XL_+-421u-HafjiSq#m-EinTu8p%)zE zYwmi0_S7MF@jM`7gk5?9;qCL?Ji|OUwDdz2qPQc$SwR;EesmiWov$kKZW_PA4r-|} zyWi67Kv{Kf6Uo9U8J43C7Llcd#Fq})N1k=17LN|s;%l(AL|);iEQ4P3piSXoXl44U z@b&wg+4>&PAAHIBTY~@4iA0N5Ic?+J(Mm{$WqF`m{(Qc5ZhqcqJCd@k6Fbs`eAqYn z`kgAg2!8u?Kss$E#@Lp7@0*vqq#w#-P#2OJm7K23Xj17G?R{X`vogVZIVwI7xk`L(Nd2<=hm?juhfQTm7+bj(%jfJfsaf!;+&a7 zsRxEW52=-t8Q#BBm$d4yEAo&q*W>&uPa9*N9l1mgNK;0h^_fR4dNR);01}l!Ff!HW zcj`Ouqfspfe*?NV)lDSt>_)H*k#mOYo~kW9x^Y@7b)p?1puf5weeCN)zFZM|%#&)c zMEx@jviqxVhg2uxGFy)$FPc3St;>ej^@dcdaj(Z(a?gLcB7rfZv}~lz$H~{gErvV# z#vuf~OW{+brU|qiriKK~oHxIN@psrZ^9v5(kI`O3IfZ#Gi%m_2?SgbiZq%G&p(ep5N;gj> zBn7at7U9*7CgYbi&q8+{x3Wo!SYqduLPVQx3F5F96Z0v|bSsnsOf@tsj&inr*ZZ{L zwb30Hvi@9if$7Pi5^t8CAj;mv?^ah6q};7-ggg64fcNDkmHYG8vPcWH5RYGpl-W@ zrJ#yE-b!Z`2k*h63ff!wmr+sFJ)i97u-F6NpIK3}C@yq4&*r$$o*r-?=qThN)>yEkvB1lCjXsRt+dL?b?x2?I(yQE>zvF>a$a&(I$1Ke_TuZD8KdEsAzH z*Naw|zBq&Xj3Z>lIT%@7X?yFOO0huj@L#&y$E#>-kEGKvZsG=CC;awCp>KJ8UY=(x zf)44Ncec;Q&hACy4Fm?_IYvsd_q?q8dia)tNG{|xhwBjTzcLLLjT^zCF!v1aQ@(S@ z%?dQC@|F!X?}}n;lJ)O3Gxl0byQ^d948=aHa)m|OTeR>>J5iXOY#vNBHcDXK_3#;9 z%VAMoJC`#jjx4l8$JLC~aGqAJ9k4n4$gP4iaTN3JBp#&aIWr|%tUfX$lF{nnw`S>8;G{-srtH_`q)(Da zR9jlAt>g+Qj@15_(E(@4+k<3rlX%`_e$koza>IOfUjw8@Q@*KnE3d){Rbpw+_76r} zLWX6eJHx2k^40UBWely(_+acVF-E1?Z`yDzxE1eJRIp`_fw6PbM-=VN6BT;XG1Sxh_rrNz4e)lTb0CDgwqIF@e zXscyA-bi)yAGj%>+2?kluQA<^!SW=y@6^+41>UV~WV3Nh{l}bTA6R;o`B&jkAp4Do z?bBeCQCSa%9qcDdO=pL1EBAywCnPD@+AV+WK$N&|+j%Jc%1pgAARvfhaF0L={usm( zAl{oE-)Y)mOikXJ((k3STWjL{JZYSQv`V($=d(7CBCxe&7EOmvf=fB6qCIcg)`SEV zkbHW&7on)d)bKy7(oY>0x~cN)?k40LF`3yB_*)CKw|E|BglfI4k7^0_%MqMHX_WY# zaEx1(s`6b^2zno4MhW)1VDdAZae?|$TXMHmjnui+JkM1%<+{(3vP{v(zr{+nPHmya z4@I4VjCY-S1I)IDsD-G_Dz16iG;{2TR!?SU4)%HcoSUL`JHB;OPxA>$xE>Yw!_UmV z5Slp^J?QJ?ZB1O$z{~VTl&5$BkARQ8iYsrDC9Lxj$DnKivBygDe4iQPtgB8qE0CX|@+ zn%+mDmKWa_#f_p)h`6^@N1eF`a)la9Xk&iIVb|Lt^*eQpU4-Yj`(LyE8hJ}P#FVyZ zU&C3kKtwEZq^jF8=5%V48n3;j!8)Q`FrU#(iqC1*=-$3+i|@x7+NQ|nh;4MeQSQ}*wnAc)E}YVw>q_Tx|Pd(19BLcT9=1r1BY7aXZ@sGUCj+NgO_ROjz@h5^W~XzZsNA8! zb9SfDVh7)7RmRVm-nZ@x+TCX8`&u4afV*(fWx3)UcW0Vme&_mZE~P`k6REkp9t!UJ zhH{09*44n>Il!MShzLe&RjYLt_ge~=O?cLYEsE|(iiKzWW3*G#ZM}-%n?kYLFs&|b zb`<^==_<}(&ddItW{%O%l#!a&>e!4ty=uT--K_B;C8^bPmaJ^^^eBZcDdPI zy}7D^)B(BYgnEaO;nr4uk*kvUb%=aDEVxf@X4I3!Z>B*l04dDZ(6nt^AXZLZK;bvo@}(BpIx1WQ`DM+Zm3$Cg>w<&@s6ufSbdb((_4mylrG zr2=a+ju*cMZIScT#*yDtj6RMC!M1Ak|2MV+xN=1KtWW-@NX+~^fC&N8nF?0N@jnP- zJJ6GmkWuV+<6o$gwE9HbIq8_#LO86;R{IE?^O&@9(xZ-JdH_`NG;lt-O~5xJfN$YY zIVfR~vwA0pyN*mpL6cK%Z$PWSWxb9OnQAylMVaTnfx~6hl^l={7u^kqKqgC%4*l+1 za>p$Y4~0_DBsb#H-0HJC?%n9FGMd zQr|etwj@a;GJz_dcJqam62j7gd+$@nPc@6E^-~=G{Bjwcs>odm@b|)wi!t|V zJgdfHDB*cKuG_XPlp-D#tiq7w8dS$#~#~CBSk5Hj_oB2bg+3ou`&IyF7o;y5@GaA>1;Gv^O(t zhiVn+`LvPFj{XbU^uSapAtr-d%@3jSaDr#pKQcuJ%uIx6oDcxj&X z>o*m&zEsa$deq<<6an&D`95)t0f=X>R|wD31L}rC?znYKE$`Sb*LwJ#jmheBoTc`f zvJQ6`YAoyWQNP7DdVc)JU}_6>5~!M~c?DNzQjaEt}-M zR$o4(NA~A^tj%Y4VMTrBeZ)R0$G!b{o|S5iLx}w6(*y=ujak}IUWKz}?czIE&N9*A zR5vR|exU}SMLS0MuKZ^6KT?6A$VW9=m)~ALKEzDT;Cq|LR&8ctb2glLDPm9e*ro>P zYm&*E5a$<`bX=McqcdseCWHx5!jtCerTVvF#E(ZIvQ2J1CP5Y$>9=h1bu);G`jRpk zUvfE1Ghw~|yF)A$n|reBo{bUXCBB}|(StQca85hF6OV<({XWJ6{daQ$Y4rjX^yN80 z?xU~fAV+2I=Ya1+1ek{3BN0SZfX%=4T)DAkh#Lhyb1-AZ$Y@C#tbusA#kLXXwoD`y zXO|ouMvZn!sWuNy{`tM3Rvz5qSfh%_VXPGfO#R31-L!1l_pJB`dP}8G6?{6 zatigS8qnBDK%RHk+wNzs+azBGHpe7`+OfJnP`!>c#mW6|-QhWBwDfZ#u>ixCwHQNe zyHI3=7;X94Eqn~@S#XsWH%=3-oZD{QfjXQyMd>508pb3Dtgw>ezx}!tDi81}1RVk1 zbMxr7(N;C>8h&oyRypaIm8nU(vN*;U)lVClN&>hnNGz-Z-bd|l67$@!P%929a zh?J{i<7;owBsKoqYY@4rhg_4s)Kob5KlDP1iFJ-Dd$UyypVM`6Vqh^&vGMEo2q<-= zuNS#v=p>>uSEKH8`lOZtBV}ZCZLl;F*8}usJOPrUS+~aQ2~Hl6^@ad=Kdz{gvOMbt zxQcOu0<7_5z-Lunvh$8m7g9jL3}~7Fqdu7*k&C9ECMRs=fy&n%K8!i`ag3{PznV+n zqQ=czbW{Jmdkv-9+^_Zd0Z5fBJ(sW8s&19h>M6TC##r8QR4HKR|TA z$aigQZNvCR17_Xmz;qF~XNcC72$%;uA-)^K_LH(8JrftT*bAVjEL4gx-)JV^H6B6u zs~^G;*K`-vHWqjv4re*ljyL*^Tyyh8ap8ft-j`mT(Y*iTZmBuaIyR;!wK*Lk^`ox5 z(yf*6TW9BbH|qm5N|bOyu1={iI@<+CCUEV|dsJT*-k0IFgs97~ z^Dkzsbr=&tV7hluz;x5$6vH#5)zjAw0n#@5`6xZ0R)aiJ)EwO>U&9rx`d`jJS0eg2 z5FuxkL@Ie4l)AJMzT5QY8|mw=0G^-EOMZJp)Wu1~AEa#5=JzC^qDleT$Yk{&Ed|_< zXm2ndE*40w|82cbM-mE}$1zJSwLLb1UkrBT|cf^42& zA>Z#1w(R~7TE4|x`~B)yJ`r&F|7J47t&z+Sm=W%Qf3;i7Nl}E4X4|_0YJ?@UN@gEd>cm9h-b*knW+FZ@=bn1S=D?31g z+VRSBI!UFF8X|OKF>cQ)pXIwJb}Y4MiCQSo#ZXO}{%zXE8L*CE73WLXf3^~9_elX3 ztPz!9s!VC@F7Is7lImlMO4mr^tiRau-z+@i96jLpspciWQkkDb=NK2}@+z`Xv&$+- z-`)MK97aH_?;48ri9-)T0%Qcx@IoL3O)?F3_Y@+{z+-!RR1&O#lc<~YALRNF6Zg!8 z7Z$*Ooz87lBoTBIn;L5R{w5)Fv{P~GR0p%MR8r@En095un-k{Ds7_Ccm9OFb2I?AD zKG14wjGGNRea*F4gkyn!dQ^*|(Oofcej9-XVEH6D(52WyAYf(HXSZZNaN~tA8=adTDitM25oF&$r6!>9q^z zNGa&-dgI$b>9>-JpCBVh1YU?v{&-@c20As*La=lnSuc37*% zC37$k<4M!QJEoeqXOwOm4aa-hI{CUK9$I|D*LRqJ%Y@b~P8sR`*Q(-|AKR#c;}c%h zmfM`~_|U+n^&n&@r%8)p&Aa2VO1{^D+e2M-Lf%ec#C03^ZK)o&glFqD^ox1zFl=dx zCh7UA^1?SgQ%PrNp@Ch_oL@j*dM^-jb#$^v3ocmG44wl9#z59Rb!eJeAURxu0-=jl z=1*+P^0#Y_+dcQ#Ci|04u}7u^A_w4dWfaM+tK2EsOQXMxebTT~*{)U)2Tf$-|64Df zgAxYI+r|?HV}==c(y!YG(&kAdEO!Du_gAuqpWlD{;k2AVM9jDrgB%0{I8`W&oJS9c z)mNj?jz}I@`m}j4$EzS1d@{u=8{K95^JZ%2Q3IlA(IjyaC(w(}AE8t33lxd) zK(r_iJFmq1mbPSy-k)}2TIR+GT04B+pFnP{8cRw0tIUpg`t49IG%L<`*7Nmxz0|3& z++J?=O{=EIZ>@#&fU|a%zbTmPW=VFGO(d)%M?rc-3Nq*{%%Eg> zUq+3xtMp6(S9Iwf|Mgv-R-XzT1tLJxL;5dZt61gWS(^( z?g=KXXT{xFqiy(2+NoAh z5=3+h6nPMakFgV-lk?TPl3+VSS?;wUBe59d0NJBy z=jMGU#AlT7Dq7bB(lvzTfef=@J5`IhJVW&@9ja-b@U&`1Og{Ts3PKN^bk>39B>f8! ziizhLve0lw=)W|_WC#DOt>U}iv~-D65{%B6FDzQZYXI48kCl`^Pa-@_U9DGe%Z*o7 zv3L(bM=t!>tA{X|KYb@Ebmx;i{aMoa90~QZ!d{Rprs*6iydt=z;M>5v<_5wU+N%~t z<1^ojLj$al`o6-ee`5BYPknn4iLTbuF~^v~A~W+VO~1dA=_Q0u)PO{!A8(vhXU*Bq zk&->n=brqt^r7LXFg`<+QI$xr_~APc>hx92PLJ-w^xzx$f>y3Dz$a>bhNFNP_25@L zrE^Vlh*>T%(=YlTu1JwrS(sBj?>~AsNH=0km}Kp_cSLcqKRP;9*dhuHq7f;S=cU}D z>#BKV^DP}F9;$$dCmqQlW`>&z&mY_0>DwM4Q)zeyS<{_bgqpKjN|n5_ph6`A6yx#g zNbZ}hXgXmgP^7mY(~Vs(sY65#wcxV}pB^#*#0=g5{KiJ)=s6v!v#&JZYLpM+f;WSKdNW5ab#K-*d zF5qhy5@e++8TtgzkE?4FpEtTae;-@!PC4b_RrB%|!J;mP&%=e}ISYuH2;6?X9Vn<{Lr@>|n}$crn@okDY#af2ER$Fx z9Z<-+uwe9TDAZS&k}8a>=wB)CAJ}8}yn$Nr03w5+Qw-3G;6pCnqObO;HPl39KdoCB z9_x1GjYF=GY0XtKcnzT(jnVU!=EP%2rNw06+*RlSYaEwG2zcv%b721NFg}(__+B&8 z11*oIA0Zsq-X=lk4w+_YA_%o=orV3nKGUTAjG(hF1FX1yv!ZtM#_jCd#x|_s!>CV_ zZIw|spc&ALwQ3;n!XX>D9HH)KLd*l##2(FK=wm}ceHbM}OKGSFB)&cuIJq4jZJCn` zg;rjY8c>IXCdtV<`OnReIZ#(e3*R7m@U{>htil7gTO|Ph2l8Fe><~P|Ngw`sBn(t; zjl@=~fs|7}NUGBl2^XPqI=M=z5P@e_p#mTZ_&oXQHY-m0bYOIUE1&fd@c7m=$#0zY z-XVh!lNAlB?ysk5!?fSaT`isEFQ^UQLNkvbsdAuh=aY##=cWma9x#b=A;1{(obUZY z1j@&466Jsqnule9pJ4Gc3CXA25ejiE4*;aIt>*$p9;*IouXR!n$AfA*j0;d%`79yE zL3?VUr;DOZmoP#4S8dk;F^zoUc22Q9ciW&i?;Gg=_@{rOMe#jE7t(6gZ6U4FCjfG& z>?!TuS`P@+3qgiolnj#>fy#G~b&q_p$MfQe8gY;{`2RACgQ_eDGJs`r%c6bz zaUj<4$|d`|O91Zy*wrAN+vD^@Kh6(A(%n!D><`sULI(FsUdfk+Tbt^x;va+q6dMG@ z^`^ZHOyB4?FUx7ByVGeV+D(XNil*V}=Vbj`Q@)IVTZzp?5ZWy09u zEGP?dD$MN(md<#?%dG1u?r~77GRbqRcN<kB2`|+Gyf*Jr2%!qhA%9S+UA!=yZH z+XY{U&QgiO9$E%U({`a*LtR7JAw6mL;bY69$!FKfsG)i?!iLS=YI$V z5mS`_tRrYgo}j2hNShVM@(81q;~9tkqTCp4`S{zGI@spL{%@h(3KT%nWP+I)eO#}* znd_fVUb}gWrV3^Q-XF>)h!l;KriLyb2kW*Oet$EZWQJ38#9Li!=Vp)hpLJO}xPH;I z@y$9m8IV#qTKbd*$RC`a@T3qW%tzaR42}v>pMV0Q0gD8A#%XJ9hMbX@<5uQ9G7^$% zQyD8M{2*)}A9#D)Q(D2a^-LtpIC{ysOx^4XW^Wep+)Wo;ZGe~xP8xw-u#J8L| z$aZ|gaQ?T4`K}o2E@)7ykxKZC`O!FPsh%0!6UxjwZ_(4Vo6hU~cT*JO?-!h)mX3aa zdaQeg!}7?~s02ixpZx&o9j8#-g+&-+p(h|S%&GPh@Yu8mpQP;iUm8(FtHhRK1^ ze(9=p^791wIho-GUOP<8yH5&A+4b2^4NBh$L9(NK_|%|7hD=`~v8Wv z)dW%4#a3M2I4Y^nT6g+{4!Ks(ueS+x$!^;g;>TH^KUU1U+quxP<92qA&=T%D{*JK~ zHwnh)JLq;>*V2A5UgH!g`e8G#BB6oAY421O_R8L$9_t3ExTRBCxths@D^{jT!#bHepQm@CQLY&4&51TREz=7s0= znk!qD;Gj6_Z2^i^``BK z1RWII6Co3?euEhOkj<8nM@_ZE@r+88)PFROgT6aw7y-TxpDql=GMrXjDDDB@S4{;T zGV7iXJwPOCxJnP`Q$naMnx=|2$1xBLWxPL5NXkAU^x;}kW850%_0#rf2=s++@xe&r z+QjW)oqOV(g;=rB2wTKK)1Maplanh=_Z$pkQH3TX^H`EM085&rRqH#fkj+~eI4Or56+!}>cZvHg(1$sUI-2d-j&2G@2Gl!j&B@H40rjxQP<&}nWPMIJSi_y@ zU=vx9=i<+MqFcY@ifOlXm5??(ZHuSWX23vbdww1OZKpq-XW-0t;yNlRiaB}cvc@HZ z+*ovj9s$s?Y5|*?6?tJX$6t_5hN8!YS{01Tp1!lTKPPIq$lFGj_^H{B zmOK!a0L=}n%Idbx-9mD>#H)A*t-M;URF|F3fFS>^85Ra7lmx<*zvU#`f zgMgELW_WC)tr0%Ve{nLi}8aJnTWwI6;QyHH$F|q1oP%L!>mKD(B;z(B$kj%>m%)yJb)2K&V4E$*26LU zT;GJKnbd4Yx#(w*{@?sEuUYZJpZa-cwo~_9Tb@7L7hh>rb7K{@t5x-4wn7sd-3^Wj z4JO0tNLFKR`}=MgKqm0HxzepIu3bgE-s%t<2}cg>3kZgblKdDko)q0{Ydwd`MEoWb zM0#PEK27Ql<|nlFY@-N|yytFhRwVb+g2p0{??xC|AZe&pS+)5dm}T7dFyr(qpH2^E z_3>QPclM{(y5{@@cw}lZfHslkAWHNMmu+?N8!rk#5oJ>6#a%IL;}TjF<;iwHiza1; zcdf$1;NTLj)Ce|B!8ohv1a#qdf8}vceXq}dhpRv(N74f?+tz)q4pHNUDECpjv*(pF z*7FiVR$=q9{mb#2sH-X0hbg{nUdiDXo|t0yTOuknZ%jLyY}sDW-tz87ea4^%z;B&vhFw(H5XPn)+;;xTHv?^qPll2*R7wOIJYtv(k_JHlYaPCARE3j`Uc?aQw7ieB3bo zf)AxFTyWv?F>~MJT|$S|n}cF8Fl`l46E|ODOANCLU(c%Vbs3d?4Oc~ z-+E{Y&T?&z=e`_}%=m*OQ|V|aP0rh3p;_`eq*&3<*o%m3KeK%jchLi&`n&#JAV9#a zqxc}+1)yRPRN?9aB$#q4ENDdD;R4*Rb2Ip>C^K`t#pz^E`st!l?&;mRHeH>h?vj(d zld+}jhjc1+e{qp^i;uq@_IZQo+!j))_?*_0TB4T#X(DB|8~6D&fYYcS^)&jp%0f^I z6^I>SIWLyh8b5pk>Qo%Id)lYN%7W`G)*psu8Pt`f7M_{)u{GT)A?qUb>IxqfrJNp^ z)(V=rf3&h^jm*O%w@bxu;EI@%4fAXUH)w_c(+>AXgJO13#2q{B!S`Onq@&ga{k}S% zw0u#BD~$vd5_G4K7Ypb0iXv|eH`KkYs7W~w0$1dQpcmG zA<$@)`TC9%!T*+Pwtz47d?)MymuFSH_<*ANTzeZs>TK~S7X2{e!}8_yfFh-Ok~^8y zy$H9lpoD}hxfq>BSjljt1?R6}D7R+qM7Ex1%ij=h#SuS^vckZNXNry?7u1%dE38L# z6ul^0Obe!4&TOziD*4Eg6az!Rp*fp$CnkS5PY7p}wwOQFBEmCJTrh20Mr)owZ>t3~ z^okmgtnhsGxYI-x+ytM&!zOYp>w_THuL%l<;oSlF>4Yf z&JGH}R`Go5a~j{QsHiYgHcK0kLKK|)#Y&)IAD%Jzp1@sAjUux%?ru5f?1~sf0Wx96 z6IXDSE={F&pQ{BsFvh{%VpTZ1b&dSUP1xM88|Ly8?Dm`EZQ(d7;nO2eG`GelY7cco zZnk6FX_5((-o~#-nCbS?OI^CM-rIXMH6Poa4DL>CNXRB!-;kup)cYhU0!+<}8BNJB zi@!zt_KV}*8L48Lxle1aO#M0efhWb=!OQ<-vZmveEAAgORmD&%&&`l8e%C|1w=n=) z`>tOyv{HL`vucMWLatG;%0k-q)QJ1UXXe{C^JdL>c}))X{}-_y|ErpL88|X1o#WYmY|tTGCP^jAC|jlK0u5tq zcsQwxEfZUc%%CSwCEDcu3#hyI{J6yoqA1FHok*Ka`sFcH$VLR*0Q1!?@1mdaMQjWz zwuLzm)_@SxRiEcyMY!>3-6VWs{;Dw=1fn@cz%>xWq6)YRZ zVLwL>xl?XA)J{@iSv(W(W%HXjKdTZC`HH)Uox(RKzhP5Ii$M6-#!VDR$jRWKlW??Vry4`b>F`Bfd zmh9e>FDu6a=$X(G;VuI+%j-9jrQ-|oVQYU5gOb-J6n!1f8Wq8>Jejfi)fQp$*fP-5W-G2?#m0>WR+n{ zFg@ERY_1ym>s>2f^pJ4`L4YA}+#o!th}AgQj6{|QkTPEj1l1aonbVVag259kGI4D_ zg%cDE&}b1j(zNLZB*W;=8eWXnP85-w&Z$uFlVo$cz(L&PH6{oI`2vKNBZZ**AGpcY z%mr(I0we}Ks;VP@UrUi4bK7}FHAE%ZaHF;3WTKDt2w}iy5gDBQny>Fi=dSEde^N;< zTr??cs5gBsR3oJ;EE$znS!wG?C1@T;itvr7*OrdtwxKKc=?!uH=hr0?jyC!|Ert_M z6N)(yZ_=Sj@?K9*gVDtbRTQ+2-2uRKh#n1H@PmtAWnUQM8Uejf0Zt!mb@a164d#w^ zT;q#;+rgPv6eDPtrVm+duDug-LwLy?3KSNhVP z4Y_Ac>KQ~)#VQ`I4d4X6)ONHT!>*fVIbMqAO;1caB^1{yYY z3)Hd!oZt}~#~P;Lt%zs6#hA#*Xu?B zBp@l853s}eK5Y_dC1g2+XhwHlRJ0CQpNb;AqX#7P$s2XEA54dFF3q$Lz6j{6;9xx8(Z|6X+Yjc@GhK?4 zB#rmy8oYJdHe4TBF<_71QGG(VM?JojXDGe5S9bZ;!^PV+M?3YT#v^KVCucWF(a^45 z!Wmn;jZrje=M1J(GytTgdRbPsuZJl0;vk&%XfLc;F-mILFg6TEnj8?$QBVQj6H8Tb z#uH^CUx2#@5^mst>c0x(@y!x+I79~}8RU_!2D0b9h4wqs23c_ zcB)SQhX6K$)jwLs_q!#gYH$R97gv`&wj{NHWju#Yy9vpee!Q@GwSPw6b}L(I_!2ux z5%Zw&3|<9in@gExhsZ%FTtLoQoy|e3_;KsbZi&9*cT$)Hn_Wmqa_R@TV|lA$!o4K( zb`8RcaSON)GbE(pkfmq@*5a?01n8^fTH4`7J+E%f$sOJV3OE^RKUA)`VG^sKjAL#Z zU4%Qb(pEJY7E?Ep9b=&62bHYO{s)4!v+_$1YOui;OPr&MF%m<|~$s4b!)!?nxGB&AOaT!>M7KA}8H@HU&>XH=uGhOav=*T;3#98ZK}EyCiMTgi&H&VV!A3>LCF?FAtz{lw7zFw;tNzc{}; zJ&fV8WdwZ6{~Q63q|G4im9k$@wih4EXG>TWZ(I0Q=EZQVDf@hCr@Ni)RRPo3!Caf2 zuGYdacS31MSU!9VO?3|wFZu}ViP@J)rbL>^C-EV)+hJ@_lncdgU`V|C)LWF6Q4s1E zZA61@MfcadYqlngRbHj7rFbK1zPLM_RhjO&R9TuWHAo{u@U)yu+3?_LHO0h%rYQuR zR)*}e;e&3^|A)Hw4r{V&`bAM6MFFuPMNt$~5Rf8Ox*#YhMWjfL2nf;3f?n?4|ojNkryY4cYDlh9N{qLe+ zipc*R(7?Y7Z9&R5;rvMMI#-NsLozysmX6{Sp%Y=X4#G%=U>7Q90qcJ?G!xUzh^FC{*_O1q2>2yD(S95x}nu>Npqz0)MmP=sD>UQ)V(P01O6L+ zV(ZIyYS8%L0G~6UAKGSxE;>vt`9*+mI0<~2!bV> zH@7QTo_sGw3m3Y%Pp&2PYz&s8JjIL;nY(T||9kO-ti!755By_+gu(A#dO-1X6Y0 zbNeBZNQ_e6Ain#;SNlK-_5I@=ebXV-oEVWHPs;Q>|Mo8qq3)zA7(#7t^>UUrC4D6jp)Aal2Lew~rt2bM11?s%qXF@U! zHb}l6zjx6YflVn28+Jul2)pTZ5(D5R zWn{olmQZLV`1{PmrwdIlT0N;p5Qvh8iwl)k1qFpUse2eP{WlSxum1)Ie}(q{D|lwW z8sdB;5z;z9>0nfOW1C-Wp|dNBy%x|F_YRO!q;;t1j%OqB?&MufJ zX&)0siOKI?Qn5hYEG#R37I#i2Kwb~J=5hsLH8s?;rUpj3*8q5rouguO-D@si3o1yR z6VvlHvAIX@Y(@eSl|?S@SM_Pl{jiRRL2s`W<7E4FecC5GHo?}T23N-S6gvzMr_#gw zeDIjeeqBseE(e3BX};9J{Pl`vC+F#cQRxMnEN;zY1|Nw}Pn24}hRrzk_C~iP5Ego7 z{T{ar`LvyQev>+io)x09Nuj+xzb&TV1F5X2LSSc5J_H9f<+ndpd>K4!4$(%`TaO3d zCWs!B3%p<3JuZ|MSxz2!*>Pv(st0+k^oft-Exj5qzmU|w@Y?jHxyc8l#k!#-_xT=m z(mptLjB;YnFCY=Z=!R-`xl@6cyLDP_b^~`N@8&!3uj}bO0o2`ZX<6)X=`#m} zXzymB5#>V8>hSsbBu`x*(@&iUeewy@sFGu_#cM{a2H4;e5wqE$RDm`_s7cs(Tlx$v zk0cyRwd452;Mvt}n=t(t)9;d9-pE3rEpALS3zO|HnV;xVA@ukawrrOM%U_;cn8Q_3 zXHLjO6Zt_`to*^IM|?phcE>$ecat7emFrK4?{$|wX-xZQGV;k|kkV3i%t0@9%6|M} zd7RZO`MN+?3ClNY$}EcZo)ME5%+!iLo=pmfxMjgQiWX2TaMVKb_C)hZfT0hImF*@pC?G% zI?@S8zuZoFas2E@k4TOeyFD=50F~;z?DiSzJ?gQNk}x-r?-W$G{d-pL{hC!NILAiE z33*iwSz3Z(H-C`c8R9rtRDjW#H}GA1cdf2}YUC4zw%7sZDN7nTp!rgaC!lsP{9`N! zdyABq$K-aIS6j39n(ZuO_(tY7u9(6o@(U^5?!i6SCiKkgeBjzFUcLzj_F>BiOOKLk ztXiMBHH8T{Z22vw$T{++#$2?g9(}_#S9KiKICou4|5+K__$%W}zU#=HHN;QqtVZ-v ze7XPt{tDymjOCuDXHNL~gDB&RY;EoS8P0qg34`%yIax20PYc#866oA(# zV(68M>>&B?dHWPP<9U=t@32G_pA*kKB#Oy5 zk|bvO^Lr_OZR2_fz#z;cDWJ&2PMP|y$h~ZyIW=pn%h<#9y&pw{$7fT6T%`gyW-+Ms z7QC^TqfMU|+kCEVZPD}*f|1(nT*y^|k>%I!9BhFLBgBI!AW0T-Eyj9d7@BG^qYR z3!ML-Sr6@oA5F6L+@AmRXl?3Y*T0X}7QS@pUydpNb1TBX9#by)KXOdDuDT;$hyhNj zm@+d5mnzB8uaB^5x?N4-9J_c|tNpACGvlSav8qZ6@}PEdlxFvV~ced_orOegXOC z@8!imT5g@WSGO?y?U7QJlW*T;_UE|x&F?bU53Tmty3?EmN`ZOm6OT>@*Y%vpG&|xc z^d-ZQUA!bjbTKNWp7vD!y=!f~_f%GQJ&r6MdD+?+5goMraC`dF{-NjSq3e8v&{Kz; z9paA)KVLIHqnxe&ed*hygS-)vhM#sh-%HeC({fSTQM)DLr#O+g9wnf`5G0|}|20Q} zmMh(?$KZf_?-D9XIk2K5YCN6CLA$@liBMmXo%JcdM2MHS{Ph8*Jy&F%QZMn(9%b%G z>7@^Uhc=JQ=hPJK)j7VywePAy0aNe*kI2M6Gv}3q%q=bUvTt66)Lc8(=lI-6H84Np zSY5fwxVB(|d}q8i=!Z0&5K@Nd6|J+33d=6`Db<`pb|R_tt=Y|De-Qd!Sec)V{^{F7Vk+V^$)^0s6ZzP^fs^T7r|YS(!wMHkeqZwaF?@oR-69f!WTgo#_7jul~K zX8m?_Ep-0&yq(zC^4Hj0asA=*8avN3c1l~fm>IVR#w;&&hDvd~^xzx(V70mscPQ?% z+N)Z_;&(Tt;?ruz&*E0@;PX%!MmJQF<$mt`q58A@@-K7k`XWzh?U|twvQ& zEY_|;^){jUG4gEI{=@Rass$Mw~H%Isj3;&PE zhK{=JsL;WR8IXlsS6&NrhkM z@Z)Er(R_C2#!J~3gzaDlj3?$}&$m>Gh}X1Y8a5OGxsSs>`y>;?FNGX__vsurX(~yx zE#b5ndG%An+7Inf@6k4^Tjsrqn&ynz8qH6Kl8tjZX_C`U6tudqT58QQo3!1eaesdP z_Q}WG1}pU2N~H-7FF*fPf2SMk9$NEr9{1h6Ni>&UeQG&sZisYM#kM{f|d}#@ayE7tQ_pVWwC!)c{m9L{viPKUAvlzuf%r|LVR1F$wYi>b?TuU$;m6f4#53-rBO) zi^sZG2cyH0CpVw>Tv@s}ozeMV^|woB7KF@hCZXL5@K$4?xF`+Gwx zBgjRLXeKNAxd!PoaEC7&HAms$O{yP9lb!}n1&xX_*flhv&%n~5VLb}A4~-Bn*hDmU zbf~!wpR=hB!GFI%jM;QZE2Vcx7P&$Q_Bn|o>ui(~Cf2FOvzC!no}dGAb1oQFiK5oq z`7LfHq%L3n=-c2dM=ZHf0>w%`M!u0}>Ay{FFgvTTi>09^L`%zU4)?)DVwOTeZ$lmg z4UNr|9ib-6w13uzPeAYG%BQ5*`h7Rw=7F|z&654vx7aJ**R8;KQ(!Y5%5%Z}*;uK{g6le!5L&cW zIf9jI8-y&y^GmDEJ&4WP167DB^zh7k?pb+P=TxBOLv3kS~M0`V?o^bJELhB+R*tkIoK|C0)+iuJ!HR{;RsSTSfcyKzp!Zp-i*JEL(YUlcj zZ12a6c-m)RaLc-0C$=riQmvC-A<2oWM0RSXK->7 z5)zj#U6Pj{vMK84gVv80;&8aqQYpBe+4R8MuRen-$(pF;=$}JQo}TONS2^}8U+LNM zCyxL4ajN{s#>N95A8AtCy+XEUkpTe#aJO(x{Xili` zl#t!{@x-xwsdgLdm3>NXtGCs|q`t&s&TxS*{P}aZpZsNPtdhv<*RNl`d?_w29(D0A z8XBGwp=1OCflf$BNKQ62F!)(+b5MnlRDA7hNE@T8ff;lv^6E*9@21OgpoByJQyh75 zQHY5pwR*2T{kRH`6kPv`r`H9N?RNI{Wv`v4r>757;R?mmsuwV(6Em1gyb05UnVzc` zKjDyDYflcyNnX0dW)rkJbaXmii}r$mK;RyUgk~)|dq>Bhp}QMvpd_q5!NtTMKQgKO zG<$av`y98?k|fO{XgXWAcTPz0!(!(x%_J#V-w3#V7QWlu+|hRaz-rm5Uj)rEBDu$J*fm25{CBAuLdit$$Hi-EgmibBAx4}WvoGvxy z)cAyi!oASnBKJ=VF}UNL8En+`3W!MuV32m zOY+w*I{0%ZOAa=&wk7nuHZs7Tdk7Y7Fi z8yg!-%bFw+F$?PRz!&^`ib_hpTZ>kH?zpRUhDw#s$bD5cW6{%E#{P%77ACZenNuOL zEJ8@{2J;iTs+zE{{hl}{#IG+KD)1(i@14B8OMC4M8J-POho2HC#qxxX5CG$%rFKgv zp(dsN*O+*#?rJeTqjpfO5q>37e?4oxtM%gMB&QB=4z->7*qW5=z|qms+}vD?LvP2X zjU@)X*Rs50kp$f-M@dHq&vp|(+xy*_&s6K%Gs4>jxeZ)rwthBH0B5P zmjKK2D~d@=C-5uAc&5|PG*;i$YU`PwcPQA~Rb5@(-*3FpN2U9d+YEFaaLK)aiAfR6 ziULc>LmZ~y8iAST+@$q!&r##(0zq$QhtxJ-fT^!8lJH zXMXay^aFI5N`{>p)DAP$-PQVhib_ar=yXIfwNWe-V4!yEVNJ?I=lAe^XBhmlqxPM* z>8_T-b85-1JHk9E*4`|s7gy+M=vv_MQV~lkT?4Oyzm2(h6%^NEhgQ_6{{#8qua{RZ zJdKDQ9W@WRyd%ch$>}{7oBZxdyPY`9Mboie4;lRBB;3A)sldD|oCSSMl@tw)b0J!w zuEz#=XtLwmDg*=tg9i~@aPc*dXx_jIX{EK!b>q4%f*9o2vK6}{MO?9G zrLR~saHw)?Y&(ZWr*ZGf3WadMi*k{sGmyA5+zDw`+(u^ip5d{*J zq<2`FQzB1@`5E|9^3u38g7S#C^OO%)Q!AK97e%rubSJteyN7K2a2CyV?jL20}ot+W(6G(;MZXiS}b=sBXcY2x6sPrus=f2p=g3zY$~& z{9pWkZT53?@Q!3s?xdg3oS-S#fwai4+vJoh2bUeq;$v8{Dunm$l?o|rb*9Xm9?b-`-uG8cQ~J>0-;44y5nA0Is`zPz{I zd>o83o^yoVRjl^N_A(q8)p&H5AGwvB_mHb&ws=f`Z)8KoS&ZX!NIck)Fj0@qLd&q% zJ`I^}g^Zb|?0kN$aEN!2k4c6t3>i%`KELDQ{v^~*_~ssz+mzM+j_FssXf zQ`Y*!T61w-1foELyln9Yyw|t(ZxVbydrbxu;O{sFL<(Z&~A{<}2{p0~U#5y@;%_u9U#6G+PG1hW>UE!F2}jw^4gH!bj1n2-l26`_m`}y zx61s{9bymW@qL5$&sFT7+CJJx>CE%4w3g|3wU}Op(khV0XmlR+U)0M|xu=@cK9ioq2stSI7H+9`8>f-58b9{(;fUuv>WXb}upJ;SseGg@>wYG|- z!P8y$uepW&_SOhnYsyoP;pmSdY&qN)?&Dss@TzDV`^z@iMzu~ypLQFnDbNVhEwgVZ zE~eZ-X<3{4XkJ8T&d?GVf8YgY26~UjT@I5m@|iF0<+`*J5nZQt4H)3Bpr9aWY3bqC zwUaQv_3yA#NOe;FT;z0hxMu&9w}H#LMh~F($5I`4l{$FPjVn!tL|>;#>M`iczt3`2 z_2xI9Z#v5r!>uCKyuH2dM^AZGwfICwUBJ9++k6t`xKJ+C&Zs!)!}zQzMI|{`b{#(} zN_)HUZwWahL+HE}JFiL{&(Y7khK--g7{lvCxDQg}D+dY0I+Y6@nefT8Gk{0fU zvGa7u8j@^w<2dFoCq&gKR+=lC1vtp^#m0z6gCxe&@1nOnVOk->-URoc-kqFp4~#Y4Se8e4AZPAxn#|#ypRwS>GWU;lo;I; z%39OY7ejcA{I=j>=fK+o`cE|XPxKDD>ddhf^j6tThdlEd4U?!mwA|u}U1{J(&z3tK z_`Da^D%r))yRsM^`veeJQax8ViI`6*CEY;8b+J%+J@}hk8RKrn1&cW?>(xBzPJ+qY z*{sqGJB!8-&OI|+Dq?Qodc=Z!@Fj50tj_1Df{aeM9I<1>C-z8v(tG|SttcTzF^ zE+WqP44ZRBxV`e3AoHUuf-N%QC%dvAoGDU>e?;8IPGp@}cw1-!EdO z53xm_bHtbN&La1RORs0e`3YO2z6gDoE)!YbWU;ah-(+DBbkl}y6zb0-z?aHsyC$>R zrqpoNiiSaO4By<`d;mG6wD6!#nzKfED1>S5z~eD1Da%`kGxP%P0vh%PiRl9E8R=rXaAc++Cy8=Aa|ah;6f z8nZ%8SoP(^pHcK=e)hbjwTa-p(r8z&ZN@ z{Znk7$jN|-rscS?YRoi6e7P3Q--q@o=7?|e@zdE7Q`PMdppCM!DL$~AXLD8^*^VuK zTS2m0SP|@N_1wE_!ouO&r1`A2T#a;d%V~}?!pm^VVk=H^B_?H19eHzqs=4>#7g{{` za!m+}m6eqb+#)agnI`dV@$1_N!~*|c-dT5UXlTfh7OU`hd}MJ9^rw$_H)3#7di}(g zHRNH>o~IwTul&4nF*p6IWB#`C!rbl1RQDdTXzRlKR($ZccVgPf%u6_{8C#bnmY%z$E%~RW4eV&FucA&38wRVSJKuGy*tcJDHG< zy2nJH&J7HCuWZes568D}@l^Dn+;TH2m>nJ<8(W9B#JMhh);P(SOiEd_n&fI}T}(cI zbyPM{wtVc4Uh5 z_nnddri?Vp>3EIhDFZiT&`Ksr+B2`q2CP;$lb$I8cDmyZyIz{ozO`o;tGQO+>ZXnO{`TV=LA6}l z69kRsdm`mOz=xkxwv`q;7S`54v|z~2sO)A+0zQ8uXs6rP$ufRas;$kDk+?AfgBTVA zyH`KY_$M*T6Sp-Wh$FcSHq)|ZYIiav5ho@=P`|bkGO+J;@83ea(4X8z@DA`(lOxla z*iVwzq5HT+dfc79Q(8MRbIzB#jZZG}`IE{E3!^>D>L2|wX^=Oyp@k*PBdSnJ^|s;9 zwLY^SYCA5PpzgW0(^6+GKJAtxN={0OZu64GMtOn?T#odK7p~!o0#Jf(`{vZEJ-TcM zWEK@3s6Vir$_3@u@2<2kKR@5!pSb1oNIP3wz5R_NY7mc4NJ@%9%O@1nNJ`Ptci zEYb&sBA)<}udWDw)R1Kc2`LC8qwA(?y{)KE>w$x9(m^d!E9Z7)Xm`b@T^}N`qm~x8 zCOS?or~MwZP8GBT9za8dSeFtD2`1@vuid#GK~BZG6Q+r(yLM>kN5^x9fp4*9b*1yq znD<+iu>y`EBOzgxClSFVR&(mKe8P+gEb2xv;sj-}#7#AS%%H+rC)52`GbVh09s~Z6 zym^uOW=|)R)tx*~WcKel>k!1cQAMX%!MDZfj+1@xiQi2(LNKAW0E$ClRe$gRM zqBD`0_MZB`&atrC_V%0i5*$!W9h^u) zTwL$aQ0q(=R^$Z6>4>9%?hS~wL zccG;}XoN}nGhC^|(vTQ}Rlee~PYD?*4V}Jr-^HasQoo{^5GYlWPe@mEKJ@m$-z@NE zZGGM9-o0gqnsDG!UO^<%8AcEUr*S9b=LkOg47F?MHW}GKS)1z!gfV4fd9(*zx?5Udiwfs>C#~CR29s~`xk_ou$Z#Q5k+KV>|K=5ZiUPI{QP$I_TvN3$Uw5UYPS%+ z(>2Z9elweEhD9*v(CWj>fMwE2fBOOzyuCFOqGep2Z=5aY0$VeLUt3#tQ04_5ivc2ovxekULxKh3y$j%_>OpH!HMgO6&;T23$|x_oh13l29H4{BqfE>(a6^2>4(#cW;R8<(y&CeGU6r3D*)-Dozun}l0u`Hrc6fna1 zg4L_|?kZ5IKnu|s0n|AvE-hVFR+iw&R|{H+XE#B4Keg*-(b3UIlWl-Cn9y)sDV1VW zYzd6bawB0=n3^wd1Z_Yj9!|eeb&!ZX`0NJqrWLeN^DZy%lVL7= zp9l6SH;UX1y?o!vA_f&J#N1F<4|wD`m|Oo8X7dKxZ;4)z;eA0tfm^FctBlB$nEfx@ zNRkT%|8{t4D!bi!Y~a}q=pIH|Qu2FmZ*N~;={6VIYi+HSY+P7j@~T{Ni7QqB;kDjX zi&>d$#m$%?HagI#EkEgCJIV?ra($uppv^^&gDHKVii;;FCs!PlyPMAX`(EJZr<#Z0 zc^vuaua8k(!!A|HIY*XIRJdQYWF3_chg8@%KLR#Qg*wKXkW zAlMtRgl2%|fiwqPD^6dPa2%AO22x5Mj747U+s7M9UB{wk{WgY!ASSVFFK>QUe%A|~ zYXdMpUd5c6KxEUt9xkGkADPtDbYqhHdup5YkoHkB!JK33Hp-rx9@=0FAOqe!G4L!g z?)u(dX(=f~1cE~cVO;)TiAb0+(dY5-@Brc85*wb0mnq3=8MAuWvGlVI*4l{Nfq{Vt z4{8h~HWuNxO=yWqHIejPjz-UJ*AAW^o{xGfv&oj?<}3O_DE46O1$TeIW&zuXQq3(Voc8IK zF;Hg-)?r`(V6D5tu?JiD$9IQdhh9z8K=@|L2ywMhtzqM_a%>*A zC3U{2A-^M6!)2jemh-frq=3X^dszFZJI83x~Ua`OH2!_jAyC^YXF_t2of(uuyD- zH*e+ckXr%FfoWU|dJ)HAI<)RtSt;EE5|7^zI8C^jP0yU=;xNKW!}GkMq2X~jJD4Ym zy!lK}F*`f^4Nc9-0Xi3IwU=3CnwpxR+Ka-m5pQ{Wc88dP6YS_H2=#J9y?Y@x#=^n^ zGTHFz`n8%DOOKTW(I&2(Q1tWkv`tP|BQ$9)aQdj$8a=ZKgy+B_TXxvJ38PvTlb6R; zR3v%wsWliYHs&0oj%vvwyRD_qx ztahTu!eGYkP8`-|jw!#>KC>q4Rs2{Hl(ox;ii#5*j)S>860ZBs7c?T?PaST|UQC!6 zpnFCwJNReCX;UtO;+!Q63vtK}4M zaD0G{?kZ{ztHgTx^We%bVdpQLnP7(jtCkyGKGe`kV?KVlcr@L^+~4?p2_l(Y&7Z^| zB&Qe5!Qr}(Z66DN3xDU`)85c9XB2uzZS`S3B^#=hotBJT>peIOX9dZT3l`-c2?ixn;3&fofdSU2-CY z;$fkK*wSF`DUKGwhsGODj@O8Sfx{bY#o(r@q?_fb$zH*nr=khnOuZ^}Wbl)J3Y(G2fkWbfXM0n_~;?W|9(IUbbt`^D_s9OzmYF=HZv zrWZdjkd&0v3@r8f*K0fAR1S7_C|58+Er;I|_`4j{c(Av#`}1OOd3l*g^rmveHcJ(p zeZxhK?t-XVG(%S^?iFH+i(@_c8r6Swu~(?)T{5+~gv7*;{G^Cg1VhzQG#f`&XT%Eq zDf6wZEfEnB;EvVbFXF(z0&5!j_!W%I0~e30Ak-+Ei0inKS*5069r3I zDHgLoe%$f)mZE+S(j`(?SNCfjOyeZ3A<*8=u4(A^2#PW{L3!E- z1iudaSE~UUCvcqYDj$;KzCHRi9N{c!c=xVQ1+c9a~IXS_QggGAdCBoAO)Iqe`5e zESC%o4g0=-2dN5;q}B>D0g?eK`h3N<{&K_Zcpq;90z4NB;fh93{}gGrLi=tJ_2sL?L>cN79gVr` zTMv3=b6F8?@+4^h_89u(h2~_ zRFb+>scejN>WZF_w{rFM?Y9;+?#kueWV_S<$A`;42JAoOL;A=UqG6UbYQ+wL(&FOc z6^GsCU>t=eIJmJxjp^$fo8YRZ#+OioKqDj&3$zY@!r`bA_weH^N_u+gsYBhG_Mvf3P{!Y>I5KN-c&C8%$Bgq@V{K-Ez z*g7EO`{m2!!Q4BmFts201_zVT=vLtR3>fkGaP$~a*@7-`)Qa^tE&svm2CNDL z?r6nbbBH|VcC>0qB;$|r{PL9gq4|#5rFQ7tYMo{_Kj*FT6Y@$0J5_$wQHaGt&P(Fo zb1k}=bP})P9%m_nWAY}+iS=Es5zaNK(SR>l%kk$dpO~KUGr7pqhKJ0Hc+!w zDixt!erT7~jRg1z$|YUL<-+JKL5IOj;sJK~(TPhLzdjC5cvhzd<6xH$DERQ&Z!Kpo0pVZrru8X?&7K({bC#2ogpb%8nKR zr}%CY36P`~C^rMvaI4&wU5DRpYQUvT(E1ki+7=tr6N6sp$A|z&jZND2$XQdqd%1o;%MTuTTnFz6c^@*CP3?Ag5W5p3i(UH3J_7itg+Zs^JKl6Xl1 zD6KwzP*;pceh7jm{TSD|B#2arp4fGYQ#BdLF96CC%CCFKx_aHacaHR}uvHFU1UFc6 zxSfXU=y&|1msI$p&{dQN>FrZQ?r*|0L^Xje5Yo~I5NgXaDHCrW6+v${HB_jk&z)yY zVi}R&Y|xw-a9Ym5^1OC(FnpG(HnO=1xT5Ut^yr_gG!_3?GTRYJ^cdQ!zf>dD$#J(B!wNjUH zHJ_qvEIN7j-z5yZ@-J#nOy-?uH9_wTm{xkW=UP*1tD~bMU>CeI#*K%+WD6aAoOCZu@#wh$ITmPWA%aQ;T_-sI@Zx|MJ;BC)YsNHl)e2NOnfAZ zQSqn1PL_b9)AVQkyapUmCq;Lsf77I_YEEt(-@$Y_n;&2_&<6agh{D3cio#ELNTKsw znP^^{8AXSiV0||s(NGuB83y3!?_5BTe=9fK=BC9WQ)sYHp%D0is_32_cE505==wAs zP5J&)Y#BSb`+~Z5$)%Mz|N!v&4D_9t9_CSqGt6Egw z*t@s3wl;=OpPFu1ijgN($;)6oH&JG0r-PVpF-(VW7FK(TWi+*N%Nvd_0IT}WVnU}Z8X7j1*3bmJ;12+*Pme4vQWN4_*Q$Z&iX;%bGE)o=$03!k=|}vQ#L_R@kkbMZ z&m5TU>gozBP%4#b>u-YrjEcyX_B8x?;?zIRkjbiv)xEZ}gu(4pL3)b8InSPGVp@Hr zL9exFVnU_|ViS`O$zxh>k_X0!but9i&7IZM$>ucyE*;C^#?@jZ-++E*xCd7y~@6GC%3 z!v?s?6b{q=}JX=4W_->!aYtRLa%i#0j>wkxgQT%79k@5nf*pa`hz~?5y#(z zD9C!5;!DB^bddxb8_>seT*iSscm)jW2b~1+q<*2LbsqI z?e`;|1{Q_g#k6I+++E$=I;};)(2ucn+KOw*k?Um1yrXSoVBz8O9^;~r%NqZ@Yj}8g zb=7Up^^~%P+;i~$pvI<3`fxAp?pOnq99t`~m?mI+e)~hC-FLL*Rn_Nkc!;osL@_nE z#`m;g!<4>1YJbNe3rOQ-1%uA2RPr^d@xWSnR1X;QJ=dcW%dxs5wp@yhtl zP92}W2*H}ZBVa0+2s(Y!S?k|*>#yBSt@b%NIgt6iphpv`!s<1@umDQ>8PBXq_a(X4 zFC)QEE`uO<=JnWf+}zyWG5`c8X}Z!|)`R`wgP3^zCiKq=`^=Ef4y6H(cF_FyBIT5w zii-3~FTkiiq&$D3f5>P*xCG7j3RhlcnO1ljz(PK`JpT2G>B8$bcK)tTHa2SKV`Did zC&iU{wD!+$vZp>CqNGgn76}OugV7tom-RWN1Wi}B=z4bW!Ktq@}v|mb!flcxxxaThY0>Q)VU0ZAu5+b3AQ_rNlxJoix!(b>>GA9+!&^yMAaB*3nYX}0;qLQzv2p<2__UfKq|RcXi$oGS9_bWiJ6043!PUFi)jgr8)~ON zRNG!Xcs(fQ>m0t=$MNMxx;!zRPe0EW&cDFq7t>j71AkKI*<(&~zWkzu)ql8?SZ&}b z+xlIZ=4Yc%#}HlXL4!Ndypq37XZBEdN_!L*YBm8WhWNYXI2@w3;r+OF?RaQocIPH0 z+VbS1!_LPSBY1^2^LFAC#{(`p!3zG>M@F%MO$9ekJc(ZPJLZy~U|RcDt>J>scB-Ds zXPV3(A|K6kCaNfnzSa7wVCnW?5^(gAwg`>+p zwQ`E6!E5zknz;1lHp;=Z30kgwC6e@^dO}~YrkE{TwF6PnZa5EmJlcVs z_a$1|z>9$g+t8qD9w?GMrnGM$_a?iUHPf>Y#V{HA?-_JX15WI`acI0^tgML0tq9GN zG~SpFZ*g7q1&8?yPb*FNuU%9jJSVa1-hY(-INJs_Z(+uqQvZ)Ry!r8OtW200REL=b zM9*w4u$w5KbP6;}NZ`H7Q|9=%byePcpp8lga5$ zYRrDtZfW-QfG z{0t!ZSM7zM?!Z~Ik^9q@Go11g7^XB<8a@Ae^sIQW{ z?8<#TVn={>w6eHLW?(p4MAoXGx3J$g zyk43&S;zb@yRh<34n$}d^wq|7iOYM^jqCChfPJpz`42iMY9nn^P)(HdkIH@Pnih?j zCK#M@^S3E_KW$AdaftSmr$Akn{z|W_7=>`v!QH*6uTV>AfGM!i9cwUd=S%h#Kdgg? zWxlZY-54#4g2B{R?E>u?)eHJa_8=$zfJa)?;KXTzy+1SiEIaE@u(SK?fc2uLf||dZ zN^=S^pQEXoqR~GnL)VZ+Eb{*0F6j*B3Nk+4l$BTij_?QmhE|ixpAd+h89jAM(4q52 z)%e6Gm@~t$u&Xlwt0p>&87sJe@e5i0AID!LTCOXj=D*fmR(SqSH!6@V*8cZeP`WH~ zO;7jj9QQLwV1=*cUTRh;U04Vq$EI%pCGGC1ey!>VJNZWXVYFhCxTW(&5ySXZpHYzIWGTfs0fif&2;*dmqf-? zKPEnqq96vaHcxORLiS-xsUJhw!R-@tD%}0kySC;t%6DMFF z8i2Har>L@p$dl3uw?s5*s1IH4{OBdzTJ1#cchwI!*@jcxtGmx&M(17(5s2I3NOzjN-n`~_#-kAd<6bc zZN==dP_6v^3|^QgOa7ns@t(7Z`KXyWBTqz9$s{od&48ec7gIh3{vM-%dJwrr0(&@3 zry2aOW;BkN0Q*hJrDxfx124HHz3TC9x;Hh8ZKdIFSKqpaM-q5qfz?;{$v+u>V- zjZvY;t8m@C!%sC6H>&qfw?(5!wIXQm8R?-M*PxSZD|_36M<+!`qLW?s*K0dgs>)f- zCxsnf^WPpu*v2^hn%+I`Q>U5ok>j>=`L_7ftFsK$W9)MI6GSPnu}B6VQ}mtxz%WB)3k?dF)lSjd8*016#Ol< zj%}s-9}0?2ZSJmUy-e?OP6nsoi~4`oF|97y;M(RbZ>1p@JCAfQEIRUh13H<=DBJRi zTjS3#GO_!(z2YZx%ktqg?V#cO;nqcW2%Yp?_)XpareD(uPNrLpJ+Lizb=WoFKdxB155PzTt%KZ{GYZfx{teAugjlH?l-y4*U1#^kNk&LqZoSy*GzBrgD zxyfB2N(gY;k=`LOY)n~7kLmYme@PZ173 zcovwAth&%iR4jRT2zW&`YTpUK!H3EQ=(cdg++vUv&V83K&l6V(Me6k0znd9jfP8c|VupJam0d6~|02(%WaHrKqvI7-l6$==Q|wPx|xAIk)7O zU}0P~pfsVU*Qmp)C!9+hbA3P9``AqLJICMU7*ik2@gZ#eOz{6jscYWBq+7a2G~#zl zOeaRvaJOt8?eT2lx?&FkMahVD+2$GEsiH_Z%6+;Hcw~i719^yB(s^0adz${#bz;8c zzDuCmfp*g&psisTu;Is`!>>lQ9+(gYcnd+5FH&?eac6xLnNLIUIcWAt{X`-s$jcad zwG+an{}+4j9oFR5?Tgw`X$mSR%?c_?=tUqXRZ&4insfmX>AfWcmmo?N0a02M1O$W# zNQXpvFVZ4iYJdO%LI|mxH>gY3`qtj}oO||j&$sV$_$wsuJLi~lj`AC0&N;@OTqp}Y2X%06)G~EO0)%v42QaKwt?f!fWF-l3w_-I>0p66JN+G@vSip2F@&wTHK zp_@{AdMR>-t7S$w_vGwkm(x>#QeiZgGImi_C=%Y&q%@ZW+S0SlJwU2mC?Ro7kp;#I zdxEG<`G|7br}2Zv-_{hUc4-Z$a9?0L6K8F^LaYvJ$#S>>q6Dzmo(SKdvnT$XlE)lc zv)M10m!1JeVzFwngzeAvOss)v{f&V1YqEC5*@9cf03h+Y+)S3^(?9jq3x+xYrnXM# zcinPk-}mo;AAVPE|JDzuOYXyjIYVsj-AhdY*cpNZL;;v~&xsVQK!7-e7C%NeUO5OC znc(EwGBi}kF(z%lb3ln}0j={yb4Xog3}B~@;rHq& z2SmCrzl#U%xsb+ph2K&b_Yj=-6HG#`l+nk9R4zOHT3&ufqUU6Bf1c>6y047$D@p zmZ>XS%Gv}WxON|RE})s4C1g@ay$sU=R4sLe+{MC%iMRc`5y7y-0xNcao!^qx82BWw z!kpSXqc1mrN18-`n94*KzsVQ~Tfe-q=)yiqEh_Y1x;nYlRhcBSX0P1%T7wWrM3d69 zsEw!Eh~HXHH&M#&V2lIM+<=&EK`ua2l^W%IwnP%(kTvt~b^(x7l3YjicaaR@%-js! zLScZUejge`Bmr1NVxZPZ0bngy@4}~YaS(((tf0Vrq+jSe!1y3=MpbAP zZwHK#AzRmET_5)w;GkN%UnO)b zVwo1OH~?gwB8@0}oK%80{7E8O2Hf1E^>V-V?ns*cH05iQlx*`k)`gV;5);GDSGt+hX9iypO!SQzk*$Lm_O`VX)Um@MU zH&XpyLf8KptnKzNG>1$IpU@;MeB@PfWq=CBAmGD9jMp;&VV{eO4*>seCIICZL!M7EP#BL#-aal-HYjHYfnDinck6EeX{t72OY=e| zCLY&zq~tt#T+2}WTDhQy0ej^F03}#;1(V>ieXc2)s z^2v@ZQq@vmKY>Q|r78iF(*hoA;HQ~`4BzLkq;vTOl(=j^g)VW|PD%2|F6E3-mn=8z zHzXi@fX7fYKdfDck^C!}zj))POjAY(CumU3gQCLKv9$ zuMLJJ*#l_GB%wp`FOV1;_Pf9F-_V%;F9CpbF7t;~qWiawkvB}#zuc(X^6zMqC@Qu| zxi{P5>32bX4+0$W`vDu9^qx%;aZ{G+?oSj<_3uI9l$*k z?%B&Z5vNs8^a5X`ZSf^#)m+^pFZlKuoH>vO<-hzd6uY_ey%H1iKPKd2q{w0< z*fM(J?}MeBLH*u|OVO+;(ker8D9e$+i;b+f;;TKJ4kHJ>OWiH2cNxF3d2g$vXt|MT zMQ!90O`ZH0&Q~UPA%(9TI!hFNk}vy50mq1?AI#6aoqgupb_vI;v^QRcgbJRMqC2!# zdC2YWQ-p|ugUTS&m;GVHLr**}55FxHjqJ>?0LhzjB|cWL54*goT^>@rcYDmIdic=U zoMEjLn?ns#9jphG#g$i&XNW%9c3>xq>^D|kGI%QL5er+ggKx?1SF#N&brbM4t6njq zZkzmyeI(VlO&!m>o4G4}1bG+h9?<&q8kifV z$#)0&9yfXPlKtJwNW?y*3iH{ndzD=~_SWdmzp@wnWM&nSnNat+=7fFqi4)3UH7_I1 zKcZywgxtj&pp^}FVL~5XxY&I-d#_1-O?klWE|tx__oqMy(#F}}3$d(_UOlgWCedbh z8>snFXL{uluh^{9%ma>mL*yNUd~#7X_mwkGm=4!QJkjmE!=k5Mpl7sOr$xncSK-sC z{pN=c#;xADqXC`GNd0PJq5{p*c@(^V_gGDJvVGCh;w)(1`H*Yb?njJPR1m5-HED}0%jKvt%5xjo)ZamM${((?!0Tty94 z6il72UJ-filvi02BvclmW_^Tf=Co7ESdm9@IC;nQhiD~xi&=r2QY`e7eJpO#jbybi z=$4kF7p~Pn0&<9rg>Q6k5zH)}Swx3HzD!CyGI(|Ga~g7~BI-Hp_V~^dcCIEyM;2Ia zXY9Iv>Lw;6k{~A1P>&fTvrfKH@snP?ZPw}RGO9Mc7r}Z_WA16d(e1uN^gS|r=|2Cc zf*5LLO9hEaN&lvSerA~bT?5JePiUZI!`AF6b(RsLfsf)htt_+Rw_-O+pj-p2lGX4I=zH1uUUbeGzMOsf;p1187tFA0YLU_GB`VJhTuOmQN)$ij+YjKh=2W=WUQC3`#nxP?r&>J>hhEl?2;C`^9hQsr-@C~3 zhI?rY+_UFh;2|WlIsg8#pnWf4RtQeOZYp_a~cX%U?{MMpnk0IJ6|WPchNuadlGh=z9}c%2@E-=$Y;viJ}X3U&on> zcVr2^^SjX7`2N7Xj2DrC4|ZK~ZOaHpPJg+ws(`4xm58;E+-~2lY#rPiMvg1md5}j&)L&54>>?TNIrr`Mm2Yt(d?snqJ?WF8 z?%u*`)wJ>z`C}T#uMouDYx&=+aB^NZ&~V*;G-h{cME`x3XV*n;VVp<66PpUxg)3N4`U0}-{%PI7Tw|@E76w$WaSun^BvMmz0 zkrZq3^lobI*yte_yVO^@{EB$zzGqkUcqG#-zpioj@XChV92Ii>aKT6FV#LvTqfqiI zbIn@9Krv1_BBk$0VNUbHzR?jcW9KW1L#h zcBn47sAW2v3EPOpcbFbC7V^x!#H@4ui)^|Yb#~MLSy=Vi*FTuF7| zeW7d4tM(B<5@Uwy_)bjSR8!Iwh;x4kW28pTfQ zCgwjAw^m)Gy}YmxuD%#~u7NF_S?Z<=C_{+ccPmBlZI{b-_vgNT;tkGw`j)>PZedb! z^m^&&=;v>}k&=I4^=u=U$Iw4qbALL=hSRqfg$D*Ejo(BVU))=Qy z8%xLiK1p$RzUR2c8Z4W9&U??^x`$=^&4nF97Xu&hJxM0#TRxEf03`AaeRrYE?1)8^ z+KDm$(*mz&kBr}>ZD);eVhyS;=G&;wBw}O8ZaYzjc0kQg!Z-KH3h&q*fC{X9O(_WN zQYldC#j}R>2%Y0SViOYNy~~(?d>wpE-Y`WY!j+UYqn1psq4aMGJW6msk^jo#^Q`K| zrHMm467yCL3-2B4bTR{Z2)w$V!fx&#c3-+xE2#UNJC^y-;jgiUr-P-!BH?XW+oEG) zdlM!~rt#_96*9K_q3_O()wp<$9(W-IUC9j3@t?Ox4!e?{3?H$D+Kul0T<4kh+0123 zcJEuuuc3DpPv1Ra+^!jP?{!<-rI`bcW{(N>Sy8O{yag|Ejumq!#+jO)lmRinyuIss zT*8HC;-~atOs4~fMy_n2^}pU1=zi!WEwNbY{k&x;5-wgHa_qihftA>4VtJXC*Ritd zTz}oN>+W38Xqoani@co`si#x_SU37qVg0#bu7I$}64aFT+O)`ikB2W8npzZ4MJDHr z6l4ul+MIV>S{Hh*?K>GCBxA+=HCD@2kgNXWo~HY3q-Ex`)sGl8?t`OkoO>LYQksqY zEQfYJByal3<_u}uN*>7=bGa?#!=!QY{LDWw(H3VgxJ6P{;+Opv|LIu(JoI0g)K{G0 zncV(=o77k7y*0*HX*u!3Wp3+zoL4UEq@7m_Pl$cusA{rn*LG)4!(qeVAkz<@zumKX zE~8_8GI->2je4STa-90!@ZqO>cReZvS@|Lq0?&-gBmqLAInWyv}G`z6yvwhb2K)%eBU zhT>(|*~eNIO$fK%9QEAZ_0scjze-i@tMY9RTFdui-;P?|Fx~da#x$643n!ZKl12suuC5$?0)4GVJ3ej-I7PvU=6zKt z4o_sf{N@-Uhs-?Nmq)*coj5R0W7NIl`No2{(@sr(+4IV0!5_GZ&JUa{%}nu|2QFLN zfMw=Dy}P^81+nwf9WrZNqOe?Y*xON=F*^zPExD)($qWHH7?=$5sftmhc>+;M$=kPV z%Atm$k;VK*=w`njZTH%|PiIKwa!`x!p-eH_vdmWkiEFa+i*S6>BA&z;(B&AG_MWCQ!>zQdcVA(Zu7|U*2{=yF-bf;61I2>;t;9L3j zisxiQ#516i{&F7@oyi!^@ey0i?74j{yN|KNB3a(tLwa24aqqRCW;=}rhz6)VDc{EJ z{+(U_4J7J+R#06reQ?xYwFZ!!`QPjB4vZMJxvI%L?UmD$9yziqwGS#?aWX zI+}#`F$D#PaEW`L3Ms*?vEJ^Ll8eH;ee#00VU!uR3hnB8Y=)gTihNgy!q=aM_QQFa zBt0SRY)nJ;HwT0eW{XDs`M5GI>7Q5LBRmVnEEWB7iT~}Ifs5w}jMAooEEok1^>zyh zO5UTSshLG4TXWxaGJYD19;LKVA5|H`(OGCbtHlSjAIil5SVZMVlv9l`7+5lDC- z4myaLYK~4V#!1^2#was!;jK5USXWX zo#yX%y-7N#mC*s8VBGc*;y=)c#{?UUjgs%YAM}pJr65Ht*b;itI%r#hCkrdFg1&?7 zo&c!ivD#Jet5I_nLFr=^4SG)F(-Z*~a{(XfCA2b}A=5bXOOV=n{7E*SY~3{cl0R=t$qRtgdeK}P3BG>Ao-_cZo7ZFYSQ#@j+JE2zW1 zRDLJ@96)+sUGzGG^sbMinIIe`56|iBSor0E54F6mG_tbiYv&qCg7*N=I#**3^Q*^# z1kVz5!%!CK{O+0izHcgk53ut#VNooKVsFj#}b%s6M2#&UE2|$}) z7O254G$>b%m3v|l^mzp1LeU&d^^!epqkg~ucD~GOagcG{D3;PQwc%Oj%IBMz4~Jqp zf$WaS|1`{FOT=8IbX1_4eV;iCfzG&5*uzEDr`31qQyXDa4SqDT5dqY>+bbX1nkWlv z8OIr*$a=JBQ=9;SOo78IDv{AM!8ifW@b9ypX#(#v;AACI`UTMDpHum8r02Rvs5>cP zuEzQ3QW29n5yiaLCDzD$|N`CXN>)_JjCji>;CvfQw zhE_Frep?X^w{LkP`oN-2ZDeUCt29 zxTwGxa3%6;D=5=sGiq}qN~rj-e?(5-3U;`(r7D?zD(N$v+6=#;KxHlNfXCxtF2(J6 zOrS_pE>Wi3d8{P1ko<7^D#aAG9SUeY#MFkGj8{9nTeDY4RZqrQi5qpYminlTT&Y!+ z;=IkOs^1?mIU(65Aj?lE(ps1Qpn)Ka{#E&Yv9BUt643(Qn$$7JTBBcVx>0K+fRkE9ME| zIl~=#?9*rcMsT@JAu80RO@2CUL|S)NfSy%*?j5qg3_s^-^4aiQACTa6c{z9MX?s6D z17V;JXzd9)#XIBH$)pcxh#w!9Xg`Ao^7N--nnP4(83jG7W&jf%n7?Iui%!CCfO(Z+ z(ffq3QgE}z-QffVgXA10S+9;CAcx(MHA0ZqE{QM<5@45en}lN6L%PhZYnuJqGtsWw zzcb-OHJ}2jY!Lk49mWiL%l@c%UFnc>(FZ=q^3%mNkS1l=+dBTca8NgPYVL=D2Jspgy~J`#}lS>wc{Eav)rzgQ3128KnrkAzXm2GWxn(H z<%7jc&(sDljiJmn{mF!qb*{{F`Qm+JP~wPUqxbXOxt*=1u=}Opk`bJS;@CDV90Ls? z{_dv9PiMA}NxwU3yB!%|Am>8^0=4N|J82+CECrGv=>k61#$;6dP}1rtR;lJp!9uB^ z1HC##f8m>}S=w6MK;fHpzKWF8k53^@ElZ3dAmVZ%|37+Ce{?uU`DGyqv>F8ELK`WPaP+7 zwmdW2eJs5w&HcJ#{g6TnqK2*b*#5wqtzn`o&^Nox7bb=G$t+5o*ck5lVw>2 zxadw5k&dQa$M{j}eCUBTa@chYe#St1|9&Qf6^>{$t&1qcsoqruTbH4@9i)$;NH77J z3;EB0Mgf3eA&A8*qv1#MIvaV=!HM)8GYGvZM)g#iGYk+?Cx!XiLbG$DCJdF{ef^@7 z8G)q5D{Ul>R~-Pjyb3b*tk)jA%hMZ185#pu*3n5QB(=W;>DjmQVJA6>P!85UijKVr z+m7clvz0mW!ymrIf;iNgu$gR)$AxU6B-48)w(d~sJp`nsT6oiDVHaa2da(=g(Tqv1 zYXpTBgtbbwF40Lm-Z1K!rtbdttefpU^a)jKI2HFtHv7s2rz zm#uZh9-XNJ_u1mbV;vi=q2!V}06twjD^TE0Q+pu1r-B?-e5N?(3&4^0=s#CjV-Uv_ z$^7b>Za<}L_ae{OM#Gw?!^CP4x|B^JVDT6_ZjCDhqq`|CJuO!yG=$6jl%PZag#gIr zJtFG@;PQ8R!AkpXuYQ-Pa{&L?!(1ylh8!e;YzSUt`n@Z^b(Gt%+ay;wi&*{!hzYne za@NIS$4XtTwz|8^hw6yHGO}8)3D~6qs_c%OEJLaFQGFS~f|voqxB9>J^9M&xL<14E zNox(q7rZR`vEq<-v{5Q#XDLTjKP8SAb;KHtk>@3B6dkXa(Y8A?&zYL-*45dmH!CGj zkV^~Z;4%DNkpp1tyQ#}ZW4sYA`~RY}9c)KIGA&d^ZQ2R++6t5caD^0@_<^`idmPjYzy8=3p#)ox1ESp zZT>*6t%GLxqx1y{dTrBwe3tGs06HsyA=idy^J(}TN<%{cbfW2C0qyWhR=_HZef4IR zK*g#nvMdfx#?w7Xk2b8rr(+Z86PhM^RWR~grgIgczfL&bK49&OMs9)nG%PhWlkJm=(30AylrcQL5quNkC9*MIdrs0QMwizHdhN{?+EU;9{@? z;oW=7P0ur=LqyydC|!|81`uUWtl>Z$4oO)`nUrt(qaQQfj|MPOF$Icnbi!B(VL_u* zTJ%{Zk>O=@J5a@@l1HM<*}20RT;ew22Wmx+RCvREXI?k*`!4{&`E#4etGYI93M&8( z29u_MgiDgHSB9kW{Jx&gag{sx(1&^+!(ZY&7BHWc$%y2;CF%yedkfHOoq?X&xBeRj z&Rb_-;1r0LV_D0QXl;@w5P1_$H{D+uONv#u0*q%bhp>F!0FRIn82gTog@cvLhdc}dyruA7{kHXY;vFM=cz4e37-CXM@So5{cQ#w*ikG;6n&ZWWUtS%^t1F2;ouz9|` zfs~v6rsLfhcj3$|q955b9>LgcS;|-?0Kh ziRAH`n4^TrAvz7fu%D=#*pmnVprjCX*ur^CbM0hc;uF-12$ZMvC1L=cShZMYWnSen zd~B-1Z`^c{nw4t+_LkAK7e#i=coUfPlO3H9KW_K24vXm-~YcWvS96i9JLQZ7?Q{dD1gIg49bz5xUA4GrqE z9ug7z5mL{yQ(=FYqv3a#cPhpEhT>Yy=f^Y#G5*J+f3 zqB^VX$YBNXAqH#Cc{zj^?(Exp?IVo?$>fZ7jJzYw6C*MVd3ndtMG(2o8t=7Ubsdu@ zS6N@}(p=h?J>;@2LA)UsW#e<%1RaW4$89>(>Ae1sNy4yCq5ONL080WZ z&R7rGROp0WT=0*t!HP>eyHJHbkONx>KG7#koG^I`mG9Dd>l@GxMGV8(oh_0QK%Oh$ zV&v~~ZI>%{gRLi!t{*iJ)?GapW_XTdqKj?LG(!UZk~Y}51PCmA;E(fC4EbS;tWrpH1!aHfrKK7kS1oXPdm~1RQkn6f7pw2%mf=^!x^bITOXO? zXSiiZ?{_b3$YjAU8?)Alnw5fIax4ZLpE@*na&@53JbWnh$}ETtl+Vl)A-Bd=XbR`L zyQPCaje%tHa-?eMsq|*3=BbZ_#zwAw9$qkgm4mqWxk3_I*$j*&db3U&^BT!uFtQLsgyJ8orYXlCd`iGKV_JAzp5%ru(5 zGF`zYLa^}YPer|t(w{;H3VbK5#ZRf^4Rn%c>=iQdrU`QW82V8o!gTUdMd(%_!n`2^ z1*&71uiTl={*pm(7_7}m8(cd?b}YWj6|k$}FaQl9c=bz)6+|5D>bMwiz zcb0QTxMw6apf$!jk#yBD=FY0lDjRGfN(nnkjD89TLw_rgObv7Q_Gxj>!ez-rE^H+7 zG(tP0%Dduv{Y|?V8QU1OWm*W%!=+-bq(K0FMw(+92qU-vZ*r96m(%dK(__;Nw4jf- z^}(&UuTl_No9Wj(ZLv&my`BRGcRF6nPIwQ15IAEE9VL-K0bTR^N%2J=0B4&ZRZAdU zr9fMxOYr$e*SUJQrgD{#zLtxE(wpj%OR|EaB`Qk*i6sHZ^%;ye+HpfQyuDS3{&FR( zqElU9@7Do{6Mz@N>7f{D2A*=rCA(hBlZIRR4x41PT!E1>jRb20@N}s}(%!hk8^AtU z2h3?v3jWIv?M&#D$#B-aPp`wqyMH6=Ta5=65gJ37Wt5BnFurjiYbC;*EV5W$8L-!< zs=9lBpRv4myIXSm&K@Lcnz4sws!lpQDakhccaS}V#a9?`M>C?jVj@HPiph_l{#8*+ zeNO)mng483egRY)h_n0bPTl3o9g-4FZHKFoQz{|aGQyxG+Gym;+@>{Rr-43Q_6 z=7pST{nFnuo zFv(pjA2SBR`|t%Ay~IcrHe{tbqYb#(4ZE!X-uQR(v|XMuoNM3o;P1}04{$s6y8wBW_(HBBu}TV=U6oNp2vRp{LwxAiwQm=q-AatjS>)rgY)O zI{tlqDVtMtW!0MIslp3n=Ajdbz|y(`1;plujN$XTojI-EKoEBth*cDrl6remuw#H? zA}X2VN!qg@)wM2a*;B~N>F1O6v9wZqO0zMFtyAPxv$Rbh;Sy+U^BecM_k00qO8$U8S9Kfe zw7yUMQqJsF6N)!7mvhaC6^yuw^clDmeDelm^L?NC>7*Or)>M@2vQ`RhG!JDx4|>Ip zVel7CZHD?iB*GY8*iPJ3mq{#)v4x~9+HItk3GgS$eTz5cHh(hWbv*rE=`t`#gzbo} zc@?E)dDl##;}ZcCph1CHffuw$i^iMdCT|Q=E1MzUs(gx9K34~${Jv_Q5;d_zdkSjx zj&~$2`k-2JWo|Ex&xp37CoNO1r?C`+Yh56Zb(MMY^i_oEt4uIXGih;G-OSbrs@zr> zDQOc}m>aUMff>C@QUNA=Eh`zHESC-`BRrfe@lN5sTje}$TpO$+TQO?o-U7(94VrQ)LSQ-D zc@0C0o+`Wsi~cp;3=-V6E3O8Trr4T(V=+KWl4SBr6KbSLGnKLOrD0y6AecZuEDaL;7re(!vL==kRc%}kG-c~ zbosBBZ}G1n_*SD?5pp=u+2j|Mi| z8buPxOAyk=LtCx^qQO*atDKjd0St&-O)FTUZClLq#IkHxF=n0MX=xc$5xOrU$ZM&O zcUlVx2;QW$?bvq}!LI$)cnHuYK#1`dZ`cF_yphE}s$z#myaMYqqUDHJ>+0k;XQC-# zevJ(XN05#Kv@q)#Ly~g|;7YsCausyhv6X*m$B9;-4#U;8hG4kj@biq*S=ysy0uYhw zpC@qD>Tgz-5f-fh^bvqv&RHC6v1s-E0yqVc=F?(OfN2YIMq6WLiIMH3{GTHEo2=pI zKwed%mSpN{H($l9QNrNz^&7pW=&a5xZf_C)Dj?)ibn4-a| z6tMJ=5FI_fCo@E!C&v^Nidy5nmDzd^+QG17Kf<)Y!sHdBzEW!`%hd;_Ka?U*zJZh= z<)#MEV~6LL8$nOJ<30%3LD&5;z!v2kXmr>IG|(>miAD{Zd&??76|)9Y%{rs*vSS%a z<7a#q&^>N?wECGcq6?{C`vZ7rg*3v6>nv-uL zJ8D(YRyadzShY|cdA4SK+5>sD7dD*&KCI6azgC|MoHykg`xe{vgd!1Mg{(16&I=^~ zN@j~{MxYyz0=puV1C}8xhHwdn9sUuJ{$-=W{{F^Kd-PxVLgEW;+O6xPS4vhDt7Sk4 zG!YkXhzwY)>ePR=WnpeXP3y>&KTXq-M#Mr5q(R{FDFM9gM=AK6fKD$I3>+ais5dWM z2nPKLB36U}qnNV0xsiHwC_$TMoeG%FUUs?joBc|?&H>9knhdY>>HFK}uL-_JYh1-D z(w^lPBF&AOGQkUANN75w4W94HI02A!5&q-YUj=w?(NHd;UJO#21|jQRXw+(j7u=F9Cyy|HsC~8xd{P z<|GAMz@|WL`Z0gP3E2RfNb}dE7&+e#U|)mW@}U#3ogeuMvU+S>sV%%HalDZGY7($J zL5MSg$E(3C<*gY;Y9mfAz-C5!W=am&W7s08HQ4}0-*2M-TFF2$c%W7|()>#-q#r^R zhZO*G*B)&K+r+!aqh-2H`VvnmhT{azq=w96Pxjje`nvt-hzFyqG;B#d;X3`IFb-N; zTf0HxI_dWwDRK|G=ampJf)!zjt=3c~8el;P*e3zldy_FzP$%xl7Zrl%L9E1Q1%Rxr z@i?|;29z%UcGezZ3QQy7;;%{E*%mWtFtZT{tWQ7047pi7AYDNhA9MZ1LBBnb2Wjzj zgBELh0?yJ(D{KGr&O87p#WCh<8-8jd?mMi#um;fkfNr7+-iEjSs|+()r2Gx!ZflGA zt4s+5`U2Yv4B7j!b2GJ5RJ$LurCJy$jR6L>%{2cNL$iNYF#4;=Zhs~8H;we45c6Hm zfK6vvN({A#;+1`nL_SqDz*kOo)3Fm{!G(N>U4QUK0Wbl?2j zVcXTB=`_Y}So5!;PeSG&bEUtP^(I9aJIA)-D)G(P|I(c6_f42g;9KvR)9C}QRV!mIp8qM{mG|(r+~rY8qQQ% zHK>Udwag!i`TGyeMHLLJ5HgBwp1LbH!MT|a&xQ+Dv(@e@G@CIb)b z*!Sp-z^$wUx741hsJ-VfA7nqivO6JG2J6WYca^&R>%i+Vf4o1Acz?oo5K{d4%`yIM zM|Z5mM%$fM-4Te`b`=T{*S6wGaXUrd4LvpaT6KP{e_(9eJ86jFNja&2h1m+w_R{4? zg`90)G1#HL9p8`wi#$SID_vARvrl6h{&>~%u;(=zeGgz!UY_E7GLgzGZz&hp^v+FM zWL!c1@dnD~`0(ht^_6D=T-y{*W+=sUO!HW7ss&1w8+KY7Wn__}yt}|prRR54BQ}o1 zeS$7l19fV66?STWmhWP3Jh4C5Me#w`c4E!q8)bHnM?2uv`!@D~Lu9_`_-yA7GO#!% zTe)w$><;!A1Isi846=`QWOzDn@{Q{Q?kRM{EW|>*MNP2f2mcT zV!okLR+(;|KJ3}PE#zQTQ|O+<-|oXxRiSD_`{OR2C@nWJ%|+-}huce%bE}dcMijd_ zyWhzCq`fG$uA98XBb<4lvPk)8x?S}8VSm=5t6|v}Gef5o0&fh%U6!|T?rHc?80Xa? zbuKijjqn;0S9qvYCbjxX&q?0YaX1Z|ng_XVyD0<(052hofdRb2OMu3?x zot0qdo%}U$8zJ7|%~`>|uQ1$d^3$$8tTH-~8@xlG!9}yv9;&!CXsB?+p#Op6kMcys zH!LsKRrBxmy~Aa7)u8dCUr}oar%uK4)Xo#oBWFDtEAH<*BkOt$!!wW(+V2;U#?`r- z3ANFuxiPfM4(@+QK8EYA=B~T)z`k7qp6^T)C9}iGNO|uWqtcNYMJ&O@|E>GWy_@To z(w)L?XRclKu$1t%v#e1hqlXmpbdO)EJGyX2!=&fqk>bx6{1VEDcWeY9ro!IsD^i)u zh&w6?Z*xuGqRn*udm{E%IjH2KPf@r6l%y4*;l0m`5CTeca@!}5={2BoCw1WUQ5~5w zpGQd^>FE{uOMaDVxh4%C^7>y4X$cC;oE0%x!U;7u+b)_(A))e$rucqEsbpAe|70QG0>yF2M2{(!baYO+pH-qT5wIo^DQ(KLTjt}*Wz2aLj*Uz zR`1fU_GWwehAqJDBTJFXXhYphr#v^wy6W+n(omB*3k92ko(2xK{YSk%ezWDhP;Fz~ zQZ3#a?bd#;2iqL}c;B69cHVHpb8X%WDmzJo4I;eK(dK*?Rzb3cfA}?HEsjcG<5{tO zYJYf;xtoDKJy(tbpf7=KMJe850o!ua8VLkW++n8lR)1{DV@9FN*gS z5<6~AuU?2tqv==Lcv^dl9(t!(TP@0WEVAp(s6b?w+YNttzO$!q-v4p}IEG>n74*kQ zHUDWZva?a>-Y73`rpJoc#cHp)cUuF61Fj18kj7aGYjm^nJ;ducg5O1(x?Ol%bs-_Q9N?8%|Tu&iZ_emUTp1(9z7QwkEEE3*L#Z&+ZKQe8ixr(UWt^DbuqXu$9>dd7ocgGk&3Wb@ILl_)%jaW?Hp7T$|V8eu`1tf!6y= z=cm}jObYkwpR~1hg`Q2md9<{k3475nvjV+a8)btZ(z^ejEC% zQ;EgvO_68(7W$z!>?U_vUwoaoEpT1z{)v$$puog1%);pA$HNtPX@^R_t|w!BPit;% zW5y_2Ox!)v{rvGc$m-|g!4macyO|B{E>Eai$m}{1#9r^E5bnyupnB+rNm4<%yNjBa0aCO*T#eEghJ4wP~`m2jYg_v7s9C4X^1o`FgOZwJBRr$jx z&aTq#>jNQE6Q`0C_C2nAs0uo`dgoKG@Tj!UMdVefCkGS`RP7ksf6p&gMtUc8=a~_I z_J6dC3|qIAu|Y;u^0(XeKNC6pylt=U?BtI^J`30B+JdSlYTDmjpfl4=F1<`xsvolaV`qQ9?}oxR|J{#Bn(>8B@?T4@(C- zt1C{n4mQU{_k*suTiG~y9G8)k+Ye&&!}#Z-xG3<8ilxg{8#~(v9>9Cj`$4)MHjeto zWq}_U%>(HpY=Bn98CLxEe!wK#I9W4BvtLX?^j{3SxP<8cL%s>q=U43Ojvold(f3DH zgs54~-Q01eRhez*Wd?1#x=>cv`x|X1Hj!x+j&GUj8~w+YdA|@a;EfArVuRbo;SiU- z_QPE}1T5DdNrlQg<4ya9L?zaZ>ay56J|6%g&I;IU% zz0j;%z@?1~GtTq>#03(+CFs~nuE3aEkgn%F4__A>&>c5Vo2_q^E!}Ole)*?Ww{vs% zP$ZGS<}q#7 z;xW(n?YgSGSJgf4=79G;j(r8r%G(Yek}TbJ^8Db#dRCX+GCOv$=-6v!d8T!h>lw!t zm-e46iq$_MfphO@yZnFxg^dwA&7b(=%CK@oxlVjiXJJxns13S9{nA5q-h%rgDfu3x zCi=mkuA#k_n6^0KlSEoRTH_Wt^7&W)j_$HBLXJU%##L#{&4jWr{mwF(WuoxG0;yA< zHX3~kZQG7jc|`KPm9qbKlr~fSh%YPg%va}NTB>iD!G~;+kKML~P5u<$fz&e+wvZA+ zb>@Nc=zdb~#L=9WBDcn7fFpljqf8{MRu)>#?96vl%umKr7rW228VpBi_Uu)}iz}i$ z1{Ts6ndtk7N_dT+JF=0Y)LA&2TJ#cUB$w(n{W~{h9K3qQJ<1f#;7SKrg7K@&C%@Df z>L}=#bf-xg^%olW;=oX#$O>7Hh&U?xaXmE*`{B9>pQKMymu0*u7*f}ylhzo{7ea@v z3w=u4cHzpn-Jx%sO;NYV%!bH!L%r0s_%(%*7l`qR;)OrDwAK_-qEa*vsVW<%hl_al zRC8xNr&Jz)seQmoJ~tSsDtS0^II^KuJ8)8|{*j09c@6o%c&|67Tow<{s`o}#eudNb zj|4eQjy|ezQrUA}HU3ThgMH&{)ob#*yA`76b4fFW)ki?cvYFWWa)ssDAP6 z+QT2Atl`3Rt)|B|4fIg}F}|l-mtVW&9eb^wWpCijTP7X(yqempcV4~Zj|2Zvd8_ff z&%FL8F1|o>9>3ktAkT4Y^0T#Thc4U9y7|EM*La4j)64tQ=g+=A^Zlja4%I4J^dD^J3;rHwbyK$*0cAZaq=#2))?1{C# zJsQ;Dich49U>IKf~%`=5$<(k**pphMm27J zw%z*&{HpS4&HdwCr&^mlr!uE3-3|pbHpxsebu=D!yOtN4Gd*8+rYoCu_{hd0hF-@+ zN`oAm9X2R6|0=j}DCIEQJ|Q*JawGNCAzK05`9<>S;M+X9#LV@KyFD;v{@L2&x882+ zQ^wkUcHX{5qyCab=y1e<8M95!xnr)0(*~{?iL$b5v5DT~adMC4E>l?@?lV?l*mRqWi_+q2b11 zcv;V|(MGy&9OxS}X%~DdWTl5>PtqWPHb6mkHO4izspmzGpu-#|#@+>V*LNG*CG{R3 zxybi?G>+$yJnY$e8dpWD0=Of0@`(%Oi|M;R*q@I*AKRv+tx;I2vr9H^p^m5d?yzQP zklw^)@dHunLZn??WT}FPB*C3!IzGEn0*^cgzs`K-L_hkqcNL|YOl@6uLOl{faCkya zk+gchn1x?u?Ij84$-t*Zl?7bk_nwVCqJPf$8Y17^Gi>VTh3ghuSkbt#lJ!(p?L#u@;{O|Bw#No*(&L0QuwubA=M`3#tXq9Q8 z(++@iw}T$Igc}7%{J=RQfiEV3hIkNu4}hNFfrI9Qj9&p->^G=YoJiWxT)~Dx>mbCx zl^Tzxrk_Gv({s@^>3dO6&<7jRYv74H(P!vxv=iT!x&bXk`5-x;;E}>ma#R?a?nyS0 z56J{_|AqYv)Q)36`Wk*Oz|O_OOK21S0h)m7(wo!o0e6>xhTV#;M#Iqwc*}30hRe7P zRFN7@_N0e$OW}P#MdQ*>rwg!(=A{>*G3aIVq$HpjQqmeUY2qbT-NhHx4jfR^zq+cj zqHmwx<-K~AB};ph6er?EvBGGiAU`i03I_Z>ugC3jI!wFG&^1+&B~joxf>GI!*wDsE zOQNxbPsA>}tS8-%&42?lx*ce2iNK+u7hcm6X=Im0F1*r$E9d;%l~(3T>)e&tjMSpq zo@J3Cu}I62!Ldjio;q#{lI z(~!o&@VGsiIw&@1w%W4{?NK!-YEWwN#g^{DzKby{5Z{midkB&ZXjDruHh4%&AU2q` zpoNPMnK7$n?6@gI28W{2`krMic+kw))h#G?X^TC{EH7(+x7Kv38nNQya-4WSS z*0E`Gn~AP&OzN{@vt~@2(!$NCr*$}zQ19Rt-}NW_=Xc@Z&OuW)bUz#7HVyI5kI>ys zn>IvRwvU_A{cM!3>+9hea4(4uZQL{zs@@Dl95EpRwUOKEr?lYPpvnk+6Z%$}_nRFX zLXR{qh_ooNOJnmkEog+U32tgZ<5x%b27}hY^l=m%64^9yN-Ww^7mC%-7#!Z?Mw`a3 z-WRYUfeX*{EZbu`GKAe@vu6vs(Y-MH+&NZam($XS@#iRuX^Uc)14Fb#W=5bTQ)2K= z{po6Uf3#_4f4B_(>M`8aG7EZSev2}wag#ZK9;f%W2yrtO+4K(t91!dL=E5U0vPZkluypF8l2CSTaw9^(o)JI(je$lXye6fzp7{1$~F>aLGbxLH&rp7F7M@+n6FLS>CxpUc4i)+vnE<~~= z65`ldV9IIdE~YzE^cFr2|3t>rv)UvXxRM>gk)bVS<7Jt3y&8@FFK=o~pQLxO&H3B1 z&1@Nvyl{Wu1^X8?Pv68rgJBpPF>&gqP3i^bfYmY;UY^|m$D@f;qLD!@Xc9&$6MQ=r(N{8jB3w)VOIzTe|t`Sj3EN zI!F$YLz|WkY0NQBTe|&@P|MKG^+2n6cmN0mL6`1{;f>?=Sa{=vsZ$PuaTeJ)amrqT z$)Ltd>-QAFxhV%D2wChXp-1UKx)Y&0Xat6r+)HG3edwTtP%}Hrvjc2@W*bKAn4CL? z(abiIIcDaL5je(Yj#=y&{i8Z&(8MX-xrd2leNW&0lrJE(1UKa8ZMV6g~jv87|ebNK?2BRuBY$kUcxB3uMV;IfEml1Zp7eY(|d z&lU`W6@F~h_3RN{7ir;NmTDMKY7hrb^C!*IN%q%J+f{3R-hk?0Ti2&|g`>g|_1u4m z{7z{9@$b*WTW*Br)Iv*Wn~zvmDg88!Od6wXQMM~BN{8~Pa#E3yQlKnVnw4$YL&uf0 zq82D%qDnmB6p_0TBT*1}Rg~fa;--B0at-M>)M0)OPxQG=}t@M?kaMn`kYx1MzVPns~9K2rBGI%jmS65rti5I9mEC=l=jlG^$$gXHhpMp!_6*V_~KiL1l(&!6ns@=}^Pg_p2z{#7gd-Omg}=^P6S|<$L zRw#NL8y>s%tP4={{OCR%1fivH8IBbxx&2Wvy8U%ADPrb;ak=egK{{fzCo{7ic2e73~U4o zU~gYMQAxMfCHb++-UYb8TVWPSR#9nXfmA1rkvJ(rJ5%!0j+Mgnv678;tQ4jXl)Uu$ zQXs#w+MgV4p2`YIa#Yue(I#}-Y1VP0I#FF`S3@#+qOQ|fQw}Pksg?ZR`l(MqlseLP25%OW#1nBD)k+9|M5MrjL&|l?!9g1=B|&( zIKBVm+t=*ElYNi3;sVTp8CsJ1B=v(C+1)-5-?x6yyr-b|hC}a#q4!EqHR)-UDTY!S zFoLB$jMCB?qo1cbG@$hI(gvfUbb&Fyw6XUlV||YYy$=O<8J?21^p~ylor|Gh1!(E1 zz%wNW0xy*u4je7{o#*2cd9WAfQ*m=psyLZY2|8U@wWW_+lW3{HSKv>Ul~&g9HD#Cc zmz7PH>yvZj`N@^~2K^2F2jhpNqq@?Dd9%Ez($_cY_D}DzqzCB{F1OX$?zU~SrES7C z+iu%;HqNF~?QF~FEmk;Xc_oLQefkdX>yjvy>efGA|>qfh6MzAQZUeoiU`X+zV9V4t6!+WhddFHl@`s0sF z!e+^+^2-{p9COiipg3;>rSuwbv;)0i4J>zIlgBZ>k{`rR;OFowcu{f4imVtehhiX3 z##&f}p#-T)$rc&Qg%KBakwOPk=%7UYT^Z*_PBzdxx+!;&DR)0Nw`&}X*fllCd}D)c?O{suWw?Q9Xi(8UiIEtT^KFk^ zJiqSBt1iCu(t%gG^ZCS%rppFAT|BI=aaq^96!}nO^A+F;2g*aG*mV%`(4t{%VCRR% zCdcN)mMga^;{4#X!ct|qc8hR}CKh`Y&R<-b@6A&bmovY#v_}sV&dUeXSCF6YK(ap} z>h$Hsw)E##1!F-cV?mLzpv;($iMQxxEI2Wq(8Kf&U8UFQOd{!3dax`n|9_3Ge#~L3 zlR0da{C8|Mn(d4_$JCt}qy-CbbFJA`TT||!oQxSCGvx{h4A|7;7A3m2krI> z^}Ntte{l9yPgNAZ+&p(rV;^q3!#iix!cn_f< z)^Z9M$v|Tyt4L5}0TZG8<0IzBM;sLulq(!`I0#uqPs=kV-NLFUc zcs7wK$7>}uV`bbdZ;@diW6K~`NzHVE?hIU>PbYFcGS75KNUo~vVC0(!o4zKN1P}mc1 zey!_}(0=BF=B2Av@jZSVN@@NC(7X_6uA$!_L9(3eMQ}_9#e@b5TKnb$Pq~r zDL7!9-Io47qwuLBW&6i1KjU!BIJ}`5zyi@SOiU@K!bAUW+-zx#o#ib4`{#Ls!JA=f zJ!0U9G1h1_mKyxPdOxU#ZmNPB5Dl4K%Fh(&)z&nW!(kvvk{J}R#9;lzA@bv)LtUcK z-t`oj`r}ZtuWJ;vacufat`qcP5Kql=UZw3OJGN`sLSxZV&>6fltVw=AOW5X-WUAaG zHpECegE=OHJZx+@^6qPN!00p&H}s_oWzb=YjtjzrT!VZQToZhau14QO*LN;EmF!%`-rY%6O1aqp`uhY` z(@nsb^*OLs>7;-f)HQ?BZ1Cf1_vC%|!bhopF8k{C=l@u+J8;v~jn6!B>w>%RZN3+e z;ykQAhsnC#J3aJXf4A%a!H;=Kyb&e~3B4Il?={KTVjXj5iyc4c_to#lm7`mbuuu*gMOA z9rh@qU|h*f6eg-y>WjG9!fbVsuKL2f4x(M=-2?=2T}uiq-oH!DV8!p zn4nxOT&?i9p&rpoTxK=&AA-Sw_NI&V9}EW2mxG_U{a1g$-W&dU$ET^zgL^lu-@EU& z4SR_T7vHrq^{1{Qf4v#!W8>|&-u~^c-g* z7p_t6Qf@7J%Jpp7A5msbQL-=b ztAw|N!c>5hX!dxMiD-`7ld2Q)WEN6brRJk~=t9&q$@bFr%ydV|Y z!ay1ArGh|RU`$|oV0YkXK(q%60!sp)2Ka)&-2oDK1v=3KjLmE{%S|sgv4x3=kHKh# zO-!imw$JUY%-C=?M4Zc{Je9tSK`Eyp)*&5qf7JLhlMNlpJ6hH~>I>uT)eDx9$(u94p18v=(|tDHS>T z7*?QnK;i2H^rq4vt11fCV`JZrzND^ib6?Vz+MPv+)rm~Tu8|Ct$s|^w4WI=pKpPP$ zvNI8~v*y_&^fEggF(R~1yNy<8XEuzz@Kc2A&=}zKK%cB}+0Zm9i+Va?F=4Z8bQa_% zlTF<)Q8J^sU|ZMO#6W&S)3W3Vvx{vqNIwho2d%cO;-2|2!CjVcm`>AWa$=zo2_dCK z3Sprqtn%Hk8@0tks4!;eat}3xONtd$O!6UAVCGRDL(;4@YcnfMt1nHiTel9KYYo+y z%bFTo)!vMF6(@>&0ptQJA>)k5DNi5R625$r5ynK_Uiu58e9e&nC}*ZSBzy@kQZ<%VrP0DCUp%y?ov1VXI3Dl9$~u*FS#R z`07|V&!rYsT(V}`)NNNhM=?TC`g>9;Y(+kb5mey8SfWy49snpb2Vh*$4Ha|9Ybr^* zDtf_Ew3~&f5F5_8j?ba3EtQ(3EfSAFvu&4Jqz>trBuW%gP*@<*o@Z(kumv;! zBx+7D6-ouavdgPu zmsbO$$^m3T72detM_p+_=BM*951r3R3E(?tR{NM47TylFG+1`#D$1c1qj zCa;H(Av;2dy5LGn*P#X~8qq4&HO0_56%Jr{DiHl>nX6m#-c^r}F|}6Bam~1KcMWWP zxb?EdW2%;ud%O1C*=N|e33qQKHD^A8-dUXfLO3YAgW}j_1w-zThcp)Bt7I2;az#Zb z>hzH~%4ho3iZD=wMPI&+i{^_8#);y1QH0|nBvRZ+I6}P}lv4@iRN6gI_=qtmp*<9$ z_mgGK#ke>x5mB+qw5S?L%)Bz=?`jy;IVy`*8)`=ZT%}Hh9BQH-%yZhNCQGTod@K|W zh67D_TQ(rweG`X z|F8|?dlS2(S07k%+o9{C{WoB8&y6Q9CUwu@uH(y=AH-Mv{(Zc>b#B{FdoOJsHSX3i z8@C-!{i}IKHFki4eiXoJ7g!wz@}s?0*=)x`HyL4$a9?R&>E<;(-)^%ZpFf{je$Ir< zEM(cFTqvKTu^fy9G5ibqjsH(;Ics0&Isfv17|nt1MswC`ZfZE4^+e`uWoAzR!Kiu6 zv@VH89Z;tDrx>i^M@f%+M=iRy{@c_Wsg3xCmmh5y+2_{O?LxcFIs3rkmr`9_&vAJ3 zP1A1i7*uEM0IsCAmm7U(sR{cOev15t%zG&pdck0-&Us5cX28-7O^klbbz8?Ml?2`bnI#$CqT*TFX)nw2{9 z?r%~*E3`6*uPW-dFcueF(cL%D*%OxORPps zgJD;TyGLq6+@g{f$Sczl?y^{o*3Ug$8|t1cP0{9QKdS%m*m}jviZ6~`Ts*RPOWF1^ zsb92TkGis<+R*5b9uuPzd(4++MrZbDENd?NsQAn1x3TYv9X_w0Arr5pg9JLfO>fD)C=if3q`)DX>IMeGZ>^P1J3yNN~AGLpKPuuwdd!2m@ z7=p~hZVxg@RLCF^>+>uSVm@1YAX&B|S_!&2IXdTLZvw#6X?C60%MDFnFP}I~2gMWA z-+qE_S=Tjz(dMJ*g1IJ(K?PIgK;3LGKxWWJcj!N7x7K&iinSa4HoUUs4=1nr?VT@Q z|J3Y1Z2$S!Tc29HX6N(Qui7~!I4<6I*3{~jJ8}g(PjxhPUNK1qiM0)74yuO~kd6(ubjckd?1AGHQ z!+pa;_41YaG~cw)0(qf6-(2il80v_; zSz$TF%sQ3YpD`vjE3m7AR5;@Zbzr;&Z^te8B<2fn9Ug-@OglS|as@W&BQcX=%pfmj z>IzfAWac`(l#Rcb`4O>`8Sa6CVby-zT^L!!5e60jJzeJyQ8m`d{HRXmt%fdMhMHVi z=P7mb5!$K64z63bZg^tAz4JC6TX5~CH%z^|m*c6GtDb#&#qvF=`NAuk#*N#Ye&F%c znL9=f=sLqaapdq@@4fZr2f5fK&2@F-83&OU@FGAVjw&W*oyPepZV1ke59}lrgAQVnMEl!DMzmhLaO|D6LVMTu_clE7aMyIQW5W#-?poXR61-D&`U`Fb^MUWO%-LkFxPn|O zZZtMJM1|p?R*kY)8xC3;pKn)`gsRF3Ef+sx1r|J}0dN*S&PBZF5sSGVw1$WaM_iU` ztgF$*yKn+!EJQ}XuX982AG1U72AGF(Jj}8nM4pXN)oG`Fe4RRIjY%R|{K} z*TmoP?~5nIucUv9Kgb@ZstO#(698k1BEya%%W+9`OOnX(d|Xi7f}pAj>`%YR|A`O_eR)ePqc#Yrr z^o|TR$PLC6dxQ6?-~xG(G0%RD_nKfw!H4=szK;Tbc75afCh(WM;|1x0Ktw3Fm%Dol zb#_Y_X&)=h5kAWM2mhm~n;si45)`5Xp6Y=C&tG&*gYm}F8ntGPFJJ?m#-hcVKP%y< za}s_sC*hev4hqMa7_+pIa+W5t0y`?QN->kSQNhIt`R^lNDwmOv8v^xiL!k45A@E=S zJ_P#N5a`Yff%(I#FMy-xhrnd=-v>cD2G+57*ZEN}8p~)=fb=Gc6&7=D-}x~R_k6l_ z*`BL+H(9CgUwL^Usho7r%IBWEcI9)RSpRYNn7iLxp878J{v-JQS0~+ZL1V;f{iLh4)+^2R?Is z=Kjw2*T8427rg}q$sq0e5kblaV3QRYy}ScRl`(=0F^0M?4_~29Hs%_iiC=hs#HVZ~ z_HZ`Mv_tP|k^@2aa+<#aqqxH!H_c-XY&tAQqodgY-ORj^tg{^qq&m)lR0jj84%Yb& zW?s-faM)-EIC3D>L5I~#S<=c1XVI(DQR!1DE%CVwko;~LAo-av33GpE^e@AwGy`O8 z_Y4pKr~igb0jkzAzX2T&YtQ!?^-X8J0#(^y0+qaOxP|LK`|wTgUAy4jTN>{#-`5p+ z?%I`4?z~~uj`fdjKJ)lC%xxNX39at`>{DN@~lg7o8fKJLDY?z)*E63#!b{Y-S3yjwN)#a`4EJBV7HFBWIsJLiyn; zZXdah<BS{knV*S^Adr9g>TnCMZdiK-+Z9wR{zwQoVea~wgET&voZW`!_kjmNN8 zDxYAEuO-+5t%w79)6*I9)s6xn(Z!6`tgh{BQ0HHh4$xD1D@}i18tZCcJxZ& z9h8UO**}vk$fE!z14by~u%^>e1obs$f+@EmuNmE%w*@^YJj*?49OPP!UmM5JiM+q( zIc&~6M_wLRDwa4(!;ykv#$@*up2>lE!os{8oOd`M)U%`p#1Hc!SH8}L@_EHf*oUJ;1Y;a5@FgNLmKizZK>o~W=iEW;oxw6= zP9TRb(_szN1cPyf<~Vit&17A_#N&2Se&<^cU6lIeXPv1J9@>ou9r`0K8~AF)p`Yyf z%e2LxuYdf{g!K9D%rEdYzxxbN+H?G^p4;zzEcM+zFQvZP^fK-5C|K9u0?!BWKeKVq zJk@RIG%g&lJ4H=&Sx&GuEj?mqkpg?5JQ@5r=syw+m~_JuGni96w9g*Kb{YU#9Ih#G zPqyz?Im@u@#2zW>U1`#lq$^IZ;dd5m#d@*PPw!_`*|s{g5@(6)GH<=J-c|3J@0{NQ+wHb$(as@ z-agoVD;URtbIs2rjyP)?vXTC3yInUOPN#~vfZOGYJ5@LA*mb)@k87%1(^MBt#L`6i z02DUEq&)m;n1tI%-F`dJ!g9BfiI!I9w47wR^HnEtw&6<;*l{5m5>n|YMlCC%_twYg z+*m!W6CJMDS8fN|kh<1TWDTGtAYNA!D374O6N;UF^VErec>Mb|gE2bR@d=5r(jEw%X2$H~Hi z7-i!LeZy=HP{YVIzxq$sq|p2wGTZM}Bgnw4bXnb&t;T0epERXeOUpd+A5LHmj;YMna6Gi&AMI7YGvl^r|F(_O$U+AjL(@?;ufXie*LNs92t8> z-V=b$ihJ+Q(KZMG1+D~m~-vhR$2hX{jF6(OS+Su z7VJ8wAWURMvmsd_swOfk$;<+%9}h49Wui=IE|VgaQARdN z2j$MvF={g}(~x-^_Lqrvg{+$pvCD1}lKGYTdi`}ErGB}7xt;65$Bi=E6z)oXrLoGk z!H_i~$Tdbk+ZZx}8!TD!DC1I_`T*I=-7noQ@8q7AL?^M^Y`p~nHW85lZ1fgnD9ZYH z`*<2kB{H3xtQm&QX3~CYbT)$wx09X7zG!&*DMqz!9uhO}YL zQtU9^*_WEwY$KCjj0lZFv%m>$WamBy^@q|7pHmIBei)6JU_&{0Zs$Y;2z6a86YAVA zXm)l|0pGBe<^F77DQ%hTpL~$&S3s)I01v*8Nc#P3%8w4`N?6K;k^a{nn@W!|VK>t6 z9*EZ1%Az#}*g_!pw!YP@xW6YH?U}P~mNhZ!sG+_dhSW@sP}C7~fXU)`02kpadwT;_ zcsdqdN=@FKnj*BH`Tm~E#y-TI{c$M&)|o2)_!&Cp-vVM<&GPa8azJ3o_yUbgSNE@E z+sdlUws)V*HiL9JthmPqY*ip^6FwFAF|ax*a0S9rAYxho>_g=`<9MM@Vh$KjMOEcC zggeklz)=4!&+x~L;c!6`Im^&TayHd4lb#QSbPj%G^YqbZ{z8uoi})rpsrt+Vx-4^; zT6MRy3hkMEscGpi_`d?y=uJFU@l0+eznohEW_WQGR}&t@T`rBx8&WX1XlU^Su3nm! zcSXtVE?bNSin58anL<2QNaPB|xk8K~sLaKgLOfSUq$2F9eN{mDiDdLLb{p^*o z!SNyGQzMgOlj4iC1;#?#9QSPhYVCUCdiz@Q+M?z0_1q@yc4L$MPV=^+TjKW`_uKFH zI4*bvYAY};BINf} z^7FkMLoP`=(q@8J4cS50S5w}Z`Gu^W@gkd{3DIy~en^%?o+BcT7Zt)W0GgqmL5ud` z-9a4e^rD^&O)=eS;s_p#8}U-GAVu7UTP#;kS|zO-T0C4ypdPpfbtq9z=s}xi(EEA> z`@%cngp-C!=qYCon>wk+v(syw6Dd0f`eZ|M06dxZsgq?)o`+;+R|880NS>l^1OSbt z{X(&x)%k?^sAxo}s5rrrfd4II&-++zB@D4eiD@qy(_de^q_JK*Batnx?!9wcWnRvl)( z9mxPk6`U~v6^7!egA~@x@KabiDjPI{1$pNGIvw?&|1s4k|39YsWXcWa(@>d@vmY1A z1cG^)7X$vFpNN{OtA@&n9KCjc` zCN>g_M=7v57n{RBJUjKq`W4GZUw_Y$+fsXQ%{@={88Yf;i$*`6dRu7s7IB zS+P_crr~$F*ffk&tqun(d}}FGxf%IxA)neeK6*iZK0TWsw!xWvW@hKNk(Vr;s6Jn$ zz;qB2DWHMocaPBZ5mZidU6L&0?I5oYyFqnD5jzH(b`yLR=2keZpJ-dC&$3|O&Di7@K+YrCq`w@*yx>V0SD!+WD~qB~{$mqb;E|d1E#^-~EINMy zip@N;Rg478Fj)P2NkscObeS4UR?-oiMp2|JRvL1vP&<6Ku)kJ5p<#bsy`$`g)hi97~`}Od1y}PPj}K zx;CL3C2`WicebzGyW-LX@9cPY^*sl7ty!~c*Ntn2H;{KQk1u*|`o2{9qf{#O%jX|> z5kHdp*>@-LJiOrB`Rh@(?*dfHQ7L{Qo0P5<_^F%DpV6)2B!4dN&`;eZC6vH^2a{?C zqqf8EC`)Q3`F2}@ZH$ex+1zL>#%$0uOwa?E&kq}gl-`pWK|9bj`UiwE4^35=5UL= zi-U7x*9X_;Zw}s(|DbnQ@a5pw-p?baBd&|Qk9wc?asztI5=n78FiVVPm`5XGq$Gcg zZMu!vY++g@erGJrFemd`X(I~SaShTym>qt`2k<(6(@*?c$^bX?Z$&o|J!5FeMH`Ra>c5>yVk7TfhU;PUo-Ni-!IkulNVz7_n%_( z!PH+;->1Gv?R()>uJWM+hacX&dp8{!ic|A(D;tCAEFUil=z}L9U-u9-2xm;r}-H;AmBaBUTl~t*PZ7eu(c(&A(49W}}ZCA?|N{0<_^Dvl_)? z$C}6!MI@r3A~ov+Do;|kN*(i4g91>V+TJ!l;@(q!Yy83d zOm*hGJDQH14!hrgp-rS3%|=Uh5fKBaDiN7|Nx2QMK*rBAM-({;Mq@0BiokQ6X1AL# zI$^urFf~vP#Lzh1R7E?ntLAIyHHDaQq_`1MIAXkJU?Z+`Ze8b8Md1LZf|}EHq>gc7 z=jFzYdZB8cAu2aoY8wu{Xo+LRW|0%y$RNuW;cg^_V}O>IJJuY|jvc{3S3_6O-)VjZ zBM6)2oQa0zygLn9>#rf}+^MnKH^_%K*v!M3HEbm2@2Sl?c3N%zyc&(tTg$7_3w<>l zEOdWww8muFJ)Rm|7_CvPa7_-F*0ag1EM8TCafOc>e$_Nm#T8>azBRS=PmlKsm&Nye zkh%xo@$p9kQeTl0ocdu{?@KGrr1Y-e;NkVDhD>B%Oz;<@82&XiIZx$02&Zym!|$z8 zno$|&Pw*#{Klwh32=57}Bg7|1Vv0W$0cytb!=i^Kt4LUkfnls3i{mZv?Qs(K`GU6i z78tU57LQ=e=3qIHEFR%z8i?T?iZ~pEMI~6KyMs+Cbma279628Z4E_z4?vHN?;ShUV z=-lH%>~SGFm^tXcGL)OG7^2VfB2p2H<6{WZ*%ySS){g;8 znBJ53ACXfw^ALHnuIO&_-`p%gAY+JTa`pp7@ix3_UvyaajGbI0tLsGf^p4K%fv&F6 zLuL>DylELQR&8xvT_*hM@O950wCQeF!mT?(*lBoj=>yqGw7J=Hz!4OfberPbEuCOT z-=`L={8_<`Z$A3WzSy*jm;SVM%B+#=2JngdMo+(bO8f2uUB%>)Mbih|_e9sv$lg_} z#y)sY*N0T6lz>io7j%jZ@3stQ8+k(}PTbe&qw(|KSPB&I#rZ6ne#jaQg&w3tDK~3y zje0pAN`}gpD`U)Qcp{l7PgTa6i||Y`Q(mClfLF*jD0kr7 zlkx{xqEhgp>8T`T&Kls!cdeMS29p7bN@P`yW8%h`V8bShWCm5GqB_Gs8N5q7%1GK& z(uVD=vMdSWOXNy~0Cb+RST9P2#&#PIL|(_j0m$?{!^Q-Jm=~ z``HD+rdfCg`LJQ-yA^B?lm~hTtiaO1L;AzUE<+9)B}Pl2Bftl!hAIgbROZPBr`y9S z_K>98#d9K3x4E%9?Xq}ZoJSnF7iXM7eX`D=WVoPm3&H`5%~`MvDr;_Lk(MxITgarZ zENhW|pN&4bv$FSfPWC=$0E^nJFEZ(S+#h%ux1%UJja3Alblx9CXQflz4}An8)!9IU zQnkzisBvTj%MDmdkwjo5(Nvrv1d1qxY3}m6b(nVAGCI^&R8>}=pP%aS(A@I9+qSua zx2zmFE!4m7_`yeyau059T39*s3g;v0(8jAbpPfU$?UDXM_*i%s*-!|*X^joqvDy_vm9ewV|-R{iZDgF!kpxo?wabG?w=gIB6Npu zD=`E49Oul}6i*@|VU{zW&Ak6MmuG)6muLTVZnn~?+-#*Et!O4~q&W}g*%Q>t6}!28 z1L0geD-+Oa$Qk^jEv9L}yX0>de&rN&>_|Gx0{;?=3v^+1Av7SC6LJ zcfOAEKKKI;t^Vqs-=sbuZ{o%Hkwd8`|M+QY`~KJQ)SsvRnL3IqacCdbev4u$20G_@#H!cAjW3KS$-Gpj`-%oeTK<64C>=?cYzi zxi{G1?F?<*ZW#i}=Q$es6a`*sBg^-(PoQA@q8P!XoWmTH_v7qL$1mwDcj^hqI!M0H z`9=Pm^OT&;IY@GjNqC}sU~6|5iFt}fJx?@zZZhbW!EI3o6~?H8xKerirc_8Uo`3$w zzh}SGB8;aQPB>-dbA{D4vNE7ptrGjG!_+Id_1p)Xv{L<$`%vX*l9R>UJ0-$qev|MF z|FtZrJg(y3=V_GrIOvpUB^RM9&=~vl8YewU)0*V$mZ#f1w(Z#G^wQ&>SQiDL&UpMH zSqTI#qIpWHBC7(&^N~z;k|N8IOvaL`B7yLjNScgfl_LPg_%<@YviBD7cA-V+5RMDH zFkGg`wB8bqNX=4<#7S*ry`^iB|JOOu-{+iA`oNtG5NF5FE;`+x&SL}u*Vbl6PFMi( zQ`KwB#oK6}k|dh|z3_+@|AY}OA?A7K)4%UupMj=y=j1-!LFskU@zY+ zq?(3VnVr^Ce?Im>6O0@R;AXijP{Y%uFjOM|Ef091=*_@s%~>NCx@&mLT|>#dKMqAt zO*i$#=Hua}WeqHtmq|a0V)!RH?mt9+kEO1yWvIB!C)V(Bl!o5{MAc+Hozu4Q0f#DS5$M5}FbKB0%9x zZf<%s<^Ue6>esKjf}Cl+`*ZmU{)UU!6udC(&FR#_4ubrebRIb}aKh^6oTAUu zAJlj0Z|K5EZlv*3o^xU%BOQzcLDe`3>0nyF$?0yM5k+WpFr4<$)dB{?YU^L0Yki# zMSLu+0&IewH5{LpSDQiqh@t_@ty@}+-aNKOw-R7EgkhTv4AoQhf-Bg(C(eP%{av?` zM}G3!Yptm&JpD=Tz}ewXrgjjX+}E`bk#rYmoO-4oZFuehY_pr$*)Z8c27R;HF!kr- zj+u{}l$*WHx$-=v(cH*wG2akg6Fbb4rX~yZcrqDl&eK}Vzw3WD{%%uvoi}(Jr>S7V z@j8WTlB7df7Ig_Dbk2#7B9aceMJF6bk9kaF>!V2y#9%&z4#WlJ&1Ff(dEI z8p2q!oO%S!mbmd_`J?=&JhvsI*)46X-XVReb6a$*(|yw}9hJyUpo@s~6Z`ugWO9E3 zu)sgC>{x)W6Zz|EgPnCJYH9SD#r1NN`jc4)A^m{G2C(RChe5w&w$OX$1AeW%os*^Z z^huf^l$qqetSLJ=H-;;~T8nb7D3>S}C5}}5mQ4Bh*{+9ne2D+Hb!cI@f<~zD%c;R+ zD!%{Vb$8xD$A%!y#0LDW;;*wdy-$#lDvMY=_d$gsD!@W{vio-x*k=`9tP(IPbkwL+ z85xcm#p?`L%5()?`}IE9;_OzXhMz*wX9=uW?z>VLuS8y0!QMyKjU~M*Q3O_Yy$32$ z5^4>qQZGZp)XC86_3{*D4xU5i%k!00=sJ8ISuL+pu2VPQ4P-rcyR=c>q&$KiQ0`Hm zLyxJipckb*>Ko`+>PP53^&9jT^$a?tmci?&e&kh4P(rO%#~=&X#)1J#0I{pgdDH3F zBt-f_6Uv%)CaQ>e)hI3KF_uzKsltvDLC`ho!2UQ1w1MSF@<~E(*`%^_9s@_sg~4JPeae1u=KNpg>kqj^4*WuD(a%rB3;fA%4yLZ*6J58? zT{3Yc*_ippmzIB6CjLxY*m{D@h__HL_gu&Kp>aA?U9(K9DHT5Xw+ zrFB^4wB)eZzUtsGC|C)oZ3k)?I*X9#pjvp9cc@ugJ~P47L0!;C%=eF&@3Q0v_FWJ5 zNu6v|ElINkymmJ(<$I`PxZ_I4U7)2R8CA;^DVywkJogc;la^8ttu(`Vnfz?)#e$+r zUepzr7*YaGfk(WkDVj}on#jeurLY{*@@z#YE|tnjTP3QJ2FL?#gSla%C5@6tXoKv- z9K)Sg+Q&N=O0(p-&eh`e(hB*Y*ls`I{D*i(DbXAysKh9?mDr1&HE$`}V;;<(8{ zC&x_!_$}Z@mQ%oia6P>rpLU&|!wi$as8bCMen5Wkj|y3X|MLrcarBpo>M*Huu=R#f z-39K#4R9s(&r#IM)(No-#tIfmVWnuvj&yHLeuA66bjVmd``(seh$kOp$diR6PJ%Fl^9pd z;Ss5q+IQ9Q6}t{@tGejG?o{hbyLx;83g)2`jyK6QT@Soef5m~eU>`~A(Yf|G# zqwo$g(QHdEAtfeJR1+gGFL1>^bsL9a+lsbvSJ|i$n*BmqCPT`W`8pmed}G;FmCpJv zuo2sH&PO(%`~`!`Mf-I=bBzD<3flA)E8)1UKRz{E*hpB*i=fS(1({b9s{D@m&LaF3X3*mZlp zs`l{Yhxz;-VWEc+Gjx9dUMa#ne-SCcCcD7piE^#54k zB@Fdq8tkN>2z?3D&*B@n3Jf3*?{6nhpa7X?6+}Y@%^f{kbn1&^TK4`HbysWc1uOr%UNVij4-nM?h z{LSvx=+`f-dUN5NSvPM#l&o4i^X6M`jqLyR+`Y4=Kin(- zmAg7p|M(mTV{tRdd%%BwwB8!7VNDI;kjkryPXCt*Nz^d$)30kwi05RV(*R3Vpx@hO zpW8Nc%?A-G8GOK;qSUY22QP%ZV|Zmvx3HUZI%X&7*tTukw#|-h+qP}n=#HHg z+qQGk&we+~{@!!GA9GcW8l%RjTC=LIYt1#Q?yv8tl=4C~tJdARV?5|`d(FZ2)M@S> zm0F!yZ~W?mQuR)Igx5#)6Xz9tsuI3oK%3cJ`*oZW&Mrbl#x}F-D2n>={sP^{cSF`N zUVfWAF^2Ro7U&%!tna`u(AuJV1j%_8sNLkyyl^5o&XGSeR=hL^ZZC1HApy_HF|Pee)6Q^hn&-W9Zgp=^ZptL0dMTPEdHI%D11 zq0QPEL~YG}CRnZcoaxQ9g^O*q6!o0TJEYzR^Fi~+3fG9ELzr8FTg&f^-aS+>5C^G? zO+>ry$ck9(O>o3HpBn2=AHxTK=(KmP4%T_+7$goo;5wc<{);5!dcRDoquA{R=w%#^ z6;SL!Zv-Swj<@=pf&CBE7n{ZCqu8p9K327HB@3X!x z!;{WE+o>WI8Of}#Ee@9ekIaWPL%mb)-`$%|Is5wPuZOeu%EY>Y46oI4*~gWMB=!S@ z7K3;e(@(lam!DI(sdL~u0I!YVw#s)!()iC0mSNSPJ&l!Md+aBPtRnz>zd)Q4NdC3+!yl-|3RsjBjH}sQjH~fDY1UK; zFRiq+ybbr@jBv3E1C@~wnt|)zMudUD*Q1&XPzF;PXg$2bWeEDv{Q@)*NR7C_8x`LG zlP@Go>YE1~r;SOFtaUJYcW9s9UaUR@k@p@MeQVaGCAb7Urc_3=SY=a33xZT_aYhU^ z02nmP_6Z8z>h=70ArCFiGQawP`AUp(85Prt*9G2+_~I2J4n~pkpTd2^mQ&?SlAI*- zH&*rI9CXw|Wyz|qmLP%l-O;4;*6jn?8ElG@q@)dZRwsZb-g7TEPpqM&U&@b}=^l>b zM^{p(%~a~~#_IJ(hEZ0(Mab$Si805nnK7CQ>qHrE?nVXp_`t@!(7JW$^no!+ae+|+ zsD2P)-Y|xVciIUEeDi}P!tx{LTZ}yufCwq_x^FiT;lVq*cpP~Qq3$VPQm!f2>3Tdl zIw?K$#n7M)WSX1mE_9c|}FTeK_^wqC}%d~OxY z|DXZ8^@{bekUwjJ39LXC*E(8Sy{&ED`zdzRS!ajx53<>P)Rb`AP` z#lYZnJ$H9G|I$ZU!sF9@THKNSvYqG>-c-av_6bGi1J|~;)Z8y(%4r>K;m7XY@>@gu z=sRfvTR`G?n&AVAL|L*x14wa)&T*YpNr7C3dXBal(V``8hN714-Et=T*Uy!2kjZf6 zoWD_4`3*qIitCCGJ%Tkkv{sdVw+Ei>iD3eC)-wY ze^NG;-ZFHM{CTx+7$nX72+;O=ocqX7fs}grDfddY=zXYv)W@6Z>z*Q2&XWNp&36ua z=3t49R}G+15GWI-7GrY>uXH)`TK7%!h9r;@2~K{*LOHRTmyzHc8HrQnbN#h`jE z(VY2(LRxh7psw(1uqf8%=l3pU-)d$b;D>fAc$C#}buFbpewvuA@lk|)Q;0sZ&3YL? z;ldQM|Mac4{z8=EF7)Ck>az4>)7Qb}^`q7OE4ZDWm1Y3{*E96@N7;3+-Ezj^twS7PJEBt}S?{t(^ zBRIq2-lvv}X3$L$Ot(!-=1nvpol@pZ{vsI?r9(ua<|a{sma`3<6Ve=B(F4tx2ShZg z$p9;IDRF>xzK&u***Z~u0eH7Y=Y=MBxbJ!(WRFA!muoT-Z*B&RYdBJfsiKL+iXUT- zz^2!?$?UYV0=HVhSJhX2?At?KTh>w!_A0QBs!_cV_2ijy)tXy<+)Q=L;*-pn ztSuA5O($8Y`@;oSOUvxk&DIj(+l?BZ_v8J|y5_Yqz}0iN>8g9GaojO4q?4XH!LeTQ z{feswHmCi5!tBXIs1m|scua(UYe4O*K(CT7jj(45#AQF{&;YORjNJ|cYscLI;r+1m zeY12kK%nc1JPUi-%k^=-UFy8YCzv&w3rKqjcsd|sZ-&;hZQ81=fyA_{Wr=QU0nLtn z)wgy_m~@U2H?oI+vO zZ)4I6<WwY(jCT4?^edf@yZN0ihUcXThVT&_AWD4Ti zWs0M77j}x+9;MKy*JtLZ7JK;79s=ZKx_S276zTbFZX7)X==pG9yk-6O+%8)QnX#dW zHmFSL!bHkSAc-lB|Fzvzioq4&#OlF4q#?U&ZT9?a=#g1h#UzW6wqX)d?|y$Ca61ds z2^2<4rOimw=VaWfa64q5ht>|?c?E82-v$rC%KaKKCeu01;xWNm%=>bkensrypt)HH zf7WifpM5E#Y!TD=IX2owJ3&FE#?I7~HQDiy97OV7hHvM6J{taUnrdBxN@_-*4NZMh zgj6NggbN|GMn1Ey_gmBHERgi>{cI?_oRodRFq1WLcU$^!1XtFpm&XDzf3uG&x%-5Y z0$(^9(KN0jdYtu^Q%vx5J6GKzNNb9W!F8LaUM zz{WC{S7q27y+{wJEkfOXdbe*BfXQ3LnWNXK_T;Dj#!qtbL1pVPW0# z&jtp0m(R(~ZVjptwNzg9qt9G+4&!5%q2hK)vA0g8OOf=ul*e8~F!$z%gWuCiS!J2e z=Tt@x0`99-o5?P9eCN*XrGQTh&Wjl1T@6mWX!X7FTD+4(^Dp7Wp8x@uR}X zWU3}@u9%8gj9m(yjlMR%0yMb_vQeFSoVp7e?%BAvr^A3!F2inuk~{=3KAp$>6K$0asYv z)OK*2!G~AY=x@VgGKFFO7chXS7|F^2u48L2zECcJQga4nt?^_Vli4@Xpgxkf)Zr zp<4Bz%W&tlP+cPJemw;Eu6>d)5KqG~bjCu}Zyv);(`IPEq0wsWc`K2Ahzs&G`}_`V zE9&p=4yvFkepjzGD!m9^F!H51SJ<6znLVU3r=$@!~| z=VLFf%tG^KGs8>Qdy4KuXz@UMQ+<{FZ}1*?tF)IrR@SV}_~u#4qXAy`qY>RV{ar%s zgvZVIr(LVbVV8~$F`hEy(DEhHaiUel=q1{sVkpZ$V_9uDS%LIQ>2;RPks~BGWEd8IexCQ z1>TJZkw;1*8^c|O%}=ZzIy}%wfVO@vl+kcw@;N(}tY~KGMcU_P1yM>i5W8O4aA*cI zaS=%o$r;XrM~bFli5Kb{YWE-#lVzLm^bo3)HX9Pw8BL}obm#PHW?j>^g?s1`S;Z{3 zGfuwf#33&6a=i_$ve2}`5+Mepn2c1vD6f6T;KHN=5sOUZ7taTUp@W28ob4=tNeg7N zxcf*RMGM0)3oE48E~tdN!IEb?t+v=EH*K3G&dQwViT|>=PD_*;yZ5!wo5S~xiDawG zlYCb^8SZaLx`)IF47W7wcE#+oRRMV}(LA>w&3>o0Sud-X-mLd6ob5HMi#?~q8{L>E zn$9j~o=3e4s$RO|G;JQI-Ksj9OC2SJX8_FXY?4GChu0W0)6b?QD>yBmbJRKOj#XT& zu9qLpAA%P_=sX=BBVs*H)8^q{aGGBkj8E3GZ7_@w`DDki=I&jw$q{U zG9^(p{bopyv=$2qTXaMB#@lvhQSo6C#mdFh#r$)n;+Fo9G455Vpir;w4JH#Qlj({m zP7|Fq@tefMtdUokSJy4#db9a`;*y>N@oewI2_~XV{0t2hNz27V4?#)il&nw5yWHX- z$xG;-$`l&PB_Zex9-ADAkY-8Y_0yjB)Z>Y|B`w9kh4qIqa7EuZB!x|Z(#kllBpIa7lR_6m!2970n^1#(gXqxwt0=qndaBe#*I|CDH8*dVNc z@{clAoQC3BTfLgmONnmibfzkK4$4T6S5O&MguppHE9BC7^}PRZf1Q6wxSI?~{hU@p z`*S_8MlSg3Wq=>RbJ~D{c3mbyXBL?sRJ(8^;b#$P5^y?qttWEwu)q#qt$t}Ct!q`6m1OapEr>H)^ z#^!%7Vyx<4pL}-8-vazJySeu>Up#LXK<>QU-*n#475lwk1Fc-za@MRg-|FyJeS2)$ zKdW}wuXQ<$EfHSm&m(*>o^3r0Io{*Tl8n@Ez~!f&0H+Ha5VK@^H13&eKp*!&RY0ha zF|pcbj}}dqzqNrx&h2ivVeu>Qsv+ONLMegXFtoAJeV<y8!^%Jqj*Q#G26eVt`#~!Q8Rr8a_`3 zA1aZt0&%ejcqc`Q=6Yb`Np?8DAWs|d^KgXreCuBfZwQ4aTAaN3w(_1XDy~!@)dTsA zWxUVGu`RCvF4uQ-bbb7;=2D8(m0h{C31w0ddk=*Atr6IfZ>=kK1l2-kJY9@qd_=cU z7Rn`TF1>a4Z&PJMb-glx`9TtUii1?aR@#eVBDtAa zJBOZkcPCPF-R;6F4cF9*^fU!vyZ>gkSb-CF!aO*+&b zFHGDr(dIdsBPm^UnXIkk>;&j?sB!>5z#*fh_3;P8y-ytYJ{m=I*I--}bMt zq$!iP=+<=z*X*^Zj|CvTD)Xm`tHw4>qfn7sZFT_Zj}0Z2clGs13o623K@nXp4TUhL_& zV?1W2I%pMs4AkcxsWJ+%w(f7PsgH8VM6B|{83E02S^A|#^z#9ltr|ETVWer$YID*K zd)g;r*L~KyCwUhv-ohtjS7g@eGjW&Pf3q%dmxO`ViFRbd$ou3Lt0nYwPAFPayv>sE zmjJWWiAgFJoz@uB&PqTl+(1uEE6xBZ0xO<3j2+=z+$m^uK=fMA0o&2&JH-gU=*1%& z9LFE6KD%l8gCQ(%Y-2F?FB$7gPiFb!ORw(zWncd>ZZ{qG2=pb#NA2bknuqS@7VIDn zDynsbyWraxIFWaQ*f9q4`nLYGW0vKtki6C(R0MWG!4>6#HTMp2w!8VNP6 zZ)_mn0YsWK|5>FHVO))9MZH!SgpTb-xn>V#CFDtIiUeT8u;P7UjntdinzX9JZU(b0 z8b8n-6A>E4juxW2hXOqzx}oJJ+!1bw5D>v2>?$GN&Hq3H2A{bXbVVR1f`H_IvF}Z% zTl?%8FC*wn6XL)l5ei0Rf(mT%tx0B$neWpjP8+MEfUyol#=lY(Oy}9c4=z&?^oHU~ zJOgS0FU?1|1eZXW12+!bB6mk=xo0FRVl+F=b1`722*Vf$hojh*C1}7e!Mj2aLIcf3 zwWmspTS_UCQfTzUikFSa6H4oJ$J+-=?t$%BoBVW8mqhquf&5*@VDv{q)c2`Kl3@pJ z5ck+o3Mtw+0;(F=HD|I8RO1V9_hgx1t+d1tdg8IFH!QBQmngor$P)fs>}LfE^z-l; zSVC2=F#CWti^F^!g2D`kE=0qZ8T+?hX?6ccvf=MD0-U|r0@cdgrHhRSR%Yn-h=SxJ z`zW9~MEQE$KL?G*qkeaTQ%3+a(8kiuX@Rp-aNP{a!RbVYU3e3Dec8)rQ(`T7lTo); zZqSK63kjxX+x@v? z?^PUibN5tLHVqGFg=~#_QXaHK=K>Wx}oIj2m2jtPTxrkNsfSfw{+m2%OS%gsrt= z0ry*HBc@%UN>BhD%=JB>vkso7t8bmSq@v^{zd5V{CA#=LfsQlU zs}#zmsJM_DdL?X`LZto++sO4A_)IWZ?PlbyO0=O4%+85ERh6$NK$l%%;!J<6&IJP~ z+}lbLzZVP$x**udQ(@Gk5m?Y*yyS=Zmo*Rs9h#bo| zD)2{4v<(=1>@9{>Enq@^#4@fL;QeRMrPR&`85X3cB*R)XNtJSmC^_?!E`U)YREKYX+V_E z#BY6>v0Tf=VIt6N@^Ds;e(}Unyo~z>pkn9z`?@>o-oQIE;3aP!A*H$hHI|k#L)-^8 zkmwZ<*WieMt3Eu=p0eWc8dt!dXcar<*d0AdY!k7K?xoqOwU}_1TNuD75_c5IZm;go z!7*TyVECvi8E*GAghtLO>@~axN@GT|ZL`BY~eZIdV`TGTzYdW;8^1_qNkP75t ztcr{}WZf-Zar$o46`V>$nZ@WgS5&=T`_IcLr_b9sdK^`|;5)=!{ln4RwNv=f*#QO9 z9;znc{y4Pn;$s9eePZ*t&?5b_dSr4m%+H1&K72}j3<(?rdH5*#V$}L#tTolu_B3qD z`wE6+L{)GP_an&WO_ifF*!Hr9Oh@ol$*;izA7)&u?l6h2X73v8<+a}qQdCtW8dm-N z%!I=3h9zPxOo+f5o$?=J=h5#UM?pT0SjcBzle8q|+h|J%_e$3YK?f9I#FiYzD&FYJ z#7?XdRy;h$h<#c`;|0UH*5Hly!!mQb@qjoW)hj*01@g}&9QwkDluD?((#zq29w~>`%$cO0x6eGTuSKsQT`nK@n?B@@h}wGq-VJ|gE>`SM;%`HB zP|x_Ed3-&{d+K$6;De0K+0af!>0yKjxT%;2{Lazn5P|Y2u4|WTv7$kZbK!s(kg>^A z>{Cg3OH1&h%&wtAs<++d{e?xW)+5sn!6Qf&WEF7#Ym#`ut zno9iMpcIruAPVlUUl=OV%-`(2#Y^`cv<&JD^5vC)%DWZUh~|DQk3UvS=mh#AHV#O7 zgEoi{Yt|R09vU2k?*bPqkw0?V7bd852aZ8s{H91Q4VayYfPWpiHVa|Q5D!h@df1gv z!PN~|Y=&A=5GoZ}LUDsoGGq{)#$}ofdAHZz}e1J34pR}fax{Q6bSpIV836)ltR_Yt| zm30k8UPbfWS}!7F^#@7V6AHWG3lkI86O^3Pw(4DEJorP zpD~%FI>9kI#Pi!RBseO;4f0KO;f)aKN(II7po_~5g*oP8)NWklp&7wiiR21Tl*-j1 znnJ;__y z!u1RnUiU+9E+k<(rq=r}QY0u^{T9`0>S9vBGQ=l?a7B275>897_e) z^KxgW{`hq&*}?nfef!KU@B1OntV5GG2QA>%ct=7x;$CwuSnof?*Mk~cpsy1^c8D34 z^f4+|3cfNOoy%3}tZJ&9Gvh~Md<5(sudS6I-HYN}>8GYJQfc5l>2%rFAe@W@>DqCK z&d>g##!aX;HviPJ3TsvNZ?iIb7opxXGu!q3l#QVM8ez+8~48l;5(j5tnu#eL9YFklCM zr~oKrh;XOiFy(HF_Bi2I^5s8rIl8mFJ%v8r;-7EvAJ4?^|4Z@txgGyuZu=p=7ISwP z?r|H*bYpJ$t(D@6*e!Uv-;~ReE8Q(!WddpfbZaq7<=bgM4^>LivWePe!D4q#^bEL= z|M||?TqdUM**@{y(AhAc;S>9;k@+Bu<_5o)$ycm%O9iMA#0snxTaVT^df8R%`xb?7 z0gz80TFwzhk3+XDVrRxo#xh2Ezi7`(t3Dx*jMi+?i#2M6w_=2ZN=^Jkg-XC!O1ZaP z+6gCgg-BYCL796oz2G?BRD{*zK3=PmYw|J~u};0L6saMQf9Wnh&kVb~oKn+cX(_%E zvJjNOy$mnmtX)JwIlXWy3J;OY&QBf$nR5F6-;fmr7Ph;>{kXq(fkc6Ywqvdyi?2x9 zBwPdJ48U7}^=NzLeRY97A##y6e0!F*FPXQQ4Uj(gD1b14SU}D|*`TiQeRZBdTAjBa ztvKo0VQhgA0yhIJQFVeWx}d71T|sMA166&SP=_r~%i#zWH2Qwn;)`klu4AWuJbp0v#EAh_05t=_d^-a2fUHd!CF`~E^#U>k;t;z< zEOdjM%>;S^?UgJ<>;c!*Yg&UHB>cODZII$i_@FvG1r9n7x=gx)SW`qX-Y zeBlMz1o?p6F4@JQHD}`I@?&zoI^R;|>r{D~5%QbkT>pAO)!+5+ZDRV@jp8H4`gt?# z(J3>!M{eKG=WCzY8S)We)Z_Qm?CvEz);mmefV`j!gvRDk)Ftd+b5woVOXv`8(}6^H zfUNBStv62IZbka_33Uz>$u7*T32Z1c^D^N}UsBqIME8p%=rxCm>|wFlwm_jk8V!sb zHXt#WUt&Or5T=3mrY!jSL3Y>Sz<2QCIw^VlIvOXhKz43s!O@WyJL&i+$p;iLWUT&-YZYX<#QDI&aQ)mS2?r3=J*N zuYmyvct+sE`!Tt*JE{h1+MdM?IkH6y|6w1bwMpd>-8Ju>=js91_kQS8l++>FIjX_aHuDycb+2HN;FXX(?`T@>G&fVjt%+Te>dyrJ#JfGj0Lf_KBTXK_QVP=Z!V7u=B0%Tp3Q1Zp5=S2ODd zXVg;U6o2(He(AV7y*q!w@Ji~I%BgrfF+Fa$HwP=}v#G@x4@M5?%Vji!@%KZUUEUs4 zaBe4%HXRugV;*0?vl*c@{(heu#s~YYEi|$yyh^}wL}7*FLCUw$S<=wwbTp@s9JK~_ z?tr$)a8hMgXz%*)oVWrOIEKXh9P#GpI zdtrg&!H1&|_7raJGuOx5hC}M}PiM7L$Pn=zZ@Oy3FFSEXRn=1>?FdJqd>>Gb+SDF` ztUf^^5mBN5(V`B~BFex!KGj~XTt*CW{MnxvQDP-|kr%lN(`$~kxj^PxbdN$9L&Ot> z?D7yyK|x{(^b#_76Je3^B8<)7#qI5V2NME_m?HM@#Nj3c;+w?dp=9h0{r5zu#0$mK zv66;wL^6kOz@`(u*L`kgXB9Z=N-1me)F*8>;y0;4tk65$M0-4}8a3nLz}nRUnMhEq zkKyhZH)&&>_Q#|R{oY89xAI{RLpOT!QTJJ~i7?YSm$28i5;BHSpHY|(Uo+ZCR4U7> zxvMHMk&KmVI7Ce<)JzsCD}Oc}hE^NTP^zgnRaR=KEJAHUQAOlN)o8d(^Cde|ujalW z`ICd5IY~O(EX~5aZXq&l2)A8OHpKJ>?%^9yoMSK^(qcCN)t0tJIbfTsV zW5=#Cghj2O z=;{9_X6~!vm-gRs<{1C-$Nm?R>_5S>|BWPLW@Y)mapvYHqBH1_LASVN`|R7%KsPP% z;_}7Pj0lWpaGB@8@wN)ZVDSV{++OW3>@>?F(6PsdJiF<2&Z1upmt-Pr4Rv$+6LnUq z(FeMGBAvvhwpX0P5*p1<$#npqFDkIV4ZI)jI%T(=&uHG=v#7eK9xvveq;#95ec*E9 zhnDIf4Og}2QgA!wJiXju25NpmuP2)PHc4RFW|+Ed!{}COsjV&1iJ9>1$jYv{CH#cq z$rcnFs>UXF+6;V^ThOm;w-j4cZx&w)86bhwzTNCH_T2L<^HJH=Iyso7y6u?A9I~$y zP&sfhn#v?R9EWSG)q=7&S7+EGK5V>B+VAAsu=fmm8+Jo>8}a1ZaFD_DF?|>XH$l@H zc9SrAap+u{$~*Knwi9lF8H6M|k;ZiTv{OGHKZ-Bj*FrGG*BZ zv!rLRJ@Dh3<&PI`Z`3gFdCGToE{yjpviI<=yt|48p`NHYT?6l^SMZ*=;dhV*5#Gh> zJ7_DYp4Oj>rFWFxmQn95Qa$MjA6VW+n}*)9J^g3LsCR>Nx+`q�S^em%=$-YrI#k zFQB&`FAf!Xy0tX8ueR(LxD_QmLb6=%;n`0|tg>gk50N3d3?bQjcAvdzbG$9^xE^oi z*MMEE7l+Kkdqb?lf^a z#rLs&O^ko>`&gOjzSw;%cnk~-|D=EOe=o)_{vHD>D;^6A%Rd+EU;Wqg`$zwk{?&cu zp;-TA^N;>tb^p`mzwH0||FUCbX2N5kr^EYCUteWk>jok5ic7J{TmH)>5Y9rKNe}C)!6Z0$1Klv}4zkdGq;cq!38~fj7<3AezkHHtM@~`5{ z(LW9NYxtknKZbu>^G}qol%AaqkDcj1D*R`Zzv;hv48{B}Xa9zN_|Gb+@c*VC{#{r8 z*HZIuSk;XGcUCps7j*M~(htu)Jv@~bnm$(!Gt+(t;KS?q0Xf9uBa9{hff-nk#6ZSe zK_Jj=yJuvMXA*%VjI+fIs!_RCEr3yPEUv7m^tsDxG)j?JfUF>PwRA0Y_wrc#s9cqF zd963km$!5+j9+#J*-&PbUkQT)_6@~1&fiD&%tnrF|=`Y zY5Za_44i5SQ)@2a&F6U;sJGfe4Yk@lf^vQonFn`9D#9VHuReQ#cc#Yqn3m6vOrb08 z5nbvuTqkA>W6+%LE(Q;T-3?%AycF;dm$lt14zkjQTA}}X(GobunOYl~$pJa2NwtH# zmD!;R^qjtNfu~A!^Dc8=y^-F>oCys=w6l?jUuo{oYXCmC>zhLo;tDH&h3zzmH%7uu^D3~M7uk|*1Q$z|Cg2#q0&2)&IF4fLHP9u_1m(EJd5xrdo2PU4 zhvrFt$H>DsxLHxz@mxc{r1y)36#C?H=GkQq7b>)E*e5D!NZ{sH73Mt(-XXC>R3&PM z8HcqGzUT5t)JO`?vKnFDk>y9t%ec%5)(*!UF}o)eH87t6JAYe(K66P%&C^5@J~lb4 z0@v#jJ*MXvQmIdxqWR6Lmqq)N_Hca&ioU9{R93Eb7xS^MPc9k}8Hjvpt4f|e| zt77IFm_3ALTWf!%2ga@&O%{<9TC|g;Stmg2l|4BFJ-utZ{4V{1r0IA1^LSv^Z}2{B zH!Mdm1=)UDV@1Y;jPIR^PuEv9r@$wVx3)*DY>TVHbKSmS-(Ux+_FSPn;9|A63#lHy zPtp!!=$^2WA)-ueNTWIFTyOo1t|KO@KBqQEOod#wUH+vBE1`$Dr%=nVj;I{ZoQ8V1 zQ>H!JeajDiU?r#5J!Wp{*o`HG+L%~vCWh{V`dFh3cxhl({n+@~`MLI{dB0#6b=ZgT zBV`Z)fM9&8A428@sq(~~0gav9&_y+_6Ljz>COgWwF9jg4iL=~CX_M|&>{k6?eeRGD zW6yh=ub;_RmsxJS?!HDvln#qQn1WI{YKjauXI3WgZby)Q&DBLv4SkraViLj??ez4I zo`tM@h2fUvEzFtm=>-|Q$!&mdcqBNnF~uEm;`NB+9_yaWHm#{`c_QB5rAVxfvnX^g zlRrte8F8v{lzEA}lXS~Fi-R8px8o+`CH@q`7nVm%hSI{M3ZaV8=rN{jw61k3_Iy3x z>~7e}YIf1VDY*vS^7dqO7#VK6?@j3zc&+<2CwvQbBa);hs?>m>PGtG|NSNk|Az zl1QQAY|Ngzy`L6=jYvY&%56 zSuv>ph|M1J&L>mAQcb8yF`+*(D{P+f7I~l92`2i={(`eUZln^uEbcvA2G6;rV~%d0 zjtSU%t@O7)nj3wzjpQ9*Y~B|h!yg0)+S8xs+P`=lYbphGT{~!1-N~2d&V}}ImTA4f zoXcVv>Fm8zkLDmo)psck&&E+7^0$Dn(H=-Vj|QEm-ph`DZVD~h8uSzZ7aN#H$>;TZ zTqvxKN@0)og#2O zA4}@l#rXRpqgl*h9f-Vz?6smiRP$kqcg!b6n|(Hzd-NL2-O3m;On>+@X^y#^?uW+D@FCS}m$y`R<#PPZw2m8cgoX!;|)ni-?DWDU(rY zG&O1m)4r%tD6|@>9eUoAoox-K#-_$5eS&>^c2pVn4I&=v(c&b^KJTq zkhYx62#w@{(Wy`hyN=nZEBMRv$C)(0oVELp8Q8RuGN}}+icjJV7S5FnH_d;Q7g$X_ zsBF2gvaQZ9+k$orZ#_b+!Ew>TgDAPk$Od2-VwZC+E^jjKU6}c{Zr?S!n|=|~6r={s zkNM{Oh7Q;R2CO!mr0{0BTo!7D$eqc4YHnHm8ad#^Yz3ol>#cG#oLJRdhi!9nvnC#* zSGlxv9v)Rk9V0`eQlc#mQ$ICip^rM*t;iER`E|WKtzD2d50GaXIK8uA{W>wEDrzcD zInWK$;MT^Q+O!^W8*pFcB6U8I6tc$7lf)Vld?9Bj+R`F(KCx@8iD@)g=sz5tCnDvE zDz)6GIHWauZe2z1%t@m3%<+^Sxo|AQTH<)7Y*;qQVLCOv0mo+2Cl~1qb1;NT^(#w4 zD;LzpskCSz4YlI8Q?ofNbcpHPbaY?bGmX>7U3UD=_Bho*bvI*NlJUeCJum*~84ifP8@r_>_6 zxiYve@vENOmQVVu{4``s{)3D`c^qOSzu*rd97>AtDz!e4K^6EIfss=o4{33`&r)Ou zFh*r1I$Y*~W(`ec^vIl)k#!HVdEqRxK{y**<`oL3gW=!GD)T4_9IjJp^`?_F8xC{; zM*7ZyFg9-iuAuR-BC4#XvC&M=9vbYxKFR(fC96wyz?!fe!zK$Yf7%o>{KVVp5rUq&^aU7f z8z;Bw6Tel2`dpS$g91~LNm)l4J6qBHX>RQ7d}KFcvWtsBT-c*?kghAwKR&lCX(}mW zH53c(|D#Y=W;``5x6;@xLR68LCsMM)Hcwv|MFQu{u^@FgP2Q$#gALWr8GnH*oyn7k zY1vr;8*!ws3}GF15}b85c|Jhnd^pKnRl;z+>}D!ysb!$xC91u8g?QJLtq_+3s=T8l zvj>~R`m0-Cb+8DzFURALu%p}^g+Ja(w!Daca(p5EO{4@EHKTX}pCU}U zVi`Rii;5;BFMzli!G!|)nvZ%H$9=4JFgv+B*h4qNkwgZ?Sm|X2iJ=Ie_W=-1R&)(tF?IFBuP!`wa41#lfgyR2}WRwMJ9LYIOONK}8M=&5c$}S!gElw1>FL z(`A9*y-_uAY~Tvq=t5x(*Hmqo^*w3y&>X)`+}&dGVp^B*kxX5`p|RS9nb=E0Y84}B z>hC~No8++CLGRbjk=PV@K5!$o%tV~QBFW|z&9+E$CGk*n+3c7nuir?MWXt3wUZy|6 zoJcsOwXVMioe+}nB-o6uG1fhRq{*hS6+~7tlhDLbSM&`UYosg~?LfKm80?^=$K8t~ zwJ4}8{y=Jp`L)C^TvV{5`&^;yK^<;Um7+b z3T?w^_hi~-nKgnSCMAkAoxLvSD{UuXV(S51(6aHH1er3sg(!R3Kj~Q&9i8+5& z&!N3@Pwgs35L{U`#=_NKJn8nl0VzLKD6WJrxvSR{cuJ>Ed#eF7Ms&*|Fw?j95b6ck zZwl2A9+FG-3ay_AR-ARpbs_fZCu$2OGmh}BG?%>0Y zf+3-3O&~Y@z6kdPcLs2{7yC{#EkEylw;+9s`FRd6hC96*1yZVVPii7nXwh|pB8N@k zWGfwiGEt8dg_~02E+PrYqD=>>Cx8BYz9g}>Poy`o7hvs_Wn_HlWJ3{HMLyXr3=q^_yQOAUGY9B3_E@~?h81Nl!g;>#4sGh}yk}nWaAq_7O zJEw6BmEh>3TT4vRIZA2_UTL({CXfufmpt=O9k38c{`|OxqN1oQhVJNep`v1>-a}&G zQgjw7+48<*qj&Dz|H!b=9}w{>F7`rV$`;NiI4v_FnLQ?{JADakc?purX@iHwL~qPR z%V;eBA^cA8`XGA-X>%IO?qb$2_)21MG5c=3y#0PoZ|LMiU?15ECv{{ySfn4q!e}M$t14oHBdV8{VW4zLL?dsIsJJkv{tQb zGqN3LTXZ6m)#!k;yS?_x({bfvd*uc@Wj;b1T^Wz-G{ynI(V{#%wBwOy+Dyb_$R)$OH&-6@oBFQq5Z#h|Zd|wAp zA(5H_!nJ4pwKpM3N4j7~TKxXF$QF#^WL|(7lS+6$HsFx9YkDG$mr)y)FaakVPVSRR z#cwbYqkfmBgqJZocy#$A^YX{k9S~Y&^ni(cot`;IxM3>2@l$G|Ufe74eV%h4W^T}i zj-X;Hu^N)v(XJTd$MA0FL}t|Gq&MTIOZeG2qb!YKwo8N5O}14pm)*0@jr4Cn#fHwh zg!XZ>w)n1Z2kosxcjjqKZKkw2Q4luiGq! z4H#lvWYba(;c99d?Qk$le9Znh2wZ=6F_T!6*+}VZDS9KYe4_b%oNyC=XskB4xu?y~ za42mL)@!-OFB&w|_Ld!XkLE5Nb)my3iSfYdtUMhV^V^DpJ9xuVIN`cZzVh9Eig-$3 zcanz7n0Z)y_lM4T#~^r~>tL5LYwT8xv8PT z&arnhwJ|mRL9Vfy#+U@0Ihs1BrOm?g!X(<9KEsV3r}U~ajN=1wv_3#WVsB2)QwQTm zp@Nv@P{#FsFXgpSEy}#T+!G_g=b{lRb6V#9k#<=20*OwTX{ZGK35G@hDHNR6%ck?< z*WSWmBV7RTVg?($CRl)b%E8P6Z8wpIF4xH!q9nOLAq*#?S}V z)IY6sPNu!M`-!#fb@00?)tah0{`vVzRrjw8*xeV|VruJoA@_1U7uMJJC;CnmJh>MT zcNSipcNe9)(8Q#r?S-1muNBUxd2~6B%I0ou8m&Wzkf8m3)uT6(PbKwXG9bVg^II~^lHL_8@PD?UP>Jg=q3(3?cUnpP&<Ysss=1nqxI)?v&%9qk3;z7tj81!Jod;tKDACL|aCdHX z`8-~DSo8kwrE2H>Fd*DKvN0zSr63w=UmezU$+@6bUWoe91fKY-k+E_UEeP&|ze(}& zySo$fbcuu88Ul!4>?Wp)2Z$UV*1hZ9uU5(v)bg_ISQ;y|V5Vw_8!A~ZuBLOrbF0R ze}?RLmV+NeyA$Yz2S1ORa3jwX%1aMQH0Yj2JZ+ig=$i=b=GCpmrC&L|eI*D;Wy81&Fz-b@mhS)o79w$k zyn_=sJ@wMTj*bkDVmpTU{ty%-(52Dh+)yJ6k179Swhn~A?0Y1{Js6j~VOXa6Z3u|} z#3?lR`${hV-NR{KXiQC0BPk-JN>UOm3{2ufdN7snQR2Oj`@3=1j}KbRG53M<9~T^h zhM||E3LDQn;BZIYIAI2(i`LYbn5>IS%~os8%Ik}zHXCY}8|`ydi`ARk&bD^8)^#O- zxxtOJWjd_OAM!v;eFhK*lve6>6u8MSme*I9Fhb8_vbnm2-w2J`u%60P&*-G@2h_au zmf8i|Ct+2}oAuRVz)V3o2r;N&E~OQNP3wWJw3HviAeaPjWKR6mN$&ld2>oo!?GAswLlk* zOa#8?6$b~jkAxt!dG1qGjv97qMlN*f;BJmAf8g7ZAUoKLEvxLsOD5jDx_g-vLi2Rf z4*Vb_y&Xjw>;*z}Y@EA4ff6+nC$Q10VjfKZ$hm?K4eSYBpsW9x>FJL@;V zu)>JJIbl>qV7Nya-_GVk&R{NleEpSsh1Tl%oC%*jUne`!HTq1l2+>5x|GmR=cEnRZ zz07GTX$UHb6wEbtljFV+Z@fUboNb^wtBFksYN@(ft6HU6OH-k{y_1XCNfjw{pHj72 zC#v3Fxk$rpBHhVy5iqx5ywr7QvRB2R$Xy42U5kYfllE5U%S!~uz-hz%u!FLvx-(1+ zNO`-Nvh=hg^-;k|?xDy5&Wx8Gi_!L~v%equvw%ves#`hzABoogEcKpA>>g=>b-^MlU}Wj63tv|{>!=Zk2!f`E;P-xyZc=8mf_Pqe5bO0+ve_k zsQapSKjX9G&yAY&bHaJ`^B>;dU2yHS_)N}an;chv#%SXo$6vmcQNgT!p}wW#*mAwi z26h{UY;{?1C@;3CX^^vqplSEswkw7jo65&_NxdqruN&>tB--1xqwV$8q(PAuL01k$ z7eytVv#M*_l(r>}6S+%g`}R4Oc^)5vJUKtN=`{3c7&Rq5y2DUcO-EyAFT=!`>*|I* z0~&{XShc*zGQGyGWL@EKh8o%5G0V1d@RL6yjP$p?<6B&~H}<}R#8H3CWTU51R)uPB zhfZ;iYyaW+(iJ5EQ3Ht=U5D(?>9?NBnk=YE)0i~$?TUwwUk?1>>|Nl#ab1X3uEqE@ zjq7!{=dHhXxJRWr`$%L=eZT7ZiwonnRODBz#Hv|OHE$H!4Up6iz9P}ouV=GGD@&b{ z-)JXyYR`L)4*u1=$rZWx8;mx;i}jft@dx}l#5Y}oxhHoes|yXL^e#UVIV|k)n_-n$ z5oOucw=z;~>QV>2Xx(kr2jeRu8&?nP<@&DNY_4rpwRq_C)-45gkC+EY^SU2rG{*e0 zEW_0&81{`%NB@eGbM#%0lxO{xcQ`DgC4G?kn3N6TZx$1~)pwWgdcTET=DXDRZN?`5 zjK*l`6pP(DM+}<>nEV;Hz_Q9{)uu~Z9kNFBzo^@K^U$%;MDjA$oXgYaIA3&L_-oa# zTcejxu`szf@YM92&G{9r$AlbAJAY2LRr7pN_WaOU?bqJSYoFJCO6qXQ%zKhg;o`z2 zd092$gBNcHv>wsO?vwp)Ui^IL7f0_263nj0{@$m$`I3|9N?RYFbT7>J;)Sibwc;=-Rp3KO=G?mBaFTW4{USbkE${qkU1i*D|NRN`W=^ae z9sOEuyN=;SH6mJV%I2ASq|@SK+sUl>YVMSYML%i9zkc)6b&o$n+O@8gVfUCbo^3n& zvh3lUgC}kVSycx1(NQno^l@0b{&#mZ!uVGOhRnY0+=Q;I-4h)R%F3q&N7|&^iEYha zj?elIO`%2Ox|EN7R zXR~Y0o~aq=``R$R<+_g3{G}BuM^|R=F$t@>oZCfR=`1t)EN>S}dG`1~>EPo-Xbju;$~kHHFtb4(H|e8Sb5F=47fZG-cL3o8`sva(r6d z66zN{M*Hxh=fjew%{I|GoMTJq9bOdwG&SOFY*wf7qL21vc*~XPI=(I0@3-92$&=KM z4A^`AP88?aJ^hsL#?*_j8GEPkVSXU);F{>&#se71QQSc3IyrxuEMYviC=I z$=%0|rK!npC9fV@UTSw8ubsQnY*ELEthBhHQT=a@dsw=1_L|1t3w|qn_4NCVw@qqh zIE=acEWO8C|6_GKLwb(+)9ElzqoA>L`Rtx)ixY2_r5Za;Xq<0Ryz_=hhNL9bbMyLg zBO8-3nT}@LG;Jm&2>Uj-CNiHUo_y^x?Wl#*%aq2+2h$$)%jCJ*by$`iys~&j!L^S2 z0fLTIjjNsSE(j^Bd+6lyGO@AXa;C1kJG(NhOjl64*XRl9Y(D^WY5qX3;x1~?{`Y#8#{X(Z`|m%KJ9^@Bh%%~$ojz2TNHP0S};dDjx8-X zfNeLfa%%2R)x?|$OAOSZ9?U!Cm3WXpaQL`g;zLDo4yjg23zIVU6J7$Rxko2>!sC(? zf%yyl-Gs(Re?4J)V)cnSqdKGQM!2*0zJ2@m?VIPEIK*f*-#gyG^yIqt%*WntcxhBe z`b)l6L`I22#e1#v68@N$)LN5M_I|fr%RK95+_=FXdeFpgMBdo2k{WHIl%LX-6PkQ9 zK0p2Ygy%ZK8`syVHSfD4`4C??OG_Zkzn^;X*~k3*^)(k#JOz4wPiG56ttDpHPrO*` zx-*pGz4~%Z?KbVa((&Y$c{gf?xLt`d zSoz~=C(V;1XWCmX%FEm3$#dYH4i7dfIF%mw(}uSFjM}V}xjO?_wNWFRbG3du;d96Yt6o2@jQ7s7=?PK-cd|dMB0j>_L-d@CO&4BBk^GA72*sLw#mc;&GA~|aDXS2ZBj7LU`13mRF7%bHspl1_P zF?xS==98$ly|+FNxD;R$S@G<_otW*57-+gNb z>7H5|7%IVIZ>_Bg30!n}jbxVbDuHof)&y>`>(Jbu5p(SW?I*lA|Ga4-{voPtaai;6 z_qWg7t!_D4m-LNzYwpH%hGnh($?yBEDb^ZzZHZRpG|tqkqiT;Yow&nuLq}QT&7*$d zmu_CWdg0{6J&!Wa-b`AW(H@XDB+J5a#mV+*Z!7#9IJY&#e{Ao_{lJf0$>^HW`JiL; zhjFj7&ousAleysL)V8QJ=2Wd2CO^d&SY8@#yJ7OZIGf@Q>tsfMR)+C9?VI^Ej}rQX z7xWK*G?vq^q1T}vExqPFNpo7M|8jgoyxQs@>ksxt#nDvUA>Q#e=lDB ztsb%G#DwV&MrpkLWQbDM?#tFKo1plT0PI7f0Zo7~~^e0u?{le=DckWI3yZ@$Kpt9qXv)dfcnK zb{Ke98BBUI;^5@y^T)T;#!UY`z3ZNl%M9}=Z4obGc~AV`)jE~8uipC%D;`#kn}!J2 zuo{L;n?t;BXiKkr?!6;X`^5dNagwQmfD!xMOWoL_;AJmEigK@q|4|-eKo+`3Ui+AG zeca_~!{hwiUXqoQW^pIo86KK$nmTl1Q|qX5_l7`+zMwdzZu=nIOc*iiWOwUQ+ybIK)4vbCcvCn}gk0t=F9 zhcPf2>3pUgR7>HgVht{FxI`18HT+yJiW-7QLQ{F|C3D^^Pd}kR3UK>CsOf?Ob%U-s zaD&Q8Wp@}10pCw|Y#0T;pYBKoCNG<^55x(mHv0qz`sGuA-hfa!t(xeD&5)0du5kt& z@{YJrQucXxF2R694(H(vI6hsI4BqF#pa2XGIh-UJaKJShfZ{UXfE%dOVmgXN0%xJr zjp=A($DA#UkOG2-kI-6vvX`H%7HR_Smoi#t`-#gkfp7$TrlW@#=_AILGny}yh(g5z zp#)edCt`-s%hv;`I+_EI;xGt`Sje0z7KH`_cb%ED#U4SDVAP9XDbv~+G(5~#AmmTA zV%jsL;!vT51=AXq1_qHZWSmx@h+fwF?^7gO31HeVg#WjATLuM*q!Kqx4C=%|;gD(jhY~L{S_-U_*_ZBRoqSG;G$CGg zGfgrluSgR;TKV^F11_`L3N*L69?I_?&T9l7I-Mo zM9{;be_x&my8D9y_U`5rL3e;e_sbJOcY$2QxbBrFE?w`q-Onf3c`4fh-v81C{xg5a zqx(Bv_lF8RdZ<8lKc7fCpUCd#6G`V2ysFaOdPmXuL?K1&URwZrAZ5Lyy5HYXbbp7j zy5HepEV{?TAW_ua%ZIV(u_ngq{$LZ6rzjL677XkD@BqW;@d1W)zvIK?i5W#+{ZDs) z|IGDaY`U$ICspXiN}|bB$+BoNzoc0}KfdHy(7w~b*GuBYkaf+FZ$@R}3mF?^g&6V$ zg6ym8PM*DD$dfq?w#+CnXnV;e_WUc{DvapCDGk`#g%;uo8%#*-bPJmpJ0WOmrIDeuRW@jx5h3pf~ zQd+{*ccd1w?Gy=jD zY2(mov-XgB1c-bfkLH7tW^&GJGG_$~gXCkn$(N2f&viZ{C^R5I{)eTUnd2yUe`~SO zLn;!R+u7RLu~-}m-cYw;v3QVP=RuC03$Lv5aP*ZY0lh*6!Y{bi@PC94c%N}O&5KjcZBZX6U5~>x+ZN6Q^d%b>cx2-t6&l)@u~`_0g=092WD^8FfklpEvBn{8eBO9Q zh=tyokXhw$HKD6dAINSJkSX!~%U3U?h@bMHsZ@Q6S=q zFt{dB9#$EK5h$2agh5*hZAukkFe(>`r!tJqra+r$FdT`g5{%6wkiICwa0*_S1z}Kx zu>g;!0wYO`#sg@}MoOvNmLyeZW>ahwY$)SVIGtB4m@tP%GmL>Fl~rns7KF}woZ=!4 zSHy$11ie2PgNw4yig+xLkgv4mQndaMo@!gjt`QW+N`QBbdl2W=@7 zEGoiS9E?<1Uk!%#>Q|u{{Rn}Kc#VjQ*7GYSQL-Tqqik_AeFSX zJa}qH$AkV<^oU0iDsv;bl#0B-xbS+p5`7Q>QRo?lBF#9(W|K4-LU?H7tB40u&qMB4 z5e98JbiG7)bY6i!;L>Fr+M-w9mHImbHsQ*?O-`e4Gew%~+Nz@yY351cMdHh>T=-R58v z7o*EPjKM+41Eu}|Peq1673lUE`s2{$3Vw6pE4B$&(Jh2WpD(~btCeX17>_Q0Y%YsO z_W>{uP;^>bE{jB)4#l~#!Aa9?9kd0@tBQvn8PeKvQJ_JG(QP)Hm@>gza%t}!Njduc5Jqt6_3QNt$>ZzgbkZ#X~(msz}i!mB-%7dq#k0aY?}Z= PL~=NqW5?RgveW!OSUrQh literal 0 HcmV?d00001 diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index 7aabd71f9..e54080a71 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -30,7 +30,9 @@ subject to the following restrictions: ///@brief GPU Parallel Linearized Bounding Volume Heirarchy(LBVH) that is reconstructed every frame ///@remarks -///Main references: \n +///See presentation in docs/b3GpuParallelLinearBvh.pdf for algorithm details. +///@par +///Related papers: \n ///"Fast BVH Construction on GPUs" [Lauterbach et al. 2009] \n ///"Maximizing Parallelism in the Construction of BVHs, Octrees, and k-d trees" [Karras 2012] \n ///@par From 19b194e8fe66d56558f7ec63fc89b70b9e9241c3 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Thu, 13 Mar 2014 19:22:05 -0700 Subject: [PATCH 014/116] Fix PLBVH symmetry optimization for calculateOverlappingPairs(). --- .../b3GpuParallelLinearBvh.cpp | 37 +++++++++++++++-- .../b3GpuParallelLinearBvh.h | 4 +- .../kernels/parallelLinearBvh.cl | 41 ++++++++++++++++--- .../kernels/parallelLinearBvhKernels.h | 40 +++++++++++++++--- 4 files changed, 106 insertions(+), 16 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp index 0593fc136..a478f9e6f 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -69,6 +69,9 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_buildBinaryRadixTreeAabbsRecursiveKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "buildBinaryRadixTreeAabbsRecursive", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_buildBinaryRadixTreeAabbsRecursiveKernel); + m_findLeafIndexRangesKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "findLeafIndexRanges", &error, m_parallelLinearBvhProgram, additionalMacros ); + b3Assert(m_findLeafIndexRangesKernel); + m_plbvhCalculateOverlappingPairsKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhCalculateOverlappingPairs", &error, m_parallelLinearBvhProgram, additionalMacros ); b3Assert(m_plbvhCalculateOverlappingPairsKernel); m_plbvhRayTraverseKernel = b3OpenCLUtils::compileCLKernelFromString( context, device, kernelSource, "plbvhRayTraverse", &error, m_parallelLinearBvhProgram, additionalMacros ); @@ -91,6 +94,8 @@ b3GpuParallelLinearBvh::~b3GpuParallelLinearBvh() clReleaseKernel(m_findDistanceFromRootKernel); clReleaseKernel(m_buildBinaryRadixTreeAabbsRecursiveKernel); + clReleaseKernel(m_findLeafIndexRangesKernel); + clReleaseKernel(m_plbvhCalculateOverlappingPairsKernel); clReleaseKernel(m_plbvhRayTraverseKernel); clReleaseKernel(m_plbvhLargeAabbAabbTestKernel); @@ -253,7 +258,33 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab } // - constructRadixBinaryTree(); + constructBinaryRadixTree(); + + + //Since it is a sorted binary radix tree, each internal node contains a contiguous subset of leaf node indices. + //The root node contains leaf node indices in the range [0, numLeafNodes - 1]. + //The child nodes of each node split their parent's index range into 2 contiguous halves. + // + //For example, if the root has indices [0, 31], its children might partition that range into [0, 11] and [12, 31]. + //The next level in the tree could then split those ranges into [0, 2], [3, 11], [12, 22], and [23, 31]. + // + //This property can be used for optimizing calculateOverlappingPairs(), to avoid testing each AABB pair twice + { + B3_PROFILE("m_findLeafIndexRangesKernel"); + + b3BufferInfoCL bufferInfo[] = + { + b3BufferInfoCL( m_internalNodeChildNodes.getBufferCL() ), + b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ) + }; + + b3LauncherCL launcher(m_queue, m_findLeafIndexRangesKernel, "m_findLeafIndexRangesKernel"); + launcher.setBuffers( bufferInfo, sizeof(bufferInfo)/sizeof(b3BufferInfoCL) ); + launcher.setConst(numInternalNodes); + + launcher.launch1D(numInternalNodes); + clFinish(m_queue); + } } void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs) @@ -410,9 +441,9 @@ void b3GpuParallelLinearBvh::testRaysAgainstBvhAabbs(const b3OpenCLArray& out_numRayRigidPairs, b3OpenCLArray& out_rayRigidPairs); private: - void constructRadixBinaryTree(); + void constructBinaryRadixTree(); }; #endif diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index b28c5ab56..83f355849 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -211,12 +211,12 @@ __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex); - //Optimization - if the node is not a leaf, check whether the highest leaf index of that node - //is less than the queried node's index to avoid testing each pair twice. + //Optimization - if the BVH is structured as a binary radix tree, then + //each internal node corresponds to a contiguous range of leaf nodes(internalNodeLeafIndexRanges[]). + //This can be used to avoid testing each AABB-AABB pair twice. { - // fix: produces duplicate pairs - // int highestLeafIndex = (isLeaf) ? numQueryAabbs : internalNodeLeafIndexRanges[bvhNodeIndex].y; - // if(highestLeafIndex < queryBvhNodeIndex) continue; + int highestLeafIndex = (isLeaf) ? bvhNodeIndex : internalNodeLeafIndexRanges[bvhNodeIndex].y; + if(highestLeafIndex < queryBvhNodeIndex) continue; } //bvhRigidIndex is not used if internal node @@ -225,7 +225,7 @@ __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex]; if( queryRigidIndex != bvhRigidIndex && TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) ) { - if(isLeaf && rigidAabbs[queryRigidIndex].m_minIndices[3] < rigidAabbs[bvhRigidIndex].m_minIndices[3]) + if(isLeaf) { int4 pair; pair.x = rigidAabbs[queryRigidIndex].m_minIndices[3]; @@ -741,3 +741,32 @@ __kernel void buildBinaryRadixTreeAabbsRecursive(__global int* distanceFromRoot, internalNodeAabbs[internalNodeIndex] = mergedAabb; } } + +__kernel void findLeafIndexRanges(__global int2* internalNodeChildNodes, __global int2* out_leafIndexRanges, int numInternalNodes) +{ + int internalNodeIndex = get_global_id(0); + if(internalNodeIndex >= numInternalNodes) return; + + int numLeafNodes = numInternalNodes + 1; + + int2 childNodes = internalNodeChildNodes[internalNodeIndex]; + + int2 leafIndexRange; //x == min leaf index, y == max leaf index + + //Find lowest leaf index covered by this internal node + { + int lowestIndex = childNodes.x; //childNodes.x == Left child + while( !isLeafNode(lowestIndex) ) lowestIndex = internalNodeChildNodes[ getIndexWithInternalNodeMarkerRemoved(lowestIndex) ].x; + leafIndexRange.x = lowestIndex; + } + + //Find highest leaf index covered by this internal node + { + int highestIndex = childNodes.y; //childNodes.y == Right child + while( !isLeafNode(highestIndex) ) highestIndex = internalNodeChildNodes[ getIndexWithInternalNodeMarkerRemoved(highestIndex) ].y; + leafIndexRange.y = highestIndex; + } + + // + out_leafIndexRanges[internalNodeIndex] = leafIndexRange; +} diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index 731423098..40c5e3218 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -196,12 +196,12 @@ static const char* parallelLinearBvhCL= \ " int isLeaf = isLeafNode(internalOrLeafNodeIndex); //Internal node if false\n" " int bvhNodeIndex = getIndexWithInternalNodeMarkerRemoved(internalOrLeafNodeIndex);\n" " \n" -" //Optimization - if the node is not a leaf, check whether the highest leaf index of that node\n" -" //is less than the queried node's index to avoid testing each pair twice.\n" +" //Optimization - if the BVH is structured as a binary radix tree, then\n" +" //each internal node corresponds to a contiguous range of leaf nodes(internalNodeLeafIndexRanges[]).\n" +" //This can be used to avoid testing each AABB-AABB pair twice.\n" " {\n" -" // fix: produces duplicate pairs\n" -" // int highestLeafIndex = (isLeaf) ? numQueryAabbs : internalNodeLeafIndexRanges[bvhNodeIndex].y;\n" -" // if(highestLeafIndex < queryBvhNodeIndex) continue;\n" +" int highestLeafIndex = (isLeaf) ? bvhNodeIndex : internalNodeLeafIndexRanges[bvhNodeIndex].y;\n" +" if(highestLeafIndex < queryBvhNodeIndex) continue;\n" " }\n" " \n" " //bvhRigidIndex is not used if internal node\n" @@ -210,7 +210,7 @@ static const char* parallelLinearBvhCL= \ " b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex];\n" " if( queryRigidIndex != bvhRigidIndex && TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) )\n" " {\n" -" if(isLeaf && rigidAabbs[queryRigidIndex].m_minIndices[3] < rigidAabbs[bvhRigidIndex].m_minIndices[3])\n" +" if(isLeaf)\n" " {\n" " int4 pair;\n" " pair.x = rigidAabbs[queryRigidIndex].m_minIndices[3];\n" @@ -702,4 +702,32 @@ static const char* parallelLinearBvhCL= \ " internalNodeAabbs[internalNodeIndex] = mergedAabb;\n" " }\n" "}\n" +"__kernel void findLeafIndexRanges(__global int2* internalNodeChildNodes, __global int2* out_leafIndexRanges, int numInternalNodes)\n" +"{\n" +" int internalNodeIndex = get_global_id(0);\n" +" if(internalNodeIndex >= numInternalNodes) return;\n" +" \n" +" int numLeafNodes = numInternalNodes + 1;\n" +" \n" +" int2 childNodes = internalNodeChildNodes[internalNodeIndex];\n" +" \n" +" int2 leafIndexRange; //x == min leaf index, y == max leaf index\n" +" \n" +" //Find lowest leaf index covered by this internal node\n" +" {\n" +" int lowestIndex = childNodes.x; //childNodes.x == Left child\n" +" while( !isLeafNode(lowestIndex) ) lowestIndex = internalNodeChildNodes[ getIndexWithInternalNodeMarkerRemoved(lowestIndex) ].x;\n" +" leafIndexRange.x = lowestIndex;\n" +" }\n" +" \n" +" //Find highest leaf index covered by this internal node\n" +" {\n" +" int highestIndex = childNodes.y; //childNodes.y == Right child\n" +" while( !isLeafNode(highestIndex) ) highestIndex = internalNodeChildNodes[ getIndexWithInternalNodeMarkerRemoved(highestIndex) ].y;\n" +" leafIndexRange.y = highestIndex;\n" +" }\n" +" \n" +" //\n" +" out_leafIndexRanges[internalNodeIndex] = leafIndexRange;\n" +"}\n" ; From f324e66f86493b598bbd9ad1e4b151bfc7286784 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Thu, 13 Mar 2014 21:27:15 -0700 Subject: [PATCH 015/116] Add access to overlapping pairs b3OpenCLArray. --- .../b3GpuBroadphaseInterface.h | 1 + .../b3GpuGridBroadphase.cpp | 4 ++++ .../BroadphaseCollision/b3GpuGridBroadphase.h | 1 + .../b3GpuParallelLinearBvh.cpp | 19 ++++++++++--------- .../b3GpuParallelLinearBvh.h | 8 ++++---- .../b3GpuParallelLinearBvhBroadphase.cpp | 6 ++---- .../b3GpuParallelLinearBvhBroadphase.h | 3 ++- .../b3GpuSapBroadphase.cpp | 4 ++++ .../BroadphaseCollision/b3GpuSapBroadphase.h | 1 + 9 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h index bcbf09a4f..09e271e6b 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuBroadphaseInterface.h @@ -35,6 +35,7 @@ public: virtual b3OpenCLArray& getAllAabbsGPU()=0; virtual b3AlignedObjectArray& getAllAabbsCPU()=0; + virtual b3OpenCLArray& getOverlappingPairsGPU() = 0; virtual b3OpenCLArray& getSmallAabbIndicesGPU() = 0; virtual b3OpenCLArray& getLargeAabbIndicesGPU() = 0; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp index 1e707f364..deb6d89d9 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.cpp @@ -368,6 +368,10 @@ b3AlignedObjectArray& b3GpuGridBroadphase::getAllAabbsCPU() return m_allAabbsCPU1; } +b3OpenCLArray& b3GpuGridBroadphase::getOverlappingPairsGPU() +{ + return m_gpuPairs; +} b3OpenCLArray& b3GpuGridBroadphase::getSmallAabbIndicesGPU() { return m_smallAabbsMappingGPU; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h index c2c66ce7c..9694a362b 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuGridBroadphase.h @@ -79,6 +79,7 @@ public: virtual b3OpenCLArray& getAllAabbsGPU(); virtual b3AlignedObjectArray& getAllAabbsCPU(); + virtual b3OpenCLArray& getOverlappingPairsGPU(); virtual b3OpenCLArray& getSmallAabbIndicesGPU(); virtual b3OpenCLArray& getLargeAabbIndicesGPU(); diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp index a478f9e6f..641df9eb1 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.cpp @@ -22,6 +22,7 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id m_rootNodeIndex(context, queue), m_maxDistanceFromRoot(context, queue), + m_temp(context, queue), m_internalNodeAabbs(context, queue), m_internalNodeLeafIndexRanges(context, queue), @@ -41,6 +42,7 @@ b3GpuParallelLinearBvh::b3GpuParallelLinearBvh(cl_context context, cl_device_id { m_rootNodeIndex.resize(1); m_maxDistanceFromRoot.resize(1); + m_temp.resize(1); // const char CL_PROGRAM_PATH[] = "src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl"; @@ -287,14 +289,13 @@ void b3GpuParallelLinearBvh::build(const b3OpenCLArray& worldSpaceAab } } -void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs) +void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_overlappingPairs) { - b3Assert( out_numPairs.size() == 1 ); - int maxPairs = out_overlappingPairs.size(); - + b3OpenCLArray& numPairsGpu = m_temp; + int reset = 0; - out_numPairs.copyFromHostPointer(&reset, 1); + numPairsGpu.copyFromHostPointer(&reset, 1); // if( m_leafNodeAabbs.size() > 1 ) @@ -313,7 +314,7 @@ void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_n b3BufferInfoCL( m_internalNodeLeafIndexRanges.getBufferCL() ), b3BufferInfoCL( m_mortonCodesAndAabbIndicies.getBufferCL() ), - b3BufferInfoCL( out_numPairs.getBufferCL() ), + b3BufferInfoCL( numPairsGpu.getBufferCL() ), b3BufferInfoCL( out_overlappingPairs.getBufferCL() ) }; @@ -338,7 +339,7 @@ void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_n b3BufferInfoCL( m_leafNodeAabbs.getBufferCL() ), b3BufferInfoCL( m_largeAabbs.getBufferCL() ), - b3BufferInfoCL( out_numPairs.getBufferCL() ), + b3BufferInfoCL( numPairsGpu.getBufferCL() ), b3BufferInfoCL( out_overlappingPairs.getBufferCL() ) }; @@ -355,12 +356,12 @@ void b3GpuParallelLinearBvh::calculateOverlappingPairs(b3OpenCLArray& out_n // int numPairs = -1; - out_numPairs.copyToHostPointer(&numPairs, 1); + numPairsGpu.copyToHostPointer(&numPairs, 1); if(numPairs > maxPairs) { b3Error("Error running out of pairs: numPairs = %d, maxPairs = %d.\n", numPairs, maxPairs); numPairs = maxPairs; - out_numPairs.copyFromHostPointer(&maxPairs, 1); + numPairsGpu.copyFromHostPointer(&maxPairs, 1); } out_overlappingPairs.resize(numPairs); diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h index f1d1049df..effe617b7 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvh.h @@ -76,6 +76,7 @@ class b3GpuParallelLinearBvh //1 element b3OpenCLArray m_rootNodeIndex; //Most significant bit(0x80000000) is set to indicate internal node b3OpenCLArray m_maxDistanceFromRoot; //Max number of internal nodes between an internal node and the root node + b3OpenCLArray m_temp; //Used to hold the number of pairs in calculateOverlappingPairs() //1 element per internal node (number_of_internal_nodes == number_of_leaves - 1) b3OpenCLArray m_internalNodeAabbs; @@ -101,15 +102,14 @@ public: b3GpuParallelLinearBvh(cl_context context, cl_device_id device, cl_command_queue queue); virtual ~b3GpuParallelLinearBvh(); + ///Must be called before any other function void build(const b3OpenCLArray& worldSpaceAabbs, const b3OpenCLArray& smallAabbIndices, const b3OpenCLArray& largeAabbIndices); - ///b3GpuParallelLinearBvh::build() must be called before this function. calculateOverlappingPairs() uses - ///the worldSpaceAabbs parameter of b3GpuParallelLinearBvh::build() as the query AABBs. - ///@param out_numPairs If number of pairs exceeds the max number of pairs, this is clamped to the max number. + ///calculateOverlappingPairs() uses the worldSpaceAabbs parameter of b3GpuParallelLinearBvh::build() as the query AABBs. ///@param out_overlappingPairs The size() of this array is used to determine the max number of pairs. ///If the number of overlapping pairs is < out_overlappingPairs.size(), out_overlappingPairs is resized. - void calculateOverlappingPairs(b3OpenCLArray& out_numPairs, b3OpenCLArray& out_overlappingPairs); + void calculateOverlappingPairs(b3OpenCLArray& out_overlappingPairs); ///@param out_numRigidRayPairs Array of length 1; contains the number of detected ray-rigid AABB intersections; ///this value may be greater than out_rayRigidPairs.size() if out_rayRigidPairs is not large enough. diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp index b48c2c1de..78b625631 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp @@ -15,15 +15,13 @@ subject to the following restrictions: b3GpuParallelLinearBvhBroadphase::b3GpuParallelLinearBvhBroadphase(cl_context context, cl_device_id device, cl_command_queue queue) : m_plbvh(context, device, queue), - - m_numOverlappingPairs(context, queue), + m_overlappingPairsGpu(context, queue), m_aabbsGpu(context, queue), m_smallAabbsMappingGpu(context, queue), m_largeAabbsMappingGpu(context, queue) { - m_numOverlappingPairs.resize(1); } void b3GpuParallelLinearBvhBroadphase::createProxy(const b3Vector3& aabbMin, const b3Vector3& aabbMax, int userPtr, short int collisionFilterGroup, short int collisionFilterMask) @@ -64,7 +62,7 @@ void b3GpuParallelLinearBvhBroadphase::calculateOverlappingPairs(int maxPairs) // m_overlappingPairsGpu.resize(maxPairs); - m_plbvh.calculateOverlappingPairs(m_numOverlappingPairs, m_overlappingPairsGpu); + m_plbvh.calculateOverlappingPairs(m_overlappingPairsGpu); } void b3GpuParallelLinearBvhBroadphase::calculateOverlappingPairsHost(int maxPairs) { diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h index 9155bc1a7..284f6c780 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.h @@ -22,7 +22,6 @@ class b3GpuParallelLinearBvhBroadphase : public b3GpuBroadphaseInterface { b3GpuParallelLinearBvh m_plbvh; - b3OpenCLArray m_numOverlappingPairs; b3OpenCLArray m_overlappingPairsGpu; b3OpenCLArray m_aabbsGpu; @@ -51,6 +50,8 @@ public: virtual cl_mem getAabbBufferWS() { return m_aabbsGpu.getBufferCL(); } virtual b3OpenCLArray& getAllAabbsGPU() { return m_aabbsGpu; } + + virtual b3OpenCLArray& getOverlappingPairsGPU() { return m_overlappingPairsGpu; } virtual b3OpenCLArray& getSmallAabbIndicesGPU() { return m_smallAabbsMappingGpu; } virtual b3OpenCLArray& getLargeAabbIndicesGPU() { return m_largeAabbsMappingGpu; } diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp index 5ab7bf0db..280503b34 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.cpp @@ -1308,6 +1308,10 @@ cl_mem b3GpuSapBroadphase::getOverlappingPairBuffer() return m_overlappingPairs.getBufferCL(); } +b3OpenCLArray& b3GpuSapBroadphase::getOverlappingPairsGPU() +{ + return m_overlappingPairs; +} b3OpenCLArray& b3GpuSapBroadphase::getSmallAabbIndicesGPU() { return m_smallAabbsMappingGPU; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h index 7cbf6c7fc..23e4d624d 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/b3GpuSapBroadphase.h @@ -143,6 +143,7 @@ public: virtual int getNumOverlap(); virtual cl_mem getOverlappingPairBuffer(); + virtual b3OpenCLArray& getOverlappingPairsGPU(); virtual b3OpenCLArray& getSmallAabbIndicesGPU(); virtual b3OpenCLArray& getLargeAabbIndicesGPU(); }; From b709d6beebde777ab29455be1ea7c3ba25ace257 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Fri, 14 Mar 2014 13:55:22 -0700 Subject: [PATCH 016/116] Clean up plbvhCalculateOverlappingPairs kernel. Also fix overlapping pair generation with triangle mesh. (Currently, large/concave AABBs must be the first entry in a pair.) --- .../kernels/parallelLinearBvh.cl | 26 +++++++------------ .../kernels/parallelLinearBvhKernels.h | 25 +++++++----------- 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index 83f355849..0c7e1db69 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -184,18 +184,12 @@ __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, __global int* out_numPairs, __global int4* out_overlappingPairs, int maxPairs, int numQueryAabbs) { -#define USE_SPATIALLY_COHERENT_INDICIES //mortonCodesAndAabbIndices[] contains rigid body indices sorted along the z-curve -#ifdef USE_SPATIALLY_COHERENT_INDICIES - int queryRigidIndex = get_group_id(0) * get_local_size(0) + get_local_id(0); - if(queryRigidIndex >= numQueryAabbs) return; + //Using get_group_id()/get_local_id() is Faster than get_global_id(0) since + //mortonCodesAndAabbIndices[] contains rigid body indices sorted along the z-curve (more spatially coherent) + int queryBvhNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0); + if(queryBvhNodeIndex >= numQueryAabbs) return; - int queryBvhNodeIndex = queryRigidIndex; - queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value; // fix queryRigidIndex naming for this branch -#else - int queryRigidIndex = get_global_id(0); - if(queryRigidIndex >= numQueryAabbs) return; -#endif - + int queryRigidIndex = mortonCodesAndAabbIndices[queryBvhNodeIndex].m_value; b3AabbCL queryAabb = rigidAabbs[queryRigidIndex]; int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE]; @@ -213,17 +207,17 @@ __kernel void plbvhCalculateOverlappingPairs(__global b3AabbCL* rigidAabbs, //Optimization - if the BVH is structured as a binary radix tree, then //each internal node corresponds to a contiguous range of leaf nodes(internalNodeLeafIndexRanges[]). - //This can be used to avoid testing each AABB-AABB pair twice. + //This can be used to avoid testing each AABB-AABB pair twice, including preventing each node from colliding with itself. { int highestLeafIndex = (isLeaf) ? bvhNodeIndex : internalNodeLeafIndexRanges[bvhNodeIndex].y; - if(highestLeafIndex < queryBvhNodeIndex) continue; + if(highestLeafIndex <= queryBvhNodeIndex) continue; } //bvhRigidIndex is not used if internal node int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1; b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex]; - if( queryRigidIndex != bvhRigidIndex && TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) ) + if( TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) ) { if(isLeaf) { @@ -388,8 +382,8 @@ __kernel void plbvhLargeAabbAabbTest(__global b3AabbCL* smallAabbs, __global b3A if( TestAabbAgainstAabb2(&smallAabb, &largeAabb) ) { int4 pair; - pair.x = smallAabb.m_minIndices[3]; - pair.y = largeAabb.m_minIndices[3]; + pair.x = largeAabb.m_minIndices[3]; + pair.y = smallAabb.m_minIndices[3]; pair.z = NEW_PAIR_MARKER; pair.w = NEW_PAIR_MARKER; diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index 40c5e3218..37a1e8a5b 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -170,17 +170,12 @@ static const char* parallelLinearBvhCL= \ " __global int* out_numPairs, __global int4* out_overlappingPairs, \n" " int maxPairs, int numQueryAabbs)\n" "{\n" -"#define USE_SPATIALLY_COHERENT_INDICIES //mortonCodesAndAabbIndices[] contains rigid body indices sorted along the z-curve\n" -"#ifdef USE_SPATIALLY_COHERENT_INDICIES\n" -" int queryRigidIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" -" if(queryRigidIndex >= numQueryAabbs) return;\n" +" //Using get_group_id()/get_local_id() is Faster than get_global_id(0) since\n" +" //mortonCodesAndAabbIndices[] contains rigid body indices sorted along the z-curve (more spatially coherent)\n" +" int queryBvhNodeIndex = get_group_id(0) * get_local_size(0) + get_local_id(0);\n" +" if(queryBvhNodeIndex >= numQueryAabbs) return;\n" " \n" -" int queryBvhNodeIndex = queryRigidIndex;\n" -" queryRigidIndex = mortonCodesAndAabbIndices[queryRigidIndex].m_value; // fix queryRigidIndex naming for this branch\n" -"#else\n" -" int queryRigidIndex = get_global_id(0);\n" -" if(queryRigidIndex >= numQueryAabbs) return;\n" -"#endif\n" +" int queryRigidIndex = mortonCodesAndAabbIndices[queryBvhNodeIndex].m_value;\n" " b3AabbCL queryAabb = rigidAabbs[queryRigidIndex];\n" " \n" " int stack[B3_PLVBH_TRAVERSE_MAX_STACK_SIZE];\n" @@ -198,17 +193,17 @@ static const char* parallelLinearBvhCL= \ " \n" " //Optimization - if the BVH is structured as a binary radix tree, then\n" " //each internal node corresponds to a contiguous range of leaf nodes(internalNodeLeafIndexRanges[]).\n" -" //This can be used to avoid testing each AABB-AABB pair twice.\n" +" //This can be used to avoid testing each AABB-AABB pair twice, including preventing each node from colliding with itself.\n" " {\n" " int highestLeafIndex = (isLeaf) ? bvhNodeIndex : internalNodeLeafIndexRanges[bvhNodeIndex].y;\n" -" if(highestLeafIndex < queryBvhNodeIndex) continue;\n" +" if(highestLeafIndex <= queryBvhNodeIndex) continue;\n" " }\n" " \n" " //bvhRigidIndex is not used if internal node\n" " int bvhRigidIndex = (isLeaf) ? mortonCodesAndAabbIndices[bvhNodeIndex].m_value : -1;\n" " \n" " b3AabbCL bvhNodeAabb = (isLeaf) ? rigidAabbs[bvhRigidIndex] : internalNodeAabbs[bvhNodeIndex];\n" -" if( queryRigidIndex != bvhRigidIndex && TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) )\n" +" if( TestAabbAgainstAabb2(&queryAabb, &bvhNodeAabb) )\n" " {\n" " if(isLeaf)\n" " {\n" @@ -365,8 +360,8 @@ static const char* parallelLinearBvhCL= \ " if( TestAabbAgainstAabb2(&smallAabb, &largeAabb) )\n" " {\n" " int4 pair;\n" -" pair.x = smallAabb.m_minIndices[3];\n" -" pair.y = largeAabb.m_minIndices[3];\n" +" pair.x = largeAabb.m_minIndices[3];\n" +" pair.y = smallAabb.m_minIndices[3];\n" " pair.z = NEW_PAIR_MARKER;\n" " pair.w = NEW_PAIR_MARKER;\n" " \n" From 26bcff31f745937fffeea0bf93476789508a95e0 Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Wed, 19 Mar 2014 22:35:23 -0700 Subject: [PATCH 017/116] Add overlapping pairs validation to PairBench. --- Demos3/GpuDemos/broadphase/PairBench.cpp | 122 +++++++++++++++++- .../kernels/parallelLinearBvh.cl | 3 +- .../kernels/parallelLinearBvhKernels.h | 3 +- src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp | 2 +- 4 files changed, 122 insertions(+), 8 deletions(-) diff --git a/Demos3/GpuDemos/broadphase/PairBench.cpp b/Demos3/GpuDemos/broadphase/PairBench.cpp index 53995fd65..67a233b84 100644 --- a/Demos3/GpuDemos/broadphase/PairBench.cpp +++ b/Demos3/GpuDemos/broadphase/PairBench.cpp @@ -121,6 +121,7 @@ static BroadphaseEntry allBroadphases[]= struct PairBenchInternalData { b3GpuBroadphaseInterface* m_broadphaseGPU; + b3GpuBroadphaseInterface* m_validationBroadphase; cl_kernel m_moveObjectsKernel; cl_kernel m_sineWaveKernel; @@ -507,7 +508,16 @@ void PairBench::initPhysics(const ConstructionInfo& ci) m_data->m_sineWaveKernel = b3OpenCLUtils::compileCLKernelFromString(m_clData->m_clContext,m_clData->m_clDevice,pairsKernelsCL,"sineWaveKernel",&errNum,pairBenchProg); m_data->m_colorPairsKernel = b3OpenCLUtils::compileCLKernelFromString(m_clData->m_clContext,m_clData->m_clDevice,pairsKernelsCL,"colorPairsKernel2",&errNum,pairBenchProg); m_data->m_updateAabbSimple = b3OpenCLUtils::compileCLKernelFromString(m_clData->m_clContext,m_clData->m_clDevice,pairsKernelsCL,"updateAabbSimple",&errNum,pairBenchProg); - + + //Method for validating the overlapping pairs requires that the + //reference broadphase does not maintain internal state aside from AABB data. + //That is, overwriting the AABB state in the broadphase using + // b3GpuBroadphaseInterface::getAllAabbsGPU(), + // b3GpuBroadphaseInterface::getSmallAabbIndicesGPU(), and + // b3GpuBroadphaseInterface::getLargeAabbIndicesGPU() + //and then calling b3GpuBroadphaseInterface::calculateOverlappingPairs() should + //always produce the same result regardless of the current state of the broadphase. + m_data->m_validationBroadphase = b3GpuParallelLinearBvhBroadphase::CreateFunc(m_clData->m_clContext,m_clData->m_clDevice,m_clData->m_clQueue); } if (ci.m_window) @@ -770,6 +780,17 @@ void PairBench::renderScene() m_instancingRenderer->renderScene(); } +struct OverlappingPairSortPredicate +{ + inline bool operator() (const b3Int4& a, const b3Int4& b) const + { + if(a.x != b.x) return (a.x < b.x); + if(a.y != b.y) return (a.y < b.y); + if(a.z != b.z) return (a.z < b.z); + return (a.w < b.w); + } +}; + void PairBench::clientMoveAndDisplay() { //color all objects blue @@ -903,7 +924,10 @@ void PairBench::clientMoveAndDisplay() } } - + + int prealloc = 3*1024*1024; + int maxOverlap = b3Min(prealloc,16*numObjects); + unsigned long dt = 0; if (numObjects) { @@ -912,16 +936,104 @@ void PairBench::clientMoveAndDisplay() B3_PROFILE("calculateOverlappingPairs"); int sz = sizeof(b3Int4)*64*numObjects; - int prealloc = 3*1024*1024; - - int maxOverlap = b3Min(prealloc,16*numObjects); m_data->m_broadphaseGPU->calculateOverlappingPairs(maxOverlap); int numPairs = m_data->m_broadphaseGPU->getNumOverlap(); //printf("numPairs = %d\n", numPairs); dt = cl.getTimeMicroseconds()-dt; + } + const bool VALIDATE_BROADPHASE = false; //Check that overlapping pairs of 2 broadphases are the same + if(numObjects && VALIDATE_BROADPHASE) + { + B3_PROFILE("validate broadphases"); + + { + B3_PROFILE("calculateOverlappingPairs m_validationBroadphase"); + //m_data->m_validationBroadphase->getAllAabbsCPU() = m_data->m_broadphaseGPU->getAllAabbsCPU(); + + m_data->m_validationBroadphase->getAllAabbsGPU().copyFromOpenCLArray( m_data->m_broadphaseGPU->getAllAabbsGPU() ); + m_data->m_validationBroadphase->getSmallAabbIndicesGPU().copyFromOpenCLArray( m_data->m_broadphaseGPU->getSmallAabbIndicesGPU() ); + m_data->m_validationBroadphase->getLargeAabbIndicesGPU().copyFromOpenCLArray( m_data->m_broadphaseGPU->getLargeAabbIndicesGPU() ); + + m_data->m_validationBroadphase->calculateOverlappingPairs(maxOverlap); + } + + static b3AlignedObjectArray overlappingPairs; + static b3AlignedObjectArray overlappingPairsReference; + m_data->m_broadphaseGPU->getOverlappingPairsGPU().copyToHost(overlappingPairs); + m_data->m_validationBroadphase->getOverlappingPairsGPU().copyToHost(overlappingPairsReference); + + //Reorder pairs so that (pair.x < pair.y) is always true + { + B3_PROFILE("reorder pairs"); + + for(int i = 0; i < overlappingPairs.size(); ++i) + { + b3Int4 pair = overlappingPairs[i]; + if(pair.x > pair.y) + { + b3Swap(pair.x, pair.y); + b3Swap(pair.z, pair.w); + overlappingPairs[i] = pair; + } + } + for(int i = 0; i < overlappingPairsReference.size(); ++i) + { + b3Int4 pair = overlappingPairsReference[i]; + if(pair.x > pair.y) + { + b3Swap(pair.x, pair.y); + b3Swap(pair.z, pair.w); + overlappingPairsReference[i] = pair; + } + } + } + + // + { + B3_PROFILE("Sort overlapping pairs from most to least significant bit"); + + overlappingPairs.quickSort( OverlappingPairSortPredicate() ); + overlappingPairsReference.quickSort( OverlappingPairSortPredicate() ); + } + + //Compare + { + B3_PROFILE("compare pairs"); + + int numPairs = overlappingPairs.size(); + int numPairsReference = overlappingPairsReference.size(); + + bool success = true; + + if(numPairs == numPairsReference) + { + for(int i = 0; i < numPairsReference; ++i) + { + const b3Int4& pairA = overlappingPairs[i]; + const b3Int4& pairB = overlappingPairsReference[i]; + if( pairA.x != pairB.x + || pairA.y != pairB.y + || pairA.z != pairB.z + || pairA.w != pairB.w ) + { + b3Error("Error: one or more overlappingPairs differs from reference.\n"); + success = false; + break; + } + } + } + else + { + b3Error("Error: numPairs %d != numPairsReference %d \n", numPairs, numPairsReference); + success = false; + } + + printf("Broadphase validation: %d \n", success); + } + } if (m_data->m_gui) { diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl index 0c7e1db69..586bb8abb 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvh.cl @@ -422,7 +422,8 @@ __kernel void plbvhLargeAabbRayTest(__global b3AabbCL* largeRigidAabbs, __global //Set so that it is always greater than the actual common prefixes, and never selected as a parent node. //If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve. -//Duplicates common prefixes increase the highest common prefix by N, where 2^N is the number of duplicate nodes. +//Duplicate common prefixes increase the highest common prefix at most by the number of bits used to index the leaf node. +//Since 32 bit ints are used to index leaf nodes, the max prefix is 64(32 + 32 bit z-curve) or 96(32 + 64 bit z-curve). #define B3_PLBVH_INVALID_COMMON_PREFIX 128 #define B3_PLBVH_ROOT_NODE_MARKER -1 diff --git a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h index 37a1e8a5b..1b72803d3 100644 --- a/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h +++ b/src/Bullet3OpenCL/BroadphaseCollision/kernels/parallelLinearBvhKernels.h @@ -398,7 +398,8 @@ static const char* parallelLinearBvhCL= \ "}\n" "//Set so that it is always greater than the actual common prefixes, and never selected as a parent node.\n" "//If there are no duplicates, then the highest common prefix is 32 or 64, depending on the number of bits used for the z-curve.\n" -"//Duplicates common prefixes increase the highest common prefix by N, where 2^N is the number of duplicate nodes.\n" +"//Duplicate common prefixes increase the highest common prefix at most by the number of bits used to index the leaf node.\n" +"//Since 32 bit ints are used to index leaf nodes, the max prefix is 64(32 + 32 bit z-curve) or 96(32 + 64 bit z-curve).\n" "#define B3_PLBVH_INVALID_COMMON_PREFIX 128\n" "#define B3_PLBVH_ROOT_NODE_MARKER -1\n" "#define b3Int64 long\n" diff --git a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp index 294a20f74..4ef38bd1d 100644 --- a/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp +++ b/src/Bullet3OpenCL/Raycast/b3GpuRaycast.cpp @@ -39,7 +39,7 @@ struct b3GpuRaycastInternalData b3OpenCLArray* m_firstRayRigidPairIndexPerRay; b3OpenCLArray* m_numRayRigidPairsPerRay; - //1 element per (ray index, rigid index) pair + //1 element per (ray index, rigid index) pair, where the ray intersects with the rigid's AABB b3OpenCLArray* m_gpuNumRayRigidPairs; b3OpenCLArray* m_gpuRayRigidPairs; //x == ray index, y == rigid index From 5c5dbc035ee78531b68d8fc1e5a3beb5c2c9a0fd Mon Sep 17 00:00:00 2001 From: Jackson Lee Date: Sat, 22 Mar 2014 00:05:30 -0700 Subject: [PATCH 018/116] Avoid memory leak with validation broadphase in PairBench. --- Demos3/GpuDemos/broadphase/PairBench.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Demos3/GpuDemos/broadphase/PairBench.cpp b/Demos3/GpuDemos/broadphase/PairBench.cpp index 67a233b84..021f7e688 100644 --- a/Demos3/GpuDemos/broadphase/PairBench.cpp +++ b/Demos3/GpuDemos/broadphase/PairBench.cpp @@ -157,6 +157,8 @@ PairBench::PairBench() m_window(0) { m_data = new PairBenchInternalData; + + m_data->m_validationBroadphase = 0; } PairBench::~PairBench() { @@ -753,6 +755,12 @@ void PairBench::deleteBroadphase() void PairBench::exitPhysics() { + if(m_data->m_validationBroadphase) + { + delete m_data->m_validationBroadphase; + m_data->m_validationBroadphase = 0; + } + #ifdef B3_USE_MIDI if (m_data->m_midiIn) { From 721cab6c3b21c0024e5e77d7269da1ea3593a9dd Mon Sep 17 00:00:00 2001 From: xantares Date: Sun, 30 Mar 2014 22:40:28 +0200 Subject: [PATCH 019/116] Fixed win32 build on a case-sensitive fs --- btgui/OpenGLTrueTypeFont/fontstash.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/btgui/OpenGLTrueTypeFont/fontstash.cpp b/btgui/OpenGLTrueTypeFont/fontstash.cpp index 02b552b8b..a43b7ff5f 100644 --- a/btgui/OpenGLTrueTypeFont/fontstash.cpp +++ b/btgui/OpenGLTrueTypeFont/fontstash.cpp @@ -22,8 +22,7 @@ #include #include #ifdef _WIN32 -#include - +#include #endif #include "fontstash.h" From a50dfe8e1953b9574a021685f39654084d9dc292 Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Tue, 8 Apr 2014 09:04:32 -0700 Subject: [PATCH 020/116] add CMake support to build gtest --- CMakeLists.txt | 4 ++-- test/CMakeLists.txt | 3 +++ test/gtest-1.7.0/CMakeLists.txt | 16 ++++++++++++++++ 3 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/CMakeLists.txt create mode 100644 test/gtest-1.7.0/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 235149c77..95053a349 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -270,10 +270,10 @@ ENDIF(INSTALL_LIBS) # OPTION(INSTALL_EXTRA_LIBS "Set when you want extra libraries installed" OFF) #ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) -OPTION(BUILD_UNIT_TESTS "Build Unit Tests" OFF) +OPTION(BUILD_UNIT_TESTS "Build Unit Tests" ON) IF (BUILD_UNIT_TESTS) - SUBDIRS(UnitTests) + SUBDIRS(test) ENDIF() set (BULLET_CONFIG_CMAKE_PATH lib${LIB_SUFFIX}/cmake/bullet ) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 000000000..990d62ce4 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,3 @@ +#SUBDIRS( gtest-1.7.0 TestBullet3OpenCL) +SUBDIRS( gtest-1.7.0 ) + diff --git a/test/gtest-1.7.0/CMakeLists.txt b/test/gtest-1.7.0/CMakeLists.txt new file mode 100644 index 000000000..0091e25ec --- /dev/null +++ b/test/gtest-1.7.0/CMakeLists.txt @@ -0,0 +1,16 @@ + +INCLUDE_DIRECTORIES( + . + include +) + +SET(gtest-1.7.0_SRCS + src/gtest-all.cc +) + +#ADD_DEFINITIONS(-DGTEST_HAS_PTHREAD=1) +ADD_DEFINITIONS(-D_VARIADIC_MAX=10) + +FILE(GLOB_RECURSE gtest-1.7.0_HDRS "*.h") + +ADD_LIBRARY(gtest ${gtest-1.7.0_SRCS} ${gtest-1.7.0_HDRS}) From 050c7d928970c926eb34297c65d8b2c0e47b0afe Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Tue, 8 Apr 2014 09:05:02 -0700 Subject: [PATCH 021/116] allow to disable 'useMpr' without crash --- .../NarrowphaseCollision/b3ConvexHullContact.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.cpp b/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.cpp index 4ca3a4dcb..a0cc00496 100644 --- a/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.cpp +++ b/src/Bullet3OpenCL/NarrowphaseCollision/b3ConvexHullContact.cpp @@ -135,6 +135,9 @@ m_unitSphereDirections(m_context,m_queue) // sprintf(flags,"-g -s \"%s\"","C:/develop/bullet3_experiments2/opencl/gpu_narrowphase/kernels/sat.cl"); //#endif m_mprPenetrationKernel = 0; + m_findSeparatingAxisUnitSphereKernel = 0; + + if (useMprGpu) { cl_program mprProg = b3OpenCLUtils::compileCLProgramFromString(m_context,m_device,mprSrc,&errNum,flags,BT_NARROWPHASE_MPR_PATH); b3Assert(errNum==CL_SUCCESS); @@ -3231,7 +3234,7 @@ void GpuSatCollision::computeConvexConvexContactsGPUSAT( b3OpenCLArray* } } - if (1) + if (useMprGpu) { B3_PROFILE("findSeparatingAxisUnitSphereKernel"); b3BufferInfoCL bInfo[] = { From d1b9ecf270de770b20ac05329c9b9ab537f8054b Mon Sep 17 00:00:00 2001 From: Michal Stawinski Date: Fri, 28 Mar 2014 00:41:49 +0100 Subject: [PATCH 022/116] Fix linking errors for cmake build on Linux Missing mainly libX11 and friends --- Demos3/GpuDemos/CMakeLists.txt | 17 ++++++++--------- Demos3/SimpleOpenGL3/CMakeLists.txt | 11 +++++------ 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Demos3/GpuDemos/CMakeLists.txt b/Demos3/GpuDemos/CMakeLists.txt index c63783f7f..74bbe45c2 100644 --- a/Demos3/GpuDemos/CMakeLists.txt +++ b/Demos3/GpuDemos/CMakeLists.txt @@ -7,10 +7,9 @@ INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/btgui ) - + SET(App_Bullet3_OpenCL_Demos_SRCS ../../src/clew/clew.c - ../../btgui/OpenGLWindow/GlewWindows/glew.c GpuDemo.cpp gwenUserInterface.cpp main_opengl3core.cpp @@ -34,23 +33,23 @@ SET(App_Bullet3_OpenCL_Demos_SRCS ${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc ) +LINK_LIBRARIES( + Bullet2FileLoader Bullet3OpenCL_clew Bullet3Dynamics Bullet3Collision Bullet3Geometry Bullet3Common OpenGLWindow gwen ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} +) + + IF (WIN32) - SET(App_Bullet3_OpenCL_Demos_SRCS ${App_Bullet3_OpenCL_Demos_SRCS} ${App_Bullet3_OpenCL_Demos_Common_SRCS}) + SET(App_Bullet3_OpenCL_Demos_SRCS ${App_Bullet3_OpenCL_Demos_SRCS} ${App_Bullet3_OpenCL_Demos_Common_SRCS} ../../btgui/OpenGLWindow/GlewWindows/glew.c) INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/btgui/OpenGLWindow/GlewWindows ) ADD_DEFINITIONS(-DGLEW_STATIC) ELSE(WIN32) IF(NOT APPLE) - LINK_LIBRARIES( GLEW) + LINK_LIBRARIES( GLEW X11 dl) ENDIF(NOT APPLE) ENDIF(WIN32) - - -LINK_LIBRARIES( - Bullet2FileLoader Bullet3OpenCL_clew Bullet3Dynamics Bullet3Collision Bullet3Geometry Bullet3Common OpenGLWindow gwen ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} -) ADD_EXECUTABLE(App_Bullet3_OpenCL_Demos ${App_Bullet3_OpenCL_Demos_SRCS} diff --git a/Demos3/SimpleOpenGL3/CMakeLists.txt b/Demos3/SimpleOpenGL3/CMakeLists.txt index e144a2ce4..1181dd8e2 100644 --- a/Demos3/SimpleOpenGL3/CMakeLists.txt +++ b/Demos3/SimpleOpenGL3/CMakeLists.txt @@ -11,6 +11,10 @@ SET(AppSimpleOpenGL3_SRCS ${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc ) +LINK_LIBRARIES( + gwen OpenGLWindow Bullet3Common ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} +) + IF (WIN32) SET(AppSimpleOpenGL3_SRCS ${AppSimpleOpenGL3_SRCS} ${AppSimpleOpenGL3_Common_SRCS}) INCLUDE_DIRECTORIES( @@ -19,15 +23,10 @@ IF (WIN32) ADD_DEFINITIONS(-DGLEW_STATIC) ELSE(WIN32) IF(NOT APPLE) - LINK_LIBRARIES( GLEW) + LINK_LIBRARIES( GLEW X11 dl Xext) ENDIF(NOT APPLE) ENDIF(WIN32) - - -LINK_LIBRARIES( - Bullet3Common OpenGLWindow gwen ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} -) ADD_EXECUTABLE(AppSimpleOpenGL3 ${AppSimpleOpenGL3_SRCS} From 84693c23844b89900a1f1ebed66d3db6fef9fde6 Mon Sep 17 00:00:00 2001 From: Michal Stawinski Date: Thu, 27 Mar 2014 19:57:27 +0100 Subject: [PATCH 023/116] Fix cmake build (for case sensitive fs) --- btgui/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/btgui/CMakeLists.txt b/btgui/CMakeLists.txt index 85b54fa39..f95d9cc8c 100644 --- a/btgui/CMakeLists.txt +++ b/btgui/CMakeLists.txt @@ -1 +1 @@ -SUBDIRS( gwen OpenGLWindow ) +SUBDIRS( Gwen OpenGLWindow ) From aa76b8893622134b57eb5d04caf2bb184bc2ceb4 Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Tue, 8 Apr 2014 09:45:09 -0700 Subject: [PATCH 024/116] Added btSoftBodyHelpers::ReoptimizeLinkOrder(btSoftBody* softBody) method, to help improve performance for modern out-of-core CPUs. It is tested in Aero2 demo (13) of AppSoftBodyDemo. Note that the cloth in Areo2 is not expensive enough to see benefits. Increase segments to see benefits. Thanks a lot for the contribution. --- CMakeLists.txt | 2 +- ObsoleteDemos/SoftDemo/SoftDemo.cpp | 9 +- src/BulletSoftBody/btSoftBodyHelpers.cpp | 162 +++++++++++++++++++++++ src/BulletSoftBody/btSoftBodyHelpers.h | 7 +- 4 files changed, 177 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 95053a349..b7c15fb89 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -179,7 +179,7 @@ ENDIF (OPENGL_FOUND) -OPTION(BUILD_OBSOLETE_DEMOS "Set when you want to build the obsolete Bullet 2 demos" OFF) +OPTION(BUILD_OBSOLETE_DEMOS "Set when you want to build the obsolete Bullet 2 demos" ON) IF(BUILD_OBSOLETE_DEMOS) IF (USE_GLUT) diff --git a/ObsoleteDemos/SoftDemo/SoftDemo.cpp b/ObsoleteDemos/SoftDemo/SoftDemo.cpp index 2413c0211..1928b36bf 100644 --- a/ObsoleteDemos/SoftDemo/SoftDemo.cpp +++ b/ObsoleteDemos/SoftDemo/SoftDemo.cpp @@ -752,11 +752,13 @@ static void Init_Aero2(SoftDemo* pdemo) { //TRACEDEMO const btScalar s=5; + //psb->getWorldInfo()->m_gravity.setValue(0,0,0); + const int segments=10; const int count=5; btVector3 pos(-s*segments, 0, 0); btScalar gap = 0.5; - + for(int i=0;im_softBodyWorldInfo,btVector3(-s,0,-s*3), @@ -793,7 +795,12 @@ static void Init_Aero2(SoftDemo* pdemo) trs.setRotation(rot); psb->transform(trs); psb->setTotalMass(2.0); + + + //this could help performance in some cases + btSoftBodyHelpers::ReoptimizeLinkOrder(psb); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); } diff --git a/src/BulletSoftBody/btSoftBodyHelpers.cpp b/src/BulletSoftBody/btSoftBodyHelpers.cpp index 36f675a6c..293a393e5 100644 --- a/src/BulletSoftBody/btSoftBodyHelpers.cpp +++ b/src/BulletSoftBody/btSoftBodyHelpers.cpp @@ -480,6 +480,168 @@ void btSoftBodyHelpers::DrawClusterTree( btSoftBody* psb, drawTree(idraw,psb->m_cdbvt.m_root,0,btVector3(0,1,1),btVector3(1,0,0),mindepth,maxdepth); } + +//The btSoftBody object from the BulletSDK includes an array of Nodes and Links. These links appear +// to be first set up to connect a node to between 5 and 6 of its neighbors [480 links], +//and then to the rest of the nodes after the execution of the Floyd-Warshall graph algorithm +//[another 930 links]. +//The way the links are stored by default, we have a number of cases where adjacent links share a node in common +// - this leads to the creation of a data dependency through memory. +//The PSolve_Links() function reads and writes nodes as it iterates over each link. +//So, we now have the possibility of a data dependency between iteration X +//that processes link L with iteration X+1 that processes link L+1 +//because L and L+1 have one node in common, and iteration X updates the positions of that node, +//and iteration X+1 reads in the position of that shared node. +// +//Such a memory dependency limits the ability of a modern CPU to speculate beyond +//a certain point because it has to respect a possible dependency +//- this prevents the CPU from making full use of its out-of-order resources. +//If we re-order the links such that we minimize the cases where a link L and L+1 share a common node, +//we create a temporal gap between when the node position is written, +//and when it is subsequently read. This in turn allows the CPU to continue execution without +//risking a dependency violation. Such a reordering would result in significant speedups on +//modern CPUs with lots of execution resources. +//In our testing, we see it have a tremendous impact not only on the A7, +//but also on all x86 cores that ship with modern Macs. +//The attached source file includes a single function (ReoptimizeLinkOrder) which can be called on a +//btSoftBody object in the solveConstraints() function before the actual solver is invoked, +//or right after generateBendingConstraints() once we have all 1410 links. + + +//=================================================================== +// +// +// This function takes in a list of interdependent Links and tries +// to maximize the distance between calculation +// of dependent links. This increases the amount of parallelism that can +// be exploited by out-of-order instruction processors with large but +// (inevitably) finite instruction windows. +// +//=================================================================== + +// A small structure to track lists of dependent link calculations +class LinkDeps_t { + public: + int value; // A link calculation that is dependent on this one + // Positive values = "input A" while negative values = "input B" + LinkDeps_t *next; // Next dependence in the list +}; +typedef LinkDeps_t *LinkDepsPtr_t; + +// Dependency list constants +#define REOP_NOT_DEPENDENT -1 +#define REOP_NODE_COMPLETE -2 // Must be less than REOP_NOT_DEPENDENT + + +void btSoftBodyHelpers::ReoptimizeLinkOrder(btSoftBody *psb /* This can be replaced by a btSoftBody pointer */) +{ + int i, nLinks=psb->m_links.size(), nNodes=psb->m_nodes.size(); + btSoftBody::Link *lr; + int ar, br; + btSoftBody::Node *node0 = &(psb->m_nodes[0]); + btSoftBody::Node *node1 = &(psb->m_nodes[1]); + LinkDepsPtr_t linkDep; + int readyListHead, readyListTail, linkNum, linkDepFrees, depLink; + + // Allocate temporary buffers + int *nodeWrittenAt = new int[nNodes+1]; // What link calculation produced this node's current values? + int *linkDepA = new int[nLinks]; // Link calculation input is dependent upon prior calculation #N + int *linkDepB = new int[nLinks]; + int *readyList = new int[nLinks]; // List of ready-to-process link calculations (# of links, maximum) + LinkDeps_t *linkDepFreeList = new LinkDeps_t[2*nLinks]; // Dependent-on-me list elements (2x# of links, maximum) + LinkDepsPtr_t *linkDepListStarts = new LinkDepsPtr_t[nLinks]; // Start nodes of dependent-on-me lists, one for each link + + // Copy the original, unsorted links to a side buffer + btSoftBody::Link *linkBuffer = new btSoftBody::Link[nLinks]; + memcpy(linkBuffer, &(psb->m_links[0]), sizeof(btSoftBody::Link)*nLinks); + + // Clear out the node setup and ready list + for (i=0; i < nNodes+1; i++) { + nodeWrittenAt[i] = REOP_NOT_DEPENDENT; + } + for (i=0; i < nLinks; i++) { + linkDepListStarts[i] = NULL; + } + readyListHead = readyListTail = linkDepFrees = 0; + + // Initial link analysis to set up data structures + for (i=0; i < nLinks; i++) { + + // Note which prior link calculations we are dependent upon & build up dependence lists + lr = &(psb->m_links[i]); + ar = (lr->m_n[0] - node0)/(node1 - node0); + br = (lr->m_n[1] - node0)/(node1 - node0); + if (nodeWrittenAt[ar] > REOP_NOT_DEPENDENT) { + linkDepA[i] = nodeWrittenAt[ar]; + linkDep = &linkDepFreeList[linkDepFrees++]; + linkDep->value = i; + linkDep->next = linkDepListStarts[nodeWrittenAt[ar]]; + linkDepListStarts[nodeWrittenAt[ar]] = linkDep; + } else { + linkDepA[i] = REOP_NOT_DEPENDENT; + } + if (nodeWrittenAt[br] > REOP_NOT_DEPENDENT) { + linkDepB[i] = nodeWrittenAt[br]; + linkDep = &linkDepFreeList[linkDepFrees++]; + linkDep->value = -(i+1); + linkDep->next = linkDepListStarts[nodeWrittenAt[br]]; + linkDepListStarts[nodeWrittenAt[br]] = linkDep; + } else { + linkDepB[i] = REOP_NOT_DEPENDENT; + } + + // Add this link to the initial ready list, if it is not dependent on any other links + if ((linkDepA[i] == REOP_NOT_DEPENDENT) && (linkDepB[i] == REOP_NOT_DEPENDENT)) { + readyList[readyListTail++] = i; + linkDepA[i] = linkDepB[i] = REOP_NODE_COMPLETE; // Probably not needed now + } + + // Update the nodes to mark which ones are calculated by this link + nodeWrittenAt[ar] = nodeWrittenAt[br] = i; + } + + // Process the ready list and create the sorted list of links + // -- By treating the ready list as a queue, we maximize the distance between any + // inter-dependent node calculations + // -- All other (non-related) nodes in the ready list will automatically be inserted + // in between each set of inter-dependent link calculations by this loop + i = 0; + while (readyListHead != readyListTail) { + // Use ready list to select the next link to process + linkNum = readyList[readyListHead++]; + // Copy the next-to-calculate link back into the original link array + psb->m_links[i++] = linkBuffer[linkNum]; + + // Free up any link inputs that are dependent on this one + linkDep = linkDepListStarts[linkNum]; + while (linkDep) { + depLink = linkDep->value; + if (depLink >= 0) { + linkDepA[depLink] = REOP_NOT_DEPENDENT; + } else { + depLink = -depLink - 1; + linkDepB[depLink] = REOP_NOT_DEPENDENT; + } + // Add this dependent link calculation to the ready list if *both* inputs are clear + if ((linkDepA[depLink] == REOP_NOT_DEPENDENT) && (linkDepB[depLink] == REOP_NOT_DEPENDENT)) { + readyList[readyListTail++] = depLink; + linkDepA[depLink] = linkDepB[depLink] = REOP_NODE_COMPLETE; // Probably not needed now + } + linkDep = linkDep->next; + } + } + + // Delete the temporary buffers + delete [] nodeWrittenAt; + delete [] linkDepA; + delete [] linkDepB; + delete [] readyList; + delete [] linkDepFreeList; + delete [] linkDepListStarts; + delete [] linkBuffer; +} + + // void btSoftBodyHelpers::DrawFrame( btSoftBody* psb, btIDebugDraw* idraw) diff --git a/src/BulletSoftBody/btSoftBodyHelpers.h b/src/BulletSoftBody/btSoftBodyHelpers.h index 620a52fe3..727153010 100644 --- a/src/BulletSoftBody/btSoftBodyHelpers.h +++ b/src/BulletSoftBody/btSoftBodyHelpers.h @@ -137,7 +137,12 @@ struct btSoftBodyHelpers bool bfacelinks, bool btetralinks, bool bfacesfromtetras); - + + /// Sort the list of links to move link calculations that are dependent upon earlier + /// ones as far as possible away from the calculation of those values + /// This tends to make adjacent loop iterations not dependent upon one another, + /// so out-of-order processors can execute instructions from multiple iterations at once + static void ReoptimizeLinkOrder(btSoftBody *psb ); }; #endif //BT_SOFT_BODY_HELPERS_H From aafbf48130afc8b3d242021a2cc027a8f660b978 Mon Sep 17 00:00:00 2001 From: xantares Date: Wed, 9 Apr 2014 10:33:22 +0000 Subject: [PATCH 025/116] Fix linux|mingw shared|static build --- Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp | 2 +- Demos3/CpuDemos/main_opengl3core.cpp | 2 +- Demos3/GpuDemos/main_opengl3core.cpp | 2 +- btgui/Gwen/Macros.h | 6 ++++-- btgui/OpenGLWindow/CMakeLists.txt | 8 ++++++++ src/Bullet3Collision/CMakeLists.txt | 3 +++ src/Bullet3Common/b3Logging.cpp | 2 +- src/Bullet3Dynamics/CMakeLists.txt | 3 +++ src/Bullet3Geometry/CMakeLists.txt | 3 +++ src/Bullet3OpenCL/CMakeLists.txt | 6 +++--- src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp | 2 +- src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt | 3 +++ 12 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp b/Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp index 594caa023..faeb09f97 100644 --- a/Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp +++ b/Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp @@ -54,7 +54,7 @@ b3GpuDynamicsWorld::~b3GpuDynamicsWorld() } -#include +#include int b3GpuDynamicsWorld::stepSimulation( btScalar timeStepUnused, int maxSubStepsUnused, btScalar fixedTimeStep) { diff --git a/Demos3/CpuDemos/main_opengl3core.cpp b/Demos3/CpuDemos/main_opengl3core.cpp index 540585b02..5de834f00 100644 --- a/Demos3/CpuDemos/main_opengl3core.cpp +++ b/Demos3/CpuDemos/main_opengl3core.cpp @@ -2,7 +2,7 @@ //#include "GpuDemo.h" #ifdef _WIN32 -#include //for GetLocalTime/GetSystemTime +#include //for GetLocalTime/GetSystemTime #else #include //gettimeofday #endif diff --git a/Demos3/GpuDemos/main_opengl3core.cpp b/Demos3/GpuDemos/main_opengl3core.cpp index 0be3fdfcd..fde95d530 100644 --- a/Demos3/GpuDemos/main_opengl3core.cpp +++ b/Demos3/GpuDemos/main_opengl3core.cpp @@ -2,7 +2,7 @@ //#include "GpuDemo.h" #ifdef _WIN32 -#include //for GetLocalTime/GetSystemTime +#include //for GetLocalTime/GetSystemTime #else #include //gettimeofday #endif diff --git a/btgui/Gwen/Macros.h b/btgui/Gwen/Macros.h index e0669f163..5204a2b0f 100644 --- a/btgui/Gwen/Macros.h +++ b/btgui/Gwen/Macros.h @@ -17,7 +17,9 @@ #ifdef _WIN32 - #define NOMINMAX + #ifndef NOMINMAX + #define NOMINMAX + #endif #include #define GwenUtil_VSNPrintFSafe( _DstBuf, _DstSize, _MaxCount, _Format, _ArgList ) vsnprintf_s( _DstBuf, _DstSize, _MaxCount, _Format, _ArgList ) @@ -79,4 +81,4 @@ namespace Gwen } } -#endif \ No newline at end of file +#endif diff --git a/btgui/OpenGLWindow/CMakeLists.txt b/btgui/OpenGLWindow/CMakeLists.txt index e12a1008b..81e9bcf3e 100644 --- a/btgui/OpenGLWindow/CMakeLists.txt +++ b/btgui/OpenGLWindow/CMakeLists.txt @@ -38,4 +38,12 @@ ENDIF() ADD_LIBRARY(OpenGLWindow ${OpenGLWindow_SRCS} ${OpenGLWindow_HDRS}) +if (UNIX AND NOT APPLE) + target_link_libraries(OpenGLWindow X11) +endif () +if (BUILD_SHARED_LIBS) + target_link_libraries(OpenGLWindow Bullet3Common) +endif() + +target_link_libraries(OpenGLWindow ${OPENGL_gl_LIBRARY}) diff --git a/src/Bullet3Collision/CMakeLists.txt b/src/Bullet3Collision/CMakeLists.txt index 39a7b348e..3ba4d9b9f 100644 --- a/src/Bullet3Collision/CMakeLists.txt +++ b/src/Bullet3Collision/CMakeLists.txt @@ -58,6 +58,9 @@ SET(Bullet3Collision_HDRS ) ADD_LIBRARY(Bullet3Collision ${Bullet3Collision_SRCS} ${Bullet3Collision_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Collision Bullet3Geometry) +endif () SET_TARGET_PROPERTIES(Bullet3Collision PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet3Collision PROPERTIES SOVERSION ${BULLET_VERSION}) diff --git a/src/Bullet3Common/b3Logging.cpp b/src/Bullet3Common/b3Logging.cpp index 2feded9de..fd5cd7d01 100644 --- a/src/Bullet3Common/b3Logging.cpp +++ b/src/Bullet3Common/b3Logging.cpp @@ -19,7 +19,7 @@ subject to the following restrictions: #include #ifdef _WIN32 -#include +#include #endif //_WIN32 diff --git a/src/Bullet3Dynamics/CMakeLists.txt b/src/Bullet3Dynamics/CMakeLists.txt index 1e48ee827..0b0deed98 100644 --- a/src/Bullet3Dynamics/CMakeLists.txt +++ b/src/Bullet3Dynamics/CMakeLists.txt @@ -30,6 +30,9 @@ SET(Bullet3Dynamics_HDRS ) ADD_LIBRARY(Bullet3Dynamics ${Bullet3Dynamics_SRCS} ${Bullet3Dynamics_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Dynamics Bullet3Collision) +endif () SET_TARGET_PROPERTIES(Bullet3Dynamics PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet3Dynamics PROPERTIES SOVERSION ${BULLET_VERSION}) diff --git a/src/Bullet3Geometry/CMakeLists.txt b/src/Bullet3Geometry/CMakeLists.txt index 8a8f8ab50..7e781278a 100644 --- a/src/Bullet3Geometry/CMakeLists.txt +++ b/src/Bullet3Geometry/CMakeLists.txt @@ -16,6 +16,9 @@ SET(Bullet3Geometry_HDRS ) ADD_LIBRARY(Bullet3Geometry ${Bullet3Geometry_SRCS} ${Bullet3Geometry_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Geometry Bullet3Common) +endif() SET_TARGET_PROPERTIES(Bullet3Geometry PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet3Geometry PROPERTIES SOVERSION ${BULLET_VERSION}) diff --git a/src/Bullet3OpenCL/CMakeLists.txt b/src/Bullet3OpenCL/CMakeLists.txt index 56f4130e0..d7d43df04 100644 --- a/src/Bullet3OpenCL/CMakeLists.txt +++ b/src/Bullet3OpenCL/CMakeLists.txt @@ -43,7 +43,7 @@ ADD_LIBRARY(Bullet3OpenCL_clew ${Bullet3OpenCL_clew_SRCS} ${Bullet3OpenCL_clew_H SET_TARGET_PROPERTIES(Bullet3OpenCL_clew PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet3OpenCL_clew PROPERTIES SOVERSION ${BULLET_VERSION}) IF (BUILD_SHARED_LIBS) - TARGET_LINK_LIBRARIES(Bullet3OpenCL_clew LinearMath) + TARGET_LINK_LIBRARIES(Bullet3OpenCL_clew LinearMath Bullet3Dynamics) ENDIF (BUILD_SHARED_LIBS) @@ -59,8 +59,8 @@ IF (INSTALL_LIBS) ARCHIVE DESTINATION lib${LIB_SUFFIX}) INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) - INSTALL(FILES ../btBullet3OpenCL_clewCommon.h -DESTINATION ${INCLUDE_INSTALL_DIR}/Bullet3OpenCL_clew) +# INSTALL(FILES ../btBullet3OpenCL_clewCommon.h +#DESTINATION ${INCLUDE_INSTALL_DIR}/Bullet3OpenCL_clew) ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) diff --git a/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp b/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp index e409658ca..e5b3ef877 100644 --- a/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp +++ b/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp @@ -36,7 +36,7 @@ bool gDebugSkipLoadingBinary = false; #define B3_MAX_CL_DEVICES 16 //who needs 16 devices? #ifdef _WIN32 -#include +#include #endif #include diff --git a/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt b/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt index a73d3ccd8..169004557 100644 --- a/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt +++ b/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt @@ -24,6 +24,9 @@ SET(Bullet2FileLoader_HDRS ) ADD_LIBRARY(Bullet2FileLoader ${Bullet2FileLoader_SRCS} ${Bullet2FileLoader_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet2FileLoader Bullet3Common) +endif () SET_TARGET_PROPERTIES(Bullet2FileLoader PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet2FileLoader PROPERTIES SOVERSION ${BULLET_VERSION}) From 477cfc6fe6376bb8a1d450c3306d5bbc64c68da7 Mon Sep 17 00:00:00 2001 From: xantares Date: Wed, 9 Apr 2014 10:33:22 +0000 Subject: [PATCH 026/116] Fix linux|mingw shared|static build --- Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp | 2 +- Demos3/CpuDemos/main_opengl3core.cpp | 2 +- Demos3/GpuDemos/main_opengl3core.cpp | 2 +- btgui/Gwen/Macros.h | 6 ++++-- btgui/OpenGLWindow/CMakeLists.txt | 8 ++++++++ src/Bullet3Collision/CMakeLists.txt | 3 +++ src/Bullet3Common/b3Logging.cpp | 2 +- src/Bullet3Dynamics/CMakeLists.txt | 3 +++ src/Bullet3Geometry/CMakeLists.txt | 3 +++ src/Bullet3OpenCL/CMakeLists.txt | 6 +++--- src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp | 2 +- src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt | 3 +++ 12 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp b/Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp index 594caa023..faeb09f97 100644 --- a/Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp +++ b/Demos3/BasicGpuDemo/b3GpuDynamicsWorld.cpp @@ -54,7 +54,7 @@ b3GpuDynamicsWorld::~b3GpuDynamicsWorld() } -#include +#include int b3GpuDynamicsWorld::stepSimulation( btScalar timeStepUnused, int maxSubStepsUnused, btScalar fixedTimeStep) { diff --git a/Demos3/CpuDemos/main_opengl3core.cpp b/Demos3/CpuDemos/main_opengl3core.cpp index 540585b02..5de834f00 100644 --- a/Demos3/CpuDemos/main_opengl3core.cpp +++ b/Demos3/CpuDemos/main_opengl3core.cpp @@ -2,7 +2,7 @@ //#include "GpuDemo.h" #ifdef _WIN32 -#include //for GetLocalTime/GetSystemTime +#include //for GetLocalTime/GetSystemTime #else #include //gettimeofday #endif diff --git a/Demos3/GpuDemos/main_opengl3core.cpp b/Demos3/GpuDemos/main_opengl3core.cpp index 0be3fdfcd..fde95d530 100644 --- a/Demos3/GpuDemos/main_opengl3core.cpp +++ b/Demos3/GpuDemos/main_opengl3core.cpp @@ -2,7 +2,7 @@ //#include "GpuDemo.h" #ifdef _WIN32 -#include //for GetLocalTime/GetSystemTime +#include //for GetLocalTime/GetSystemTime #else #include //gettimeofday #endif diff --git a/btgui/Gwen/Macros.h b/btgui/Gwen/Macros.h index e0669f163..5204a2b0f 100644 --- a/btgui/Gwen/Macros.h +++ b/btgui/Gwen/Macros.h @@ -17,7 +17,9 @@ #ifdef _WIN32 - #define NOMINMAX + #ifndef NOMINMAX + #define NOMINMAX + #endif #include #define GwenUtil_VSNPrintFSafe( _DstBuf, _DstSize, _MaxCount, _Format, _ArgList ) vsnprintf_s( _DstBuf, _DstSize, _MaxCount, _Format, _ArgList ) @@ -79,4 +81,4 @@ namespace Gwen } } -#endif \ No newline at end of file +#endif diff --git a/btgui/OpenGLWindow/CMakeLists.txt b/btgui/OpenGLWindow/CMakeLists.txt index e12a1008b..81e9bcf3e 100644 --- a/btgui/OpenGLWindow/CMakeLists.txt +++ b/btgui/OpenGLWindow/CMakeLists.txt @@ -38,4 +38,12 @@ ENDIF() ADD_LIBRARY(OpenGLWindow ${OpenGLWindow_SRCS} ${OpenGLWindow_HDRS}) +if (UNIX AND NOT APPLE) + target_link_libraries(OpenGLWindow X11) +endif () +if (BUILD_SHARED_LIBS) + target_link_libraries(OpenGLWindow Bullet3Common) +endif() + +target_link_libraries(OpenGLWindow ${OPENGL_gl_LIBRARY}) diff --git a/src/Bullet3Collision/CMakeLists.txt b/src/Bullet3Collision/CMakeLists.txt index 39a7b348e..3ba4d9b9f 100644 --- a/src/Bullet3Collision/CMakeLists.txt +++ b/src/Bullet3Collision/CMakeLists.txt @@ -58,6 +58,9 @@ SET(Bullet3Collision_HDRS ) ADD_LIBRARY(Bullet3Collision ${Bullet3Collision_SRCS} ${Bullet3Collision_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Collision Bullet3Geometry) +endif () SET_TARGET_PROPERTIES(Bullet3Collision PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet3Collision PROPERTIES SOVERSION ${BULLET_VERSION}) diff --git a/src/Bullet3Common/b3Logging.cpp b/src/Bullet3Common/b3Logging.cpp index 2feded9de..fd5cd7d01 100644 --- a/src/Bullet3Common/b3Logging.cpp +++ b/src/Bullet3Common/b3Logging.cpp @@ -19,7 +19,7 @@ subject to the following restrictions: #include #ifdef _WIN32 -#include +#include #endif //_WIN32 diff --git a/src/Bullet3Dynamics/CMakeLists.txt b/src/Bullet3Dynamics/CMakeLists.txt index 1e48ee827..0b0deed98 100644 --- a/src/Bullet3Dynamics/CMakeLists.txt +++ b/src/Bullet3Dynamics/CMakeLists.txt @@ -30,6 +30,9 @@ SET(Bullet3Dynamics_HDRS ) ADD_LIBRARY(Bullet3Dynamics ${Bullet3Dynamics_SRCS} ${Bullet3Dynamics_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Dynamics Bullet3Collision) +endif () SET_TARGET_PROPERTIES(Bullet3Dynamics PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet3Dynamics PROPERTIES SOVERSION ${BULLET_VERSION}) diff --git a/src/Bullet3Geometry/CMakeLists.txt b/src/Bullet3Geometry/CMakeLists.txt index 8a8f8ab50..7e781278a 100644 --- a/src/Bullet3Geometry/CMakeLists.txt +++ b/src/Bullet3Geometry/CMakeLists.txt @@ -16,6 +16,9 @@ SET(Bullet3Geometry_HDRS ) ADD_LIBRARY(Bullet3Geometry ${Bullet3Geometry_SRCS} ${Bullet3Geometry_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet3Geometry Bullet3Common) +endif() SET_TARGET_PROPERTIES(Bullet3Geometry PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet3Geometry PROPERTIES SOVERSION ${BULLET_VERSION}) diff --git a/src/Bullet3OpenCL/CMakeLists.txt b/src/Bullet3OpenCL/CMakeLists.txt index 56f4130e0..d7d43df04 100644 --- a/src/Bullet3OpenCL/CMakeLists.txt +++ b/src/Bullet3OpenCL/CMakeLists.txt @@ -43,7 +43,7 @@ ADD_LIBRARY(Bullet3OpenCL_clew ${Bullet3OpenCL_clew_SRCS} ${Bullet3OpenCL_clew_H SET_TARGET_PROPERTIES(Bullet3OpenCL_clew PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet3OpenCL_clew PROPERTIES SOVERSION ${BULLET_VERSION}) IF (BUILD_SHARED_LIBS) - TARGET_LINK_LIBRARIES(Bullet3OpenCL_clew LinearMath) + TARGET_LINK_LIBRARIES(Bullet3OpenCL_clew LinearMath Bullet3Dynamics) ENDIF (BUILD_SHARED_LIBS) @@ -59,8 +59,8 @@ IF (INSTALL_LIBS) ARCHIVE DESTINATION lib${LIB_SUFFIX}) INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.h" PATTERN ".svn" EXCLUDE PATTERN "CMakeFiles" EXCLUDE) - INSTALL(FILES ../btBullet3OpenCL_clewCommon.h -DESTINATION ${INCLUDE_INSTALL_DIR}/Bullet3OpenCL_clew) +# INSTALL(FILES ../btBullet3OpenCL_clewCommon.h +#DESTINATION ${INCLUDE_INSTALL_DIR}/Bullet3OpenCL_clew) ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) diff --git a/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp b/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp index e409658ca..e5b3ef877 100644 --- a/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp +++ b/src/Bullet3OpenCL/Initialize/b3OpenCLUtils.cpp @@ -36,7 +36,7 @@ bool gDebugSkipLoadingBinary = false; #define B3_MAX_CL_DEVICES 16 //who needs 16 devices? #ifdef _WIN32 -#include +#include #endif #include diff --git a/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt b/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt index a73d3ccd8..169004557 100644 --- a/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt +++ b/src/Bullet3Serialize/Bullet2FileLoader/CMakeLists.txt @@ -24,6 +24,9 @@ SET(Bullet2FileLoader_HDRS ) ADD_LIBRARY(Bullet2FileLoader ${Bullet2FileLoader_SRCS} ${Bullet2FileLoader_HDRS}) +if (BUILD_SHARED_LIBS) + target_link_libraries(Bullet2FileLoader Bullet3Common) +endif () SET_TARGET_PROPERTIES(Bullet2FileLoader PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(Bullet2FileLoader PROPERTIES SOVERSION ${BULLET_VERSION}) From 5dafea7c06acc876024252ad0a62355244019223 Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Wed, 9 Apr 2014 21:23:22 -0700 Subject: [PATCH 027/116] avoid allocations in renderer (messes up AMD buggy OpenGL driver) add missing file in cmake build system (BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp and BroadphaseCollision/b3GpuParallelLinearBvh.cpp) --- .../opengl_fontstashcallbacks.cpp | 1 + btgui/OpenGLWindow/GLInstancingRenderer.cpp | 14 ++++++++++++-- btgui/OpenGLWindow/GLPrimitiveRenderer.cpp | 4 ++-- src/Bullet3OpenCL/CMakeLists.txt | 2 ++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/btgui/OpenGLTrueTypeFont/opengl_fontstashcallbacks.cpp b/btgui/OpenGLTrueTypeFont/opengl_fontstashcallbacks.cpp index e1554bf08..1ef12906f 100644 --- a/btgui/OpenGLTrueTypeFont/opengl_fontstashcallbacks.cpp +++ b/btgui/OpenGLTrueTypeFont/opengl_fontstashcallbacks.cpp @@ -220,6 +220,7 @@ void InternalOpenGL2RenderCallbacks::render(sth_texture* texture) glBindBuffer(GL_ARRAY_BUFFER, s_vertexBuffer); glBindVertexArray(s_vertexArrayObject); glBufferData(GL_ARRAY_BUFFER, texture->nverts * sizeof(Vertex), &texture->newverts[0].position.p[0], GL_DYNAMIC_DRAW); + err = glGetError(); assert(err==GL_NO_ERROR); diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index ecf66c6a8..6097a9f88 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -742,6 +742,12 @@ void GLInstancingRenderer::InitShaders() glGenBuffers(1, &lineVertexBufferObject); glGenBuffers(1, &lineIndexVbo); + + int sz = 8*sizeof(float); + glBindVertexArray(lineVertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER, lineVertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, sz, 0, GL_DYNAMIC_DRAW); + glBindVertexArray(0); @@ -1456,8 +1462,12 @@ void GLInstancingRenderer::drawLine(const float from[4], const float to[4], cons err = glGetError(); b3Assert(err==GL_NO_ERROR); - glBufferData(GL_ARRAY_BUFFER, sz, vertexPositions, GL_STATIC_DRAW); - + + { + glBufferSubData(GL_ARRAY_BUFFER, 0,sz, vertexPositions); + } + + err = glGetError(); b3Assert(err==GL_NO_ERROR); diff --git a/btgui/OpenGLWindow/GLPrimitiveRenderer.cpp b/btgui/OpenGLWindow/GLPrimitiveRenderer.cpp index a3024a21e..e1c424659 100644 --- a/btgui/OpenGLWindow/GLPrimitiveRenderer.cpp +++ b/btgui/OpenGLWindow/GLPrimitiveRenderer.cpp @@ -130,7 +130,7 @@ void GLPrimitiveRenderer::loadBufferData() glGenBuffers(1, &m_data->m_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vertexBuffer); - glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vertex), vertexData, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vertex), vertexData, GL_DYNAMIC_DRAW); GLuint err = glGetError(); assert(err==GL_NO_ERROR); @@ -269,7 +269,7 @@ void GLPrimitiveRenderer::drawTexturedRect(float x0, float y0, float x1, float y { vec4( -1.+2.*x1/float(m_screenWidth), 1.-2.*y0/float(m_screenHeight), 1, 0 ), vec4( color[0], color[1], color[2], color[3] ) ,vec2(u1,v0)} }; - glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(Vertex), vertexData, GL_STATIC_DRAW); + glBufferSubData(GL_ARRAY_BUFFER, 0,4 * sizeof(Vertex), vertexData); diff --git a/src/Bullet3OpenCL/CMakeLists.txt b/src/Bullet3OpenCL/CMakeLists.txt index d7d43df04..286822272 100644 --- a/src/Bullet3OpenCL/CMakeLists.txt +++ b/src/Bullet3OpenCL/CMakeLists.txt @@ -6,6 +6,8 @@ SET(Bullet3OpenCL_clew_SRCS ../clew/clew.c BroadphaseCollision/b3GpuGridBroadphase.cpp BroadphaseCollision/b3GpuSapBroadphase.cpp + BroadphaseCollision/b3GpuParallelLinearBvhBroadphase.cpp + BroadphaseCollision/b3GpuParallelLinearBvh.cpp Initialize/b3OpenCLUtils.cpp NarrowphaseCollision/b3ContactCache.cpp NarrowphaseCollision/b3ConvexHullContact.cpp From ed42e217b54b1047d9fe47de0bc214ed494dee4e Mon Sep 17 00:00:00 2001 From: XBog Date: Sat, 12 Apr 2014 18:11:58 +0200 Subject: [PATCH 028/116] subdivion backface shouldnt be in front --- .../CollisionShapes/btHeightfieldTerrainShape.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp b/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp index 26322791d..bf255dfc8 100644 --- a/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp +++ b/src/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp @@ -365,14 +365,15 @@ void btHeightfieldTerrainShape::processAllTriangles(btTriangleCallback* callback { //first triangle getVertex(x,j,vertices[0]); - getVertex(x+1,j,vertices[1]); - getVertex(x+1,j+1,vertices[2]); + getVertex(x, j + 1, vertices[1]); + getVertex(x + 1, j + 1, vertices[2]); callback->processTriangle(vertices,x,j); //second triangle // getVertex(x,j,vertices[0]);//already got this vertex before, thanks to Danny Chapman getVertex(x+1,j+1,vertices[1]); - getVertex(x,j+1,vertices[2]); - callback->processTriangle(vertices,x,j); + getVertex(x + 1, j, vertices[2]); + callback->processTriangle(vertices, x, j); + } else { //first triangle From a3369e2d14dee6836905c3b98cc797c824cfa702 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Sat, 12 Apr 2014 19:53:44 -0700 Subject: [PATCH 029/116] minor fix in GL3+ rendering --- Demos3/ImplicitCloth/main.cpp | 6 +- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 126 +++++++++++++------- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 6 + 3 files changed, 96 insertions(+), 42 deletions(-) diff --git a/Demos3/ImplicitCloth/main.cpp b/Demos3/ImplicitCloth/main.cpp index be95c76a2..e51062816 100644 --- a/Demos3/ImplicitCloth/main.cpp +++ b/Demos3/ImplicitCloth/main.cpp @@ -29,7 +29,11 @@ void drawCloth(class GLInstancingRenderer* renderer) err = glGetError(); assert(err==GL_NO_ERROR); float pointColor[4]={1,0.4,0.4,1}; - renderer->drawPoints(&cloth->X[0].x,pointColor,total_points,sizeof(float3),6); + + glDisable(GL_DEPTH_TEST); + renderer->drawPoints(&cloth->X[0].x,pointColor,total_points,sizeof(float3),3); + glEnable(GL_DEPTH_TEST); + err = glGetError(); assert(err==GL_NO_ERROR); diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index 6097a9f88..9fdc05848 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -21,6 +21,9 @@ float shadowMapHeight=8192; float shadowMapWorldSize=100; float WHEEL_MULTIPLIER=0.01f; float MOUSE_MOVE_MULTIPLIER = 0.4f; +#define MAX_POINTS_IN_BATCH 1024 +#define MAX_LINES_IN_BATCH 1024 + #include "OpenGLInclude.h" #include "b3gWindowInterface.h" @@ -324,6 +327,9 @@ GLuint lineVertexBufferObject=0; GLuint lineVertexArrayObject=0; GLuint lineIndexVbo = 0; +GLuint linesVertexBufferObject=0; +GLuint linesVertexArrayObject=0; +GLuint linesIndexVbo = 0; static GLint useShadow_ModelViewMatrix=0; @@ -735,21 +741,35 @@ void GLInstancingRenderer::InitShaders() lines_position=glGetAttribLocation(linesShader, "position"); glLinkProgram(linesShader); glUseProgram(linesShader); - - - glGenVertexArrays(1, &lineVertexArrayObject); - glBindVertexArray(lineVertexArrayObject); - glGenBuffers(1, &lineVertexBufferObject); - glGenBuffers(1, &lineIndexVbo); + { + glGenVertexArrays(1, &linesVertexArrayObject); + glBindVertexArray(linesVertexArrayObject); + + glGenBuffers(1, &linesVertexBufferObject); + glGenBuffers(1, &linesIndexVbo); - int sz = 8*sizeof(float); - glBindVertexArray(lineVertexArrayObject); - glBindBuffer(GL_ARRAY_BUFFER, lineVertexBufferObject); - glBufferData(GL_ARRAY_BUFFER, sz, 0, GL_DYNAMIC_DRAW); + int sz = MAX_LINES_IN_BATCH*sizeof(b3Vector3); + glBindVertexArray(linesVertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER, linesVertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, sz, 0, GL_DYNAMIC_DRAW); - glBindVertexArray(0); + glBindVertexArray(0); + } + { + glGenVertexArrays(1, &lineVertexArrayObject); + glBindVertexArray(lineVertexArrayObject); + + glGenBuffers(1, &lineVertexBufferObject); + glGenBuffers(1, &lineIndexVbo); + int sz = MAX_POINTS_IN_BATCH*sizeof(b3Vector3); + glBindVertexArray(lineVertexArrayObject); + glBindBuffer(GL_ARRAY_BUFFER, lineVertexBufferObject); + glBufferData(GL_ARRAY_BUFFER, sz, 0, GL_DYNAMIC_DRAW); + + glBindVertexArray(0); + } //glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, range); glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, lineWidthRange); @@ -1333,13 +1353,30 @@ void GLInstancingRenderer::drawPoints(const float* positions, const float color[ glBindVertexArray(lineVertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, lineVertexBufferObject); - glBufferData(GL_ARRAY_BUFFER, numPoints*pointStrideInBytes, positions, GL_STATIC_DRAW); -// glBindBuffer(GL_ARRAY_BUFFER, 0); -// glBindBuffer(GL_ARRAY_BUFFER, lineVertexBufferObject); - glEnableVertexAttribArray(0); - int numFloats = pointStrideInBytes/sizeof(float); - glVertexAttribPointer(0, numFloats, GL_FLOAT, GL_FALSE, 0, 0); - glDrawArrays(GL_POINTS, 0, numPoints); + + int maxPointsInBatch = MAX_POINTS_IN_BATCH; + int remainingPoints = numPoints; + int offsetNumPoints= 0; + while (1) + { + int curPointsInBatch = b3Min(maxPointsInBatch, remainingPoints); + if (curPointsInBatch) + { + + glBufferSubData(GL_ARRAY_BUFFER, 0, curPointsInBatch*pointStrideInBytes, positions + offsetNumPoints*(pointStrideInBytes / sizeof(float))); + glEnableVertexAttribArray(0); + int numFloats = 3;// pointStrideInBytes / sizeof(float); + glVertexAttribPointer(0, numFloats, GL_FLOAT, GL_FALSE, pointStrideInBytes, 0); + glDrawArrays(GL_POINTS, 0, curPointsInBatch); + remainingPoints -= curPointsInBatch; + offsetNumPoints += curPointsInBatch; + } + else + { + break; + } + } + glBindVertexArray(0); glPointSize(1); } @@ -1365,36 +1402,43 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 glUniform4f(lines_colour,color[0],color[1],color[2],color[3]); // glPointSize(pointDrawSize); - glBindVertexArray(lineVertexArrayObject); + glBindVertexArray(linesVertexArrayObject); err = glGetError(); b3Assert(err==GL_NO_ERROR); - glBindBuffer(GL_ARRAY_BUFFER, lineVertexBufferObject); - glBufferData(GL_ARRAY_BUFFER, numPoints*pointStrideInBytes, positions, GL_STATIC_DRAW); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + glBindBuffer(GL_ARRAY_BUFFER, linesVertexBufferObject); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ARRAY_BUFFER, lineVertexBufferObject); - glEnableVertexAttribArray(0); - - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + { - int numFloats = pointStrideInBytes/sizeof(float); - glVertexAttribPointer(0, numFloats, GL_FLOAT, GL_FALSE, 0, 0); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + glBufferData(GL_ARRAY_BUFFER, numPoints*pointStrideInBytes, 0,GL_DYNAMIC_DRAW); + + glBufferSubData(GL_ARRAY_BUFFER, 0, numPoints*pointStrideInBytes, positions); + err = glGetError(); + b3Assert(err == GL_NO_ERROR); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, linesVertexBufferObject); + glEnableVertexAttribArray(0); + + err = glGetError(); + b3Assert(err == GL_NO_ERROR); + + int numFloats = pointStrideInBytes / sizeof(float); + glVertexAttribPointer(0, numFloats, GL_FLOAT, GL_FALSE, 0, 0); + err = glGetError(); + b3Assert(err == GL_NO_ERROR); + + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, linesIndexVbo); + int indexBufferSizeInBytes = numIndices*sizeof(int); + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeInBytes, NULL, GL_DYNAMIC_DRAW); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, indexBufferSizeInBytes, indices); + + glDrawElements(GL_LINES, numIndices, GL_UNSIGNED_INT, 0); + } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, lineIndexVbo); - int indexBufferSizeInBytes = numIndices*sizeof(int); - - glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeInBytes, NULL, GL_STATIC_DRAW); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,indexBufferSizeInBytes,indices); - - glDrawElements(GL_LINES, numIndices, GL_UNSIGNED_INT,0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0); // for (int i=0;idrawLine(b3MakeVector3(0,0,0),b3MakeVector3(0,1,0),b3MakeVector3(0,1,0),3); m_instancingRenderer->drawLine(b3MakeVector3(0,0,0),b3MakeVector3(0,0,1),b3MakeVector3(0,0,1),3); +// void GLInstancingRenderer::drawPoints(const float* positions, const float color[4], int numPoints, int pointStrideInBytes, float pointDrawSize) + + //we don't use drawPoints because all points would have the same color +// b3Vector3 points[3] = { b3MakeVector3(1, 0, 0), b3MakeVector3(0, 1, 0), b3MakeVector3(0, 0, 1) }; +// m_instancingRenderer->drawPoints(&points[0].x, b3MakeVector3(1, 0, 0), 3, sizeof(b3Vector3), 6); + m_instancingRenderer->drawPoint(b3MakeVector3(1,0,0),b3MakeVector3(1,0,0),6); m_instancingRenderer->drawPoint(b3MakeVector3(0,1,0),b3MakeVector3(0,1,0),6); m_instancingRenderer->drawPoint(b3MakeVector3(0,0,1),b3MakeVector3(0,0,1),6); From 4996a642381bbcf118d602251c7835fc36f36830 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 28 Apr 2014 11:11:45 -0700 Subject: [PATCH 030/116] fix CMake build on Mac OSX --- Demos3/AllBullet2Demos/CMakeLists.txt | 10 +++++++--- Demos3/GpuDemos/CMakeLists.txt | 10 +++++++--- Demos3/SimpleOpenGL3/CMakeLists.txt | 10 +++++++--- build3/premake4.lua | 17 ++++++++++++----- src/Bullet3Common/b3Vector3.cpp | 5 +++-- test/TestBullet3OpenCL/main.cpp | 6 +++--- 6 files changed, 39 insertions(+), 19 deletions(-) diff --git a/Demos3/AllBullet2Demos/CMakeLists.txt b/Demos3/AllBullet2Demos/CMakeLists.txt index 29cfb6d24..04e995302 100644 --- a/Demos3/AllBullet2Demos/CMakeLists.txt +++ b/Demos3/AllBullet2Demos/CMakeLists.txt @@ -41,9 +41,13 @@ IF (WIN32) ) ADD_DEFINITIONS(-DGLEW_STATIC) ELSE(WIN32) - IF(NOT APPLE) + IF(APPLE) + find_library(COCOA NAMES Cocoa) + MESSAGE(${COCOA}) + link_libraries(${COCOA}) + ELSE(APPLE) LINK_LIBRARIES( GLEW) - ENDIF(NOT APPLE) + ENDIF(APPLE) ENDIF(WIN32) @@ -61,4 +65,4 @@ IF (INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) SET_TARGET_PROPERTIES(App_AllBullet2Demos PROPERTIES DEBUG_POSTFIX "_Debug") SET_TARGET_PROPERTIES(App_AllBullet2Demos PROPERTIES MINSIZEREL_POSTFIX "_MinsizeRel") SET_TARGET_PROPERTIES(App_AllBullet2Demos PROPERTIES RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo") -ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) \ No newline at end of file +ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) diff --git a/Demos3/GpuDemos/CMakeLists.txt b/Demos3/GpuDemos/CMakeLists.txt index 74bbe45c2..06dc4e81a 100644 --- a/Demos3/GpuDemos/CMakeLists.txt +++ b/Demos3/GpuDemos/CMakeLists.txt @@ -45,9 +45,13 @@ IF (WIN32) ) ADD_DEFINITIONS(-DGLEW_STATIC) ELSE(WIN32) - IF(NOT APPLE) + IF(APPLE) + find_library(COCOA NAMES Cocoa) + MESSAGE(${COCOA}) + link_libraries(${COCOA}) + ELSE(APPLE) LINK_LIBRARIES( GLEW X11 dl) - ENDIF(NOT APPLE) + ENDIF(APPLE) ENDIF(WIN32) @@ -60,4 +64,4 @@ IF (INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) SET_TARGET_PROPERTIES(App_Bullet3_OpenCL_Demos PROPERTIES DEBUG_POSTFIX "_Debug") SET_TARGET_PROPERTIES(App_Bullet3_OpenCL_Demos PROPERTIES MINSIZEREL_POSTFIX "_MinsizeRel") SET_TARGET_PROPERTIES(App_Bullet3_OpenCL_Demos PROPERTIES RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo") -ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) \ No newline at end of file +ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) diff --git a/Demos3/SimpleOpenGL3/CMakeLists.txt b/Demos3/SimpleOpenGL3/CMakeLists.txt index 1181dd8e2..7cae8b701 100644 --- a/Demos3/SimpleOpenGL3/CMakeLists.txt +++ b/Demos3/SimpleOpenGL3/CMakeLists.txt @@ -22,9 +22,13 @@ IF (WIN32) ) ADD_DEFINITIONS(-DGLEW_STATIC) ELSE(WIN32) - IF(NOT APPLE) + IF(APPLE) + find_library(COCOA NAMES Cocoa) + MESSAGE(${COCOA}) + link_libraries(${COCOA}) + ELSE(APPLE) LINK_LIBRARIES( GLEW X11 dl Xext) - ENDIF(NOT APPLE) + ENDIF(APPLE) ENDIF(WIN32) @@ -37,4 +41,4 @@ IF (INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) SET_TARGET_PROPERTIES(AppSimpleOpenGL3 PROPERTIES DEBUG_POSTFIX "_Debug") SET_TARGET_PROPERTIES(AppSimpleOpenGL3 PROPERTIES MINSIZEREL_POSTFIX "_MinsizeRel") SET_TARGET_PROPERTIES(AppSimpleOpenGL3 PROPERTIES RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo") -ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) \ No newline at end of file +ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) diff --git a/build3/premake4.lua b/build3/premake4.lua index 00c770f62..a5c308db5 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -32,7 +32,12 @@ trigger = "enet", description = "Enable enet NAT punchthrough test" } - + + newoption + { + trigger = "gtest", + description = "Enable unit tests using gtest" + } configurations {"Release", "Debug"} configuration "Release" flags { "Optimize", "EnableSSE2","StaticRuntime", "NoMinimalRebuild", "FloatFast"} @@ -88,11 +93,13 @@ dofile ("findOpenGLGlewGlut.lua") language "C++" + + if _OPTIONS["gtest"] then + include "../test/gtest-1.7.0" +-- include "../test/hello_gtest" - include "../test/gtest-1.7.0" --- include "../test/hello_gtest" - - include "../test/TestBullet3OpenCL" + include "../test/TestBullet3OpenCL" + end include "../Demos3/AllBullet2Demos" diff --git a/src/Bullet3Common/b3Vector3.cpp b/src/Bullet3Common/b3Vector3.cpp index 5da6a18ca..e43f13897 100644 --- a/src/Bullet3Common/b3Vector3.cpp +++ b/src/Bullet3Common/b3Vector3.cpp @@ -42,7 +42,7 @@ long b3_maxdot_large( const float *vv, const float *vec, unsigned long count, fl long b3_maxdot_large( const float *vv, const float *vec, unsigned long count, float *dotResult ) { const float4 *vertices = (const float4*) vv; - static const unsigned char indexTable[16] = {-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; + static const unsigned char indexTable[16] = {(unsigned char)-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; float4 dotMax = b3Assign128( -B3_INFINITY, -B3_INFINITY, -B3_INFINITY, -B3_INFINITY ); float4 vvec = _mm_loadu_ps( vec ); float4 vHi = b3CastiTo128f(_mm_shuffle_epi32( b3CastfTo128i( vvec), 0xaa )); /// zzzz @@ -427,7 +427,8 @@ long b3_mindot_large( const float *vv, const float *vec, unsigned long count, fl long b3_mindot_large( const float *vv, const float *vec, unsigned long count, float *dotResult ) { const float4 *vertices = (const float4*) vv; - static const unsigned char indexTable[16] = {-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; + static const unsigned char indexTable[16] = {(unsigned char)-1, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; + float4 dotmin = b3Assign128( B3_INFINITY, B3_INFINITY, B3_INFINITY, B3_INFINITY ); float4 vvec = _mm_loadu_ps( vec ); float4 vHi = b3CastiTo128f(_mm_shuffle_epi32( b3CastfTo128i( vvec), 0xaa )); /// zzzz diff --git a/test/TestBullet3OpenCL/main.cpp b/test/TestBullet3OpenCL/main.cpp index 4a18ce702..aee2434c2 100644 --- a/test/TestBullet3OpenCL/main.cpp +++ b/test/TestBullet3OpenCL/main.cpp @@ -6,7 +6,7 @@ void myerrorprintf(const char* msg) { - printf(msg); + printf("%s",msg); } static bool sVerboseWarning = true; @@ -16,7 +16,7 @@ void mywarningprintf(const char* msg) if (sVerboseWarning) { //OutputDebugStringA(msg); - printf(msg); + printf("%s",msg); } } @@ -27,7 +27,7 @@ void myprintf(const char* msg) if (sVerbosePrintf) { //OutputDebugStringA(msg); - printf(msg); + printf("%s",msg); } } From 8eb1835415294d2bc5ad3da293fedfae2e160e8f Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 28 Apr 2014 11:24:29 -0700 Subject: [PATCH 031/116] fix a potential bug in CProfileNode destructor, if the SDK is included/used multiple times. --- src/LinearMath/btQuickprof.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LinearMath/btQuickprof.cpp b/src/LinearMath/btQuickprof.cpp index 68c90c1cd..44e212f31 100644 --- a/src/LinearMath/btQuickprof.cpp +++ b/src/LinearMath/btQuickprof.cpp @@ -293,8 +293,7 @@ void CProfileNode::CleanupMemory() CProfileNode::~CProfileNode( void ) { - delete ( Child); - delete ( Sibling); + CleanupMemory(); } From 907ac49892ede3f4a3295f7cbd96759107e5fc0e Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 29 Apr 2014 11:44:52 -0700 Subject: [PATCH 032/116] work-around what appears to be a bug in Clang 3.4. Todo: create a small repro case for Clang/LLVM or see if they already fixed it. --- .../ConstraintSolver/btSequentialImpulseConstraintSolver.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index f855581c7..7d749a0cb 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -434,8 +434,8 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr // btScalar positionalError = 0.f; - btSimdScalar velocityError = desiredVelocity - rel_vel; - btSimdScalar velocityImpulse = velocityError * btSimdScalar(solverConstraint.m_jacDiagABInv); + btScalar velocityError = desiredVelocity - rel_vel; + btScalar velocityImpulse = velocityError * solverConstraint.m_jacDiagABInv; solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; solverConstraint.m_cfm = cfmSlip; From 7151865c16ba996996206e1fd7869cbb1e7edd8d Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 1 May 2014 13:51:56 -0700 Subject: [PATCH 033/116] Introduce kF_UseGjkConvexCastRaytest, and make kF_UseSubSimplexConvexCastRaytest the default for btCollisionWorld::rayTest See https://github.com/bulletphysics/bullet3/issues/34 Add btCollisionObject::setIgnoreCollisionCheck to disable collisions between specific instances, without having a btTypedConstraint. See https://github.com/bulletphysics/bullet3/issues/165 Make btMultiBody and btMultiBodyJointMotor backwards compatible with Bullet 2.82 API (single-DOF API) --- .../FeatherstoneMultiBodyDemo.cpp | 9 +--- .../btCollisionDispatcher.cpp | 2 +- .../CollisionDispatch/btCollisionObject.h | 35 +++++++++++-- .../CollisionDispatch/btCollisionWorld.cpp | 7 +-- .../NarrowPhaseCollision/btRaycastCallback.h | 7 ++- src/BulletDynamics/Dynamics/btRigidBody.cpp | 52 +++++++++++-------- src/BulletDynamics/Dynamics/btRigidBody.h | 4 +- src/BulletDynamics/Featherstone/btMultiBody.h | 13 ++--- .../Featherstone/btMultiBodyJointMotor.cpp | 6 +++ .../Featherstone/btMultiBodyJointMotor.h | 1 + 10 files changed, 87 insertions(+), 49 deletions(-) diff --git a/ObsoleteDemos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp b/ObsoleteDemos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp index 412b51315..987928c20 100644 --- a/ObsoleteDemos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp +++ b/ObsoleteDemos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp @@ -394,23 +394,16 @@ btMultiBody* FeatherstoneMultiBodyDemo::createFeatherstoneMultiBody(class btMult if (1) { btCollisionShape* box = new btBoxShape(btVector3(halfExtents[0],halfExtents[1],halfExtents[2])*scaling); - btRigidBody* body = new btRigidBody(mass,0,box,inertia); btMultiBodyLinkCollider* col= new btMultiBodyLinkCollider(bod,-1); - - body->setCollisionShape(box); col->setCollisionShape(box); - btTransform tr; tr.setIdentity(); tr.setOrigin(local_origin[0]); tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3])); - body->setWorldTransform(tr); col->setWorldTransform(tr); - world->addCollisionObject(col, 2,1+2); col->setFriction(friction); - bod->setBaseCollider(col); - + bod->setBaseCollider(col); } } diff --git a/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp b/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp index 669d0b6b5..3b6913c0e 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp +++ b/src/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp @@ -189,7 +189,7 @@ bool btCollisionDispatcher::needsCollision(const btCollisionObject* body0,const if ((!body0->isActive()) && (!body1->isActive())) needsCollision = false; - else if (!body0->checkCollideWith(body1)) + else if ((!body0->checkCollideWith(body1)) || (!body1->checkCollideWith(body0))) needsCollision = false; return needsCollision ; diff --git a/src/BulletCollision/CollisionDispatch/btCollisionObject.h b/src/BulletCollision/CollisionDispatch/btCollisionObject.h index 89cad1682..587786ce9 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionObject.h +++ b/src/BulletCollision/CollisionDispatch/btCollisionObject.h @@ -110,13 +110,11 @@ protected: /// If some object should have elaborate collision filtering by sub-classes int m_checkCollideWith; + btAlignedObjectArray m_objectsWithoutCollisionCheck; + ///internal update revision number. It will be increased when the object changes. This allows some subsystems to perform lazy evaluation. int m_updateRevision; - virtual bool checkCollideWithOverride(const btCollisionObject* /* co */) const - { - return true; - } public: @@ -225,7 +223,34 @@ public: return m_collisionShape; } - + void setIgnoreCollisionCheck(const btCollisionObject* co, bool ignoreCollisionCheck) + { + if (ignoreCollisionCheck) + { + //We don't check for duplicates. Is it ok to leave that up to the user of this API? + //int index = m_objectsWithoutCollisionCheck.findLinearSearch(co); + //if (index == m_objectsWithoutCollisionCheck.size()) + //{ + m_objectsWithoutCollisionCheck.push_back(co); + //} + } + else + { + m_objectsWithoutCollisionCheck.remove(co); + } + m_checkCollideWith = m_objectsWithoutCollisionCheck.size() > 0; + } + + virtual bool checkCollideWithOverride(const btCollisionObject* co) const + { + int index = m_objectsWithoutCollisionCheck.findLinearSearch(co); + if (index < m_objectsWithoutCollisionCheck.size()) + { + return false; + } + return true; + } + diff --git a/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp b/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp index 0010ee2a9..bdd60a541 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp +++ b/src/BulletCollision/CollisionDispatch/btCollisionWorld.cpp @@ -294,10 +294,11 @@ void btCollisionWorld::rayTestSingleInternal(const btTransform& rayFromTrans,con //btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0); bool condition = true; btConvexCast* convexCasterPtr = 0; - if (resultCallback.m_flags & btTriangleRaycastCallback::kF_UseSubSimplexConvexCastRaytest) - convexCasterPtr = &subSimplexConvexCaster; - else + //use kF_UseSubSimplexConvexCastRaytest by default + if (resultCallback.m_flags & btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest) convexCasterPtr = &gjkConvexCaster; + else + convexCasterPtr = &subSimplexConvexCaster; btConvexCast& convexCaster = *convexCasterPtr; diff --git a/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h b/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h index 3999d4005..4aecffd64 100644 --- a/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h +++ b/src/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h @@ -21,6 +21,7 @@ subject to the following restrictions: struct btBroadphaseProxy; class btConvexShape; + class btTriangleRaycastCallback: public btTriangleCallback { public: @@ -32,10 +33,12 @@ public: //@BP Mod - allow backface filtering and unflipped normals enum EFlags { - kF_None = 0, + kF_None = 0, kF_FilterBackfaces = 1 << 0, kF_KeepUnflippedNormal = 1 << 1, // Prevents returned face normal getting flipped when a ray hits a back-facing triangle - kF_UseSubSimplexConvexCastRaytest = 1 << 2, // Uses an approximate but faster ray versus convex intersection algorithm + ///SubSimplexConvexCastRaytest is the default, even if kF_None is set. + kF_UseSubSimplexConvexCastRaytest = 1 << 2, // Uses an approximate but faster ray versus convex intersection algorithm + kF_UseGjkConvexCastRaytest = 1 << 3, kF_Terminator = 0xFFFFFFFF }; unsigned int m_flags; diff --git a/src/BulletDynamics/Dynamics/btRigidBody.cpp b/src/BulletDynamics/Dynamics/btRigidBody.cpp index 222f90066..aad5089ed 100644 --- a/src/BulletDynamics/Dynamics/btRigidBody.cpp +++ b/src/BulletDynamics/Dynamics/btRigidBody.cpp @@ -317,38 +317,48 @@ void btRigidBody::setCenterOfMassTransform(const btTransform& xform) } -bool btRigidBody::checkCollideWithOverride(const btCollisionObject* co) const -{ - const btRigidBody* otherRb = btRigidBody::upcast(co); - if (!otherRb) - return true; - - for (int i = 0; i < m_constraintRefs.size(); ++i) - { - const btTypedConstraint* c = m_constraintRefs[i]; - if (c->isEnabled()) - if (&c->getRigidBodyA() == otherRb || &c->getRigidBodyB() == otherRb) - return false; - } - - return true; -} void btRigidBody::addConstraintRef(btTypedConstraint* c) { - int index = m_constraintRefs.findLinearSearch(c); - if (index == m_constraintRefs.size()) - m_constraintRefs.push_back(c); + ///disable collision with the 'other' body - m_checkCollideWith = true; + int index = m_constraintRefs.findLinearSearch(c); + //don't add constraints that are already referenced + btAssert(index == m_constraintRefs.size()); + if (index == m_constraintRefs.size()) + { + m_constraintRefs.push_back(c); + btCollisionObject* colObjA = &c->getRigidBodyA(); + btCollisionObject* colObjB = &c->getRigidBodyB(); + if (colObjA == this) + { + colObjA->setIgnoreCollisionCheck(colObjB, true); + } + else + { + colObjB->setIgnoreCollisionCheck(colObjA, true); + } + } } void btRigidBody::removeConstraintRef(btTypedConstraint* c) { + int index = m_constraintRefs.findLinearSearch(c); + //don't remove constraints that are not referenced + btAssert(index < m_constraintRefs.size()); m_constraintRefs.remove(c); - m_checkCollideWith = m_constraintRefs.size() > 0; + btCollisionObject* colObjA = &c->getRigidBodyA(); + btCollisionObject* colObjB = &c->getRigidBodyB(); + if (colObjA == this) + { + colObjA->setIgnoreCollisionCheck(colObjB, false); + } + else + { + colObjB->setIgnoreCollisionCheck(colObjA, false); + } } int btRigidBody::calculateSerializeBufferSize() const diff --git a/src/BulletDynamics/Dynamics/btRigidBody.h b/src/BulletDynamics/Dynamics/btRigidBody.h index ed90fb441..7ba7b1f23 100644 --- a/src/BulletDynamics/Dynamics/btRigidBody.h +++ b/src/BulletDynamics/Dynamics/btRigidBody.h @@ -87,7 +87,7 @@ class btRigidBody : public btCollisionObject //m_optionalMotionState allows to automatic synchronize the world transform for active objects btMotionState* m_optionalMotionState; - //keep track of typed constraints referencing this rigid body + //keep track of typed constraints referencing this rigid body, to disable collision between linked bodies btAlignedObjectArray m_constraintRefs; int m_rigidbodyFlags; @@ -506,8 +506,6 @@ public: return (getBroadphaseProxy() != 0); } - virtual bool checkCollideWithOverride(const btCollisionObject* co) const; - void addConstraintRef(btTypedConstraint* c); void removeConstraintRef(btTypedConstraint* c); diff --git a/src/BulletDynamics/Featherstone/btMultiBody.h b/src/BulletDynamics/Featherstone/btMultiBody.h index b14fc95b8..85d6a2f3f 100644 --- a/src/BulletDynamics/Featherstone/btMultiBody.h +++ b/src/BulletDynamics/Featherstone/btMultiBody.h @@ -45,14 +45,15 @@ public: // initialization // - btMultiBody(int n_links, // NOT including the base - btScalar mass, // mass of base - const btVector3 &inertia, // inertia of base, in base frame; assumed diagonal - bool fixedBase, // whether the base is fixed (true) or can move (false) - bool canSleep, - bool multiDof + btMultiBody(int n_links, // NOT including the base + btScalar mass, // mass of base + const btVector3 &inertia, // inertia of base, in base frame; assumed diagonal + bool fixedBase, // whether the base is fixed (true) or can move (false) + bool canSleep, + bool multiDof = false ); + ~btMultiBody(); void setupPrismatic(int i, // 0 to num_links-1 diff --git a/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp index 2f10118a0..e424d5c92 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp @@ -21,6 +21,12 @@ subject to the following restrictions: #include "BulletCollision/CollisionDispatch/btCollisionObject.h" +btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse) +:btMultiBodyJointMotor(body,link,0,desiredVelocity,maxMotorImpulse) +{ +} + + btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse) //:btMultiBodyConstraint(body,0,link,-1,1,true), :btMultiBodyConstraint(body,body,link,link,1,true), diff --git a/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h b/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h index 551813807..ada7ccd60 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h +++ b/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h @@ -30,6 +30,7 @@ protected: public: + btMultiBodyJointMotor(btMultiBody* body, int link,btScalar desiredVelocity, btScalar maxMotorImpulse); btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse); virtual ~btMultiBodyJointMotor(); From 0e1b90d708a5ca93dc5959c3836711633e063450 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 1 May 2014 17:13:50 -0700 Subject: [PATCH 034/116] Added SSE4/FMA optimized constraint row solver implementation for btSequentialImpulseConstraintSolver, thanks to Vladimir Bondarev (https://github.com/VladimirBondarev/bullet3/tree/c25d) --- ObsoleteDemos/CMakeLists.txt | 2 +- ObsoleteDemos/ConstraintDemo/CMakeLists.txt | 8 +- .../btSequentialImpulseConstraintSolver.cpp | 235 +++++++++++++----- .../btSequentialImpulseConstraintSolver.h | 38 ++- src/LinearMath/btCpuFeatureUtility.h | 87 +++++++ 5 files changed, 301 insertions(+), 69 deletions(-) create mode 100644 src/LinearMath/btCpuFeatureUtility.h diff --git a/ObsoleteDemos/CMakeLists.txt b/ObsoleteDemos/CMakeLists.txt index 912c348a6..c6d13ac9c 100644 --- a/ObsoleteDemos/CMakeLists.txt +++ b/ObsoleteDemos/CMakeLists.txt @@ -10,7 +10,7 @@ IF (USE_GLUT) # ENDIF() SET(SharedDemoSubdirs OpenGL - CcdPhysicsDemo SliderConstraintDemo GenericJointDemo Raytracer + CcdPhysicsDemo ConstraintDemo SliderConstraintDemo GenericJointDemo Raytracer RagdollDemo ForkLiftDemo BasicDemo FeatherstoneMultiBodyDemo RollingFrictionDemo RaytestDemo VoronoiFractureDemo GyroscopicDemo FractureDemo Box2dDemo BspDemo MovingConcaveDemo VehicleDemo UserCollisionAlgorithm CharacterDemo SoftDemo diff --git a/ObsoleteDemos/ConstraintDemo/CMakeLists.txt b/ObsoleteDemos/ConstraintDemo/CMakeLists.txt index 70945677b..d43a3bfa4 100644 --- a/ObsoleteDemos/ConstraintDemo/CMakeLists.txt +++ b/ObsoleteDemos/ConstraintDemo/CMakeLists.txt @@ -14,14 +14,14 @@ INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src ../OpenGL -${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletFileLoader -${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletWorldImporter +${GLUT_INCLUDE_DIR} ) IF (USE_GLUT) LINK_LIBRARIES( - OpenGLSupport BulletWorldImporter BulletDynamics BulletCollision LinearMath BulletFileLoader ${GLUT_glut_LIBRARY} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} + OpenGLSupport BulletDynamics BulletCollision LinearMath ${GLUT_glut_LIBRARY} + ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) ADD_EXECUTABLE(AppConstraintDemo @@ -31,7 +31,7 @@ IF (USE_GLUT) ) ELSE (USE_GLUT) LINK_LIBRARIES( - OpenGLSupport BulletWorldImporter BulletDynamics BulletCollision LinearMath BulletFileLoader ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} + OpenGLSupport BulletDynamics BulletCollision LinearMath ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) ADD_EXECUTABLE(AppConstraintDemo diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index 7d749a0cb..3608c40df 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -37,57 +37,164 @@ int gNumSplitImpulseRecoveries = 0; #include "BulletDynamics/Dynamics/btRigidBody.h" -btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver() -:m_btSeed2(0) -{ -} - -btSequentialImpulseConstraintSolver::~btSequentialImpulseConstraintSolver() -{ -} #ifdef USE_SIMD -#include +#include //is it safe to include this header? + #define btVecSplat(x, e) _mm_shuffle_ps(x, x, _MM_SHUFFLE(e,e,e,e)) static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 ) { __m128 result = _mm_mul_ps( vec0, vec1); return _mm_add_ps( btVecSplat( result, 0 ), _mm_add_ps( btVecSplat( result, 1 ), btVecSplat( result, 2 ) ) ); } -#endif//USE_SIMD + +#define USE_FMA 1 +#define USE_FMA3_INSTEAD_FMA4 1 +#define USE_SSE4_DOT 0 + +#define SSE4_DP(a, b) _mm_dp_ps(a, b, 0x7f) +#define SSE4_DP_FP(a, b) _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7f)) + +#if USE_SSE4_DOT +#define DOT_PRODUCT(a, b) SSE4_DP(a, b) +#else +#define DOT_PRODUCT(a, b) btSimdDot3(a, b) +#endif + +#if USE_FMA +#if USE_FMA3_INSTEAD_FMA4 +// a*b + c +#define FMADD(a, b, c) _mm_fmadd_ps(a, b, c) +// -(a*b) + c +#define FMNADD(a, b, c) _mm_fnmadd_ps(a, b, c) +#else // USE_FMA3 +// a*b + c +#define FMADD(a, b, c) _mm_macc_ps(a, b, c) +// -(a*b) + c +#define FMNADD(a, b, c) _mm_nmacc_ps(a, b, c) +#endif +#else // USE_FMA +// c + a*b +#define FMADD(a, b, c) _mm_add_ps(c, _mm_mul_ps(a, b)) +// c - a*b +#define FMNADD(a, b, c) _mm_sub_ps(c, _mm_mul_ps(a, b)) +#endif // Project Gauss Seidel or the equivalent Sequential Impulse -btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGenericSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c) +static btSimdScalar gResolveSingleConstraintRowGeneric_sse2(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) { -#ifdef USE_SIMD __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse); __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); - btSimdScalar deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse),_mm_set1_ps(c.m_cfm))); - __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128,body1.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetDeltaAngularVelocity().mVec128)); - __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128,body2.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetDeltaAngularVelocity().mVec128)); - deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv))); - deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv))); - btSimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse); - btSimdScalar resultLowerLess,resultUpperLess; - resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1); - resultUpperLess = _mm_cmplt_ps(sum,upperLimit1); - __m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp); - deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) ); - c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) ); - __m128 upperMinApplied = _mm_sub_ps(upperLimit1,cpAppliedImp); - deltaImpulse = _mm_or_ps( _mm_and_ps(resultUpperLess, deltaImpulse), _mm_andnot_ps(resultUpperLess, upperMinApplied) ); - c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultUpperLess, c.m_appliedImpulse), _mm_andnot_ps(resultUpperLess, upperLimit1) ); - __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128,body1.internalGetInvMass().mVec128); - __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal2).mVec128,body2.internalGetInvMass().mVec128); + btSimdScalar deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse), _mm_set1_ps(c.m_cfm))); + __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128, body1.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128, body1.internalGetDeltaAngularVelocity().mVec128)); + __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128, body2.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128, body2.internalGetDeltaAngularVelocity().mVec128)); + deltaImpulse = _mm_sub_ps(deltaImpulse, _mm_mul_ps(deltaVel1Dotn, _mm_set1_ps(c.m_jacDiagABInv))); + deltaImpulse = _mm_sub_ps(deltaImpulse, _mm_mul_ps(deltaVel2Dotn, _mm_set1_ps(c.m_jacDiagABInv))); + btSimdScalar sum = _mm_add_ps(cpAppliedImp, deltaImpulse); + btSimdScalar resultLowerLess, resultUpperLess; + resultLowerLess = _mm_cmplt_ps(sum, lowerLimit1); + resultUpperLess = _mm_cmplt_ps(sum, upperLimit1); + __m128 lowMinApplied = _mm_sub_ps(lowerLimit1, cpAppliedImp); + deltaImpulse = _mm_or_ps(_mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse)); + c.m_appliedImpulse = _mm_or_ps(_mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum)); + __m128 upperMinApplied = _mm_sub_ps(upperLimit1, cpAppliedImp); + deltaImpulse = _mm_or_ps(_mm_and_ps(resultUpperLess, deltaImpulse), _mm_andnot_ps(resultUpperLess, upperMinApplied)); + c.m_appliedImpulse = _mm_or_ps(_mm_and_ps(resultUpperLess, c.m_appliedImpulse), _mm_andnot_ps(resultUpperLess, upperLimit1)); + __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128, body1.internalGetInvMass().mVec128); + __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal2).mVec128, body2.internalGetInvMass().mVec128); __m128 impulseMagnitude = deltaImpulse; - body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude)); - body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); - body2.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); - body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); - + body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentA, impulseMagnitude)); + body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentA.mVec128, impulseMagnitude)); + body2.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentB, impulseMagnitude)); + body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentB.mVec128, impulseMagnitude)); return deltaImpulse; +} + + +// Enhanced version of gResolveSingleConstraintRowGeneric_sse2 with SSE4.1 and FMA3 +static btSimdScalar gResolveSingleConstraintRowGeneric_sse4_1_fma3(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) +{ + __m128 tmp = _mm_set_ps1(c.m_jacDiagABInv); + __m128 deltaImpulse = _mm_set_ps1(c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm); + const __m128 lowerLimit = _mm_set_ps1(c.m_lowerLimit); + const __m128 upperLimit = _mm_set_ps1(c.m_upperLimit); + const __m128 deltaVel1Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal1.mVec128, body1.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos1CrossNormal.mVec128, body1.internalGetDeltaAngularVelocity().mVec128)); + const __m128 deltaVel2Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal2.mVec128, body2.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos2CrossNormal.mVec128, body2.internalGetDeltaAngularVelocity().mVec128)); + deltaImpulse = FMNADD(deltaVel1Dotn, tmp, deltaImpulse); + deltaImpulse = FMNADD(deltaVel2Dotn, tmp, deltaImpulse); + tmp = _mm_add_ps(c.m_appliedImpulse, deltaImpulse); // sum + const __m128 maskLower = _mm_cmpgt_ps(tmp, lowerLimit); + const __m128 maskUpper = _mm_cmpgt_ps(upperLimit, tmp); + deltaImpulse = _mm_blendv_ps(_mm_sub_ps(lowerLimit, c.m_appliedImpulse), _mm_blendv_ps(_mm_sub_ps(upperLimit, c.m_appliedImpulse), deltaImpulse, maskUpper), maskLower); + c.m_appliedImpulse = _mm_blendv_ps(lowerLimit, _mm_blendv_ps(upperLimit, tmp, maskUpper), maskLower); + body1.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal1.mVec128, body1.internalGetInvMass().mVec128), deltaImpulse, body1.internalGetDeltaLinearVelocity().mVec128); + body1.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentA.mVec128, deltaImpulse, body1.internalGetDeltaAngularVelocity().mVec128); + body2.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal2.mVec128, body2.internalGetInvMass().mVec128), deltaImpulse, body2.internalGetDeltaLinearVelocity().mVec128); + body2.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentB.mVec128, deltaImpulse, body2.internalGetDeltaAngularVelocity().mVec128); + return deltaImpulse; +} + + +static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse2(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) +{ + __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse); + __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); + __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); + btSimdScalar deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse), _mm_set1_ps(c.m_cfm))); + __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128, body1.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128, body1.internalGetDeltaAngularVelocity().mVec128)); + __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128, body2.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128, body2.internalGetDeltaAngularVelocity().mVec128)); + deltaImpulse = _mm_sub_ps(deltaImpulse, _mm_mul_ps(deltaVel1Dotn, _mm_set1_ps(c.m_jacDiagABInv))); + deltaImpulse = _mm_sub_ps(deltaImpulse, _mm_mul_ps(deltaVel2Dotn, _mm_set1_ps(c.m_jacDiagABInv))); + btSimdScalar sum = _mm_add_ps(cpAppliedImp, deltaImpulse); + btSimdScalar resultLowerLess, resultUpperLess; + resultLowerLess = _mm_cmplt_ps(sum, lowerLimit1); + resultUpperLess = _mm_cmplt_ps(sum, upperLimit1); + __m128 lowMinApplied = _mm_sub_ps(lowerLimit1, cpAppliedImp); + deltaImpulse = _mm_or_ps(_mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse)); + c.m_appliedImpulse = _mm_or_ps(_mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum)); + __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128, body1.internalGetInvMass().mVec128); + __m128 linearComponentB = _mm_mul_ps(c.m_contactNormal2.mVec128, body2.internalGetInvMass().mVec128); + __m128 impulseMagnitude = deltaImpulse; + body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentA, impulseMagnitude)); + body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentA.mVec128, impulseMagnitude)); + body2.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaLinearVelocity().mVec128, _mm_mul_ps(linearComponentB, impulseMagnitude)); + body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128, _mm_mul_ps(c.m_angularComponentB.mVec128, impulseMagnitude)); + return deltaImpulse; +} + + +// Enhanced version of gResolveSingleConstraintRowGeneric_sse2 with SSE4.1 and FMA3 +static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse4_1_fma3(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) +{ + __m128 tmp = _mm_set_ps1(c.m_jacDiagABInv); + __m128 deltaImpulse = _mm_set_ps1(c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm); + const __m128 lowerLimit = _mm_set_ps1(c.m_lowerLimit); + const __m128 deltaVel1Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal1.mVec128, body1.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos1CrossNormal.mVec128, body1.internalGetDeltaAngularVelocity().mVec128)); + const __m128 deltaVel2Dotn = _mm_add_ps(DOT_PRODUCT(c.m_contactNormal2.mVec128, body2.internalGetDeltaLinearVelocity().mVec128), DOT_PRODUCT(c.m_relpos2CrossNormal.mVec128, body2.internalGetDeltaAngularVelocity().mVec128)); + deltaImpulse = FMNADD(deltaVel1Dotn, tmp, deltaImpulse); + deltaImpulse = FMNADD(deltaVel2Dotn, tmp, deltaImpulse); + tmp = _mm_add_ps(c.m_appliedImpulse, deltaImpulse); + const __m128 mask = _mm_cmpgt_ps(tmp, lowerLimit); + deltaImpulse = _mm_blendv_ps(_mm_sub_ps(lowerLimit, c.m_appliedImpulse), deltaImpulse, mask); + c.m_appliedImpulse = _mm_blendv_ps(lowerLimit, tmp, mask); + body1.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal1.mVec128, body1.internalGetInvMass().mVec128), deltaImpulse, body1.internalGetDeltaLinearVelocity().mVec128); + body1.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentA.mVec128, deltaImpulse, body1.internalGetDeltaAngularVelocity().mVec128); + body2.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal2.mVec128, body2.internalGetInvMass().mVec128), deltaImpulse, body2.internalGetDeltaLinearVelocity().mVec128); + body2.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentB.mVec128, deltaImpulse, body2.internalGetDeltaAngularVelocity().mVec128); + return deltaImpulse; +} + + +#endif //USE_SIMD + + + +btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGenericSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c) +{ +#ifdef USE_SIMD + return m_resolveSingleConstraintRowGeneric(body1, body2, c); #else return resolveSingleConstraintRowGeneric(body1,body2,c); #endif @@ -129,29 +236,7 @@ btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGene btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimitSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c) { #ifdef USE_SIMD - __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse); - __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); - __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); - btSimdScalar deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse),_mm_set1_ps(c.m_cfm))); - __m128 deltaVel1Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal1.mVec128,body1.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetDeltaAngularVelocity().mVec128)); - __m128 deltaVel2Dotn = _mm_add_ps(btSimdDot3(c.m_contactNormal2.mVec128,body2.internalGetDeltaLinearVelocity().mVec128), btSimdDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetDeltaAngularVelocity().mVec128)); - deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv))); - deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv))); - btSimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse); - btSimdScalar resultLowerLess,resultUpperLess; - resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1); - resultUpperLess = _mm_cmplt_ps(sum,upperLimit1); - __m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp); - deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) ); - c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) ); - __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal1.mVec128,body1.internalGetInvMass().mVec128); - __m128 linearComponentB = _mm_mul_ps(c.m_contactNormal2.mVec128,body2.internalGetInvMass().mVec128); - __m128 impulseMagnitude = deltaImpulse; - body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude)); - body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); - body2.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); - body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); - return deltaImpulse; + return m_resolveSingleConstraintRowLowerLimit(body1, body2, c); #else return resolveSingleConstraintRowLowerLimit(body1,body2,c); #endif @@ -248,6 +333,36 @@ void btSequentialImpulseConstraintSolver::resolveSplitPenetrationImpulseCacheFri } + btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver() + :m_btSeed2(0), + m_resolveSingleConstraintRowGeneric(gResolveSingleConstraintRowGeneric_sse2), + m_resolveSingleConstraintRowLowerLimit(gResolveSingleConstraintRowLowerLimit_sse2) + { + + } + + btSequentialImpulseConstraintSolver::~btSequentialImpulseConstraintSolver() + { + } + + + btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE2ConstraintRowSolverGeneric() + { + return gResolveSingleConstraintRowGeneric_sse2; + } + btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE4_1ConstraintRowSolverGeneric() + { + return gResolveSingleConstraintRowGeneric_sse4_1_fma3; + } + btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE2ConstraintRowSolverLowerLimit() + { + return gResolveSingleConstraintRowLowerLimit_sse2; + } + btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE4_1ConstraintRowSolverLowerLimit() + { + return gResolveSingleConstraintRowLowerLimit_sse4_1_fma3; + } + unsigned long btSequentialImpulseConstraintSolver::btRand2() { @@ -434,8 +549,8 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr // btScalar positionalError = 0.f; - btScalar velocityError = desiredVelocity - rel_vel; - btScalar velocityImpulse = velocityError * solverConstraint.m_jacDiagABInv; + btSimdScalar velocityError = desiredVelocity - rel_vel; + btSimdScalar velocityImpulse = velocityError * btSimdScalar(solverConstraint.m_jacDiagABInv); solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; solverConstraint.m_cfm = cfmSlip; @@ -1741,5 +1856,3 @@ void btSequentialImpulseConstraintSolver::reset() { m_btSeed2 = 0; } - - diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h index 47dbbe339..001708a21 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h @@ -27,6 +27,8 @@ class btCollisionObject; #include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" #include "BulletDynamics/ConstraintSolver/btConstraintSolver.h" +typedef btSimdScalar(*btSingleConstraintRowSolver)(btSolverBody&, btSolverBody&, const btSolverConstraint&); + ///The btSequentialImpulseConstraintSolver is a fast SIMD implementation of the Projected Gauss Seidel (iterative LCP) method. ATTRIBUTE_ALIGNED16(class) btSequentialImpulseConstraintSolver : public btConstraintSolver { @@ -43,6 +45,10 @@ protected: btAlignedObjectArray m_tmpConstraintSizesPool; int m_maxOverrideNumSolverIterations; int m_fixedBodyId; + + btSingleConstraintRowSolver m_resolveSingleConstraintRowGeneric; + btSingleConstraintRowSolver m_resolveSingleConstraintRowLowerLimit; + void setupFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB, btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2, btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, @@ -112,9 +118,7 @@ public: virtual ~btSequentialImpulseConstraintSolver(); virtual btScalar solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& info, btIDebugDraw* debugDrawer,btDispatcher* dispatcher); - - - + ///clear internal cached data and reset random seed virtual void reset(); @@ -136,6 +140,34 @@ public: { return BT_SEQUENTIAL_IMPULSE_SOLVER; } + + btSingleConstraintRowSolver getActiveConstraintRowSolverGeneric() + { + return m_resolveSingleConstraintRowGeneric; + } + void setConstraintRowSolverGeneric(btSingleConstraintRowSolver rowSolver) + { + m_resolveSingleConstraintRowGeneric = rowSolver; + } + btSingleConstraintRowSolver getActiveConstraintRowSolverLowerLimit() + { + return m_resolveSingleConstraintRowLowerLimit; + } + void setConstraintRowSolverLowerLimit(btSingleConstraintRowSolver rowSolver) + { + m_resolveSingleConstraintRowLowerLimit = rowSolver; + } + + + // btSingleConstraintRowSolver getScalarConstraintRowSolverLowerLimit(); + btSingleConstraintRowSolver getSSE2ConstraintRowSolverGeneric(); + btSingleConstraintRowSolver getSSE4_1ConstraintRowSolverGeneric(); + btSingleConstraintRowSolver getSSE2ConstraintRowSolverLowerLimit(); + btSingleConstraintRowSolver getSSE4_1ConstraintRowSolverLowerLimit(); + + + + }; diff --git a/src/LinearMath/btCpuFeatureUtility.h b/src/LinearMath/btCpuFeatureUtility.h new file mode 100644 index 000000000..0c9ba99a9 --- /dev/null +++ b/src/LinearMath/btCpuFeatureUtility.h @@ -0,0 +1,87 @@ + +#ifndef BT_CPU_UTILITY_H +#define BT_CPU_UTILITY_H + +#include "LinearMath/btScalar.h" + +#include //memset +#ifdef BT_USE_SSE +#if (_MSC_FULL_VER >= 160040219) +#include +#endif +#endif + +#if defined BT_USE_NEON +#define ARM_NEON_GCC_COMPATIBILITY 1 +#include +#include +#include //for sysctlbyname +#endif //BT_USE_NEON + +///Rudimentary btCpuFeatureUtility for CPU features: only report the features that Bullet actually uses (SSE4/FMA3, NEON_HPFP) +///We assume SSE2 in case BT_USE_SSE2 is defined in LinearMath/btScalar.h +class btCpuFeatureUtility +{ +public: + enum btCpuFeature + { + CPU_FEATURE_FMA3=1, + CPU_FEATURE_SSE4_1=2, + CPU_FEATURE_NEON_HPFP=4 + }; + + static int getCpuFeatures(btCpuFeature inFeature) + { + + static int capabilities = 0; + static bool testedCapabilities = false; + if (0 != testedCapabilities) + { + return capabilities; + } + +#ifdef BT_USE_NEON + { + uint32_t hasFeature = 0; + size_t featureSize = sizeof(hasFeature); + int err = sysctlbyname("hw.optional.neon_hpfp", &hasFeature, &featureSize, NULL, 0); + if (0 == err && hasFeature) + capabilities |= CPU_FEATURE_NEON_HPFP; + } +#endif //BT_USE_NEON + +#ifdef BT_USE_SSE +#if (_MSC_FULL_VER >= 160040219) + { + int cpuInfo[4]; + memset(cpuInfo, 0, sizeof(cpuInfo)); + unsigned long long sseExt; + __cpuid(mCpuInfo, 1); + mExt = _xgetbv(0); + + const int OSXSAVEFlag = (1UL << 27); + const int AVXFlag = ((1UL << 28) | OSXSAVEFlag); + const int FMAFlag = ((1UL << 12) | AVXFlag | OSXSAVEFlag); + if ((mCpuInfo[2] & FMAFlag) == FMAFlag && (mExt & 6) == 6) + { + capabilities |= btCpuFeatureUtility::CPU_FEATURE_FMA3; + } + + const int SSE41Flag = (1 << 19); + if (mCpuInfo[2] & SSE41Flag) + { + capabilities |= btCpuFeatureUtility::CPU_FEATURE_SSE4_1; + } + } +#endif//(_MSC_FULL_VER >= 160040219) +#endif//BT_USE_SSE + + testedCapabilities = true; + return capabilities; + } + + +}; + + +#endif //BT_CPU_UTILITY_H From 0b6d1af1d41b571fb138fecd1f026707e5f2047a Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Thu, 1 May 2014 22:23:37 -0700 Subject: [PATCH 035/116] Only enable SSE4 for Visual Studio 2012 or later (_MSC_FULL_VER >= 170050727), it breaks the build for Visual Studio 2010 Add additional constructor for btMultiBodyJointMotor --- .../btSequentialImpulseConstraintSolver.cpp | 10 ++++++++++ .../Featherstone/btMultiBodyJointMotor.cpp | 17 ++++++++++++++++- .../Featherstone/btMultiBodyJointMotor.h | 2 +- src/LinearMath/btCpuFeatureUtility.h | 18 +++++++----------- src/LinearMath/btScalar.h | 5 +++++ 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index 3608c40df..58a35a289 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -49,6 +49,7 @@ static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 ) return _mm_add_ps( btVecSplat( result, 0 ), _mm_add_ps( btVecSplat( result, 1 ), btVecSplat( result, 2 ) ) ); } +#if defined (BT_USE_SSE4) #define USE_FMA 1 #define USE_FMA3_INSTEAD_FMA4 1 #define USE_SSE4_DOT 0 @@ -80,6 +81,7 @@ static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 ) // c - a*b #define FMNADD(a, b, c) _mm_sub_ps(c, _mm_mul_ps(a, b)) #endif +#endif // Project Gauss Seidel or the equivalent Sequential Impulse static btSimdScalar gResolveSingleConstraintRowGeneric_sse2(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) @@ -116,6 +118,7 @@ static btSimdScalar gResolveSingleConstraintRowGeneric_sse2(btSolverBody& body1, // Enhanced version of gResolveSingleConstraintRowGeneric_sse2 with SSE4.1 and FMA3 static btSimdScalar gResolveSingleConstraintRowGeneric_sse4_1_fma3(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) { +#if defined (BT_ALLOW_SSE4) __m128 tmp = _mm_set_ps1(c.m_jacDiagABInv); __m128 deltaImpulse = _mm_set_ps1(c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm); const __m128 lowerLimit = _mm_set_ps1(c.m_lowerLimit); @@ -134,6 +137,9 @@ static btSimdScalar gResolveSingleConstraintRowGeneric_sse4_1_fma3(btSolverBody& body2.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal2.mVec128, body2.internalGetInvMass().mVec128), deltaImpulse, body2.internalGetDeltaLinearVelocity().mVec128); body2.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentB.mVec128, deltaImpulse, body2.internalGetDeltaAngularVelocity().mVec128); return deltaImpulse; +#else + return gResolveSingleConstraintRowGeneric_sse2(body1,body2,c); +#endif } @@ -168,6 +174,7 @@ static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse2(btSolverBody& bod // Enhanced version of gResolveSingleConstraintRowGeneric_sse2 with SSE4.1 and FMA3 static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse4_1_fma3(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) { +#ifdef BT_ALLOW_SSE4 __m128 tmp = _mm_set_ps1(c.m_jacDiagABInv); __m128 deltaImpulse = _mm_set_ps1(c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm); const __m128 lowerLimit = _mm_set_ps1(c.m_lowerLimit); @@ -184,6 +191,9 @@ static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse4_1_fma3(btSolverBo body2.internalGetDeltaLinearVelocity().mVec128 = FMADD(_mm_mul_ps(c.m_contactNormal2.mVec128, body2.internalGetInvMass().mVec128), deltaImpulse, body2.internalGetDeltaLinearVelocity().mVec128); body2.internalGetDeltaAngularVelocity().mVec128 = FMADD(c.m_angularComponentB.mVec128, deltaImpulse, body2.internalGetDeltaAngularVelocity().mVec128); return deltaImpulse; +#else + return gResolveSingleConstraintRowLowerLimit_sse2(body1,body2,c); +#endif //BT_ALLOW_SSE4 } diff --git a/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp b/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp index e424d5c92..18f49533b 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.cpp @@ -22,8 +22,23 @@ subject to the following restrictions: btMultiBodyJointMotor::btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse) -:btMultiBodyJointMotor(body,link,0,desiredVelocity,maxMotorImpulse) + :btMultiBodyConstraint(body,body,link,link,1,true), + m_desiredVelocity(desiredVelocity) { + int linkDoF = 0; + + m_maxAppliedImpulse = maxMotorImpulse; + // the data.m_jacobians never change, so may as well + // initialize them here + + // note: we rely on the fact that data.m_jacobians are + // always initialized to zero by the Constraint ctor + + unsigned int offset = 6 + (body->isMultiDof() ? body->getLink(link).m_dofOffset + linkDoF : link); + + // row 0: the lower bound + // row 0: the lower bound + jacobianA(0)[offset] = 1; } diff --git a/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h b/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h index ada7ccd60..e863c7cc0 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h +++ b/src/BulletDynamics/Featherstone/btMultiBodyJointMotor.h @@ -30,7 +30,7 @@ protected: public: - btMultiBodyJointMotor(btMultiBody* body, int link,btScalar desiredVelocity, btScalar maxMotorImpulse); + btMultiBodyJointMotor(btMultiBody* body, int link, btScalar desiredVelocity, btScalar maxMotorImpulse); btMultiBodyJointMotor(btMultiBody* body, int link, int linkDoF, btScalar desiredVelocity, btScalar maxMotorImpulse); virtual ~btMultiBodyJointMotor(); diff --git a/src/LinearMath/btCpuFeatureUtility.h b/src/LinearMath/btCpuFeatureUtility.h index 0c9ba99a9..b3ed59eab 100644 --- a/src/LinearMath/btCpuFeatureUtility.h +++ b/src/LinearMath/btCpuFeatureUtility.h @@ -6,10 +6,8 @@ #include //memset #ifdef BT_USE_SSE -#if (_MSC_FULL_VER >= 160040219) #include #endif -#endif #if defined BT_USE_NEON #define ARM_NEON_GCC_COMPATIBILITY 1 @@ -30,7 +28,7 @@ public: CPU_FEATURE_NEON_HPFP=4 }; - static int getCpuFeatures(btCpuFeature inFeature) + static int getCpuFeatures() { static int capabilities = 0; @@ -50,31 +48,29 @@ public: } #endif //BT_USE_NEON -#ifdef BT_USE_SSE -#if (_MSC_FULL_VER >= 160040219) +#ifdef BT_ALLOW_SSE4 { int cpuInfo[4]; memset(cpuInfo, 0, sizeof(cpuInfo)); unsigned long long sseExt; - __cpuid(mCpuInfo, 1); - mExt = _xgetbv(0); + __cpuid(cpuInfo, 1); + sseExt = _xgetbv(0); const int OSXSAVEFlag = (1UL << 27); const int AVXFlag = ((1UL << 28) | OSXSAVEFlag); const int FMAFlag = ((1UL << 12) | AVXFlag | OSXSAVEFlag); - if ((mCpuInfo[2] & FMAFlag) == FMAFlag && (mExt & 6) == 6) + if ((cpuInfo[2] & FMAFlag) == FMAFlag && (sseExt & 6) == 6) { capabilities |= btCpuFeatureUtility::CPU_FEATURE_FMA3; } const int SSE41Flag = (1 << 19); - if (mCpuInfo[2] & SSE41Flag) + if (cpuInfo[2] & SSE41Flag) { capabilities |= btCpuFeatureUtility::CPU_FEATURE_SSE4_1; } } -#endif//(_MSC_FULL_VER >= 160040219) -#endif//BT_USE_SSE +#endif//BT_ALLOW_SSE4 testedCapabilities = true; return capabilities; diff --git a/src/LinearMath/btScalar.h b/src/LinearMath/btScalar.h index 401e11eaa..da3e88313 100644 --- a/src/LinearMath/btScalar.h +++ b/src/LinearMath/btScalar.h @@ -74,6 +74,11 @@ inline int btGetVersion() #define BT_USE_SSE #ifdef BT_USE_SSE + +#if (_MSC_FULL_VER >= 170050727)//Visual Studio 2012 can compile SSE4/FMA3 (but SSE4/FMA3 is not enabled by default) + #define BT_ALLOW_SSE4 +#endif //(_MSC_FULL_VER >= 160040219) + //BT_USE_SSE_IN_API is disabled under Windows by default, because //it makes it harder to integrate Bullet into your application under Windows //(structured embedding Bullet structs/classes need to be 16-byte aligned) From 66ab2a20224c5230dbaaab5398432b2708aaafd8 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Sat, 3 May 2014 08:48:46 -0700 Subject: [PATCH 036/116] fix OSX build --- .../btSequentialImpulseConstraintSolver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index 58a35a289..ddc65f79b 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -40,7 +40,9 @@ int gNumSplitImpulseRecoveries = 0; #ifdef USE_SIMD -#include //is it safe to include this header? +#include + +//#include //is it safe to include this header? #define btVecSplat(x, e) _mm_shuffle_ps(x, x, _MM_SHUFFLE(e,e,e,e)) static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 ) @@ -50,6 +52,8 @@ static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 ) } #if defined (BT_USE_SSE4) +#include + #define USE_FMA 1 #define USE_FMA3_INSTEAD_FMA4 1 #define USE_SSE4_DOT 0 From 0e1a77047cfaa9bf94f7318686ba4179f40c8c1b Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Sat, 3 May 2014 02:50:09 -0700 Subject: [PATCH 037/116] fix Linux build --- Demos3/AllBullet2Demos/CMakeLists.txt | 7 +- Demos3/SimpleOpenGL3/CMakeLists.txt | 2 +- .../btSequentialImpulseConstraintSolver.cpp | 295 ++++++++++-------- .../btSequentialImpulseConstraintSolver.h | 11 +- 4 files changed, 179 insertions(+), 136 deletions(-) diff --git a/Demos3/AllBullet2Demos/CMakeLists.txt b/Demos3/AllBullet2Demos/CMakeLists.txt index 04e995302..0d16efb3d 100644 --- a/Demos3/AllBullet2Demos/CMakeLists.txt +++ b/Demos3/AllBullet2Demos/CMakeLists.txt @@ -34,6 +34,10 @@ SET(App_AllBullet2Demos_SRCS ${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc ) +LINK_LIBRARIES( + Bullet3Common BulletSoftBody BulletDynamics BulletCollision LinearMath OpenGLWindow gwen ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} +) + IF (WIN32) SET(App_AllBullet2Demos_SRCS ${App_AllBullet2Demos_SRCS} ${App_AllBullet2Demos_Common_SRCS}) INCLUDE_DIRECTORIES( @@ -52,9 +56,6 @@ ENDIF(WIN32) -LINK_LIBRARIES( - Bullet3Common BulletSoftBody BulletDynamics BulletCollision LinearMath OpenGLWindow gwen ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} -) ADD_EXECUTABLE(App_AllBullet2Demos ${App_AllBullet2Demos_SRCS} diff --git a/Demos3/SimpleOpenGL3/CMakeLists.txt b/Demos3/SimpleOpenGL3/CMakeLists.txt index 7cae8b701..14f604717 100644 --- a/Demos3/SimpleOpenGL3/CMakeLists.txt +++ b/Demos3/SimpleOpenGL3/CMakeLists.txt @@ -12,7 +12,7 @@ SET(AppSimpleOpenGL3_SRCS ) LINK_LIBRARIES( - gwen OpenGLWindow Bullet3Common ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} + gwen OpenGLWindow Bullet3Common ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ) IF (WIN32) diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index ddc65f79b..ee5000e22 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -4,8 +4,8 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -22,6 +22,8 @@ subject to the following restrictions: #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "LinearMath/btIDebugDraw.h" +#include "LinearMath/btCpuFeatureUtility.h" + //#include "btJacobianEntry.h" #include "LinearMath/btMinMax.h" #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" @@ -38,11 +40,70 @@ int gNumSplitImpulseRecoveries = 0; #include "BulletDynamics/Dynamics/btRigidBody.h" +///This is the scalar reference implementation of solving a single constraint row, the innerloop of the Projected Gauss Seidel/Sequential Impulse constraint solver +///Below are optional SSE2 and SSE4/FMA3 versions. We assume most hardware has SSE2. For SSE4/FMA3 we perform a CPU feature check. +static btSimdScalar gResolveSingleConstraintRowGeneric_scalar_reference(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) +{ + btScalar deltaImpulse = c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm; + const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity()); + const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity()); + + // const btScalar delta_rel_vel = deltaVel1Dotn-deltaVel2Dotn; + deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; + deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; + + const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse; + if (sum < c.m_lowerLimit) + { + deltaImpulse = c.m_lowerLimit - c.m_appliedImpulse; + c.m_appliedImpulse = c.m_lowerLimit; + } + else if (sum > c.m_upperLimit) + { + deltaImpulse = c.m_upperLimit - c.m_appliedImpulse; + c.m_appliedImpulse = c.m_upperLimit; + } + else + { + c.m_appliedImpulse = sum; + } + + body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(), c.m_angularComponentA, deltaImpulse); + body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(), c.m_angularComponentB, deltaImpulse); + + return deltaImpulse; +} + + +static btSimdScalar gResolveSingleConstraintRowLowerLimit_scalar_reference(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) +{ + btScalar deltaImpulse = c.m_rhs - btScalar(c.m_appliedImpulse)*c.m_cfm; + const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity()); + const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity()); + + deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; + deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; + const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse; + if (sum < c.m_lowerLimit) + { + deltaImpulse = c.m_lowerLimit - c.m_appliedImpulse; + c.m_appliedImpulse = c.m_lowerLimit; + } + else + { + c.m_appliedImpulse = sum; + } + body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(), c.m_angularComponentA, deltaImpulse); + body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(), c.m_angularComponentB, deltaImpulse); + + return deltaImpulse; +} + + #ifdef USE_SIMD #include -//#include //is it safe to include this header? #define btVecSplat(x, e) _mm_shuffle_ps(x, x, _MM_SHUFFLE(e,e,e,e)) static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 ) @@ -51,12 +112,12 @@ static inline __m128 btSimdDot3( __m128 vec0, __m128 vec1 ) return _mm_add_ps( btVecSplat( result, 0 ), _mm_add_ps( btVecSplat( result, 1 ), btVecSplat( result, 2 ) ) ); } -#if defined (BT_USE_SSE4) +#if defined (BT_ALLOW_SSE4) #include #define USE_FMA 1 #define USE_FMA3_INSTEAD_FMA4 1 -#define USE_SSE4_DOT 0 +#define USE_SSE4_DOT 1 #define SSE4_DP(a, b) _mm_dp_ps(a, b, 0x7f) #define SSE4_DP_FP(a, b) _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7f)) @@ -147,6 +208,7 @@ static btSimdScalar gResolveSingleConstraintRowGeneric_sse4_1_fma3(btSolverBody& } + static btSimdScalar gResolveSingleConstraintRowLowerLimit_sse2(btSolverBody& body1, btSolverBody& body2, const btSolverConstraint& c) { __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse); @@ -217,34 +279,7 @@ btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGene // Project Gauss Seidel or the equivalent Sequential Impulse btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGeneric(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c) { - btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm; - const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity()); - const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity()); - -// const btScalar delta_rel_vel = deltaVel1Dotn-deltaVel2Dotn; - deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; - deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; - - const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse; - if (sum < c.m_lowerLimit) - { - deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse; - c.m_appliedImpulse = c.m_lowerLimit; - } - else if (sum > c.m_upperLimit) - { - deltaImpulse = c.m_upperLimit-c.m_appliedImpulse; - c.m_appliedImpulse = c.m_upperLimit; - } - else - { - c.m_appliedImpulse = sum; - } - - body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); - body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); - - return deltaImpulse; + return gResolveSingleConstraintRowGeneric_scalar_reference(body1, body2, c); } btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimitSIMD(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c) @@ -259,26 +294,7 @@ btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowe btSimdScalar btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimit(btSolverBody& body1,btSolverBody& body2,const btSolverConstraint& c) { - btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm; - const btScalar deltaVel1Dotn = c.m_contactNormal1.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity()); - const btScalar deltaVel2Dotn = c.m_contactNormal2.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity()); - - deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; - deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; - const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse; - if (sum < c.m_lowerLimit) - { - deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse; - c.m_appliedImpulse = c.m_lowerLimit; - } - else - { - c.m_appliedImpulse = sum; - } - body1.internalApplyImpulse(c.m_contactNormal1*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); - body2.internalApplyImpulse(c.m_contactNormal2*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); - - return deltaImpulse; + return gResolveSingleConstraintRowLowerLimit_scalar_reference(body1,body2,c); } @@ -349,34 +365,61 @@ void btSequentialImpulseConstraintSolver::resolveSplitPenetrationImpulseCacheFri btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver() :m_btSeed2(0), - m_resolveSingleConstraintRowGeneric(gResolveSingleConstraintRowGeneric_sse2), - m_resolveSingleConstraintRowLowerLimit(gResolveSingleConstraintRowLowerLimit_sse2) + m_resolveSingleConstraintRowGeneric(gResolveSingleConstraintRowGeneric_scalar_reference), + m_resolveSingleConstraintRowLowerLimit(gResolveSingleConstraintRowLowerLimit_scalar_reference) { +#ifdef USE_SIMD + m_resolveSingleConstraintRowGeneric = gResolveSingleConstraintRowGeneric_sse2; + m_resolveSingleConstraintRowLowerLimit=gResolveSingleConstraintRowLowerLimit_sse2; +#endif //USE_SIMD + +#ifdef BT_ALLOW_SSE4 + int cpuFeatures = btCpuFeatureUtility::getCpuFeatures(); + if ((cpuFeatures & btCpuFeatureUtility::CPU_FEATURE_FMA3) && (cpuFeatures & btCpuFeatureUtility::CPU_FEATURE_SSE4_1)) + { + m_resolveSingleConstraintRowGeneric = gResolveSingleConstraintRowGeneric_sse4_1_fma3; + m_resolveSingleConstraintRowLowerLimit = gResolveSingleConstraintRowLowerLimit_sse4_1_fma3; + } +#endif//BT_ALLOW_SSE4 + } btSequentialImpulseConstraintSolver::~btSequentialImpulseConstraintSolver() { } + btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getScalarConstraintRowSolverGeneric() + { + return gResolveSingleConstraintRowGeneric_scalar_reference; + } + btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getScalarConstraintRowSolverLowerLimit() + { + return gResolveSingleConstraintRowLowerLimit_scalar_reference; + } + + +#ifdef USE_SIMD btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE2ConstraintRowSolverGeneric() { return gResolveSingleConstraintRowGeneric_sse2; } - btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE4_1ConstraintRowSolverGeneric() - { - return gResolveSingleConstraintRowGeneric_sse4_1_fma3; - } btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE2ConstraintRowSolverLowerLimit() { return gResolveSingleConstraintRowLowerLimit_sse2; } +#ifdef BT_ALLOW_SSE4 + btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE4_1ConstraintRowSolverGeneric() + { + return gResolveSingleConstraintRowGeneric_sse4_1_fma3; + } btSingleConstraintRowSolver btSequentialImpulseConstraintSolver::getSSE4_1ConstraintRowSolverLowerLimit() { return gResolveSingleConstraintRowLowerLimit_sse4_1_fma3; } - +#endif //BT_ALLOW_SSE4 +#endif //USE_SIMD unsigned long btSequentialImpulseConstraintSolver::btRand2() { @@ -437,7 +480,7 @@ void btSequentialImpulseConstraintSolver::initSolverBody(btSolverBody* solverBod solverBody->m_angularVelocity = rb->getAngularVelocity(); solverBody->m_externalForceImpulse = rb->getTotalForce()*rb->getInvMass()*timeStep; solverBody->m_externalTorqueImpulse = rb->getTotalTorque()*rb->getInvInertiaTensorWorld()*timeStep ; - + } else { solverBody->m_worldTransform.setIdentity(); @@ -469,7 +512,7 @@ btScalar btSequentialImpulseConstraintSolver::restitutionCurve(btScalar rel_vel, void btSequentialImpulseConstraintSolver::applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection, int frictionMode) { - + if (colObj && colObj->hasAnisotropicFriction(frictionMode)) { @@ -490,7 +533,7 @@ void btSequentialImpulseConstraintSolver::applyAnisotropicFriction(btCollisionOb void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstraint& solverConstraint, const btVector3& normalAxis,int solverBodyIdA,int solverBodyIdB,btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity, btScalar cfmSlip) { - + btSolverBody& solverBodyA = m_tmpSolverBodyPool[solverBodyIdA]; btSolverBody& solverBodyB = m_tmpSolverBodyPool[solverBodyIdB]; @@ -551,12 +594,12 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr } { - + btScalar rel_vel; - btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(body0?solverBodyA.m_linearVelocity+solverBodyA.m_externalForceImpulse:btVector3(0,0,0)) + btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(body0?solverBodyA.m_linearVelocity+solverBodyA.m_externalForceImpulse:btVector3(0,0,0)) + solverConstraint.m_relpos1CrossNormal.dot(body0?solverBodyA.m_angularVelocity:btVector3(0,0,0)); - btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(body1?solverBodyB.m_linearVelocity+solverBodyB.m_externalForceImpulse:btVector3(0,0,0)) + btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(body1?solverBodyB.m_linearVelocity+solverBodyB.m_externalForceImpulse:btVector3(0,0,0)) + solverConstraint.m_relpos2CrossNormal.dot(body1?solverBodyB.m_angularVelocity:btVector3(0,0,0)); rel_vel = vel1Dotn+vel2Dotn; @@ -570,7 +613,7 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr solverConstraint.m_cfm = cfmSlip; solverConstraint.m_lowerLimit = -solverConstraint.m_friction; solverConstraint.m_upperLimit = solverConstraint.m_friction; - + } } @@ -578,7 +621,7 @@ btSolverConstraint& btSequentialImpulseConstraintSolver::addFrictionConstraint(c { btSolverConstraint& solverConstraint = m_tmpSolverContactFrictionConstraintPool.expandNonInitializing(); solverConstraint.m_frictionIndex = frictionIndex; - setupFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, + setupFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, desiredVelocity, cfmSlip); return solverConstraint; } @@ -586,7 +629,7 @@ btSolverConstraint& btSequentialImpulseConstraintSolver::addFrictionConstraint(c void btSequentialImpulseConstraintSolver::setupRollingFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis1,int solverBodyIdA,int solverBodyIdB, btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2, - btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, + btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity, btScalar cfmSlip) { @@ -632,12 +675,12 @@ void btSequentialImpulseConstraintSolver::setupRollingFrictionConstraint( btSolv } { - + btScalar rel_vel; - btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(body0?solverBodyA.m_linearVelocity+solverBodyA.m_externalForceImpulse:btVector3(0,0,0)) + btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(body0?solverBodyA.m_linearVelocity+solverBodyA.m_externalForceImpulse:btVector3(0,0,0)) + solverConstraint.m_relpos1CrossNormal.dot(body0?solverBodyA.m_angularVelocity:btVector3(0,0,0)); - btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(body1?solverBodyB.m_linearVelocity+solverBodyB.m_externalForceImpulse:btVector3(0,0,0)) + btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(body1?solverBodyB.m_linearVelocity+solverBodyB.m_externalForceImpulse:btVector3(0,0,0)) + solverConstraint.m_relpos2CrossNormal.dot(body1?solverBodyB.m_angularVelocity:btVector3(0,0,0)); rel_vel = vel1Dotn+vel2Dotn; @@ -650,7 +693,7 @@ void btSequentialImpulseConstraintSolver::setupRollingFrictionConstraint( btSolv solverConstraint.m_cfm = cfmSlip; solverConstraint.m_lowerLimit = -solverConstraint.m_friction; solverConstraint.m_upperLimit = solverConstraint.m_friction; - + } } @@ -665,7 +708,7 @@ btSolverConstraint& btSequentialImpulseConstraintSolver::addRollingFrictionConst { btSolverConstraint& solverConstraint = m_tmpSolverContactRollingFrictionConstraintPool.expandNonInitializing(); solverConstraint.m_frictionIndex = frictionIndex; - setupRollingFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, + setupRollingFrictionConstraint(solverConstraint, normalAxis, solverBodyIdA, solverBodyIdB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, desiredVelocity, cfmSlip); return solverConstraint; } @@ -693,7 +736,7 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& body.setCompanionId(solverBodyIdA); } else { - + if (m_fixedBodyId<0) { m_fixedBodyId = m_tmpSolverBodyPool.size(); @@ -711,13 +754,13 @@ int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& #include -void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstraint& solverConstraint, +void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstraint& solverConstraint, int solverBodyIdA, int solverBodyIdB, btManifoldPoint& cp, const btContactSolverInfo& infoGlobal, btScalar& relaxation, const btVector3& rel_pos1, const btVector3& rel_pos2) { - + const btVector3& pos1 = cp.getPositionWorldOnA(); const btVector3& pos2 = cp.getPositionWorldOnB(); @@ -727,23 +770,23 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra btRigidBody* rb0 = bodyA->m_originalBody; btRigidBody* rb1 = bodyB->m_originalBody; -// btVector3 rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); +// btVector3 rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); // btVector3 rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin(); - //rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin(); + //rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin(); //rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin(); relaxation = 1.f; btVector3 torqueAxis0 = rel_pos1.cross(cp.m_normalWorldOnB); solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0); - btVector3 torqueAxis1 = rel_pos2.cross(cp.m_normalWorldOnB); + btVector3 torqueAxis1 = rel_pos2.cross(cp.m_normalWorldOnB); solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0); { #ifdef COMPUTE_IMPULSE_DENOM btScalar denom0 = rb0->computeImpulseDenominator(pos1,cp.m_normalWorldOnB); btScalar denom1 = rb1->computeImpulseDenominator(pos2,cp.m_normalWorldOnB); -#else +#else btVector3 vec; btScalar denom0 = 0.f; btScalar denom1 = 0.f; @@ -757,7 +800,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2); denom1 = rb1->getInvMass() + cp.m_normalWorldOnB.dot(vec); } -#endif //COMPUTE_IMPULSE_DENOM +#endif //COMPUTE_IMPULSE_DENOM btScalar denom = relaxation/(denom0+denom1); solverConstraint.m_jacDiagABInv = denom; @@ -795,11 +838,11 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra btVector3 vel = vel1 - vel2; btScalar rel_vel = cp.m_normalWorldOnB.dot(vel); - + solverConstraint.m_friction = cp.m_combinedFriction; - + restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution); if (restitution <= btScalar(0.)) { @@ -829,17 +872,17 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra btVector3 externalTorqueImpulseA = bodyA->m_originalBody ? bodyA->m_externalTorqueImpulse: btVector3(0,0,0); btVector3 externalForceImpulseB = bodyB->m_originalBody ? bodyB->m_externalForceImpulse: btVector3(0,0,0); btVector3 externalTorqueImpulseB = bodyB->m_originalBody ?bodyB->m_externalTorqueImpulse : btVector3(0,0,0); - - btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(bodyA->m_linearVelocity+externalForceImpulseA) + + btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(bodyA->m_linearVelocity+externalForceImpulseA) + solverConstraint.m_relpos1CrossNormal.dot(bodyA->m_angularVelocity+externalTorqueImpulseA); - btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(bodyB->m_linearVelocity+externalForceImpulseB) + btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(bodyB->m_linearVelocity+externalForceImpulseB) + solverConstraint.m_relpos2CrossNormal.dot(bodyB->m_angularVelocity+externalTorqueImpulseB); btScalar rel_vel = vel1Dotn+vel2Dotn; btScalar positionalError = 0.f; btScalar velocityError = restitution - rel_vel;// * damping; - + btScalar erp = infoGlobal.m_erp2; if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) @@ -884,7 +927,7 @@ void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstra -void btSequentialImpulseConstraintSolver::setFrictionConstraintImpulse( btSolverConstraint& solverConstraint, +void btSequentialImpulseConstraintSolver::setFrictionConstraintImpulse( btSolverConstraint& solverConstraint, int solverBodyIdA, int solverBodyIdB, btManifoldPoint& cp, const btContactSolverInfo& infoGlobal) { @@ -963,7 +1006,7 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m btVector3 rel_pos1; btVector3 rel_pos2; btScalar relaxation; - + int frictionIndex = m_tmpSolverContactConstraintPool.size(); btSolverConstraint& solverConstraint = m_tmpSolverContactConstraintPool.expandNonInitializing(); @@ -977,7 +1020,7 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m const btVector3& pos1 = cp.getPositionWorldOnA(); const btVector3& pos2 = cp.getPositionWorldOnB(); - rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); + rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin(); btVector3 vel1;// = rb0 ? rb0->getVelocityInLocalPoint(rel_pos1) : btVector3(0,0,0); @@ -985,13 +1028,13 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m solverBodyA->getVelocityInLocalPointNoDelta(rel_pos1,vel1); solverBodyB->getVelocityInLocalPointNoDelta(rel_pos2,vel2 ); - + btVector3 vel = vel1 - vel2; btScalar rel_vel = cp.m_normalWorldOnB.dot(vel); setupContactConstraint(solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal, relaxation, rel_pos1, rel_pos2); - + // const btVector3& pos1 = cp.getPositionWorldOnA(); // const btVector3& pos2 = cp.getPositionWorldOnB(); @@ -1032,21 +1075,21 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m addRollingFrictionConstraint(axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); if (axis1.length()>0.001) addRollingFrictionConstraint(axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); - + } } ///Bullet has several options to set the friction directions - ///By default, each contact has only a single friction direction that is recomputed automatically very frame + ///By default, each contact has only a single friction direction that is recomputed automatically very frame ///based on the relative linear velocity. ///If the relative velocity it zero, it will automatically compute a friction direction. - + ///You can also enable two friction directions, using the SOLVER_USE_2_FRICTION_DIRECTIONS. ///In that case, the second friction direction will be orthogonal to both contact normal and first friction direction. /// ///If you choose SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION, then the friction will be independent from the relative projected velocity. /// - ///The user can manually override the friction directions for certain contacts using a contact callback, + ///The user can manually override the friction directions for certain contacts using a contact callback, ///and set the cp.m_lateralFrictionInitialized to true ///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2) ///this will give a conveyor belt effect @@ -1102,9 +1145,9 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m } setFrictionConstraintImpulse( solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal); - - + + } } @@ -1144,7 +1187,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol bool found=false; for (int b=0;bgetRigidBodyA()==bodies[b]) { found = true; @@ -1176,7 +1219,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol bool found=false; for (int b=0;bgetBody0()==bodies[b]) { found = true; @@ -1200,8 +1243,8 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol } } #endif //BT_ADDITIONAL_DEBUG - - + + for (int i = 0; i < numBodies; i++) { bodies[i]->setCompanionId(-1); @@ -1232,7 +1275,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol } } } - + if (1) { int j; @@ -1252,7 +1295,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol int totalNumRows = 0; int i; - + m_tmpConstraintSizesPool.resizeNoInitialize(numConstraints); //calculate the total number of contraint rows for (i=0;im_originalBody ? bodyAPtr->m_externalForceImpulse : btVector3(0,0,0); @@ -1405,11 +1448,11 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol btVector3 externalForceImpulseB = bodyBPtr->m_originalBody ? bodyBPtr->m_externalForceImpulse : btVector3(0,0,0); btVector3 externalTorqueImpulseB = bodyBPtr->m_originalBody ?bodyBPtr->m_externalTorqueImpulse : btVector3(0,0,0); - - btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(rbA.getLinearVelocity()+externalForceImpulseA) + + btScalar vel1Dotn = solverConstraint.m_contactNormal1.dot(rbA.getLinearVelocity()+externalForceImpulseA) + solverConstraint.m_relpos1CrossNormal.dot(rbA.getAngularVelocity()+externalTorqueImpulseA); - - btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(rbB.getLinearVelocity()+externalForceImpulseB) + + btScalar vel2Dotn = solverConstraint.m_contactNormal2.dot(rbB.getLinearVelocity()+externalForceImpulseB) + solverConstraint.m_relpos2CrossNormal.dot(rbB.getAngularVelocity()+externalTorqueImpulseB); rel_vel = vel1Dotn+vel2Dotn; @@ -1475,7 +1518,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration int numNonContactPool = m_tmpSolverNonContactConstraintPool.size(); int numConstraintPool = m_tmpSolverContactConstraintPool.size(); int numFrictionPool = m_tmpSolverContactFrictionConstraintPool.size(); - + if (infoGlobal.m_solverMode & SOLVER_RANDMIZE_ORDER) { if (1) // uncomment this for a bit less random ((iteration & 7) == 0) @@ -1488,7 +1531,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration m_orderNonContactConstraintPool[swapi] = tmp; } - //contact/friction constraints are not solved more than + //contact/friction constraints are not solved more than if (iteration< infoGlobal.m_numIterations) { for (int j=0; jbtScalar(0)) { solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); @@ -1592,8 +1635,8 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration resolveSingleConstraintRowLowerLimitSIMD(m_tmpSolverBodyPool[solveManifold.m_solverBodyIdA],m_tmpSolverBodyPool[solveManifold.m_solverBodyIdB],solveManifold); } - - + + ///solve all friction constraints, using SIMD, if available @@ -1612,7 +1655,7 @@ btScalar btSequentialImpulseConstraintSolver::solveSingleIteration(int iteration } } - + int numRollingFrictionPoolConstraints = m_tmpSolverContactRollingFrictionConstraintPool.size(); for (j=0;j= 0;iteration--) - { + { solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer); } - + } return 0.f; } @@ -1802,7 +1845,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCo fb->m_appliedForceBodyB += solverConstr.m_contactNormal2*solverConstr.m_appliedImpulse*constr->getRigidBodyB().getLinearFactor()/infoGlobal.m_timeStep; fb->m_appliedTorqueBodyA += solverConstr.m_relpos1CrossNormal* constr->getRigidBodyA().getAngularFactor()*solverConstr.m_appliedImpulse/infoGlobal.m_timeStep; fb->m_appliedTorqueBodyB += solverConstr.m_relpos2CrossNormal* constr->getRigidBodyB().getAngularFactor()*solverConstr.m_appliedImpulse/infoGlobal.m_timeStep; /*RGM ???? */ - + } constr->internalSetAppliedImpulse(solverConstr.m_appliedImpulse); @@ -1823,7 +1866,7 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(btCo m_tmpSolverBodyPool[i].writebackVelocityAndTransform(infoGlobal.m_timeStep, infoGlobal.m_splitImpulseTurnErp); else m_tmpSolverBodyPool[i].writebackVelocity(); - + m_tmpSolverBodyPool[i].m_originalBody->setLinearVelocity( m_tmpSolverBodyPool[i].m_linearVelocity+ m_tmpSolverBodyPool[i].m_externalForceImpulse); @@ -1856,13 +1899,13 @@ btScalar btSequentialImpulseConstraintSolver::solveGroup(btCollisionObject** bod BT_PROFILE("solveGroup"); //you need to provide at least some bodies - + solveGroupCacheFriendlySetup( bodies, numBodies, manifoldPtr, numManifolds,constraints, numConstraints,infoGlobal,debugDrawer); solveGroupCacheFriendlyIterations(bodies, numBodies, manifoldPtr, numManifolds,constraints, numConstraints,infoGlobal,debugDrawer); solveGroupCacheFriendlyFinish(bodies, numBodies, infoGlobal); - + return 0.f; } diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h index 001708a21..a60291809 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h @@ -158,16 +158,15 @@ public: m_resolveSingleConstraintRowLowerLimit = rowSolver; } - - // btSingleConstraintRowSolver getScalarConstraintRowSolverLowerLimit(); + ///Various implementations of solving a single constraint row using a generic equality constraint, using scalar reference, SSE2 or SSE4 + btSingleConstraintRowSolver getScalarConstraintRowSolverGeneric(); btSingleConstraintRowSolver getSSE2ConstraintRowSolverGeneric(); btSingleConstraintRowSolver getSSE4_1ConstraintRowSolverGeneric(); + + ///Various implementations of solving a single constraint row using an inequality (lower limit) constraint, using scalar reference, SSE2 or SSE4 + btSingleConstraintRowSolver getScalarConstraintRowSolverLowerLimit(); btSingleConstraintRowSolver getSSE2ConstraintRowSolverLowerLimit(); btSingleConstraintRowSolver getSSE4_1ConstraintRowSolverLowerLimit(); - - - - }; From e279aed08fab5ed562e4c966c8bc0d78bd8e906d Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Sat, 3 May 2014 10:11:49 -0700 Subject: [PATCH 038/116] re-enable the fix for broken friction in Clang (got accidently undone in a recent commit) fix OSX build --- .../btSequentialImpulseConstraintSolver.cpp | 4 ++-- src/LinearMath/btCpuFeatureUtility.h | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index ee5000e22..8385639a1 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -606,8 +606,8 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr // btScalar positionalError = 0.f; - btSimdScalar velocityError = desiredVelocity - rel_vel; - btSimdScalar velocityImpulse = velocityError * btSimdScalar(solverConstraint.m_jacDiagABInv); + btScalar velocityError = desiredVelocity - rel_vel; + btScalar velocityImpulse = velocityError * solverConstraint.m_jacDiagABInv; solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; solverConstraint.m_cfm = cfmSlip; diff --git a/src/LinearMath/btCpuFeatureUtility.h b/src/LinearMath/btCpuFeatureUtility.h index b3ed59eab..47e5a4178 100644 --- a/src/LinearMath/btCpuFeatureUtility.h +++ b/src/LinearMath/btCpuFeatureUtility.h @@ -5,9 +5,12 @@ #include "LinearMath/btScalar.h" #include //memset -#ifdef BT_USE_SSE +#ifdef USE_SIMD +#include +#ifdef BT_ALLOW_SSE4 #include -#endif +#endif //BT_ALLOW_SSE4 +#endif //USE_SIMD #if defined BT_USE_NEON #define ARM_NEON_GCC_COMPATIBILITY 1 From c1940169bc7a92995ac41869f9895ac80e5461c1 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 5 May 2014 13:47:00 -0700 Subject: [PATCH 039/116] workaround of premake for link error on Ubuntu/Linux, see https://bugs.launchpad.net/ubuntu/+source/nvidia-graphics-drivers-319/+bug/1248642 --- Demos3/AllBullet2Demos/premake4.lua | 2 +- Demos3/GpuDemos/premake4.lua | 2 +- Demos3/GpuGuiInitialize/premake4.lua | 2 +- Demos3/ImplicitCloth/premake4.lua | 1 + Demos3/SimpleOpenGL3/premake4.lua | 2 +- btgui/GwenOpenGLTest/premake4.lua | 1 + btgui/OpenGLWindow/X11OpenGLWindow.cpp | 9 +++++++++ btgui/OpenGLWindow/premake4.lua | 4 +++- 8 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Demos3/AllBullet2Demos/premake4.lua b/Demos3/AllBullet2Demos/premake4.lua index eeac13583..436e1fa8d 100644 --- a/Demos3/AllBullet2Demos/premake4.lua +++ b/Demos3/AllBullet2Demos/premake4.lua @@ -48,7 +48,7 @@ "../GpuDemos/gwenUserInterface.h" } -if os.is("Linux") then links{"X11"} end +if os.is("Linux") then links{"X11","pthread"} end if os.is("MacOSX") then links{"Cocoa.framework"} end diff --git a/Demos3/GpuDemos/premake4.lua b/Demos3/GpuDemos/premake4.lua index 24ca2eaf2..77e2f7119 100644 --- a/Demos3/GpuDemos/premake4.lua +++ b/Demos3/GpuDemos/premake4.lua @@ -91,7 +91,7 @@ function createProject(vendor) } end if os.is("Linux") then - links{"X11"} + links{"X11","pthread"} files { "../../btgui/OpenGLWindow/X11OpenGLWindow.cpp", "../../btgui/OpenGLWindow/X11OpenGLWindows.h" diff --git a/Demos3/GpuGuiInitialize/premake4.lua b/Demos3/GpuGuiInitialize/premake4.lua index 696235966..b36da7dd5 100644 --- a/Demos3/GpuGuiInitialize/premake4.lua +++ b/Demos3/GpuGuiInitialize/premake4.lua @@ -68,7 +68,7 @@ function createProject(vendor) } end if os.is("Linux") then - links {"X11"} + links {"X11","pthread"} files { "../../btgui/OpenGLWindow/X11OpenGLWindow.cpp", "../../btgui/OpenGLWindow/X11OpenGLWindows.h" diff --git a/Demos3/ImplicitCloth/premake4.lua b/Demos3/ImplicitCloth/premake4.lua index 8eea82ce3..beb20168d 100644 --- a/Demos3/ImplicitCloth/premake4.lua +++ b/Demos3/ImplicitCloth/premake4.lua @@ -61,6 +61,7 @@ if os.is("Windows") then "../../btgui/OpenGLWindow/X11OpenGLWindow.h", "../../btgui/OpenGLWindow/X11OpenGLWindow.cpp" } + links{"pthread"} end if os.is("MacOSX") then links{"Cocoa.framework"} diff --git a/Demos3/SimpleOpenGL3/premake4.lua b/Demos3/SimpleOpenGL3/premake4.lua index 2ab575f07..57a2a04f7 100644 --- a/Demos3/SimpleOpenGL3/premake4.lua +++ b/Demos3/SimpleOpenGL3/premake4.lua @@ -27,7 +27,7 @@ } -if os.is("Linux") then links {"X11"} end +if os.is("Linux") then links {"X11","pthread"} end if os.is("MacOSX") then links{"Cocoa.framework"} diff --git a/btgui/GwenOpenGLTest/premake4.lua b/btgui/GwenOpenGLTest/premake4.lua index fb39dcbfe..1bca96bc8 100644 --- a/btgui/GwenOpenGLTest/premake4.lua +++ b/btgui/GwenOpenGLTest/premake4.lua @@ -55,6 +55,7 @@ "../OpenGLWindow/X11OpenGLWindow.h", "../OpenGLWindow/X11OpenGLWindow.cpp" } + links{"pthread"} end if os.is("MacOSX") then links{"Cocoa.framework"} diff --git a/btgui/OpenGLWindow/X11OpenGLWindow.cpp b/btgui/OpenGLWindow/X11OpenGLWindow.cpp index 0a525b081..6b5bcb39d 100644 --- a/btgui/OpenGLWindow/X11OpenGLWindow.cpp +++ b/btgui/OpenGLWindow/X11OpenGLWindow.cpp @@ -11,6 +11,8 @@ #include +#include + GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; @@ -82,6 +84,13 @@ void X11OpenGLWindow::enableOpenGL() printf("GL_VERSION=%s\n", ver); const GLubyte* sl = glGetString(GL_SHADING_LANGUAGE_VERSION); printf("GL_SHADING_LANGUAGE_VERSION=%s\n", sl); + +//Access pthreads as a workaround for a bug in Linux/Ubuntu +//See https://bugs.launchpad.net/ubuntu/+source/nvidia-graphics-drivers-319/+bug/1248642 + + int i=pthread_getconcurrency(); + printf("pthread_getconcurrency()=%d\n",i); + // const GLubyte* ext = glGetString(GL_EXTENSIONS); // printf("GL_EXTENSIONS=%s\n", ext); } diff --git a/btgui/OpenGLWindow/premake4.lua b/btgui/OpenGLWindow/premake4.lua index be45bbe0d..b6c869646 100644 --- a/btgui/OpenGLWindow/premake4.lua +++ b/btgui/OpenGLWindow/premake4.lua @@ -30,7 +30,9 @@ "Win32Window.h", } end - if not os.is("Linux") then + if os.is("Linux") then + links {"pthread"} + else excludes { "X11OpenGLWindow.cpp", "X11OpenGLWindows.h" From 7cec30dede5f9a9731f97c7174b38b2e3c3210ce Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 5 May 2014 15:37:02 -0700 Subject: [PATCH 040/116] fix Linux build optional Midi under Linux (ALSA/libasound) --- btgui/MidiTest/cmidiin.cpp | 3 ++- btgui/MidiTest/premake4.lua | 2 ++ btgui/OpenGLWindow/premake4.lua | 4 +--- build3/premake4.lua | 7 +++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/btgui/MidiTest/cmidiin.cpp b/btgui/MidiTest/cmidiin.cpp index bc5e3aaf9..9de7ab83c 100644 --- a/btgui/MidiTest/cmidiin.cpp +++ b/btgui/MidiTest/cmidiin.cpp @@ -58,7 +58,8 @@ int main( int argc, char *argv[] ) std::cout << "\nReading MIDI input ... press to quit.\n"; char input; std::cin.get(input); -// getchar(); + std::cin.get(input); + cleanup: diff --git a/btgui/MidiTest/premake4.lua b/btgui/MidiTest/premake4.lua index 639f23223..e09468e6a 100644 --- a/btgui/MidiTest/premake4.lua +++ b/btgui/MidiTest/premake4.lua @@ -26,6 +26,8 @@ end if os.is("Linux") then + defines {"__LINUX_ALSA__"} + links {"asound","pthread"} end if os.is("MacOSX") then diff --git a/btgui/OpenGLWindow/premake4.lua b/btgui/OpenGLWindow/premake4.lua index b6c869646..be45bbe0d 100644 --- a/btgui/OpenGLWindow/premake4.lua +++ b/btgui/OpenGLWindow/premake4.lua @@ -30,9 +30,7 @@ "Win32Window.h", } end - if os.is("Linux") then - links {"pthread"} - else + if not os.is("Linux") then excludes { "X11OpenGLWindow.cpp", "X11OpenGLWindows.h" diff --git a/build3/premake4.lua b/build3/premake4.lua index a5c308db5..9f3c22fde 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -19,7 +19,7 @@ description = "Use Midi controller to control parameters" } - --_OPTIONS["midi"] = "1"; +-- _OPTIONS["midi"] = "1"; newoption { @@ -118,7 +118,10 @@ include "../Demos3/SimpleOpenGL3" include "../test/lua" -- include "../demo/gpudemo" - include "../btgui/MidiTest" +if _OPTIONS["midi"] then + include "../btgui/MidiTest" +end + -- include "../opencl/vector_add_simplified" -- include "../opencl/vector_add" include "../btgui/Gwen" From a5d050bc5e1d88a4baf822fda6e18b57ce5035c4 Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Mon, 5 May 2014 15:56:57 -0700 Subject: [PATCH 041/116] fix Cmake under Linux (using the premake workaround) --- Demos3/AllBullet2Demos/CMakeLists.txt | 2 +- Demos3/GpuDemos/CMakeLists.txt | 2 +- Demos3/SimpleOpenGL3/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Demos3/AllBullet2Demos/CMakeLists.txt b/Demos3/AllBullet2Demos/CMakeLists.txt index 0d16efb3d..6023d44c6 100644 --- a/Demos3/AllBullet2Demos/CMakeLists.txt +++ b/Demos3/AllBullet2Demos/CMakeLists.txt @@ -50,7 +50,7 @@ ELSE(WIN32) MESSAGE(${COCOA}) link_libraries(${COCOA}) ELSE(APPLE) - LINK_LIBRARIES( GLEW) + LINK_LIBRARIES( pthread GLEW) ENDIF(APPLE) ENDIF(WIN32) diff --git a/Demos3/GpuDemos/CMakeLists.txt b/Demos3/GpuDemos/CMakeLists.txt index 06dc4e81a..b6fadf82e 100644 --- a/Demos3/GpuDemos/CMakeLists.txt +++ b/Demos3/GpuDemos/CMakeLists.txt @@ -50,7 +50,7 @@ ELSE(WIN32) MESSAGE(${COCOA}) link_libraries(${COCOA}) ELSE(APPLE) - LINK_LIBRARIES( GLEW X11 dl) + LINK_LIBRARIES( GLEW X11 pthread dl) ENDIF(APPLE) ENDIF(WIN32) diff --git a/Demos3/SimpleOpenGL3/CMakeLists.txt b/Demos3/SimpleOpenGL3/CMakeLists.txt index 14f604717..417cef45a 100644 --- a/Demos3/SimpleOpenGL3/CMakeLists.txt +++ b/Demos3/SimpleOpenGL3/CMakeLists.txt @@ -27,7 +27,7 @@ ELSE(WIN32) MESSAGE(${COCOA}) link_libraries(${COCOA}) ELSE(APPLE) - LINK_LIBRARIES( GLEW X11 dl Xext) + LINK_LIBRARIES( GLEW X11 pthread dl Xext) ENDIF(APPLE) ENDIF(WIN32) From efd3157d1f59b28229a270763b47cd340665cf52 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Wed, 7 May 2014 10:19:27 -0700 Subject: [PATCH 042/116] only compile Bullet 3 if desired (with CMake) remove empty namespace --- src/BulletDynamics/Featherstone/btMultiBodyLink.h | 4 ++-- src/CMakeLists.txt | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/BulletDynamics/Featherstone/btMultiBodyLink.h b/src/BulletDynamics/Featherstone/btMultiBodyLink.h index af926f57f..df96b3c41 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyLink.h +++ b/src/BulletDynamics/Featherstone/btMultiBodyLink.h @@ -32,7 +32,7 @@ enum btMultiBodyLinkFlags // Various spatial helper functions // -namespace { +//namespace { #ifdef TEST_SPATIAL_ALGEBRA_LAYER @@ -343,7 +343,7 @@ namespace { } #endif -} +//} // // Link struct diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 820ac612f..f6755e520 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,8 +1,10 @@ -SUBDIRS( Bullet3OpenCL Bullet3Serialize/Bullet2FileLoader Bullet3Dynamics Bullet3Collision Bullet3Geometry Bullet3Common BulletSoftBody BulletCollision BulletDynamics LinearMath ) -IF(BUILD_MULTITHREADING) - SUBDIRS(MiniCL BulletMultiThreaded) -ENDIF() +IF(BUILD_BULLET3) + SUBDIRS( Bullet3OpenCL Bullet3Serialize/Bullet2FileLoader Bullet3Dynamics Bullet3Collision Bullet3Geometry Bullet3Common ) +ENDIF(BUILD_BULLET3) + +SUBDIRS( BulletSoftBody BulletCollision BulletDynamics LinearMath ) + IF(INSTALL_LIBS) #INSTALL of other files requires CMake 2.6 From dc491936a24b58b218028ebbdc2c87e89e34820f Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 12 May 2014 16:12:01 -0700 Subject: [PATCH 043/116] rename ObsoleteDemos back to Demos fix some relative path issues for loading assets --- CMakeLists.txt | 32 +- .../AllBulletDemos/CMakeLists.txt | 0 .../AllBulletDemos/DemoEntries.cpp | 0 .../AllBulletDemos/DemoEntries.h | 0 .../AllBulletDemos/Main.cpp | 0 .../AllBulletDemos/Makefile.am | 0 .../BasicDemo/BasicDemo.cpp | 0 .../BasicDemo/BasicDemo.h | 0 .../BasicDemo/CMakeLists.txt | 0 .../BasicDemo/Makefile.am | 0 .../BasicDemo/Win32BasicDemo.cpp | 0 {ObsoleteDemos => Demos}/BasicDemo/main.cpp | 0 .../Benchmarks/BenchmarkDemo.cpp | 0 .../Benchmarks/BenchmarkDemo.h | 0 .../Benchmarks/CMakeLists.txt | 0 {ObsoleteDemos => Demos}/Benchmarks/Taru.mdl | 0 .../Benchmarks/Win32BenchmarkDemo.cpp | 0 .../Benchmarks/landscape.mdl | 0 {ObsoleteDemos => Demos}/Benchmarks/main.cpp | 0 .../Benchmarks/premake4.lua | 0 .../Box2dDemo/Box2dDemo.cpp | 0 .../Box2dDemo/Box2dDemo.h | 0 .../Box2dDemo/CMakeLists.txt | 0 .../Box2dDemo/Win32Box2dDemo.cpp | 0 {ObsoleteDemos => Demos}/Box2dDemo/main.cpp | 0 .../BspDemo/BspConverter.cpp | 0 .../BspDemo/BspConverter.h | 0 {ObsoleteDemos => Demos}/BspDemo/BspDemo.bsp | Bin {ObsoleteDemos => Demos}/BspDemo/BspDemo.cpp | 62 +- {ObsoleteDemos => Demos}/BspDemo/BspDemo.h | 0 .../BspDemo/BspLoader.cpp | 0 {ObsoleteDemos => Demos}/BspDemo/BspLoader.h | 0 .../BspDemo/CMakeLists.txt | 4 +- {ObsoleteDemos => Demos}/BspDemo/main.cpp | 0 .../BulletDinoDemo/BulletDino.c | 0 .../BulletDinoDemo/CMakeLists.txt | 0 .../BulletXmlImportDemo.cpp | 58 +- .../BulletXmlImportDemo/BulletXmlImportDemo.h | 0 .../BulletXmlImportDemo/CMakeLists.txt | 0 .../Win32BulletXmlImportDemo.cpp | 0 .../BulletXmlImportDemo/bullet_basic.xml | 0 .../BulletXmlImportDemo/bulletser.xml | 0 .../BulletXmlImportDemo/main.cpp | 0 {ObsoleteDemos => Demos}/CMakeLists.txt | 6 +- .../CcdPhysicsDemo/CMakeLists.txt | 0 .../CcdPhysicsDemo/CcdPhysicsDemo.cpp | 0 .../CcdPhysicsDemo/CcdPhysicsDemo.h | 0 .../CcdPhysicsDemo/Makefile.am | 0 .../CcdPhysicsDemo/main.cpp | 0 .../CellSpuDemo/BasicDemo2.cpp | 0 .../CellSpuDemo/BasicDemo2.h | 0 .../CharacterDemo/CMakeLists.txt | 2 +- .../CharacterDemo/CharacterDemo.cpp | 55 +- .../CharacterDemo/CharacterDemo.h | 0 .../DynamicCharacterController.cpp | 0 .../DynamicCharacterController.h | 0 .../CharacterDemo/main.cpp | 0 .../CollisionDemo/CMakeLists.txt | 0 .../CollisionDemo/CollisionDemo.cpp | 0 .../CollisionDemo/CollisionDemo.h | 0 .../CollisionInterfaceDemo/CMakeLists.txt | 0 .../CollisionInterfaceDemo.cpp | 0 .../CollisionInterfaceDemo.h | 0 .../Win32CollisionInterfaceDemo.cpp | 0 .../CollisionInterfaceDemo/main.cpp | 0 .../ConcaveConvexcastDemo/CMakeLists.txt | 0 .../ConcaveConvexcastDemo.cpp | 0 .../ConcaveConvexcastDemo.h | 0 .../ConcaveConvexcastDemo/main.cpp | 0 .../ConcaveDemo/CMakeLists.txt | 0 .../ConcaveDemo/ConcaveDemo.h | 0 .../ConcaveDemo/ConcavePhysicsDemo.cpp | 0 {ObsoleteDemos => Demos}/ConcaveDemo/Jamfile | 0 .../ConcaveDemo/Win32ConcaveDemo.cpp | 0 {ObsoleteDemos => Demos}/ConcaveDemo/main.cpp | 0 .../ConcaveRaycastDemo/CMakeLists.txt | 0 .../ConcaveRaycastDemo/ConcaveRaycastDemo.cpp | 0 .../ConcaveRaycastDemo/ConcaveRaycastDemo.h | 0 .../ConcaveRaycastDemo/main.cpp | 0 .../ConstraintDemo/CMakeLists.txt | 0 .../ConstraintDemo/ConstraintDemo.cpp | 0 .../ConstraintDemo/ConstraintDemo.h | 0 .../ConstraintDemo/Win32ConstraintDemo.cpp | 0 .../ConstraintDemo/main.cpp | 0 .../ContinuousConvexCollision/CMakeLists.txt | 0 .../ContinuousConvexCollision.h | 0 .../ContinuousConvexCollisionDemo.cpp | 0 .../ConvexDecompositionDemo/CMakeLists.txt | 3 +- .../ConvexDecompositionDemo.cpp | 123 +- .../ConvexDecompositionDemo.h | 0 .../Win32ConvexDecompositionDemo.cpp | 0 Demos/ConvexDecompositionDemo/file.obj | 3578 +++++++++++++++++ .../ConvexDecompositionDemo/main.cpp | 0 .../testFile32Single.bullet | Bin .../ConvexHullDistance/CMakeLists.txt | 0 .../ConvexHullDistanceDemo.cpp | 0 .../DoublePrecisionDemo/CMakeLists.txt | 0 .../DoublePrecisionDemo.cpp | 0 .../DoublePrecisionDemo/DoublePrecisionDemo.h | 0 .../DynamicControlDemo/CMakeLists.txt | 0 .../DynamicControlDemo/MotorDemo.cpp | 0 .../DynamicControlDemo/MotorDemo.h | 0 .../DynamicControlDemo/main.cpp | 0 .../EPAPenDepthDemo/PenetrationTestBullet.cpp | 0 .../FeatherstoneMultiBodyDemo/CMakeLists.txt | 0 .../FeatherstoneMultiBodyDemo.cpp | 0 .../FeatherstoneMultiBodyDemo.h | 0 .../FeatherstoneMultiBodyDemo/Makefile.am | 0 .../Win32FeatherstoneMultiBodyDemo.cpp | 0 .../FeatherstoneMultiBodyDemo/main.cpp | 0 .../ForkLiftDemo/CMakeLists.txt | 0 .../ForkLiftDemo/ForkLiftDemo.cpp | 0 .../ForkLiftDemo/ForkLiftDemo.h | 0 .../ForkLiftDemo/Makefile.am | 0 .../ForkLiftDemo/main.cpp | 0 .../FractureDemo/CMakeLists.txt | 0 .../FractureDemo/FractureDemo.cpp | 0 .../FractureDemo/FractureDemo.h | 0 .../FractureDemo/Win32FractureDemo.cpp | 0 .../FractureDemo/btFractureBody.cpp | 0 .../FractureDemo/btFractureBody.h | 0 .../FractureDemo/btFractureDynamicsWorld.cpp | 0 .../FractureDemo/btFractureDynamicsWorld.h | 0 .../FractureDemo/main.cpp | 0 .../GenericJointDemo/CMakeLists.txt | 0 .../GenericJointDemo/GenericJointDemo.cpp | 0 .../GenericJointDemo/GenericJointDemo.h | 0 .../GenericJointDemo/Ragdoll.cpp | 0 .../GenericJointDemo/Ragdoll.h | 0 .../Win32GenericJointDemo.cpp | 0 .../GenericJointDemo/main.cpp | 0 .../GimpactTestDemo/BunnyMesh.h | 0 .../GimpactTestDemo/CMakeLists.txt | 0 .../GimpactTestDemo/GimpactTestDemo.cpp | 0 .../GimpactTestDemo/GimpactTestDemo.h | 0 .../GimpactTestDemo/TorusMesh.h | 0 .../GimpactTestDemo/Win32GimpactDemo.cpp | 0 .../GimpactTestDemo/main.cpp | 0 .../GjkConvexCastDemo/CMakeLists.txt | 0 .../LinearConvexCastDemo.cpp | 0 .../GjkConvexCastDemo/LinearConvexCastDemo.h | 0 .../GjkConvexCastDemo/main.cpp | 0 {ObsoleteDemos => Demos}/Glut/GL/freeglut.h | 0 .../Glut/GL/freeglut_ext.h | 0 .../Glut/GL/freeglut_std.h | 0 {ObsoleteDemos => Demos}/Glut/GL/glew.h | 0 {ObsoleteDemos => Demos}/Glut/GL/glext.h | 0 {ObsoleteDemos => Demos}/Glut/GL/glut.h | 0 {ObsoleteDemos => Demos}/Glut/GL/glxew.h | 0 {ObsoleteDemos => Demos}/Glut/GL/glxext.h | 0 {ObsoleteDemos => Demos}/Glut/GL/wglew.h | 0 {ObsoleteDemos => Demos}/Glut/GL/wglext.h | 0 {ObsoleteDemos => Demos}/Glut/btGlutInclude.h | 0 {ObsoleteDemos => Demos}/Glut/glew32s.lib | Bin {ObsoleteDemos => Demos}/Glut/glew64s.lib | Bin {ObsoleteDemos => Demos}/Glut/glut32.lib | Bin {ObsoleteDemos => Demos}/Glut/glut64.lib | Bin .../GyroscopicDemo/CMakeLists.txt | 0 .../GyroscopicDemo/GyroscopicDemo.cpp | 0 .../GyroscopicDemo/GyroscopicDemo.h | 0 .../GyroscopicDemo/Win32GyroscopicDemo.cpp | 0 .../GyroscopicDemo/main.cpp | 0 .../HelloWorld/CMakeLists.txt | 0 .../HelloWorld/HelloWorld.cpp | 0 .../HelloWorld/premake4.lua | 0 .../InternalEdgeDemo/CMakeLists.txt | 0 .../InternalEdgeDemo/InternalEdgeDemo.cpp | 0 .../InternalEdgeDemo/InternalEdgeDemo.h | 0 .../InternalEdgeDemo/Taru.mdl | 0 .../Win32InternalEdgeDemo.cpp | 0 .../InternalEdgeDemo/main.cpp | 0 .../MovingConcaveDemo/CMakeLists.txt | 0 .../MovingConcaveDemo/ConcaveDemo.h | 0 .../MovingConcaveDemo/ConcavePhysicsDemo.cpp | 0 .../MultiMaterialDemo/CMakeLists.txt | 0 .../MultiMaterialDemo/MultiMaterialDemo.cpp | 0 .../MultiMaterialDemo/MultiMaterialDemo.h | 0 .../MultiMaterialDemo/main.cpp | 0 .../MultiThreadedDemo/CMakeLists.txt | 0 .../MultiThreadedDemo/Makefile.am | 0 .../MultiThreadedDemo/MultiThreadedDemo.cpp | 0 .../MultiThreadedDemo/MultiThreadedDemo.h | 0 .../MultiThreadedDemo/main.cpp | 0 .../NativeClient/bin_html/bind.js | 0 .../NativeClient/bin_html/dragger.js | 0 .../NativeClient/bin_html/httpd.cmd | 0 .../NativeClient/bin_html/httpd.py | 0 .../NativeClient/bin_html/index.html | 0 .../NativeClient/bin_html/trackball.js | 0 .../NativeClient/bin_html/tumbler.js | 0 .../NativeClient/bin_html/tumbler.nmf | 0 .../NativeClient/bin_html/vector3.js | 0 .../NativeClient/callback.h | 0 {ObsoleteDemos => Demos}/NativeClient/cube.cc | 0 {ObsoleteDemos => Demos}/NativeClient/cube.h | 0 .../NativeClient/opengl_context.cc | 0 .../NativeClient/opengl_context.h | 0 .../NativeClient/opengl_context_ptrs.h | 0 .../NativeClient/premake4.lua | 0 .../NativeClient/scripting_bridge.cc | 0 .../NativeClient/scripting_bridge.h | 0 .../NativeClient/shader_util.cc | 0 .../NativeClient/shader_util.h | 0 .../NativeClient/transforms.cc | 0 .../NativeClient/transforms.h | 0 .../NativeClient/tumbler.cc | 0 .../NativeClient/tumbler.h | 0 .../NativeClient/tumbler_module.cc | 0 .../OpenGL/CMakeLists.txt | 0 .../OpenGL/CommandLineArguments.h | 0 .../OpenGL/DebugCastResult.h | 0 .../OpenGL/DemoApplication.cpp | 148 +- .../OpenGL/DemoApplication.h | 36 +- .../OpenGL/GLDebugDrawer.cpp | 0 .../OpenGL/GLDebugDrawer.h | 0 .../OpenGL/GLDebugFont.cpp | 0 {ObsoleteDemos => Demos}/OpenGL/GLDebugFont.h | 0 .../OpenGL/GL_DialogDynamicsWorld.cpp | 0 .../OpenGL/GL_DialogDynamicsWorld.h | 0 .../OpenGL/GL_DialogWindow.cpp | 0 .../OpenGL/GL_DialogWindow.h | 0 .../OpenGL/GL_ShapeDrawer.cpp | 0 .../OpenGL/GL_ShapeDrawer.h | 0 .../OpenGL/GL_Simplex1to4.cpp | 0 .../OpenGL/GL_Simplex1to4.h | 0 .../OpenGL/GlutDemoApplication.cpp | 0 .../OpenGL/GlutDemoApplication.h | 0 {ObsoleteDemos => Demos}/OpenGL/GlutStuff.cpp | 0 {ObsoleteDemos => Demos}/OpenGL/GlutStuff.h | 0 {ObsoleteDemos => Demos}/OpenGL/Makefile.am | 0 .../OpenGL/RenderTexture.cpp | 0 .../OpenGL/RenderTexture.h | 0 .../OpenGL/Win32AppMain.cpp | 0 .../OpenGL/Win32DemoApplication.cpp | 0 .../OpenGL/Win32DemoApplication.h | 0 {ObsoleteDemos => Demos}/OpenGL/premake4.lua | 0 {ObsoleteDemos => Demos}/OpenGL/stb_image.cpp | 0 {ObsoleteDemos => Demos}/OpenGL/stb_image.h | 0 {ObsoleteDemos => Demos}/OpenPL_Demo/CApi.cpp | 0 .../OpenPL_Demo/OpenPL_Demo.c | 0 .../RagdollDemo/CMakeLists.txt | 0 .../RagdollDemo/RagdollDemo.cpp | 0 .../RagdollDemo/RagdollDemo.h | 0 {ObsoleteDemos => Demos}/RagdollDemo/main.cpp | 0 .../RaytestDemo/CMakeLists.txt | 0 .../RaytestDemo/Makefile.am | 0 .../RaytestDemo/RaytestDemo.cpp | 0 .../RaytestDemo/RaytestDemo.h | 0 .../RaytestDemo/Win32RaytestDemo.cpp | 0 {ObsoleteDemos => Demos}/RaytestDemo/main.cpp | 0 .../Raytracer/CMakeLists.txt | 0 .../Raytracer/Raytracer.cpp | 0 .../Raytracer/Raytracer.h | 0 {ObsoleteDemos => Demos}/Raytracer/main.cpp | 0 .../RollingFrictionDemo/CMakeLists.txt | 0 .../RollingFrictionDemo/Makefile.am | 0 .../RollingFrictionDemo.cpp | 0 .../RollingFrictionDemo/RollingFrictionDemo.h | 0 .../Win32RollingFrictionDemo.cpp | 0 .../RollingFrictionDemo/main.cpp | 0 .../SerializeDemo/AMD/CMakeLists.txt | 0 .../SerializeDemo/AMD/premake4.lua | 0 .../SerializeDemo/CMakeLists.txt | 0 .../SerializeDemo/SerializeDemo.cpp | 125 +- .../SerializeDemo/SerializeDemo.h | 0 .../SerializeDemo/Win32SerializeDemo.cpp | 0 .../SerializeDemo/main.cpp | 0 .../SerializeDemo/testFile.bullet | Bin .../SerializeDemo/testFileCloth.bullet | Bin .../SimplexDemo/CMakeLists.txt | 0 .../SimplexDemo/SimplexDemo.cpp | 0 .../SimplexDemo/SimplexDemo.h | 0 .../SliderConstraintDemo/CMakeLists.txt | 0 .../SliderConstraintDemo.cpp | 0 .../SliderConstraintDemo.h | 0 .../SliderConstraintDemo/main.cpp | 0 .../SoftDemo/AMD/premake4.lua | 0 .../SoftDemo/CMakeLists.txt | 0 {ObsoleteDemos => Demos}/SoftDemo/Makefile.am | 0 .../SoftDemo/SoftDemo.cpp | 0 {ObsoleteDemos => Demos}/SoftDemo/SoftDemo.h | 0 {ObsoleteDemos => Demos}/SoftDemo/bunny.inl | 0 {ObsoleteDemos => Demos}/SoftDemo/cube.inl | 0 {ObsoleteDemos => Demos}/SoftDemo/main.cpp | 0 .../TerrainDemo/Makefile.am | 0 .../TerrainDemo/TerrainDemo.cpp | 0 .../TerrainDemo/TerrainDemo.h | 0 {ObsoleteDemos => Demos}/TerrainDemo/main.cpp | 0 .../ThreadingDemo/CMakeLists.txt | 0 .../ThreadingDemo/main.cpp | 0 .../UserCollisionAlgorithm/CMakeLists.txt | 0 .../UserCollisionAlgorithm.cpp | 0 .../UserCollisionAlgorithm.h | 0 .../VehicleDemo/CMakeLists.txt | 0 .../VehicleDemo/Makefile.am | 0 .../VehicleDemo/VehicleDemo.cpp | 0 .../VehicleDemo/VehicleDemo.h | 0 .../VehicleDemo/heightfield128x128.cpp | 0 {ObsoleteDemos => Demos}/VehicleDemo/main.cpp | 0 .../VoronoiFractureDemo/CMakeLists.txt | 0 .../VoronoiFractureDemo/Makefile.am | 0 .../VoronoiFractureDemo.cpp | 0 .../VoronoiFractureDemo/VoronoiFractureDemo.h | 0 .../Win32VoronoiFractureDemo.cpp | 0 .../VoronoiFractureDemo/main.cpp | 0 {ObsoleteDemos => Demos}/premake4.lua | 0 Demos3/CMakeLists.txt | 5 +- Demos3/ImplicitCloth/stan/Cloth.cpp | 6 +- Extras/CMakeLists.txt | 6 +- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 6 +- data/testFile.bullet | Bin 73336 -> 0 bytes data/testFileFracture.bullet | Bin 183864 -> 12292 bytes 312 files changed, 3933 insertions(+), 322 deletions(-) rename {ObsoleteDemos => Demos}/AllBulletDemos/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/AllBulletDemos/DemoEntries.cpp (100%) rename {ObsoleteDemos => Demos}/AllBulletDemos/DemoEntries.h (100%) rename {ObsoleteDemos => Demos}/AllBulletDemos/Main.cpp (100%) rename {ObsoleteDemos => Demos}/AllBulletDemos/Makefile.am (100%) rename {ObsoleteDemos => Demos}/BasicDemo/BasicDemo.cpp (100%) rename {ObsoleteDemos => Demos}/BasicDemo/BasicDemo.h (100%) rename {ObsoleteDemos => Demos}/BasicDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/BasicDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/BasicDemo/Win32BasicDemo.cpp (100%) rename {ObsoleteDemos => Demos}/BasicDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/Benchmarks/BenchmarkDemo.cpp (100%) rename {ObsoleteDemos => Demos}/Benchmarks/BenchmarkDemo.h (100%) rename {ObsoleteDemos => Demos}/Benchmarks/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/Benchmarks/Taru.mdl (100%) rename {ObsoleteDemos => Demos}/Benchmarks/Win32BenchmarkDemo.cpp (100%) rename {ObsoleteDemos => Demos}/Benchmarks/landscape.mdl (100%) rename {ObsoleteDemos => Demos}/Benchmarks/main.cpp (100%) rename {ObsoleteDemos => Demos}/Benchmarks/premake4.lua (100%) rename {ObsoleteDemos => Demos}/Box2dDemo/Box2dDemo.cpp (100%) rename {ObsoleteDemos => Demos}/Box2dDemo/Box2dDemo.h (100%) rename {ObsoleteDemos => Demos}/Box2dDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/Box2dDemo/Win32Box2dDemo.cpp (100%) rename {ObsoleteDemos => Demos}/Box2dDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/BspDemo/BspConverter.cpp (100%) rename {ObsoleteDemos => Demos}/BspDemo/BspConverter.h (100%) rename {ObsoleteDemos => Demos}/BspDemo/BspDemo.bsp (100%) rename {ObsoleteDemos => Demos}/BspDemo/BspDemo.cpp (88%) rename {ObsoleteDemos => Demos}/BspDemo/BspDemo.h (100%) rename {ObsoleteDemos => Demos}/BspDemo/BspLoader.cpp (100%) rename {ObsoleteDemos => Demos}/BspDemo/BspLoader.h (100%) rename {ObsoleteDemos => Demos}/BspDemo/CMakeLists.txt (91%) rename {ObsoleteDemos => Demos}/BspDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/BulletDinoDemo/BulletDino.c (100%) rename {ObsoleteDemos => Demos}/BulletDinoDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/BulletXmlImportDemo/BulletXmlImportDemo.cpp (83%) rename {ObsoleteDemos => Demos}/BulletXmlImportDemo/BulletXmlImportDemo.h (100%) rename {ObsoleteDemos => Demos}/BulletXmlImportDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/BulletXmlImportDemo/Win32BulletXmlImportDemo.cpp (100%) rename {ObsoleteDemos => Demos}/BulletXmlImportDemo/bullet_basic.xml (100%) rename {ObsoleteDemos => Demos}/BulletXmlImportDemo/bulletser.xml (100%) rename {ObsoleteDemos => Demos}/BulletXmlImportDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/CMakeLists.txt (91%) rename {ObsoleteDemos => Demos}/CcdPhysicsDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/CcdPhysicsDemo/CcdPhysicsDemo.cpp (100%) rename {ObsoleteDemos => Demos}/CcdPhysicsDemo/CcdPhysicsDemo.h (100%) rename {ObsoleteDemos => Demos}/CcdPhysicsDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/CcdPhysicsDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/CellSpuDemo/BasicDemo2.cpp (100%) rename {ObsoleteDemos => Demos}/CellSpuDemo/BasicDemo2.h (100%) rename {ObsoleteDemos => Demos}/CharacterDemo/CMakeLists.txt (95%) rename {ObsoleteDemos => Demos}/CharacterDemo/CharacterDemo.cpp (94%) rename {ObsoleteDemos => Demos}/CharacterDemo/CharacterDemo.h (100%) rename {ObsoleteDemos => Demos}/CharacterDemo/DynamicCharacterController.cpp (100%) rename {ObsoleteDemos => Demos}/CharacterDemo/DynamicCharacterController.h (100%) rename {ObsoleteDemos => Demos}/CharacterDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/CollisionDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/CollisionDemo/CollisionDemo.cpp (100%) rename {ObsoleteDemos => Demos}/CollisionDemo/CollisionDemo.h (100%) rename {ObsoleteDemos => Demos}/CollisionInterfaceDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/CollisionInterfaceDemo/CollisionInterfaceDemo.cpp (100%) rename {ObsoleteDemos => Demos}/CollisionInterfaceDemo/CollisionInterfaceDemo.h (100%) rename {ObsoleteDemos => Demos}/CollisionInterfaceDemo/Win32CollisionInterfaceDemo.cpp (100%) rename {ObsoleteDemos => Demos}/CollisionInterfaceDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/ConcaveConvexcastDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/ConcaveConvexcastDemo/ConcaveConvexcastDemo.cpp (100%) rename {ObsoleteDemos => Demos}/ConcaveConvexcastDemo/ConcaveConvexcastDemo.h (100%) rename {ObsoleteDemos => Demos}/ConcaveConvexcastDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/ConcaveDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/ConcaveDemo/ConcaveDemo.h (100%) rename {ObsoleteDemos => Demos}/ConcaveDemo/ConcavePhysicsDemo.cpp (100%) rename {ObsoleteDemos => Demos}/ConcaveDemo/Jamfile (100%) rename {ObsoleteDemos => Demos}/ConcaveDemo/Win32ConcaveDemo.cpp (100%) rename {ObsoleteDemos => Demos}/ConcaveDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/ConcaveRaycastDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/ConcaveRaycastDemo/ConcaveRaycastDemo.cpp (100%) rename {ObsoleteDemos => Demos}/ConcaveRaycastDemo/ConcaveRaycastDemo.h (100%) rename {ObsoleteDemos => Demos}/ConcaveRaycastDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/ConstraintDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/ConstraintDemo/ConstraintDemo.cpp (100%) rename {ObsoleteDemos => Demos}/ConstraintDemo/ConstraintDemo.h (100%) rename {ObsoleteDemos => Demos}/ConstraintDemo/Win32ConstraintDemo.cpp (100%) rename {ObsoleteDemos => Demos}/ConstraintDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/ContinuousConvexCollision/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/ContinuousConvexCollision/ContinuousConvexCollision.h (100%) rename {ObsoleteDemos => Demos}/ContinuousConvexCollision/ContinuousConvexCollisionDemo.cpp (100%) rename {ObsoleteDemos => Demos}/ConvexDecompositionDemo/CMakeLists.txt (96%) rename {ObsoleteDemos => Demos}/ConvexDecompositionDemo/ConvexDecompositionDemo.cpp (95%) rename {ObsoleteDemos => Demos}/ConvexDecompositionDemo/ConvexDecompositionDemo.h (100%) rename {ObsoleteDemos => Demos}/ConvexDecompositionDemo/Win32ConvexDecompositionDemo.cpp (100%) create mode 100644 Demos/ConvexDecompositionDemo/file.obj rename {ObsoleteDemos => Demos}/ConvexDecompositionDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/ConvexDecompositionDemo/testFile32Single.bullet (100%) rename {ObsoleteDemos => Demos}/ConvexHullDistance/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/ConvexHullDistance/ConvexHullDistanceDemo.cpp (100%) rename {ObsoleteDemos => Demos}/DoublePrecisionDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/DoublePrecisionDemo/DoublePrecisionDemo.cpp (100%) rename {ObsoleteDemos => Demos}/DoublePrecisionDemo/DoublePrecisionDemo.h (100%) rename {ObsoleteDemos => Demos}/DynamicControlDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/DynamicControlDemo/MotorDemo.cpp (100%) rename {ObsoleteDemos => Demos}/DynamicControlDemo/MotorDemo.h (100%) rename {ObsoleteDemos => Demos}/DynamicControlDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/EPAPenDepthDemo/PenetrationTestBullet.cpp (100%) rename {ObsoleteDemos => Demos}/FeatherstoneMultiBodyDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp (100%) rename {ObsoleteDemos => Demos}/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.h (100%) rename {ObsoleteDemos => Demos}/FeatherstoneMultiBodyDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/FeatherstoneMultiBodyDemo/Win32FeatherstoneMultiBodyDemo.cpp (100%) rename {ObsoleteDemos => Demos}/FeatherstoneMultiBodyDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/ForkLiftDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/ForkLiftDemo/ForkLiftDemo.cpp (100%) rename {ObsoleteDemos => Demos}/ForkLiftDemo/ForkLiftDemo.h (100%) rename {ObsoleteDemos => Demos}/ForkLiftDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/ForkLiftDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/FractureDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/FractureDemo/FractureDemo.cpp (100%) rename {ObsoleteDemos => Demos}/FractureDemo/FractureDemo.h (100%) rename {ObsoleteDemos => Demos}/FractureDemo/Win32FractureDemo.cpp (100%) rename {ObsoleteDemos => Demos}/FractureDemo/btFractureBody.cpp (100%) rename {ObsoleteDemos => Demos}/FractureDemo/btFractureBody.h (100%) rename {ObsoleteDemos => Demos}/FractureDemo/btFractureDynamicsWorld.cpp (100%) rename {ObsoleteDemos => Demos}/FractureDemo/btFractureDynamicsWorld.h (100%) rename {ObsoleteDemos => Demos}/FractureDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/GenericJointDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/GenericJointDemo/GenericJointDemo.cpp (100%) rename {ObsoleteDemos => Demos}/GenericJointDemo/GenericJointDemo.h (100%) rename {ObsoleteDemos => Demos}/GenericJointDemo/Ragdoll.cpp (100%) rename {ObsoleteDemos => Demos}/GenericJointDemo/Ragdoll.h (100%) rename {ObsoleteDemos => Demos}/GenericJointDemo/Win32GenericJointDemo.cpp (100%) rename {ObsoleteDemos => Demos}/GenericJointDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/GimpactTestDemo/BunnyMesh.h (100%) rename {ObsoleteDemos => Demos}/GimpactTestDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/GimpactTestDemo/GimpactTestDemo.cpp (100%) rename {ObsoleteDemos => Demos}/GimpactTestDemo/GimpactTestDemo.h (100%) rename {ObsoleteDemos => Demos}/GimpactTestDemo/TorusMesh.h (100%) rename {ObsoleteDemos => Demos}/GimpactTestDemo/Win32GimpactDemo.cpp (100%) rename {ObsoleteDemos => Demos}/GimpactTestDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/GjkConvexCastDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/GjkConvexCastDemo/LinearConvexCastDemo.cpp (100%) rename {ObsoleteDemos => Demos}/GjkConvexCastDemo/LinearConvexCastDemo.h (100%) rename {ObsoleteDemos => Demos}/GjkConvexCastDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/Glut/GL/freeglut.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/freeglut_ext.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/freeglut_std.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/glew.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/glext.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/glut.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/glxew.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/glxext.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/wglew.h (100%) rename {ObsoleteDemos => Demos}/Glut/GL/wglext.h (100%) rename {ObsoleteDemos => Demos}/Glut/btGlutInclude.h (100%) rename {ObsoleteDemos => Demos}/Glut/glew32s.lib (100%) rename {ObsoleteDemos => Demos}/Glut/glew64s.lib (100%) rename {ObsoleteDemos => Demos}/Glut/glut32.lib (100%) rename {ObsoleteDemos => Demos}/Glut/glut64.lib (100%) rename {ObsoleteDemos => Demos}/GyroscopicDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/GyroscopicDemo/GyroscopicDemo.cpp (100%) rename {ObsoleteDemos => Demos}/GyroscopicDemo/GyroscopicDemo.h (100%) rename {ObsoleteDemos => Demos}/GyroscopicDemo/Win32GyroscopicDemo.cpp (100%) rename {ObsoleteDemos => Demos}/GyroscopicDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/HelloWorld/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/HelloWorld/HelloWorld.cpp (100%) rename {ObsoleteDemos => Demos}/HelloWorld/premake4.lua (100%) rename {ObsoleteDemos => Demos}/InternalEdgeDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/InternalEdgeDemo/InternalEdgeDemo.cpp (100%) rename {ObsoleteDemos => Demos}/InternalEdgeDemo/InternalEdgeDemo.h (100%) rename {ObsoleteDemos => Demos}/InternalEdgeDemo/Taru.mdl (100%) rename {ObsoleteDemos => Demos}/InternalEdgeDemo/Win32InternalEdgeDemo.cpp (100%) rename {ObsoleteDemos => Demos}/InternalEdgeDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/MovingConcaveDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/MovingConcaveDemo/ConcaveDemo.h (100%) rename {ObsoleteDemos => Demos}/MovingConcaveDemo/ConcavePhysicsDemo.cpp (100%) rename {ObsoleteDemos => Demos}/MultiMaterialDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/MultiMaterialDemo/MultiMaterialDemo.cpp (100%) rename {ObsoleteDemos => Demos}/MultiMaterialDemo/MultiMaterialDemo.h (100%) rename {ObsoleteDemos => Demos}/MultiMaterialDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/MultiThreadedDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/MultiThreadedDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/MultiThreadedDemo/MultiThreadedDemo.cpp (100%) rename {ObsoleteDemos => Demos}/MultiThreadedDemo/MultiThreadedDemo.h (100%) rename {ObsoleteDemos => Demos}/MultiThreadedDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/bind.js (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/dragger.js (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/httpd.cmd (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/httpd.py (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/index.html (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/trackball.js (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/tumbler.js (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/tumbler.nmf (100%) rename {ObsoleteDemos => Demos}/NativeClient/bin_html/vector3.js (100%) rename {ObsoleteDemos => Demos}/NativeClient/callback.h (100%) rename {ObsoleteDemos => Demos}/NativeClient/cube.cc (100%) rename {ObsoleteDemos => Demos}/NativeClient/cube.h (100%) rename {ObsoleteDemos => Demos}/NativeClient/opengl_context.cc (100%) rename {ObsoleteDemos => Demos}/NativeClient/opengl_context.h (100%) rename {ObsoleteDemos => Demos}/NativeClient/opengl_context_ptrs.h (100%) rename {ObsoleteDemos => Demos}/NativeClient/premake4.lua (100%) rename {ObsoleteDemos => Demos}/NativeClient/scripting_bridge.cc (100%) rename {ObsoleteDemos => Demos}/NativeClient/scripting_bridge.h (100%) rename {ObsoleteDemos => Demos}/NativeClient/shader_util.cc (100%) rename {ObsoleteDemos => Demos}/NativeClient/shader_util.h (100%) rename {ObsoleteDemos => Demos}/NativeClient/transforms.cc (100%) rename {ObsoleteDemos => Demos}/NativeClient/transforms.h (100%) rename {ObsoleteDemos => Demos}/NativeClient/tumbler.cc (100%) rename {ObsoleteDemos => Demos}/NativeClient/tumbler.h (100%) rename {ObsoleteDemos => Demos}/NativeClient/tumbler_module.cc (100%) rename {ObsoleteDemos => Demos}/OpenGL/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/OpenGL/CommandLineArguments.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/DebugCastResult.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/DemoApplication.cpp (97%) rename {ObsoleteDemos => Demos}/OpenGL/DemoApplication.h (97%) rename {ObsoleteDemos => Demos}/OpenGL/GLDebugDrawer.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/GLDebugDrawer.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/GLDebugFont.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/GLDebugFont.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/GL_DialogDynamicsWorld.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/GL_DialogDynamicsWorld.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/GL_DialogWindow.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/GL_DialogWindow.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/GL_ShapeDrawer.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/GL_ShapeDrawer.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/GL_Simplex1to4.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/GL_Simplex1to4.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/GlutDemoApplication.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/GlutDemoApplication.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/GlutStuff.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/GlutStuff.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/Makefile.am (100%) rename {ObsoleteDemos => Demos}/OpenGL/RenderTexture.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/RenderTexture.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/Win32AppMain.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/Win32DemoApplication.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/Win32DemoApplication.h (100%) rename {ObsoleteDemos => Demos}/OpenGL/premake4.lua (100%) rename {ObsoleteDemos => Demos}/OpenGL/stb_image.cpp (100%) rename {ObsoleteDemos => Demos}/OpenGL/stb_image.h (100%) rename {ObsoleteDemos => Demos}/OpenPL_Demo/CApi.cpp (100%) rename {ObsoleteDemos => Demos}/OpenPL_Demo/OpenPL_Demo.c (100%) rename {ObsoleteDemos => Demos}/RagdollDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/RagdollDemo/RagdollDemo.cpp (100%) rename {ObsoleteDemos => Demos}/RagdollDemo/RagdollDemo.h (100%) rename {ObsoleteDemos => Demos}/RagdollDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/RaytestDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/RaytestDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/RaytestDemo/RaytestDemo.cpp (100%) rename {ObsoleteDemos => Demos}/RaytestDemo/RaytestDemo.h (100%) rename {ObsoleteDemos => Demos}/RaytestDemo/Win32RaytestDemo.cpp (100%) rename {ObsoleteDemos => Demos}/RaytestDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/Raytracer/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/Raytracer/Raytracer.cpp (100%) rename {ObsoleteDemos => Demos}/Raytracer/Raytracer.h (100%) rename {ObsoleteDemos => Demos}/Raytracer/main.cpp (100%) rename {ObsoleteDemos => Demos}/RollingFrictionDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/RollingFrictionDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/RollingFrictionDemo/RollingFrictionDemo.cpp (100%) rename {ObsoleteDemos => Demos}/RollingFrictionDemo/RollingFrictionDemo.h (100%) rename {ObsoleteDemos => Demos}/RollingFrictionDemo/Win32RollingFrictionDemo.cpp (100%) rename {ObsoleteDemos => Demos}/RollingFrictionDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/SerializeDemo/AMD/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/SerializeDemo/AMD/premake4.lua (100%) rename {ObsoleteDemos => Demos}/SerializeDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/SerializeDemo/SerializeDemo.cpp (96%) rename {ObsoleteDemos => Demos}/SerializeDemo/SerializeDemo.h (100%) rename {ObsoleteDemos => Demos}/SerializeDemo/Win32SerializeDemo.cpp (100%) rename {ObsoleteDemos => Demos}/SerializeDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/SerializeDemo/testFile.bullet (100%) rename {ObsoleteDemos => Demos}/SerializeDemo/testFileCloth.bullet (100%) rename {ObsoleteDemos => Demos}/SimplexDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/SimplexDemo/SimplexDemo.cpp (100%) rename {ObsoleteDemos => Demos}/SimplexDemo/SimplexDemo.h (100%) rename {ObsoleteDemos => Demos}/SliderConstraintDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/SliderConstraintDemo/SliderConstraintDemo.cpp (100%) rename {ObsoleteDemos => Demos}/SliderConstraintDemo/SliderConstraintDemo.h (100%) rename {ObsoleteDemos => Demos}/SliderConstraintDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/SoftDemo/AMD/premake4.lua (100%) rename {ObsoleteDemos => Demos}/SoftDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/SoftDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/SoftDemo/SoftDemo.cpp (100%) rename {ObsoleteDemos => Demos}/SoftDemo/SoftDemo.h (100%) rename {ObsoleteDemos => Demos}/SoftDemo/bunny.inl (100%) rename {ObsoleteDemos => Demos}/SoftDemo/cube.inl (100%) rename {ObsoleteDemos => Demos}/SoftDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/TerrainDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/TerrainDemo/TerrainDemo.cpp (100%) rename {ObsoleteDemos => Demos}/TerrainDemo/TerrainDemo.h (100%) rename {ObsoleteDemos => Demos}/TerrainDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/ThreadingDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/ThreadingDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/UserCollisionAlgorithm/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/UserCollisionAlgorithm/UserCollisionAlgorithm.cpp (100%) rename {ObsoleteDemos => Demos}/UserCollisionAlgorithm/UserCollisionAlgorithm.h (100%) rename {ObsoleteDemos => Demos}/VehicleDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/VehicleDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/VehicleDemo/VehicleDemo.cpp (100%) rename {ObsoleteDemos => Demos}/VehicleDemo/VehicleDemo.h (100%) rename {ObsoleteDemos => Demos}/VehicleDemo/heightfield128x128.cpp (100%) rename {ObsoleteDemos => Demos}/VehicleDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/VoronoiFractureDemo/CMakeLists.txt (100%) rename {ObsoleteDemos => Demos}/VoronoiFractureDemo/Makefile.am (100%) rename {ObsoleteDemos => Demos}/VoronoiFractureDemo/VoronoiFractureDemo.cpp (100%) rename {ObsoleteDemos => Demos}/VoronoiFractureDemo/VoronoiFractureDemo.h (100%) rename {ObsoleteDemos => Demos}/VoronoiFractureDemo/Win32VoronoiFractureDemo.cpp (100%) rename {ObsoleteDemos => Demos}/VoronoiFractureDemo/main.cpp (100%) rename {ObsoleteDemos => Demos}/premake4.lua (100%) delete mode 100644 data/testFile.bullet diff --git a/CMakeLists.txt b/CMakeLists.txt index 094695ca6..ca08f5a19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,10 +44,10 @@ IF(MSVC) SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/INCREMENTAL:NO ${replacementFlags}" ) MESSAGE("CMAKE_EXE_LINKER_FLAGS_DEBUG=${CMAKE_EXE_LINKER_FLAGS_DEBUG}") -# STRING(REPLACE "INCREMENTAL:YES" "INCREMENTAL:NO" replacementFlags2 ${CMAKE_EXE_LINKER_FLAGS}) -# SET(CMAKE_EXE_LINKER_FLAGS ${replacementFlag2}) -# STRING(REPLACE "INCREMENTAL:YES" "" replacementFlags3 ${CMAKE_EXTRA_LINK_FLAGS}) -# SET(CMAKE_EXTRA_LINK_FLAGS ${replacementFlag3}) + STRING(REPLACE "INCREMENTAL:YES" "INCREMENTAL:NO" replacementFlags2 ${CMAKE_EXE_LINKER_FLAGS}) + SET(CMAKE_EXE_LINKER_FLAGS ${replacementFlag2}) + STRING(REPLACE "INCREMENTAL:YES" "" replacementFlags3 ${CMAKE_EXTRA_LINK_FLAGS}) + SET(CMAKE_EXTRA_LINK_FLAGS ${replacementFlag3}) STRING(REPLACE "INCREMENTAL:YES" "INCREMENTAL:NO" replacementFlags3 ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}) @@ -188,13 +188,13 @@ IF (USE_GLUT) ADD_DEFINITIONS(-DBT_USE_FREEGLUT) IF (CMAKE_CL_64) - message("Win64 using static freeglut in ObsoleteDemos/Glut/glut64.lib") - SET(GLUT_glut_LIBRARY ${BULLET_PHYSICS_SOURCE_DIR}/ObsoleteDemos/Glut/glut64.lib glu32.lib gdi32.lib winmm.lib user32.lib) + message("Win64 using static freeglut in Demos/Glut/glut64.lib") + SET(GLUT_glut_LIBRARY ${BULLET_PHYSICS_SOURCE_DIR}/Demos/Glut/glut64.lib glu32.lib gdi32.lib winmm.lib user32.lib) ELSE(CMAKE_CL_64) - message("Win32 using static freeglut in ObsoleteDemos/Glut/glut32.lib") - SET(GLUT_glut_LIBRARY ${BULLET_PHYSICS_SOURCE_DIR}/ObsoleteDemos/Glut/glut32.lib glu32.lib gdi32.lib winmm.lib user32.lib) + message("Win32 using static freeglut in Demos/Glut/glut32.lib") + SET(GLUT_glut_LIBRARY ${BULLET_PHYSICS_SOURCE_DIR}/Demos/Glut/glut32.lib glu32.lib gdi32.lib winmm.lib user32.lib) ENDIF (CMAKE_CL_64) - SET(GLUT_INCLUDE_DIR ${BULLET_PHYSICS_SOURCE_DIR}/ObsoleteDemos/Glut ) + SET(GLUT_INCLUDE_DIR ${BULLET_PHYSICS_SOURCE_DIR}/Demos/Glut ) ELSE() FIND_PACKAGE(GLUT) IF (GLUT_FOUND) @@ -219,8 +219,8 @@ IF (USE_GLUT) ENDIF(USE_GLUT) - IF(EXISTS ${BULLET_PHYSICS_SOURCE_DIR}/ObsoleteDemos AND IS_DIRECTORY ${BULLET_PHYSICS_SOURCE_DIR}/ObsoleteDemos) - SUBDIRS(ObsoleteDemos) + IF(EXISTS ${BULLET_PHYSICS_SOURCE_DIR}/Demos AND IS_DIRECTORY ${BULLET_PHYSICS_SOURCE_DIR}/Demos) + SUBDIRS(Demos) ENDIF() ENDIF(BUILD_OBSOLETE_DEMOS) @@ -232,6 +232,10 @@ IF(BUILD_BULLET3_DEMOS) ENDIF() ENDIF(BUILD_BULLET3_DEMOS) +OPTION(BUILD_EXTRAS "Set when you want to build the extras" ON) +IF(BUILD_EXTRAS) + SUBDIRS(Extras) +ENDIF(BUILD_EXTRAS) #Maya Dynamica plugin is moved to http://dynamica.googlecode.com @@ -266,9 +270,9 @@ IF(INSTALL_LIBS) ENDIF(INSTALL_LIBS) #INSTALL of other files requires CMake 2.6 -#IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) -# OPTION(INSTALL_EXTRA_LIBS "Set when you want extra libraries installed" OFF) -#ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) +IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) + OPTION(INSTALL_EXTRA_LIBS "Set when you want extra libraries installed" OFF) +ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) OPTION(BUILD_UNIT_TESTS "Build Unit Tests" ON) diff --git a/ObsoleteDemos/AllBulletDemos/CMakeLists.txt b/Demos/AllBulletDemos/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/AllBulletDemos/CMakeLists.txt rename to Demos/AllBulletDemos/CMakeLists.txt diff --git a/ObsoleteDemos/AllBulletDemos/DemoEntries.cpp b/Demos/AllBulletDemos/DemoEntries.cpp similarity index 100% rename from ObsoleteDemos/AllBulletDemos/DemoEntries.cpp rename to Demos/AllBulletDemos/DemoEntries.cpp diff --git a/ObsoleteDemos/AllBulletDemos/DemoEntries.h b/Demos/AllBulletDemos/DemoEntries.h similarity index 100% rename from ObsoleteDemos/AllBulletDemos/DemoEntries.h rename to Demos/AllBulletDemos/DemoEntries.h diff --git a/ObsoleteDemos/AllBulletDemos/Main.cpp b/Demos/AllBulletDemos/Main.cpp similarity index 100% rename from ObsoleteDemos/AllBulletDemos/Main.cpp rename to Demos/AllBulletDemos/Main.cpp diff --git a/ObsoleteDemos/AllBulletDemos/Makefile.am b/Demos/AllBulletDemos/Makefile.am similarity index 100% rename from ObsoleteDemos/AllBulletDemos/Makefile.am rename to Demos/AllBulletDemos/Makefile.am diff --git a/ObsoleteDemos/BasicDemo/BasicDemo.cpp b/Demos/BasicDemo/BasicDemo.cpp similarity index 100% rename from ObsoleteDemos/BasicDemo/BasicDemo.cpp rename to Demos/BasicDemo/BasicDemo.cpp diff --git a/ObsoleteDemos/BasicDemo/BasicDemo.h b/Demos/BasicDemo/BasicDemo.h similarity index 100% rename from ObsoleteDemos/BasicDemo/BasicDemo.h rename to Demos/BasicDemo/BasicDemo.h diff --git a/ObsoleteDemos/BasicDemo/CMakeLists.txt b/Demos/BasicDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/BasicDemo/CMakeLists.txt rename to Demos/BasicDemo/CMakeLists.txt diff --git a/ObsoleteDemos/BasicDemo/Makefile.am b/Demos/BasicDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/BasicDemo/Makefile.am rename to Demos/BasicDemo/Makefile.am diff --git a/ObsoleteDemos/BasicDemo/Win32BasicDemo.cpp b/Demos/BasicDemo/Win32BasicDemo.cpp similarity index 100% rename from ObsoleteDemos/BasicDemo/Win32BasicDemo.cpp rename to Demos/BasicDemo/Win32BasicDemo.cpp diff --git a/ObsoleteDemos/BasicDemo/main.cpp b/Demos/BasicDemo/main.cpp similarity index 100% rename from ObsoleteDemos/BasicDemo/main.cpp rename to Demos/BasicDemo/main.cpp diff --git a/ObsoleteDemos/Benchmarks/BenchmarkDemo.cpp b/Demos/Benchmarks/BenchmarkDemo.cpp similarity index 100% rename from ObsoleteDemos/Benchmarks/BenchmarkDemo.cpp rename to Demos/Benchmarks/BenchmarkDemo.cpp diff --git a/ObsoleteDemos/Benchmarks/BenchmarkDemo.h b/Demos/Benchmarks/BenchmarkDemo.h similarity index 100% rename from ObsoleteDemos/Benchmarks/BenchmarkDemo.h rename to Demos/Benchmarks/BenchmarkDemo.h diff --git a/ObsoleteDemos/Benchmarks/CMakeLists.txt b/Demos/Benchmarks/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/Benchmarks/CMakeLists.txt rename to Demos/Benchmarks/CMakeLists.txt diff --git a/ObsoleteDemos/Benchmarks/Taru.mdl b/Demos/Benchmarks/Taru.mdl similarity index 100% rename from ObsoleteDemos/Benchmarks/Taru.mdl rename to Demos/Benchmarks/Taru.mdl diff --git a/ObsoleteDemos/Benchmarks/Win32BenchmarkDemo.cpp b/Demos/Benchmarks/Win32BenchmarkDemo.cpp similarity index 100% rename from ObsoleteDemos/Benchmarks/Win32BenchmarkDemo.cpp rename to Demos/Benchmarks/Win32BenchmarkDemo.cpp diff --git a/ObsoleteDemos/Benchmarks/landscape.mdl b/Demos/Benchmarks/landscape.mdl similarity index 100% rename from ObsoleteDemos/Benchmarks/landscape.mdl rename to Demos/Benchmarks/landscape.mdl diff --git a/ObsoleteDemos/Benchmarks/main.cpp b/Demos/Benchmarks/main.cpp similarity index 100% rename from ObsoleteDemos/Benchmarks/main.cpp rename to Demos/Benchmarks/main.cpp diff --git a/ObsoleteDemos/Benchmarks/premake4.lua b/Demos/Benchmarks/premake4.lua similarity index 100% rename from ObsoleteDemos/Benchmarks/premake4.lua rename to Demos/Benchmarks/premake4.lua diff --git a/ObsoleteDemos/Box2dDemo/Box2dDemo.cpp b/Demos/Box2dDemo/Box2dDemo.cpp similarity index 100% rename from ObsoleteDemos/Box2dDemo/Box2dDemo.cpp rename to Demos/Box2dDemo/Box2dDemo.cpp diff --git a/ObsoleteDemos/Box2dDemo/Box2dDemo.h b/Demos/Box2dDemo/Box2dDemo.h similarity index 100% rename from ObsoleteDemos/Box2dDemo/Box2dDemo.h rename to Demos/Box2dDemo/Box2dDemo.h diff --git a/ObsoleteDemos/Box2dDemo/CMakeLists.txt b/Demos/Box2dDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/Box2dDemo/CMakeLists.txt rename to Demos/Box2dDemo/CMakeLists.txt diff --git a/ObsoleteDemos/Box2dDemo/Win32Box2dDemo.cpp b/Demos/Box2dDemo/Win32Box2dDemo.cpp similarity index 100% rename from ObsoleteDemos/Box2dDemo/Win32Box2dDemo.cpp rename to Demos/Box2dDemo/Win32Box2dDemo.cpp diff --git a/ObsoleteDemos/Box2dDemo/main.cpp b/Demos/Box2dDemo/main.cpp similarity index 100% rename from ObsoleteDemos/Box2dDemo/main.cpp rename to Demos/Box2dDemo/main.cpp diff --git a/ObsoleteDemos/BspDemo/BspConverter.cpp b/Demos/BspDemo/BspConverter.cpp similarity index 100% rename from ObsoleteDemos/BspDemo/BspConverter.cpp rename to Demos/BspDemo/BspConverter.cpp diff --git a/ObsoleteDemos/BspDemo/BspConverter.h b/Demos/BspDemo/BspConverter.h similarity index 100% rename from ObsoleteDemos/BspDemo/BspConverter.h rename to Demos/BspDemo/BspConverter.h diff --git a/ObsoleteDemos/BspDemo/BspDemo.bsp b/Demos/BspDemo/BspDemo.bsp similarity index 100% rename from ObsoleteDemos/BspDemo/BspDemo.bsp rename to Demos/BspDemo/BspDemo.bsp diff --git a/ObsoleteDemos/BspDemo/BspDemo.cpp b/Demos/BspDemo/BspDemo.cpp similarity index 88% rename from ObsoleteDemos/BspDemo/BspDemo.cpp rename to Demos/BspDemo/BspDemo.cpp index 8301eac3e..52e48eb1b 100644 --- a/ObsoleteDemos/BspDemo/BspDemo.cpp +++ b/Demos/BspDemo/BspDemo.cpp @@ -4,8 +4,8 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -60,7 +60,7 @@ public: { ///perhaps we can do something special with entities (isEntity) ///like adding a collision Triggering (as example) - + if (vertices.size() > 0) { float mass = 0.f; @@ -69,7 +69,7 @@ public: startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,0,-10.f)); //this create an internal copy of the vertices - + btCollisionShape* shape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); m_demoApp->m_collisionShapes.push_back(shape); @@ -134,7 +134,7 @@ BspDemo::~BspDemo() void BspDemo::initPhysics() { const char* bspfilename = "BspDemo.bsp"; - + initPhysics(bspfilename); } @@ -144,7 +144,7 @@ void BspDemo::initPhysics(const char* bspfilename) { setTexturing(true); setShadows(false); - + m_cameraUp = btVector3(0,0,1); m_forwardAxis = 1; @@ -170,31 +170,23 @@ void BspDemo::initPhysics(const char* bspfilename) #ifdef QUAKE_BSP_IMPORTING void* memoryBuffer = 0; - - FILE* file = fopen(bspfilename,"r"); - if (!file) - { - //try again other path, - //sight... visual studio leaves the current working directory in the projectfiles folder - //instead of executable folder. who wants this default behaviour?!? - bspfilename = "../../BspDemo.bsp"; - file = fopen(bspfilename,"r"); - } - if (!file) - { - //try again other path, cmake needs 4 levels deep back... - bspfilename = "../../../../BspDemo.bsp"; - file = fopen(bspfilename,"r"); - } - if (!file) - { - //try again other path, - //sight... visual studio leaves the current working directory in the projectfiles folder - //instead of executable folder. who wants this default behaviour?!? - bspfilename = "BspDemo.bsp"; - file = fopen(bspfilename,"r"); - } + const char* filename = "BspDemo.bsp"; + + const char* prefix[]={"./","../","../../","../../../","../../../../", "BspDemo/", "Demos/BspDemo/", + "../Demos/BspDemo/","../../Demos/BspDemo/"}; + int numPrefixes = sizeof(prefix)/sizeof(const char*); + char relativeFileName[1024]; + FILE* file=0; + + for (int i=0;istepSimulation(dt); //optional but useful: debug drawing @@ -248,7 +240,7 @@ void BspDemo::clientMoveAndDisplay() void BspDemo::displayCallback(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderme(); @@ -295,7 +287,7 @@ char* makeExeToBspFilename(const char* lpCmdLine) // If we hit a null or a quote, stop copying. This will get just the first filename. if(i && (in[0] == '.') && (in[1] == 'e') && (in[2] == 'x') && (in[3] == 'e')) break; - + // If we hit a null or a quote, stop copying. This will get just the first filename. if(*in == '\0' || *in == '\"') break; @@ -316,6 +308,6 @@ char* makeExeToBspFilename(const char* lpCmdLine) *(out++) = 's'; *(out++) = 'p'; *(out++) = 0; - + return cleaned_filename; } diff --git a/ObsoleteDemos/BspDemo/BspDemo.h b/Demos/BspDemo/BspDemo.h similarity index 100% rename from ObsoleteDemos/BspDemo/BspDemo.h rename to Demos/BspDemo/BspDemo.h diff --git a/ObsoleteDemos/BspDemo/BspLoader.cpp b/Demos/BspDemo/BspLoader.cpp similarity index 100% rename from ObsoleteDemos/BspDemo/BspLoader.cpp rename to Demos/BspDemo/BspLoader.cpp diff --git a/ObsoleteDemos/BspDemo/BspLoader.h b/Demos/BspDemo/BspLoader.h similarity index 100% rename from ObsoleteDemos/BspDemo/BspLoader.h rename to Demos/BspDemo/BspLoader.h diff --git a/ObsoleteDemos/BspDemo/CMakeLists.txt b/Demos/BspDemo/CMakeLists.txt similarity index 91% rename from ObsoleteDemos/BspDemo/CMakeLists.txt rename to Demos/BspDemo/CMakeLists.txt index 0a070a541..4d201988f 100644 --- a/ObsoleteDemos/BspDemo/CMakeLists.txt +++ b/Demos/BspDemo/CMakeLists.txt @@ -35,7 +35,7 @@ IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) ADD_CUSTOM_COMMAND( TARGET AppBspPhysicsDemo POST_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/ObsoleteDemos/BspDemo/BspDemo.bsp ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/Demos/BspDemo/BspDemo.bsp ${CMAKE_CURRENT_BINARY_DIR} ) ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) @@ -43,4 +43,4 @@ IF (INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) SET_TARGET_PROPERTIES(AppBspPhysicsDemo PROPERTIES DEBUG_POSTFIX "_Debug") SET_TARGET_PROPERTIES(AppBspPhysicsDemo PROPERTIES MINSIZEREL_POSTFIX "_MinsizeRel") SET_TARGET_PROPERTIES(AppBspPhysicsDemo PROPERTIES RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo") -ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) \ No newline at end of file +ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES) diff --git a/ObsoleteDemos/BspDemo/main.cpp b/Demos/BspDemo/main.cpp similarity index 100% rename from ObsoleteDemos/BspDemo/main.cpp rename to Demos/BspDemo/main.cpp diff --git a/ObsoleteDemos/BulletDinoDemo/BulletDino.c b/Demos/BulletDinoDemo/BulletDino.c similarity index 100% rename from ObsoleteDemos/BulletDinoDemo/BulletDino.c rename to Demos/BulletDinoDemo/BulletDino.c diff --git a/ObsoleteDemos/BulletDinoDemo/CMakeLists.txt b/Demos/BulletDinoDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/BulletDinoDemo/CMakeLists.txt rename to Demos/BulletDinoDemo/CMakeLists.txt diff --git a/ObsoleteDemos/BulletXmlImportDemo/BulletXmlImportDemo.cpp b/Demos/BulletXmlImportDemo/BulletXmlImportDemo.cpp similarity index 83% rename from ObsoleteDemos/BulletXmlImportDemo/BulletXmlImportDemo.cpp rename to Demos/BulletXmlImportDemo/BulletXmlImportDemo.cpp index 9c670a81a..e1338dbc7 100644 --- a/ObsoleteDemos/BulletXmlImportDemo/BulletXmlImportDemo.cpp +++ b/Demos/BulletXmlImportDemo/BulletXmlImportDemo.cpp @@ -4,8 +4,8 @@ Copyright (c) 2003-2010 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -38,16 +38,36 @@ void BulletXmlImportDemo::initPhysics() setTexturing(true); setShadows(true); - + setupEmptyDynamicsWorld(); - + m_dynamicsWorld->setDebugDrawer(&gDebugDrawer); btBulletXmlWorldImporter* importer = new btBulletXmlWorldImporter(m_dynamicsWorld); - importer->loadFile("bullet_basic.xml"); + static const char* filename = "bullet_basic.xml"; + + const char* prefix[]={"./","../","../../","../../../","../../../../", "BulletXmlImportDemo/", "Demos/BulletXmlImportDemo/", + "../Demos/BulletXmlImportDemo/","../../Demos/BulletXmlImportDemo/"}; + int numPrefixes = sizeof(prefix)/sizeof(const char*); + char relativeFileName[1024]; + bool fileFound = false; + + for (int i=0;iloadFile(relativeFileName); // importer->loadFile("bulletser.xml"); // importer->loadFile("bullet_constraints.xml"); @@ -55,21 +75,21 @@ void BulletXmlImportDemo::initPhysics() void BulletXmlImportDemo::clientMoveAndDisplay() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //simple dynamics world doesn't handle fixed-time-stepping float ms = getDeltaTimeMicroseconds(); - + ///step the simulation if (m_dynamicsWorld) { - + m_dynamicsWorld->stepSimulation(ms / 1000000.f); m_dynamicsWorld->debugDrawWorld(); } - - renderme(); + + renderme(); glFlush(); @@ -81,8 +101,8 @@ void BulletXmlImportDemo::clientMoveAndDisplay() void BulletXmlImportDemo::displayCallback(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + renderme(); @@ -105,7 +125,7 @@ void BulletXmlImportDemo::setupEmptyDynamicsWorld() btGImpactCollisionAlgorithm::registerAlgorithm(m_dispatcher); m_broadphase = new btDbvtBroadphase(); - + ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; m_solver = sol; @@ -113,7 +133,7 @@ void BulletXmlImportDemo::setupEmptyDynamicsWorld() //btGImpactCollisionAlgorithm::registerAlgorithm((btCollisionDispatcher*)m_dynamicsWorld->getDispatcher()); - + } @@ -123,7 +143,7 @@ void BulletXmlImportDemo::setupEmptyDynamicsWorld() BulletXmlImportDemo::~BulletXmlImportDemo() { m_fileLoader->deleteAllData(); - delete m_fileLoader; + delete m_fileLoader; exitPhysics(); } @@ -163,16 +183,16 @@ void BulletXmlImportDemo::exitPhysics() m_collisionShapes.clear(); delete m_dynamicsWorld; - + delete m_solver; - + delete m_broadphase; - + delete m_dispatcher; delete m_collisionConfiguration; - + } diff --git a/ObsoleteDemos/BulletXmlImportDemo/BulletXmlImportDemo.h b/Demos/BulletXmlImportDemo/BulletXmlImportDemo.h similarity index 100% rename from ObsoleteDemos/BulletXmlImportDemo/BulletXmlImportDemo.h rename to Demos/BulletXmlImportDemo/BulletXmlImportDemo.h diff --git a/ObsoleteDemos/BulletXmlImportDemo/CMakeLists.txt b/Demos/BulletXmlImportDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/BulletXmlImportDemo/CMakeLists.txt rename to Demos/BulletXmlImportDemo/CMakeLists.txt diff --git a/ObsoleteDemos/BulletXmlImportDemo/Win32BulletXmlImportDemo.cpp b/Demos/BulletXmlImportDemo/Win32BulletXmlImportDemo.cpp similarity index 100% rename from ObsoleteDemos/BulletXmlImportDemo/Win32BulletXmlImportDemo.cpp rename to Demos/BulletXmlImportDemo/Win32BulletXmlImportDemo.cpp diff --git a/ObsoleteDemos/BulletXmlImportDemo/bullet_basic.xml b/Demos/BulletXmlImportDemo/bullet_basic.xml similarity index 100% rename from ObsoleteDemos/BulletXmlImportDemo/bullet_basic.xml rename to Demos/BulletXmlImportDemo/bullet_basic.xml diff --git a/ObsoleteDemos/BulletXmlImportDemo/bulletser.xml b/Demos/BulletXmlImportDemo/bulletser.xml similarity index 100% rename from ObsoleteDemos/BulletXmlImportDemo/bulletser.xml rename to Demos/BulletXmlImportDemo/bulletser.xml diff --git a/ObsoleteDemos/BulletXmlImportDemo/main.cpp b/Demos/BulletXmlImportDemo/main.cpp similarity index 100% rename from ObsoleteDemos/BulletXmlImportDemo/main.cpp rename to Demos/BulletXmlImportDemo/main.cpp diff --git a/ObsoleteDemos/CMakeLists.txt b/Demos/CMakeLists.txt similarity index 91% rename from ObsoleteDemos/CMakeLists.txt rename to Demos/CMakeLists.txt index c6d13ac9c..5c53f021e 100644 --- a/ObsoleteDemos/CMakeLists.txt +++ b/Demos/CMakeLists.txt @@ -5,9 +5,9 @@ SUBDIRS( HelloWorld ) IF (USE_GLUT) IF (GLUT_FOUND) IF(BUILD_CPU_DEMOS) -# IF(BUILD_EXTRAS) -# SUBDIRS( BulletXmlImportDemo ConcaveDemo ConstraintDemo ConvexDecompositionDemo SerializeDemo ) -# ENDIF() + IF(BUILD_EXTRAS) + SUBDIRS( BulletXmlImportDemo ConcaveDemo ConvexDecompositionDemo SerializeDemo ) + ENDIF() SET(SharedDemoSubdirs OpenGL CcdPhysicsDemo ConstraintDemo SliderConstraintDemo GenericJointDemo Raytracer diff --git a/ObsoleteDemos/CcdPhysicsDemo/CMakeLists.txt b/Demos/CcdPhysicsDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/CcdPhysicsDemo/CMakeLists.txt rename to Demos/CcdPhysicsDemo/CMakeLists.txt diff --git a/ObsoleteDemos/CcdPhysicsDemo/CcdPhysicsDemo.cpp b/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp similarity index 100% rename from ObsoleteDemos/CcdPhysicsDemo/CcdPhysicsDemo.cpp rename to Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp diff --git a/ObsoleteDemos/CcdPhysicsDemo/CcdPhysicsDemo.h b/Demos/CcdPhysicsDemo/CcdPhysicsDemo.h similarity index 100% rename from ObsoleteDemos/CcdPhysicsDemo/CcdPhysicsDemo.h rename to Demos/CcdPhysicsDemo/CcdPhysicsDemo.h diff --git a/ObsoleteDemos/CcdPhysicsDemo/Makefile.am b/Demos/CcdPhysicsDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/CcdPhysicsDemo/Makefile.am rename to Demos/CcdPhysicsDemo/Makefile.am diff --git a/ObsoleteDemos/CcdPhysicsDemo/main.cpp b/Demos/CcdPhysicsDemo/main.cpp similarity index 100% rename from ObsoleteDemos/CcdPhysicsDemo/main.cpp rename to Demos/CcdPhysicsDemo/main.cpp diff --git a/ObsoleteDemos/CellSpuDemo/BasicDemo2.cpp b/Demos/CellSpuDemo/BasicDemo2.cpp similarity index 100% rename from ObsoleteDemos/CellSpuDemo/BasicDemo2.cpp rename to Demos/CellSpuDemo/BasicDemo2.cpp diff --git a/ObsoleteDemos/CellSpuDemo/BasicDemo2.h b/Demos/CellSpuDemo/BasicDemo2.h similarity index 100% rename from ObsoleteDemos/CellSpuDemo/BasicDemo2.h rename to Demos/CellSpuDemo/BasicDemo2.h diff --git a/ObsoleteDemos/CharacterDemo/CMakeLists.txt b/Demos/CharacterDemo/CMakeLists.txt similarity index 95% rename from ObsoleteDemos/CharacterDemo/CMakeLists.txt rename to Demos/CharacterDemo/CMakeLists.txt index 1a74ed557..9b344f8ae 100644 --- a/ObsoleteDemos/CharacterDemo/CMakeLists.txt +++ b/Demos/CharacterDemo/CMakeLists.txt @@ -46,7 +46,7 @@ IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) ADD_CUSTOM_COMMAND( TARGET AppCharacterDemo POST_BUILD - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/ObsoleteDemos/BspDemo/BspDemo.bsp ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/Demos/BspDemo/BspDemo.bsp ${CMAKE_CURRENT_BINARY_DIR} ) ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) diff --git a/ObsoleteDemos/CharacterDemo/CharacterDemo.cpp b/Demos/CharacterDemo/CharacterDemo.cpp similarity index 94% rename from ObsoleteDemos/CharacterDemo/CharacterDemo.cpp rename to Demos/CharacterDemo/CharacterDemo.cpp index d944e1309..29a544a12 100644 --- a/ObsoleteDemos/CharacterDemo/CharacterDemo.cpp +++ b/Demos/CharacterDemo/CharacterDemo.cpp @@ -69,11 +69,11 @@ void CharacterDemo::initPhysics() m_constraintSolver = new btSequentialImpulseConstraintSolver(); m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_constraintSolver,m_collisionConfiguration); m_dynamicsWorld->getDispatchInfo().m_allowedCcdPenetration=0.0001f; - + #ifdef DYNAMIC_CHARACTER_CONTROLLER m_character = new DynamicCharacterController (); #else - + btTransform startTransform; startTransform.setIdentity (); //startTransform.setOrigin (btVector3(0.0, 4.0, 0.0)); @@ -101,35 +101,30 @@ void CharacterDemo::initPhysics() btTransform tr; tr.setIdentity(); - const char* bspfilename = "BspDemo.bsp"; + const char* filename = "BspDemo.bsp"; + + const char* prefix[]={"./","../","../../","../../../","../../../../", "BspDemo/", "Demos/BspDemo/", + "../Demos/BspDemo/","../../Demos/BspDemo/"}; + int numPrefixes = sizeof(prefix)/sizeof(const char*); + char relativeFileName[1024]; + FILE* file=0; + + for (int i=0;igetOverlappingPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1); if (!collisionPair) continue; @@ -217,7 +212,7 @@ void CharacterDemo::clientMoveAndDisplay() /* Character stuff &*/ if (m_character) { - + } debugDrawContacts(); @@ -265,7 +260,7 @@ void CharacterDemo::clientMoveAndDisplay() walkDirection += forwardDir; if (gBackward) - walkDirection -= forwardDir; + walkDirection -= forwardDir; m_character->setWalkDirection(walkDirection*walkSpeed); @@ -344,7 +339,7 @@ void CharacterDemo::clientResetScene() m_character->reset (m_dynamicsWorld); ///WTF m_character->warp (btVector3(10.210001,-2.0306311,16.576973)); - + } void CharacterDemo::specialKeyboardUp(int key, int x, int y) @@ -444,7 +439,7 @@ void CharacterDemo::updateCamera() m_cameraTargetPosition = characterWorldTrans.getOrigin(); m_cameraPosition = m_cameraTargetPosition + up * 10.0 + backward * 12.0; - + //use the convex sweep test to find a safe position for the camera (not blocked by static geometry) btSphereShape cameraSphere(0.2f); btTransform cameraFrom,cameraTo; @@ -452,10 +447,10 @@ void CharacterDemo::updateCamera() cameraFrom.setOrigin(characterWorldTrans.getOrigin()); cameraTo.setIdentity(); cameraTo.setOrigin(m_cameraPosition); - + btCollisionWorld::ClosestConvexResultCallback cb( characterWorldTrans.getOrigin(), cameraTo.getOrigin() ); cb.m_collisionFilterMask = btBroadphaseProxy::StaticFilter; - + m_dynamicsWorld->convexSweepTest(&cameraSphere,cameraFrom,cameraTo,cb); if (cb.hasHit()) { diff --git a/ObsoleteDemos/CharacterDemo/CharacterDemo.h b/Demos/CharacterDemo/CharacterDemo.h similarity index 100% rename from ObsoleteDemos/CharacterDemo/CharacterDemo.h rename to Demos/CharacterDemo/CharacterDemo.h diff --git a/ObsoleteDemos/CharacterDemo/DynamicCharacterController.cpp b/Demos/CharacterDemo/DynamicCharacterController.cpp similarity index 100% rename from ObsoleteDemos/CharacterDemo/DynamicCharacterController.cpp rename to Demos/CharacterDemo/DynamicCharacterController.cpp diff --git a/ObsoleteDemos/CharacterDemo/DynamicCharacterController.h b/Demos/CharacterDemo/DynamicCharacterController.h similarity index 100% rename from ObsoleteDemos/CharacterDemo/DynamicCharacterController.h rename to Demos/CharacterDemo/DynamicCharacterController.h diff --git a/ObsoleteDemos/CharacterDemo/main.cpp b/Demos/CharacterDemo/main.cpp similarity index 100% rename from ObsoleteDemos/CharacterDemo/main.cpp rename to Demos/CharacterDemo/main.cpp diff --git a/ObsoleteDemos/CollisionDemo/CMakeLists.txt b/Demos/CollisionDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/CollisionDemo/CMakeLists.txt rename to Demos/CollisionDemo/CMakeLists.txt diff --git a/ObsoleteDemos/CollisionDemo/CollisionDemo.cpp b/Demos/CollisionDemo/CollisionDemo.cpp similarity index 100% rename from ObsoleteDemos/CollisionDemo/CollisionDemo.cpp rename to Demos/CollisionDemo/CollisionDemo.cpp diff --git a/ObsoleteDemos/CollisionDemo/CollisionDemo.h b/Demos/CollisionDemo/CollisionDemo.h similarity index 100% rename from ObsoleteDemos/CollisionDemo/CollisionDemo.h rename to Demos/CollisionDemo/CollisionDemo.h diff --git a/ObsoleteDemos/CollisionInterfaceDemo/CMakeLists.txt b/Demos/CollisionInterfaceDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/CollisionInterfaceDemo/CMakeLists.txt rename to Demos/CollisionInterfaceDemo/CMakeLists.txt diff --git a/ObsoleteDemos/CollisionInterfaceDemo/CollisionInterfaceDemo.cpp b/Demos/CollisionInterfaceDemo/CollisionInterfaceDemo.cpp similarity index 100% rename from ObsoleteDemos/CollisionInterfaceDemo/CollisionInterfaceDemo.cpp rename to Demos/CollisionInterfaceDemo/CollisionInterfaceDemo.cpp diff --git a/ObsoleteDemos/CollisionInterfaceDemo/CollisionInterfaceDemo.h b/Demos/CollisionInterfaceDemo/CollisionInterfaceDemo.h similarity index 100% rename from ObsoleteDemos/CollisionInterfaceDemo/CollisionInterfaceDemo.h rename to Demos/CollisionInterfaceDemo/CollisionInterfaceDemo.h diff --git a/ObsoleteDemos/CollisionInterfaceDemo/Win32CollisionInterfaceDemo.cpp b/Demos/CollisionInterfaceDemo/Win32CollisionInterfaceDemo.cpp similarity index 100% rename from ObsoleteDemos/CollisionInterfaceDemo/Win32CollisionInterfaceDemo.cpp rename to Demos/CollisionInterfaceDemo/Win32CollisionInterfaceDemo.cpp diff --git a/ObsoleteDemos/CollisionInterfaceDemo/main.cpp b/Demos/CollisionInterfaceDemo/main.cpp similarity index 100% rename from ObsoleteDemos/CollisionInterfaceDemo/main.cpp rename to Demos/CollisionInterfaceDemo/main.cpp diff --git a/ObsoleteDemos/ConcaveConvexcastDemo/CMakeLists.txt b/Demos/ConcaveConvexcastDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/ConcaveConvexcastDemo/CMakeLists.txt rename to Demos/ConcaveConvexcastDemo/CMakeLists.txt diff --git a/ObsoleteDemos/ConcaveConvexcastDemo/ConcaveConvexcastDemo.cpp b/Demos/ConcaveConvexcastDemo/ConcaveConvexcastDemo.cpp similarity index 100% rename from ObsoleteDemos/ConcaveConvexcastDemo/ConcaveConvexcastDemo.cpp rename to Demos/ConcaveConvexcastDemo/ConcaveConvexcastDemo.cpp diff --git a/ObsoleteDemos/ConcaveConvexcastDemo/ConcaveConvexcastDemo.h b/Demos/ConcaveConvexcastDemo/ConcaveConvexcastDemo.h similarity index 100% rename from ObsoleteDemos/ConcaveConvexcastDemo/ConcaveConvexcastDemo.h rename to Demos/ConcaveConvexcastDemo/ConcaveConvexcastDemo.h diff --git a/ObsoleteDemos/ConcaveConvexcastDemo/main.cpp b/Demos/ConcaveConvexcastDemo/main.cpp similarity index 100% rename from ObsoleteDemos/ConcaveConvexcastDemo/main.cpp rename to Demos/ConcaveConvexcastDemo/main.cpp diff --git a/ObsoleteDemos/ConcaveDemo/CMakeLists.txt b/Demos/ConcaveDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/ConcaveDemo/CMakeLists.txt rename to Demos/ConcaveDemo/CMakeLists.txt diff --git a/ObsoleteDemos/ConcaveDemo/ConcaveDemo.h b/Demos/ConcaveDemo/ConcaveDemo.h similarity index 100% rename from ObsoleteDemos/ConcaveDemo/ConcaveDemo.h rename to Demos/ConcaveDemo/ConcaveDemo.h diff --git a/ObsoleteDemos/ConcaveDemo/ConcavePhysicsDemo.cpp b/Demos/ConcaveDemo/ConcavePhysicsDemo.cpp similarity index 100% rename from ObsoleteDemos/ConcaveDemo/ConcavePhysicsDemo.cpp rename to Demos/ConcaveDemo/ConcavePhysicsDemo.cpp diff --git a/ObsoleteDemos/ConcaveDemo/Jamfile b/Demos/ConcaveDemo/Jamfile similarity index 100% rename from ObsoleteDemos/ConcaveDemo/Jamfile rename to Demos/ConcaveDemo/Jamfile diff --git a/ObsoleteDemos/ConcaveDemo/Win32ConcaveDemo.cpp b/Demos/ConcaveDemo/Win32ConcaveDemo.cpp similarity index 100% rename from ObsoleteDemos/ConcaveDemo/Win32ConcaveDemo.cpp rename to Demos/ConcaveDemo/Win32ConcaveDemo.cpp diff --git a/ObsoleteDemos/ConcaveDemo/main.cpp b/Demos/ConcaveDemo/main.cpp similarity index 100% rename from ObsoleteDemos/ConcaveDemo/main.cpp rename to Demos/ConcaveDemo/main.cpp diff --git a/ObsoleteDemos/ConcaveRaycastDemo/CMakeLists.txt b/Demos/ConcaveRaycastDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/ConcaveRaycastDemo/CMakeLists.txt rename to Demos/ConcaveRaycastDemo/CMakeLists.txt diff --git a/ObsoleteDemos/ConcaveRaycastDemo/ConcaveRaycastDemo.cpp b/Demos/ConcaveRaycastDemo/ConcaveRaycastDemo.cpp similarity index 100% rename from ObsoleteDemos/ConcaveRaycastDemo/ConcaveRaycastDemo.cpp rename to Demos/ConcaveRaycastDemo/ConcaveRaycastDemo.cpp diff --git a/ObsoleteDemos/ConcaveRaycastDemo/ConcaveRaycastDemo.h b/Demos/ConcaveRaycastDemo/ConcaveRaycastDemo.h similarity index 100% rename from ObsoleteDemos/ConcaveRaycastDemo/ConcaveRaycastDemo.h rename to Demos/ConcaveRaycastDemo/ConcaveRaycastDemo.h diff --git a/ObsoleteDemos/ConcaveRaycastDemo/main.cpp b/Demos/ConcaveRaycastDemo/main.cpp similarity index 100% rename from ObsoleteDemos/ConcaveRaycastDemo/main.cpp rename to Demos/ConcaveRaycastDemo/main.cpp diff --git a/ObsoleteDemos/ConstraintDemo/CMakeLists.txt b/Demos/ConstraintDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/ConstraintDemo/CMakeLists.txt rename to Demos/ConstraintDemo/CMakeLists.txt diff --git a/ObsoleteDemos/ConstraintDemo/ConstraintDemo.cpp b/Demos/ConstraintDemo/ConstraintDemo.cpp similarity index 100% rename from ObsoleteDemos/ConstraintDemo/ConstraintDemo.cpp rename to Demos/ConstraintDemo/ConstraintDemo.cpp diff --git a/ObsoleteDemos/ConstraintDemo/ConstraintDemo.h b/Demos/ConstraintDemo/ConstraintDemo.h similarity index 100% rename from ObsoleteDemos/ConstraintDemo/ConstraintDemo.h rename to Demos/ConstraintDemo/ConstraintDemo.h diff --git a/ObsoleteDemos/ConstraintDemo/Win32ConstraintDemo.cpp b/Demos/ConstraintDemo/Win32ConstraintDemo.cpp similarity index 100% rename from ObsoleteDemos/ConstraintDemo/Win32ConstraintDemo.cpp rename to Demos/ConstraintDemo/Win32ConstraintDemo.cpp diff --git a/ObsoleteDemos/ConstraintDemo/main.cpp b/Demos/ConstraintDemo/main.cpp similarity index 100% rename from ObsoleteDemos/ConstraintDemo/main.cpp rename to Demos/ConstraintDemo/main.cpp diff --git a/ObsoleteDemos/ContinuousConvexCollision/CMakeLists.txt b/Demos/ContinuousConvexCollision/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/ContinuousConvexCollision/CMakeLists.txt rename to Demos/ContinuousConvexCollision/CMakeLists.txt diff --git a/ObsoleteDemos/ContinuousConvexCollision/ContinuousConvexCollision.h b/Demos/ContinuousConvexCollision/ContinuousConvexCollision.h similarity index 100% rename from ObsoleteDemos/ContinuousConvexCollision/ContinuousConvexCollision.h rename to Demos/ContinuousConvexCollision/ContinuousConvexCollision.h diff --git a/ObsoleteDemos/ContinuousConvexCollision/ContinuousConvexCollisionDemo.cpp b/Demos/ContinuousConvexCollision/ContinuousConvexCollisionDemo.cpp similarity index 100% rename from ObsoleteDemos/ContinuousConvexCollision/ContinuousConvexCollisionDemo.cpp rename to Demos/ContinuousConvexCollision/ContinuousConvexCollisionDemo.cpp diff --git a/ObsoleteDemos/ConvexDecompositionDemo/CMakeLists.txt b/Demos/ConvexDecompositionDemo/CMakeLists.txt similarity index 96% rename from ObsoleteDemos/ConvexDecompositionDemo/CMakeLists.txt rename to Demos/ConvexDecompositionDemo/CMakeLists.txt index d3cd02e13..979c792bc 100644 --- a/ObsoleteDemos/ConvexDecompositionDemo/CMakeLists.txt +++ b/Demos/ConvexDecompositionDemo/CMakeLists.txt @@ -1,3 +1,4 @@ + # This is basically the overall name of the project in Visual Studio this is the name of the Solution File @@ -53,7 +54,7 @@ IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) TARGET AppConvexDecompositionDemo POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/Demos/SerializeDemo/testFile.bullet ${CMAKE_CURRENT_BINARY_DIR}/testFile.bullet - COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/file.obj ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different ${BULLET_PHYSICS_SOURCE_DIR}/Demos/ConvexDecompositionDemo/file.obj ${CMAKE_CURRENT_BINARY_DIR} ) ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) diff --git a/ObsoleteDemos/ConvexDecompositionDemo/ConvexDecompositionDemo.cpp b/Demos/ConvexDecompositionDemo/ConvexDecompositionDemo.cpp similarity index 95% rename from ObsoleteDemos/ConvexDecompositionDemo/ConvexDecompositionDemo.cpp rename to Demos/ConvexDecompositionDemo/ConvexDecompositionDemo.cpp index c2b9bcf87..3b081eaf9 100644 --- a/ObsoleteDemos/ConvexDecompositionDemo/ConvexDecompositionDemo.cpp +++ b/Demos/ConvexDecompositionDemo/ConvexDecompositionDemo.cpp @@ -4,8 +4,8 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -178,23 +178,22 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) ConvexDecomposition::WavefrontObj wo; - tcount = wo.loadObj(filename); + tcount = 0; + const char* prefix[]={"./","../","../../","../../../","../../../../", "ConvexDecompositionDemo/", "Demos/ConvexDecompositionDemo/", + "../Demos/ConvexDecompositionDemo/","../../Demos/ConvexDecompositionDemo/"}; + int numPrefixes = sizeof(prefix)/sizeof(const char*); + char relativeFileName[1024]; + + for (int i=0;i m_convexShapes; @@ -220,7 +219,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) { } - + virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { @@ -256,7 +255,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; centroid += vertex; - + } } @@ -273,8 +272,8 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) vertices.push_back(vertex); } } - - + + if ( 1 ) { @@ -292,7 +291,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; - + vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; @@ -303,20 +302,20 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; - + fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } // float mass = 1.f; - + //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #ifdef SHRINK_OBJECT_INWARDS float collisionMargin = 0.01f; - + btAlignedObjectArray planeEquations; btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations); @@ -330,13 +329,13 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) btAlignedObjectArray shiftedVertices; btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices); - + btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size()); - + #else //SHRINK_OBJECT_INWARDS - + btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); -#endif +#endif if (sEnableSAT) convexShape->initializePolyhedralFeatures(); convexShape->setMargin(0.01f); @@ -361,7 +360,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); - + int i; for ( i=0;iaddTriangle(vertex0,vertex1,vertex2); } - + btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh); - + printf("old numTriangles= %d\n",wo.mTriCount); printf("old numIndices = %d\n",wo.mTriCount*3); printf("old numVertices = %d\n",wo.mVertexCount); - + printf("reducing vertices by creating a convex hull\n"); //create a hull approximation @@ -394,18 +393,18 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); - - + + printf("new numTriangles = %d\n", hull->numTriangles ()); printf("new numIndices = %d\n", hull->numIndices ()); printf("new numVertices = %d\n", hull->numVertices ()); - + btConvexHullShape* convexShape = new btConvexHullShape(); bool updateLocalAabb = false; for (i=0;inumVertices();i++) { - convexShape->addPoint(hull->getVertexPointer()[i],updateLocalAabb); + convexShape->addPoint(hull->getVertexPointer()[i],updateLocalAabb); } convexShape->recalcLocalAabb(); @@ -419,13 +418,13 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) m_collisionShapes.push_back(convexShape); float mass = 1.f; - + btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,2,14)); localCreateRigidBody(mass, startTransform,convexShape); - + bool useQuantization = true; btCollisionShape* concaveShape = new btBvhTriangleMeshShape(trimesh,useQuantization); startTransform.setOrigin(convexDecompositionObjectOffset); @@ -434,7 +433,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) m_collisionShapes.push_back (concaveShape); } - + if (tcount) { @@ -445,11 +444,11 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); - if ( dot ) + if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); - + unsigned int depth = 5; float cpercent = 5; float ppercent = 15; @@ -479,7 +478,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) std::vector< HACD::Vec3 > points; std::vector< HACD::Vec3 > triangles; - for(int i=0; i vertex(wo.mVertices[index], wo.mVertices[index+1],wo.mVertices[index+2]); @@ -509,17 +508,17 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) bool invert = false; bool addExtraDistPoints = false; bool addNeighboursDistPoints = false; - bool addFacesPoints = false; + bool addFacesPoints = false; myHACD.SetNClusters(nClusters); // minimum number of clusters myHACD.SetNVerticesPerCH(100); // max of 100 vertices per convex-hull myHACD.SetConcavity(concavity); // maximum concavity - myHACD.SetAddExtraDistPoints(addExtraDistPoints); - myHACD.SetAddNeighboursDistPoints(addNeighboursDistPoints); - myHACD.SetAddFacesPoints(addFacesPoints); + myHACD.SetAddExtraDistPoints(addExtraDistPoints); + myHACD.SetAddNeighboursDistPoints(addNeighboursDistPoints); + myHACD.SetAddFacesPoints(addFacesPoints); myHACD.Compute(); - nClusters = myHACD.GetNClusters(); + nClusters = myHACD.GetNClusters(); myHACD.Save("output.wrl", false); @@ -529,7 +528,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) // ConvexBuilder cb(desc.mCallback); // cb.process(desc); //now create some bodies - + if (1) { btCompoundShape* compound = new btCompoundShape(); @@ -546,7 +545,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) float* vertices = new float[nPoints*3]; unsigned int* triangles = new unsigned int[nTriangles*3]; - + HACD::Vec3 * pointsCH = new HACD::Vec3[nPoints]; HACD::Vec3 * trianglesCH = new HACD::Vec3[nTriangles]; myHACD.GetCH(c, pointsCH, trianglesCH); @@ -585,7 +584,7 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) } /* for (int i=0;iserialize(serializer); - + FILE* f2 = fopen("testFile.bullet","wb"); fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1,f2); fclose(f2); @@ -651,17 +650,17 @@ void ConvexDecompositionDemo::initPhysics(const char* filename) //fileLoader->loadFile("testFile64Double.bullet"); //fileLoader->loadFile("testFile64Single.bullet"); //fileLoader->loadFile("testFile32Single.bullet"); - + #endif //TEST_SERIALIZATION - + } void ConvexDecompositionDemo::clientMoveAndDisplay() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); float dt = getDeltaTimeMicroseconds() * 0.000001f; @@ -681,7 +680,7 @@ void ConvexDecompositionDemo::clientMoveAndDisplay() void ConvexDecompositionDemo::displayCallback(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if (m_dynamicsWorld) @@ -749,7 +748,7 @@ void ConvexDecompositionDemo::exitPhysics() delete m_collisionConfiguration; - + } @@ -768,7 +767,7 @@ void ConvexDecompositionDemo::keyboardCallback(unsigned char key, int x, int y) { printf("SAT enabled after the next restart of the demo\n"); } else - { + { printf("SAT disabled after the next restart of the demo\n"); } } else @@ -776,4 +775,4 @@ void ConvexDecompositionDemo::keyboardCallback(unsigned char key, int x, int y) PlatformDemoApplication::keyboardCallback(key,x,y); } -} \ No newline at end of file +} diff --git a/ObsoleteDemos/ConvexDecompositionDemo/ConvexDecompositionDemo.h b/Demos/ConvexDecompositionDemo/ConvexDecompositionDemo.h similarity index 100% rename from ObsoleteDemos/ConvexDecompositionDemo/ConvexDecompositionDemo.h rename to Demos/ConvexDecompositionDemo/ConvexDecompositionDemo.h diff --git a/ObsoleteDemos/ConvexDecompositionDemo/Win32ConvexDecompositionDemo.cpp b/Demos/ConvexDecompositionDemo/Win32ConvexDecompositionDemo.cpp similarity index 100% rename from ObsoleteDemos/ConvexDecompositionDemo/Win32ConvexDecompositionDemo.cpp rename to Demos/ConvexDecompositionDemo/Win32ConvexDecompositionDemo.cpp diff --git a/Demos/ConvexDecompositionDemo/file.obj b/Demos/ConvexDecompositionDemo/file.obj new file mode 100644 index 000000000..15047b022 --- /dev/null +++ b/Demos/ConvexDecompositionDemo/file.obj @@ -0,0 +1,3578 @@ +v 0.000118 -0.390977 -0.478607 +v 0.017389 -0.390977 -0.478271 +v 0.029547 -0.390983 -0.429828 +v 0.000118 -0.390983 -0.429848 +v 0.017389 -0.390977 -0.478271 +v 0.017389 -0.342855 -0.474044 +v 0.029547 -0.317820 -0.429577 +v 0.029547 -0.390983 -0.429828 +v 0.017389 -0.342855 -0.474044 +v 0.000118 -0.331762 -0.473074 +v 0.000118 -0.306727 -0.429520 +v 0.029547 -0.317820 -0.429577 +v -0.017152 -0.342855 -0.474044 +v -0.029311 -0.317820 -0.429577 +v -0.017152 -0.342855 -0.474044 +v -0.017152 -0.390977 -0.478271 +v -0.029311 -0.390983 -0.429828 +v -0.029311 -0.317820 -0.429577 +v -0.017152 -0.390977 -0.478271 +v -0.029311 -0.390983 -0.429828 +v 0.017389 -0.391071 -0.377731 +v 0.000118 -0.391100 -0.378066 +v 0.017389 -0.336012 -0.378305 +v 0.017389 -0.391071 -0.377731 +v 0.029547 -0.317820 -0.429577 +v 0.000118 -0.306727 -0.429520 +v 0.000118 -0.324876 -0.378305 +v 0.017389 -0.336012 -0.378305 +v 0.000118 -0.306727 -0.429520 +v -0.029311 -0.317820 -0.429577 +v -0.017152 -0.336012 -0.378305 +v 0.000118 -0.324876 -0.378305 +v -0.017152 -0.391071 -0.377731 +v -0.017152 -0.336012 -0.378305 +v -0.017152 -0.391071 -0.377731 +v 0.017389 -0.355018 -0.311310 +v 0.000118 -0.358745 -0.310312 +v 0.017389 -0.313071 -0.327714 +v 0.017389 -0.355018 -0.311310 +v 0.000118 -0.302315 -0.330597 +v 0.017389 -0.313071 -0.327714 +v -0.017152 -0.313071 -0.327714 +v 0.000118 -0.302315 -0.330597 +v -0.017152 -0.355018 -0.311310 +v -0.017152 -0.313071 -0.327714 +v -0.017152 -0.355018 -0.311310 +v 0.027414 -0.282077 -0.242925 +v 0.000118 -0.286749 -0.239005 +v 0.027414 -0.244765 -0.265699 +v 0.027414 -0.282077 -0.242925 +v 0.000118 -0.231283 -0.277012 +v 0.027414 -0.244765 -0.265699 +v -0.027178 -0.244765 -0.265699 +v 0.000118 -0.231283 -0.277012 +v -0.027178 -0.282077 -0.242925 +v -0.027178 -0.244765 -0.265699 +v -0.027178 -0.282077 -0.242925 +v 0.035601 -0.254040 -0.188841 +v 0.000118 -0.261848 -0.187464 +v 0.035601 -0.172486 -0.190596 +v 0.035601 -0.254040 -0.188841 +v 0.000118 -0.149955 -0.194569 +v 0.035601 -0.172486 -0.190596 +v -0.035364 -0.172486 -0.190596 +v 0.000118 -0.149955 -0.194569 +v -0.035364 -0.254040 -0.188841 +v -0.035364 -0.172486 -0.190596 +v -0.035364 -0.254040 -0.188841 +v 0.000118 -0.360973 -0.484897 +v 0.017389 -0.390977 -0.478271 +v 0.000118 -0.390977 -0.478607 +v 0.017389 -0.342855 -0.474044 +v 0.000118 -0.331762 -0.473074 +v -0.017152 -0.342855 -0.474044 +v -0.017152 -0.390977 -0.478271 +v 0.035601 -0.232880 -0.098411 +v 0.000118 -0.240808 -0.098411 +v 0.035601 -0.144967 -0.098411 +v 0.035601 -0.232880 -0.098411 +v 0.000118 -0.122088 -0.098411 +v 0.035601 -0.144967 -0.098411 +v -0.035364 -0.144967 -0.098411 +v 0.000118 -0.122088 -0.098411 +v -0.035364 -0.232880 -0.098411 +v -0.035364 -0.144967 -0.098411 +v -0.035364 -0.232880 -0.098411 +v 0.478607 -0.390977 0.000118 +v 0.478271 -0.390977 0.017389 +v 0.429828 -0.390983 0.029547 +v 0.429848 -0.390983 0.000118 +v 0.478271 -0.390977 0.017389 +v 0.474044 -0.342855 0.017389 +v 0.429577 -0.317820 0.029547 +v 0.429828 -0.390983 0.029547 +v 0.474044 -0.342855 0.017389 +v 0.473074 -0.331762 0.000118 +v 0.429520 -0.306727 0.000118 +v 0.429577 -0.317820 0.029547 +v 0.474044 -0.342855 -0.017152 +v 0.429577 -0.317820 -0.029311 +v 0.474044 -0.342855 -0.017152 +v 0.478271 -0.390977 -0.017152 +v 0.429828 -0.390983 -0.029311 +v 0.429577 -0.317820 -0.029311 +v 0.478271 -0.390977 -0.017152 +v 0.429828 -0.390983 -0.029311 +v 0.377731 -0.391071 0.017389 +v 0.378066 -0.391100 0.000118 +v 0.378305 -0.336012 0.017389 +v 0.377731 -0.391071 0.017389 +v 0.429577 -0.317820 0.029547 +v 0.429520 -0.306727 0.000118 +v 0.378305 -0.324876 0.000118 +v 0.378305 -0.336012 0.017389 +v 0.429520 -0.306727 0.000118 +v 0.429577 -0.317820 -0.029311 +v 0.378305 -0.336012 -0.017152 +v 0.378305 -0.324876 0.000118 +v 0.377731 -0.391071 -0.017152 +v 0.378305 -0.336012 -0.017152 +v 0.377731 -0.391071 -0.017152 +v 0.311310 -0.355018 0.017389 +v 0.310312 -0.358745 0.000118 +v 0.327714 -0.313071 0.017389 +v 0.311310 -0.355018 0.017389 +v 0.330597 -0.302315 0.000118 +v 0.327714 -0.313071 0.017389 +v 0.327714 -0.313071 -0.017152 +v 0.330597 -0.302315 0.000118 +v 0.311310 -0.355018 -0.017152 +v 0.327714 -0.313071 -0.017152 +v 0.311310 -0.355018 -0.017152 +v 0.242925 -0.282077 0.027414 +v 0.239005 -0.286749 0.000118 +v 0.265699 -0.244765 0.027414 +v 0.242925 -0.282077 0.027414 +v 0.277012 -0.231283 0.000118 +v 0.265699 -0.244765 0.027414 +v 0.265699 -0.244765 -0.027178 +v 0.277012 -0.231283 0.000118 +v 0.242925 -0.282077 -0.027178 +v 0.265699 -0.244765 -0.027178 +v 0.242925 -0.282077 -0.027178 +v 0.188841 -0.254040 0.035601 +v 0.187464 -0.261848 0.000118 +v 0.190596 -0.172486 0.035601 +v 0.188841 -0.254040 0.035601 +v 0.194569 -0.149955 0.000118 +v 0.190596 -0.172486 0.035601 +v 0.190596 -0.172486 -0.035364 +v 0.194569 -0.149955 0.000118 +v 0.188841 -0.254040 -0.035364 +v 0.190596 -0.172486 -0.035364 +v 0.188841 -0.254040 -0.035364 +v 0.484897 -0.360973 0.000118 +v 0.478271 -0.390977 0.017389 +v 0.478607 -0.390977 0.000118 +v 0.474044 -0.342855 0.017389 +v 0.473074 -0.331762 0.000118 +v 0.474044 -0.342855 -0.017152 +v 0.478271 -0.390977 -0.017152 +v 0.098411 -0.232880 0.035601 +v 0.098411 -0.240808 0.000118 +v 0.098411 -0.144967 0.035601 +v 0.098411 -0.232880 0.035601 +v 0.098411 -0.122088 0.000118 +v 0.098411 -0.144967 0.035601 +v 0.098411 -0.144967 -0.035364 +v 0.098411 -0.122088 0.000118 +v 0.098411 -0.232880 -0.035364 +v 0.098411 -0.144967 -0.035364 +v 0.098411 -0.232880 -0.035364 +v -0.000118 -0.390977 0.478607 +v -0.017389 -0.390977 0.478271 +v -0.029547 -0.390983 0.429828 +v -0.000118 -0.390983 0.429848 +v -0.017389 -0.390977 0.478271 +v -0.017389 -0.342855 0.474044 +v -0.029547 -0.317820 0.429577 +v -0.029547 -0.390983 0.429828 +v -0.017389 -0.342855 0.474044 +v -0.000118 -0.331762 0.473074 +v -0.000118 -0.306727 0.429520 +v -0.029547 -0.317820 0.429577 +v 0.017152 -0.342855 0.474044 +v 0.029310 -0.317820 0.429577 +v 0.017152 -0.342855 0.474044 +v 0.017152 -0.390977 0.478271 +v 0.029310 -0.390983 0.429828 +v 0.029310 -0.317820 0.429577 +v 0.017152 -0.390977 0.478271 +v 0.029310 -0.390983 0.429828 +v -0.017389 -0.391071 0.377731 +v -0.000118 -0.391100 0.378066 +v -0.017389 -0.336012 0.378305 +v -0.017389 -0.391071 0.377731 +v -0.029547 -0.317820 0.429577 +v -0.000118 -0.306727 0.429520 +v -0.000118 -0.324876 0.378305 +v -0.017389 -0.336012 0.378305 +v -0.000118 -0.306727 0.429520 +v 0.029310 -0.317820 0.429577 +v 0.017152 -0.336012 0.378305 +v -0.000118 -0.324876 0.378305 +v 0.017152 -0.391071 0.377731 +v 0.017152 -0.336012 0.378305 +v 0.017152 -0.391071 0.377731 +v -0.017389 -0.355018 0.311310 +v -0.000118 -0.358745 0.310312 +v -0.017389 -0.313071 0.327714 +v -0.017389 -0.355018 0.311310 +v -0.000118 -0.302315 0.330597 +v -0.017389 -0.313071 0.327714 +v 0.017152 -0.313071 0.327714 +v -0.000118 -0.302315 0.330597 +v 0.017152 -0.355018 0.311310 +v 0.017152 -0.313071 0.327714 +v 0.017152 -0.355018 0.311310 +v -0.027414 -0.282077 0.242925 +v -0.000118 -0.286749 0.239005 +v -0.027414 -0.244765 0.265699 +v -0.027414 -0.282077 0.242925 +v -0.000118 -0.231283 0.277012 +v -0.027414 -0.244765 0.265699 +v 0.027178 -0.244765 0.265699 +v -0.000118 -0.231283 0.277012 +v 0.027178 -0.282077 0.242925 +v 0.027178 -0.244765 0.265699 +v 0.027178 -0.282077 0.242925 +v -0.035601 -0.254040 0.188841 +v -0.000118 -0.261848 0.187464 +v -0.035601 -0.172486 0.190596 +v -0.035601 -0.254040 0.188841 +v -0.000118 -0.149955 0.194569 +v -0.035601 -0.172486 0.190596 +v 0.035364 -0.172486 0.190596 +v -0.000118 -0.149955 0.194569 +v 0.035364 -0.254040 0.188841 +v 0.035364 -0.172486 0.190596 +v 0.035364 -0.254040 0.188841 +v -0.000118 -0.360973 0.484897 +v -0.017389 -0.390977 0.478271 +v -0.000118 -0.390977 0.478607 +v -0.017389 -0.342855 0.474044 +v -0.000118 -0.331762 0.473074 +v 0.017152 -0.342855 0.474044 +v 0.017152 -0.390977 0.478271 +v -0.035601 -0.232880 0.098411 +v -0.000118 -0.240808 0.098411 +v -0.035601 -0.144967 0.098411 +v -0.035601 -0.232880 0.098411 +v -0.000118 -0.122088 0.098411 +v -0.035601 -0.144967 0.098411 +v 0.035364 -0.144967 0.098411 +v -0.000118 -0.122088 0.098411 +v 0.035364 -0.232880 0.098411 +v 0.035364 -0.144967 0.098411 +v 0.035364 -0.232880 0.098411 +v -0.478607 -0.390977 -0.000118 +v -0.478271 -0.390977 -0.017389 +v -0.429828 -0.390983 -0.029547 +v -0.429848 -0.390983 -0.000118 +v -0.478271 -0.390977 -0.017389 +v -0.474044 -0.342855 -0.017389 +v -0.429577 -0.317820 -0.029547 +v -0.429828 -0.390983 -0.029547 +v -0.474044 -0.342855 -0.017389 +v -0.473074 -0.331762 -0.000118 +v -0.429520 -0.306727 -0.000118 +v -0.429577 -0.317820 -0.029547 +v -0.474044 -0.342855 0.017152 +v -0.429577 -0.317820 0.029310 +v -0.474044 -0.342855 0.017152 +v -0.478271 -0.390977 0.017152 +v -0.429828 -0.390983 0.029310 +v -0.429577 -0.317820 0.029310 +v -0.478271 -0.390977 0.017152 +v -0.429828 -0.390983 0.029310 +v -0.377731 -0.391071 -0.017389 +v -0.378066 -0.391100 -0.000118 +v -0.378305 -0.336012 -0.017389 +v -0.377731 -0.391071 -0.017389 +v -0.429577 -0.317820 -0.029547 +v -0.429520 -0.306727 -0.000118 +v -0.378305 -0.324876 -0.000118 +v -0.378305 -0.336012 -0.017389 +v -0.429520 -0.306727 -0.000118 +v -0.429577 -0.317820 0.029310 +v -0.378305 -0.336012 0.017152 +v -0.378305 -0.324876 -0.000118 +v -0.377731 -0.391071 0.017152 +v -0.378305 -0.336012 0.017152 +v -0.377731 -0.391071 0.017152 +v -0.311310 -0.355018 -0.017389 +v -0.310312 -0.358745 -0.000118 +v -0.327714 -0.313071 -0.017389 +v -0.311310 -0.355018 -0.017389 +v -0.330597 -0.302315 -0.000118 +v -0.327714 -0.313071 -0.017389 +v -0.327714 -0.313071 0.017152 +v -0.330597 -0.302315 -0.000118 +v -0.311310 -0.355018 0.017152 +v -0.327714 -0.313071 0.017152 +v -0.311310 -0.355018 0.017152 +v -0.242925 -0.282077 -0.027414 +v -0.239005 -0.286749 -0.000118 +v -0.265699 -0.244765 -0.027414 +v -0.242925 -0.282077 -0.027414 +v -0.277012 -0.231283 -0.000118 +v -0.265699 -0.244765 -0.027414 +v -0.265699 -0.244765 0.027178 +v -0.277012 -0.231283 -0.000118 +v -0.242925 -0.282077 0.027178 +v -0.265699 -0.244765 0.027178 +v -0.242925 -0.282077 0.027178 +v -0.188841 -0.254040 -0.035601 +v -0.187464 -0.261848 -0.000118 +v -0.190596 -0.172486 -0.035601 +v -0.188841 -0.254040 -0.035601 +v -0.194569 -0.149955 -0.000118 +v -0.190596 -0.172486 -0.035601 +v -0.190596 -0.172486 0.035364 +v -0.194569 -0.149955 -0.000118 +v -0.188841 -0.254040 0.035364 +v -0.190596 -0.172486 0.035364 +v -0.188841 -0.254040 0.035364 +v -0.484897 -0.360973 -0.000118 +v -0.478271 -0.390977 -0.017389 +v -0.478607 -0.390977 -0.000118 +v -0.474044 -0.342855 -0.017389 +v -0.473074 -0.331762 -0.000118 +v -0.474044 -0.342855 0.017152 +v -0.478271 -0.390977 0.017152 +v -0.098411 -0.232880 -0.035601 +v -0.098411 -0.240808 -0.000118 +v -0.098411 -0.144967 -0.035601 +v -0.098411 -0.232880 -0.035601 +v -0.098411 -0.122088 -0.000118 +v -0.098411 -0.144967 -0.035601 +v -0.098411 -0.144967 0.035364 +v -0.098411 -0.122088 -0.000118 +v -0.098411 -0.232880 0.035364 +v -0.098411 -0.144967 0.035364 +v -0.098411 -0.232880 0.035364 +v 0.000000 -0.094464 0.000000 +v 0.043796 -0.094464 0.105844 +v 0.105811 -0.094464 0.043875 +v -0.043875 -0.094464 0.105811 +v -0.105844 -0.094464 0.043796 +v -0.105811 -0.094464 -0.043875 +v -0.043796 -0.094464 -0.105844 +v 0.043875 -0.094464 -0.105811 +v 0.105844 -0.094464 -0.043796 +v 0.043796 -0.255563 0.105844 +v 0.105811 -0.255563 0.043875 +v 0.105811 -0.094464 0.043875 +v 0.043796 -0.094464 0.105844 +v -0.043875 -0.255563 0.105811 +v 0.043796 -0.255563 0.105844 +v 0.043796 -0.094464 0.105844 +v -0.043875 -0.094464 0.105811 +v -0.105844 -0.255563 0.043796 +v -0.043875 -0.255563 0.105811 +v -0.043875 -0.094464 0.105811 +v -0.105844 -0.094464 0.043796 +v -0.105811 -0.255563 -0.043875 +v -0.105844 -0.255563 0.043796 +v -0.105844 -0.094464 0.043796 +v -0.105811 -0.094464 -0.043875 +v -0.043796 -0.255563 -0.105844 +v -0.105811 -0.255563 -0.043875 +v -0.105811 -0.094464 -0.043875 +v -0.043796 -0.094464 -0.105844 +v 0.043875 -0.255563 -0.105811 +v -0.043796 -0.255563 -0.105844 +v -0.043796 -0.094464 -0.105844 +v 0.043875 -0.094464 -0.105811 +v 0.105844 -0.255563 -0.043796 +v 0.043875 -0.255563 -0.105811 +v 0.043875 -0.094464 -0.105811 +v 0.105844 -0.094464 -0.043796 +v 0.105811 -0.255563 0.043875 +v 0.105844 -0.255563 -0.043796 +v 0.105844 -0.094464 -0.043796 +v 0.105811 -0.094464 0.043875 +v 0.000000 -0.255563 0.000000 +v 0.105811 -0.255563 0.043875 +v 0.043796 -0.255563 0.105844 +v -0.043875 -0.255563 0.105811 +v -0.105844 -0.255563 0.043796 +v -0.105811 -0.255563 -0.043875 +v -0.043796 -0.255563 -0.105844 +v 0.043875 -0.255563 -0.105811 +v 0.105844 -0.255563 -0.043796 +v -0.275954 0.604340 0.275954 +v -0.275954 0.604340 -0.275954 +v -0.275954 0.612392 -0.275954 +v -0.275954 0.612392 0.275954 +v -0.275954 0.604340 -0.275954 +v 0.275954 0.604340 -0.275954 +v 0.275954 0.612392 -0.275954 +v -0.275954 0.612392 -0.275954 +v 0.275954 0.604340 -0.275954 +v 0.275954 0.604340 0.275954 +v 0.275954 0.612392 0.275954 +v 0.275954 0.612392 -0.275954 +v 0.275954 0.604340 0.275954 +v -0.275954 0.604340 0.275954 +v -0.275954 0.612392 0.275954 +v 0.275954 0.612392 0.275954 +v -0.275954 0.612392 0.275954 +v -0.275954 0.612392 -0.275954 +v -0.284007 0.611587 -0.284007 +v -0.284007 0.611587 0.284007 +v -0.275954 0.612392 -0.275954 +v 0.275954 0.612392 -0.275954 +v 0.284007 0.611587 -0.284007 +v -0.284007 0.611587 -0.284007 +v 0.275954 0.612392 -0.275954 +v 0.275954 0.612392 0.275954 +v 0.284007 0.611587 0.284007 +v 0.284007 0.611587 -0.284007 +v 0.275954 0.612392 0.275954 +v -0.275954 0.612392 0.275954 +v -0.284007 0.611587 0.284007 +v 0.284007 0.611587 0.284007 +v -0.284007 0.611587 0.284007 +v -0.284007 0.611587 -0.284007 +v -0.284007 0.603535 -0.284007 +v -0.284007 0.603535 0.284007 +v -0.284007 0.611587 -0.284007 +v 0.284007 0.611587 -0.284007 +v 0.284007 0.603535 -0.284007 +v -0.284007 0.603535 -0.284007 +v 0.284007 0.611587 -0.284007 +v 0.284007 0.611587 0.284007 +v 0.284007 0.603535 0.284007 +v 0.284007 0.603535 -0.284007 +v 0.284007 0.611587 0.284007 +v -0.284007 0.611587 0.284007 +v -0.284007 0.603535 0.284007 +v 0.284007 0.603535 0.284007 +v -0.507297 0.549194 0.507297 +v 0.507297 0.549194 0.507297 +v 0.507297 0.550000 0.507297 +v -0.507297 0.550000 0.507297 +v 0.507297 0.549194 0.507297 +v 0.507297 0.549194 -0.507297 +v 0.507297 0.550000 -0.507297 +v 0.507297 0.550000 0.507297 +v 0.507297 0.549194 -0.507297 +v -0.507297 0.549194 -0.507297 +v -0.507297 0.550000 -0.507297 +v 0.507297 0.550000 -0.507297 +v -0.507297 0.549194 -0.507297 +v -0.507297 0.549194 0.507297 +v -0.507297 0.550000 0.507297 +v -0.507297 0.550000 -0.507297 +v 0.507297 0.558052 0.507297 +v -0.507297 0.558052 0.507297 +v 0.507297 0.558052 -0.507297 +v 0.507297 0.558052 0.507297 +v -0.507297 0.558052 -0.507297 +v 0.507297 0.558052 -0.507297 +v -0.507297 0.558052 0.507297 +v -0.507297 0.558052 -0.507297 +v 0.499245 0.566104 0.499245 +v -0.499245 0.566104 0.499245 +v 0.499245 0.566104 -0.499245 +v 0.499245 0.566104 0.499245 +v -0.499245 0.566104 -0.499245 +v 0.499245 0.566104 -0.499245 +v -0.499245 0.566104 0.499245 +v -0.499245 0.566104 -0.499245 +v 0.499245 0.574157 0.499245 +v -0.499245 0.574157 0.499245 +v 0.499245 0.574157 -0.499245 +v 0.499245 0.574157 0.499245 +v -0.499245 0.574157 -0.499245 +v 0.499245 0.574157 -0.499245 +v -0.499245 0.574157 0.499245 +v -0.499245 0.574157 -0.499245 +v 0.491193 0.582209 0.491193 +v -0.491193 0.582209 0.491193 +v 0.491193 0.582209 -0.491193 +v 0.491193 0.582209 0.491193 +v -0.491193 0.582209 -0.491193 +v 0.491193 0.582209 -0.491193 +v -0.491193 0.582209 0.491193 +v -0.491193 0.582209 -0.491193 +v -0.491193 0.582209 0.491193 +v 0.491193 0.582209 0.491193 +v 0.483140 0.583014 0.483140 +v -0.483140 0.583014 0.483140 +v 0.491193 0.582209 0.491193 +v 0.491193 0.582209 -0.491193 +v 0.483140 0.583014 -0.483140 +v 0.483140 0.583014 0.483140 +v 0.491193 0.582209 -0.491193 +v -0.491193 0.582209 -0.491193 +v -0.483140 0.583014 -0.483140 +v 0.483140 0.583014 -0.483140 +v -0.491193 0.582209 -0.491193 +v -0.491193 0.582209 0.491193 +v -0.483140 0.583014 0.483140 +v -0.483140 0.583014 -0.483140 +v -0.314041 0.591939 -0.314041 +v -0.314041 0.591939 0.314041 +v 0.314041 0.591939 -0.314041 +v -0.314041 0.591939 -0.314041 +v 0.314041 0.591939 0.314041 +v 0.314041 0.591939 -0.314041 +v -0.314041 0.591939 0.314041 +v 0.314041 0.591939 0.314041 +v -0.322094 0.591134 -0.322094 +v -0.322094 0.591134 0.322094 +v 0.322094 0.591134 -0.322094 +v -0.322094 0.591134 -0.322094 +v 0.322094 0.591134 0.322094 +v 0.322094 0.591134 -0.322094 +v -0.322094 0.591134 0.322094 +v 0.322094 0.591134 0.322094 +v -0.322094 0.583082 -0.322094 +v -0.322094 0.583082 0.322094 +v 0.322094 0.583082 -0.322094 +v -0.322094 0.583082 -0.322094 +v 0.322094 0.583082 0.322094 +v 0.322094 0.583082 -0.322094 +v -0.322094 0.583082 0.322094 +v 0.322094 0.583082 0.322094 +v -0.322094 0.583082 0.322094 +v -0.322094 0.583082 -0.322094 +v -0.483140 0.575029 -0.483140 +v -0.483140 0.575029 0.483140 +v -0.322094 0.583082 -0.322094 +v 0.322094 0.583082 -0.322094 +v 0.483140 0.575029 -0.483140 +v -0.483140 0.575029 -0.483140 +v 0.322094 0.583082 -0.322094 +v 0.322094 0.583082 0.322094 +v 0.483140 0.575029 0.483140 +v 0.483140 0.575029 -0.483140 +v 0.322094 0.583082 0.322094 +v -0.322094 0.583082 0.322094 +v -0.483140 0.575029 0.483140 +v 0.483140 0.575029 0.483140 +v -0.483140 0.575029 0.483140 +v -0.483140 0.575029 -0.483140 +v -0.483140 0.583014 -0.483140 +v -0.483140 0.583014 0.483140 +v -0.483140 0.575029 -0.483140 +v 0.483140 0.575029 -0.483140 +v 0.483140 0.583014 -0.483140 +v -0.483140 0.583014 -0.483140 +v 0.483140 0.575029 -0.483140 +v 0.483140 0.575029 0.483140 +v 0.483140 0.583014 0.483140 +v 0.483140 0.583014 -0.483140 +v 0.483140 0.575029 0.483140 +v -0.483140 0.575029 0.483140 +v -0.483140 0.583014 0.483140 +v 0.483140 0.583014 0.483140 +v 0.275954 0.604340 -0.275954 +v -0.275954 0.604340 -0.275954 +v -0.275954 0.604340 0.275954 +v 0.275954 0.604340 0.275954 +v 0.507297 0.549194 -0.507297 +v 0.507297 0.549194 0.507297 +v -0.507297 0.549194 0.507297 +v -0.507297 0.549194 -0.507297 +v 0.061122 0.493612 0.044408 +v 0.075551 0.493612 0.000000 +v 0.153763 0.549783 0.000000 +v 0.124397 0.549782 0.090379 +v 0.023346 0.493612 0.071853 +v 0.047515 0.549782 0.146237 +v -0.023346 0.493612 0.071853 +v -0.047515 0.549782 0.146237 +v -0.061122 0.493612 0.044408 +v -0.124396 0.549782 0.090380 +v -0.075551 0.493612 0.000000 +v -0.153763 0.549783 0.000000 +v -0.061122 0.493612 -0.044407 +v -0.124397 0.549783 -0.090379 +v -0.023346 0.493612 -0.071853 +v -0.047515 0.549783 -0.146237 +v 0.023346 0.493612 -0.071853 +v 0.047515 0.549783 -0.146237 +v 0.061122 0.493612 -0.044407 +v 0.124396 0.549783 -0.090379 +v 0.039643 0.457110 0.028802 +v 0.049002 0.457110 0.000000 +v 0.015142 0.457110 0.046603 +v -0.015142 0.457110 0.046603 +v -0.039643 0.457110 0.028802 +v -0.049002 0.457110 0.000000 +v -0.039643 0.457110 -0.028802 +v -0.015142 0.457110 -0.046603 +v 0.015142 0.457110 -0.046603 +v 0.039643 0.457110 -0.028802 +v 0.065534 -0.100432 0.047613 +v 0.081005 -0.100432 0.000000 +v 0.081005 -0.082613 0.000000 +v 0.065534 -0.082613 0.047613 +v 0.025032 -0.100432 0.077040 +v 0.065534 -0.100432 0.047613 +v 0.065534 -0.082613 0.047613 +v 0.025032 -0.082613 0.077040 +v -0.025032 -0.100432 0.077040 +v 0.025032 -0.100432 0.077040 +v 0.025032 -0.082613 0.077040 +v -0.025032 -0.082613 0.077040 +v -0.065534 -0.100432 0.047613 +v -0.025032 -0.100432 0.077040 +v -0.025032 -0.082613 0.077040 +v -0.065534 -0.082613 0.047613 +v -0.081005 -0.100432 0.000000 +v -0.065534 -0.100432 0.047613 +v -0.065534 -0.082613 0.047613 +v -0.081005 -0.082613 0.000000 +v -0.065534 -0.100432 -0.047613 +v -0.081005 -0.100432 0.000000 +v -0.081005 -0.082613 0.000000 +v -0.065534 -0.082613 -0.047613 +v -0.025032 -0.100432 -0.077040 +v -0.065534 -0.100432 -0.047613 +v -0.065534 -0.082613 -0.047613 +v -0.025032 -0.082613 -0.077040 +v 0.025032 -0.100432 -0.077040 +v -0.025032 -0.100432 -0.077040 +v -0.025032 -0.082613 -0.077040 +v 0.025032 -0.082613 -0.077040 +v 0.065534 -0.100432 -0.047613 +v 0.025032 -0.100432 -0.077040 +v 0.025032 -0.082613 -0.077040 +v 0.065534 -0.082613 -0.047613 +v 0.081005 -0.100432 0.000000 +v 0.065534 -0.100432 -0.047613 +v 0.065534 -0.082613 -0.047613 +v 0.081005 -0.082613 0.000000 +v 0.065534 -0.082613 0.047613 +v 0.081005 -0.082613 0.000000 +v 0.062269 -0.081722 0.000000 +v 0.050377 -0.081722 0.036601 +v 0.025032 -0.082613 0.077040 +v 0.065534 -0.082613 0.047613 +v 0.050377 -0.081722 0.036601 +v 0.019242 -0.081722 0.059221 +v -0.025032 -0.082613 0.077040 +v 0.025032 -0.082613 0.077040 +v 0.019242 -0.081722 0.059221 +v -0.019242 -0.081722 0.059221 +v -0.065534 -0.082613 0.047613 +v -0.025032 -0.082613 0.077040 +v -0.019242 -0.081722 0.059221 +v -0.050377 -0.081722 0.036601 +v -0.081005 -0.082613 0.000000 +v -0.065534 -0.082613 0.047613 +v -0.050377 -0.081722 0.036601 +v -0.062269 -0.081722 0.000000 +v -0.065534 -0.082613 -0.047613 +v -0.081005 -0.082613 0.000000 +v -0.062269 -0.081722 0.000000 +v -0.050377 -0.081722 -0.036601 +v -0.025032 -0.082613 -0.077040 +v -0.065534 -0.082613 -0.047613 +v -0.050377 -0.081722 -0.036601 +v -0.019242 -0.081722 -0.059221 +v 0.025032 -0.082613 -0.077040 +v -0.025032 -0.082613 -0.077040 +v -0.019242 -0.081722 -0.059221 +v 0.019242 -0.081722 -0.059221 +v 0.065534 -0.082613 -0.047613 +v 0.025032 -0.082613 -0.077040 +v 0.019242 -0.081722 -0.059221 +v 0.050377 -0.081722 -0.036601 +v 0.081005 -0.082613 0.000000 +v 0.065534 -0.082613 -0.047613 +v 0.050377 -0.081722 -0.036601 +v 0.062269 -0.081722 0.000000 +v 0.050377 -0.081722 0.036601 +v 0.062269 -0.081722 0.000000 +v 0.062269 -0.063904 0.000000 +v 0.050377 -0.063904 0.036601 +v 0.019242 -0.081722 0.059221 +v 0.050377 -0.081722 0.036601 +v 0.050377 -0.063904 0.036601 +v 0.019242 -0.063904 0.059221 +v -0.019242 -0.081722 0.059221 +v 0.019242 -0.081722 0.059221 +v 0.019242 -0.063904 0.059221 +v -0.019242 -0.063904 0.059221 +v -0.050377 -0.081722 0.036601 +v -0.019242 -0.081722 0.059221 +v -0.019242 -0.063904 0.059221 +v -0.050377 -0.063904 0.036601 +v -0.062269 -0.081722 0.000000 +v -0.050377 -0.081722 0.036601 +v -0.050377 -0.063904 0.036601 +v -0.062269 -0.063904 0.000000 +v -0.050377 -0.081722 -0.036601 +v -0.062269 -0.081722 0.000000 +v -0.062269 -0.063904 0.000000 +v -0.050377 -0.063904 -0.036601 +v -0.019242 -0.081722 -0.059221 +v -0.050377 -0.081722 -0.036601 +v -0.050377 -0.063904 -0.036601 +v -0.019242 -0.063904 -0.059221 +v 0.019242 -0.081722 -0.059221 +v -0.019242 -0.081722 -0.059221 +v -0.019242 -0.063904 -0.059221 +v 0.019242 -0.063904 -0.059221 +v 0.050377 -0.081722 -0.036601 +v 0.019242 -0.081722 -0.059221 +v 0.019242 -0.063904 -0.059221 +v 0.050377 -0.063904 -0.036601 +v 0.062269 -0.081722 0.000000 +v 0.050377 -0.081722 -0.036601 +v 0.050377 -0.063904 -0.036601 +v 0.062269 -0.063904 0.000000 +v 0.050377 -0.063904 0.036601 +v 0.062269 -0.063904 0.000000 +v 0.071637 -0.059449 0.000000 +v 0.057955 -0.059449 0.042107 +v 0.019242 -0.063904 0.059221 +v 0.050377 -0.063904 0.036601 +v 0.057955 -0.059449 0.042107 +v 0.022137 -0.059449 0.068131 +v -0.019242 -0.063904 0.059221 +v 0.019242 -0.063904 0.059221 +v 0.022137 -0.059449 0.068131 +v -0.022137 -0.059449 0.068131 +v -0.050377 -0.063904 0.036601 +v -0.019242 -0.063904 0.059221 +v -0.022137 -0.059449 0.068131 +v -0.057955 -0.059449 0.042107 +v -0.062269 -0.063904 0.000000 +v -0.050377 -0.063904 0.036601 +v -0.057955 -0.059449 0.042107 +v -0.071637 -0.059449 0.000000 +v -0.050377 -0.063904 -0.036601 +v -0.062269 -0.063904 0.000000 +v -0.071637 -0.059449 0.000000 +v -0.057955 -0.059449 -0.042107 +v -0.019242 -0.063904 -0.059221 +v -0.050377 -0.063904 -0.036601 +v -0.057955 -0.059449 -0.042107 +v -0.022137 -0.059449 -0.068131 +v 0.019242 -0.063904 -0.059221 +v -0.019242 -0.063904 -0.059221 +v -0.022137 -0.059449 -0.068131 +v 0.022137 -0.059449 -0.068131 +v 0.050377 -0.063904 -0.036601 +v 0.019242 -0.063904 -0.059221 +v 0.022137 -0.059449 -0.068131 +v 0.057955 -0.059449 -0.042107 +v 0.062269 -0.063904 0.000000 +v 0.050377 -0.063904 -0.036601 +v 0.057955 -0.059449 -0.042107 +v 0.071637 -0.059449 0.000000 +v 0.057955 -0.059449 0.042107 +v 0.071637 -0.059449 0.000000 +v 0.071637 -0.050540 0.000000 +v 0.057955 -0.050540 0.042107 +v 0.022137 -0.059449 0.068131 +v 0.057955 -0.059449 0.042107 +v 0.057955 -0.050540 0.042107 +v 0.022137 -0.050540 0.068131 +v -0.022137 -0.059449 0.068131 +v 0.022137 -0.059449 0.068131 +v 0.022137 -0.050540 0.068131 +v -0.022137 -0.050540 0.068131 +v -0.057955 -0.059449 0.042107 +v -0.022137 -0.059449 0.068131 +v -0.022137 -0.050540 0.068131 +v -0.057955 -0.050540 0.042107 +v -0.071637 -0.059449 0.000000 +v -0.057955 -0.059449 0.042107 +v -0.057955 -0.050540 0.042107 +v -0.071637 -0.050540 0.000000 +v -0.057955 -0.059449 -0.042107 +v -0.071637 -0.059449 0.000000 +v -0.071637 -0.050540 0.000000 +v -0.057955 -0.050540 -0.042107 +v -0.022137 -0.059449 -0.068131 +v -0.057955 -0.059449 -0.042107 +v -0.057955 -0.050540 -0.042107 +v -0.022137 -0.050540 -0.068131 +v 0.022137 -0.059449 -0.068131 +v -0.022137 -0.059449 -0.068131 +v -0.022137 -0.050540 -0.068131 +v 0.022137 -0.050540 -0.068131 +v 0.057955 -0.059449 -0.042107 +v 0.022137 -0.059449 -0.068131 +v 0.022137 -0.050540 -0.068131 +v 0.057955 -0.050540 -0.042107 +v 0.071637 -0.059449 0.000000 +v 0.057955 -0.059449 -0.042107 +v 0.057955 -0.050540 -0.042107 +v 0.071637 -0.050540 0.000000 +v 0.057955 -0.050540 0.042107 +v 0.071637 -0.050540 0.000000 +v 0.062269 -0.046085 0.000000 +v 0.050377 -0.046085 0.036601 +v 0.022137 -0.050540 0.068131 +v 0.057955 -0.050540 0.042107 +v 0.050377 -0.046085 0.036601 +v 0.019242 -0.046085 0.059221 +v -0.022137 -0.050540 0.068131 +v 0.022137 -0.050540 0.068131 +v 0.019242 -0.046085 0.059221 +v -0.019242 -0.046085 0.059221 +v -0.057955 -0.050540 0.042107 +v -0.022137 -0.050540 0.068131 +v -0.019242 -0.046085 0.059221 +v -0.050377 -0.046085 0.036601 +v -0.071637 -0.050540 0.000000 +v -0.057955 -0.050540 0.042107 +v -0.050377 -0.046085 0.036601 +v -0.062269 -0.046085 0.000000 +v -0.057955 -0.050540 -0.042107 +v -0.071637 -0.050540 0.000000 +v -0.062269 -0.046085 0.000000 +v -0.050377 -0.046085 -0.036601 +v -0.022137 -0.050540 -0.068131 +v -0.057955 -0.050540 -0.042107 +v -0.050377 -0.046085 -0.036601 +v -0.019242 -0.046085 -0.059221 +v 0.022137 -0.050540 -0.068131 +v -0.022137 -0.050540 -0.068131 +v -0.019242 -0.046085 -0.059221 +v 0.019242 -0.046085 -0.059221 +v 0.057955 -0.050540 -0.042107 +v 0.022137 -0.050540 -0.068131 +v 0.019242 -0.046085 -0.059221 +v 0.050377 -0.046085 -0.036601 +v 0.071637 -0.050540 0.000000 +v 0.057955 -0.050540 -0.042107 +v 0.050377 -0.046085 -0.036601 +v 0.062269 -0.046085 0.000000 +v 0.050377 -0.046085 0.036601 +v 0.062269 -0.046085 0.000000 +v 0.062269 -0.037015 0.000000 +v 0.050377 -0.037015 0.036601 +v 0.019242 -0.046085 0.059221 +v 0.050377 -0.046085 0.036601 +v 0.050377 -0.037015 0.036601 +v 0.019242 -0.037015 0.059221 +v -0.019242 -0.046085 0.059221 +v 0.019242 -0.046085 0.059221 +v 0.019242 -0.037015 0.059221 +v -0.019242 -0.037015 0.059221 +v -0.050377 -0.046085 0.036601 +v -0.019242 -0.046085 0.059221 +v -0.019242 -0.037015 0.059221 +v -0.050377 -0.037015 0.036601 +v -0.062269 -0.046085 0.000000 +v -0.050377 -0.046085 0.036601 +v -0.050377 -0.037015 0.036601 +v -0.062269 -0.037015 0.000000 +v -0.050377 -0.046085 -0.036601 +v -0.062269 -0.046085 0.000000 +v -0.062269 -0.037015 0.000000 +v -0.050377 -0.037015 -0.036601 +v -0.019242 -0.046085 -0.059221 +v -0.050377 -0.046085 -0.036601 +v -0.050377 -0.037015 -0.036601 +v -0.019242 -0.037015 -0.059221 +v 0.019242 -0.046085 -0.059221 +v -0.019242 -0.046085 -0.059221 +v -0.019242 -0.037015 -0.059221 +v 0.019242 -0.037015 -0.059221 +v 0.050377 -0.046085 -0.036601 +v 0.019242 -0.046085 -0.059221 +v 0.019242 -0.037015 -0.059221 +v 0.050377 -0.037015 -0.036601 +v 0.062269 -0.046085 0.000000 +v 0.050377 -0.046085 -0.036601 +v 0.050377 -0.037015 -0.036601 +v 0.062269 -0.037015 0.000000 +v 0.035221 0.414309 0.025590 +v 0.043536 0.414309 0.000000 +v 0.049002 0.457110 0.000000 +v 0.039643 0.457110 0.028802 +v 0.013453 0.414309 0.041405 +v 0.015142 0.457110 0.046603 +v -0.013453 0.414309 0.041405 +v -0.015142 0.457110 0.046603 +v -0.035221 0.414309 0.025590 +v -0.039643 0.457110 0.028802 +v -0.043536 0.414309 0.000000 +v -0.049002 0.457110 0.000000 +v -0.035221 0.414309 -0.025590 +v -0.039643 0.457110 -0.028802 +v -0.013453 0.414309 -0.041405 +v -0.015142 0.457110 -0.046603 +v 0.013453 0.414309 -0.041405 +v 0.015142 0.457110 -0.046603 +v 0.035221 0.414309 -0.025590 +v 0.013453 0.414309 -0.041405 +v 0.015142 0.457110 -0.046603 +v 0.039643 0.457110 -0.028802 +v 0.051175 0.223460 0.037181 +v 0.063256 0.223460 0.000000 +v 0.019547 0.223460 0.060160 +v -0.019547 0.223460 0.060160 +v -0.051175 0.223460 0.037181 +v -0.063256 0.223460 0.000000 +v -0.051175 0.223460 -0.037181 +v -0.019547 0.223460 -0.060160 +v 0.019547 0.223460 -0.060160 +v 0.051176 0.223460 -0.037181 +v 0.019547 0.223460 -0.060160 +v 0.076220 0.102045 0.055377 +v 0.094213 0.102045 0.000000 +v 0.029113 0.102045 0.089602 +v -0.029113 0.102045 0.089602 +v -0.076220 0.102045 0.055377 +v -0.094213 0.102045 0.000000 +v -0.076220 0.102045 -0.055377 +v -0.029113 0.102045 -0.089602 +v 0.029113 0.102045 -0.089602 +v 0.076220 0.102045 -0.055377 +v 0.029113 0.102045 -0.089602 +v 0.068919 -0.002139 0.050073 +v 0.085189 -0.002139 0.000000 +v 0.026325 -0.002139 0.081019 +v -0.026325 -0.002139 0.081019 +v -0.068919 -0.002139 0.050073 +v -0.085189 -0.002139 0.000000 +v -0.068919 -0.002139 -0.050073 +v -0.026325 -0.002139 -0.081019 +v 0.026325 -0.002139 -0.081019 +v 0.068919 -0.002139 -0.050073 +v 0.026325 -0.002139 -0.081019 +v 0.050377 -0.037015 0.036601 +v 0.062269 -0.037015 0.000000 +v 0.019242 -0.037015 0.059221 +v -0.019242 -0.037015 0.059221 +v -0.050377 -0.037015 0.036601 +v -0.062269 -0.037015 0.000000 +v -0.050377 -0.037015 -0.036601 +v -0.019242 -0.037015 -0.059221 +v 0.019242 -0.037015 -0.059221 +v 0.050377 -0.037015 -0.036601 +v 0.019242 -0.037015 -0.059221 +vt 0.017083 0.467481 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.077277 0.475172 +vt 0.017498 0.425773 +vt 0.022716 0.366365 +vt 0.077611 0.335458 +vt 0.077301 0.425780 +vt 0.022716 0.366365 +vt 0.023914 0.320840 +vt 0.077682 0.295421 +vt 0.077611 0.335458 +vt 0.022716 0.366365 +vt 0.077611 0.335458 +vt 0.022716 0.366365 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.077611 0.335458 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.141617 0.425888 +vt 0.141203 0.458853 +vt 0.140908 0.357917 +vt 0.141617 0.425888 +vt 0.077611 0.335458 +vt 0.077682 0.295421 +vt 0.140908 0.303558 +vt 0.140908 0.357917 +vt 0.077682 0.295421 +vt 0.077611 0.335458 +vt 0.140908 0.357917 +vt 0.140908 0.303558 +vt 0.141617 0.425888 +vt 0.140908 0.357917 +vt 0.141617 0.425888 +vt 0.223614 0.381380 +vt 0.233628 0.407934 +vt 0.203363 0.329596 +vt 0.223614 0.381380 +vt 0.187732 0.293268 +vt 0.203363 0.329596 +vt 0.203363 0.329596 +vt 0.187732 0.293268 +vt 0.223614 0.381380 +vt 0.203363 0.329596 +vt 0.223614 0.381380 +vt 0.308037 0.291333 +vt 0.324950 0.321248 +vt 0.279922 0.245271 +vt 0.308037 0.291333 +vt 0.264859 0.213261 +vt 0.279922 0.245271 +vt 0.279922 0.245271 +vt 0.264859 0.213261 +vt 0.308037 0.291333 +vt 0.279922 0.245271 +vt 0.308037 0.291333 +vt 0.377000 0.255623 +vt 0.378700 0.295995 +vt 0.372639 0.156040 +vt 0.377000 0.255623 +vt 0.367735 0.111762 +vt 0.372639 0.156040 +vt 0.372639 0.156040 +vt 0.367735 0.111762 +vt 0.377000 0.255623 +vt 0.372639 0.156040 +vt 0.377000 0.255623 +vt 0.393655 0.410963 +vt 0.467714 0.453591 +vt 0.467714 0.410963 +vt 0.348935 0.453591 +vt 0.321554 0.410963 +vt 0.348935 0.368334 +vt 0.467714 0.368334 +vt 0.486443 0.230599 +vt 0.486443 0.273314 +vt 0.486443 0.122067 +vt 0.486443 0.230599 +vt 0.486443 0.071872 +vt 0.486443 0.122067 +vt 0.486443 0.122067 +vt 0.486443 0.071872 +vt 0.486443 0.230599 +vt 0.486443 0.122067 +vt 0.486443 0.230599 +vt 0.017083 0.467481 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.077277 0.475172 +vt 0.017498 0.425773 +vt 0.022716 0.366365 +vt 0.077611 0.335458 +vt 0.077301 0.425780 +vt 0.022716 0.366365 +vt 0.023914 0.320840 +vt 0.077682 0.295421 +vt 0.077611 0.335458 +vt 0.022716 0.366365 +vt 0.077611 0.335458 +vt 0.022716 0.366365 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.077611 0.335458 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.141617 0.425888 +vt 0.141203 0.458853 +vt 0.140908 0.357917 +vt 0.141617 0.425888 +vt 0.077611 0.335458 +vt 0.077682 0.295421 +vt 0.140908 0.303558 +vt 0.140908 0.357917 +vt 0.077682 0.295421 +vt 0.077611 0.335458 +vt 0.140908 0.357917 +vt 0.140908 0.303558 +vt 0.141617 0.425888 +vt 0.140908 0.357917 +vt 0.141617 0.425888 +vt 0.223614 0.381380 +vt 0.233628 0.407934 +vt 0.203363 0.329596 +vt 0.223614 0.381380 +vt 0.187732 0.293268 +vt 0.203363 0.329596 +vt 0.203363 0.329596 +vt 0.187732 0.293268 +vt 0.223614 0.381380 +vt 0.203363 0.329596 +vt 0.223614 0.381380 +vt 0.308037 0.291333 +vt 0.324950 0.321248 +vt 0.279922 0.245271 +vt 0.308037 0.291333 +vt 0.264859 0.213261 +vt 0.279922 0.245271 +vt 0.279922 0.245271 +vt 0.264859 0.213261 +vt 0.308037 0.291333 +vt 0.279922 0.245271 +vt 0.308037 0.291333 +vt 0.377000 0.255623 +vt 0.378700 0.295995 +vt 0.372639 0.156040 +vt 0.377000 0.255623 +vt 0.367735 0.111762 +vt 0.372639 0.156040 +vt 0.372639 0.156040 +vt 0.367735 0.111762 +vt 0.377000 0.255623 +vt 0.372639 0.156040 +vt 0.377000 0.255623 +vt 0.393655 0.410963 +vt 0.467714 0.453591 +vt 0.467714 0.410963 +vt 0.348935 0.453591 +vt 0.321554 0.410963 +vt 0.348935 0.368334 +vt 0.467714 0.368334 +vt 0.486443 0.230599 +vt 0.486443 0.273314 +vt 0.486443 0.122067 +vt 0.486443 0.230599 +vt 0.486443 0.071872 +vt 0.486443 0.122067 +vt 0.486443 0.122067 +vt 0.486443 0.071872 +vt 0.486443 0.230599 +vt 0.486443 0.122067 +vt 0.486443 0.230599 +vt 0.017083 0.467481 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.077277 0.475172 +vt 0.017498 0.425773 +vt 0.022716 0.366365 +vt 0.077611 0.335458 +vt 0.077301 0.425780 +vt 0.022716 0.366365 +vt 0.023914 0.320840 +vt 0.077682 0.295421 +vt 0.077611 0.335458 +vt 0.022716 0.366365 +vt 0.077611 0.335458 +vt 0.022716 0.366365 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.077611 0.335458 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.141617 0.425888 +vt 0.141203 0.458853 +vt 0.140908 0.357917 +vt 0.141617 0.425888 +vt 0.077611 0.335458 +vt 0.077682 0.295421 +vt 0.140908 0.303558 +vt 0.140908 0.357917 +vt 0.077682 0.295421 +vt 0.077611 0.335458 +vt 0.140908 0.357917 +vt 0.140908 0.303558 +vt 0.141617 0.425888 +vt 0.140908 0.357917 +vt 0.141617 0.425888 +vt 0.223614 0.381380 +vt 0.233628 0.407934 +vt 0.203363 0.329596 +vt 0.223614 0.381380 +vt 0.187732 0.293268 +vt 0.203363 0.329596 +vt 0.203363 0.329596 +vt 0.187732 0.293268 +vt 0.223614 0.381380 +vt 0.203363 0.329596 +vt 0.223614 0.381380 +vt 0.308037 0.291333 +vt 0.324950 0.321248 +vt 0.279922 0.245271 +vt 0.308037 0.291333 +vt 0.264859 0.213261 +vt 0.279922 0.245271 +vt 0.279922 0.245271 +vt 0.264859 0.213261 +vt 0.308037 0.291333 +vt 0.279922 0.245271 +vt 0.308037 0.291333 +vt 0.377000 0.255623 +vt 0.378700 0.295995 +vt 0.372639 0.156040 +vt 0.377000 0.255623 +vt 0.367735 0.111762 +vt 0.372639 0.156040 +vt 0.372639 0.156040 +vt 0.367735 0.111762 +vt 0.377000 0.255623 +vt 0.372639 0.156040 +vt 0.377000 0.255623 +vt 0.393655 0.410963 +vt 0.467714 0.453591 +vt 0.467714 0.410963 +vt 0.348935 0.453591 +vt 0.321554 0.410963 +vt 0.348935 0.368334 +vt 0.467714 0.368334 +vt 0.486443 0.230599 +vt 0.486443 0.273314 +vt 0.486443 0.122067 +vt 0.486443 0.230599 +vt 0.486443 0.071872 +vt 0.486443 0.122067 +vt 0.486443 0.122067 +vt 0.486443 0.071872 +vt 0.486443 0.230599 +vt 0.486443 0.122067 +vt 0.486443 0.230599 +vt 0.017083 0.467481 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.077277 0.475172 +vt 0.017498 0.425773 +vt 0.022716 0.366365 +vt 0.077611 0.335458 +vt 0.077301 0.425780 +vt 0.022716 0.366365 +vt 0.023914 0.320840 +vt 0.077682 0.295421 +vt 0.077611 0.335458 +vt 0.022716 0.366365 +vt 0.077611 0.335458 +vt 0.022716 0.366365 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.077611 0.335458 +vt 0.017498 0.425773 +vt 0.077301 0.425780 +vt 0.141617 0.425888 +vt 0.141203 0.458853 +vt 0.140908 0.357917 +vt 0.141617 0.425888 +vt 0.077611 0.335458 +vt 0.077682 0.295421 +vt 0.140908 0.303558 +vt 0.140908 0.357917 +vt 0.077682 0.295421 +vt 0.077611 0.335458 +vt 0.140908 0.357917 +vt 0.140908 0.303558 +vt 0.141617 0.425888 +vt 0.140908 0.357917 +vt 0.141617 0.425888 +vt 0.223614 0.381380 +vt 0.233628 0.407934 +vt 0.203363 0.329596 +vt 0.223614 0.381380 +vt 0.187732 0.293268 +vt 0.203363 0.329596 +vt 0.203363 0.329596 +vt 0.187732 0.293268 +vt 0.223614 0.381380 +vt 0.203363 0.329596 +vt 0.223614 0.381380 +vt 0.308037 0.291333 +vt 0.324950 0.321248 +vt 0.279922 0.245271 +vt 0.308037 0.291333 +vt 0.264859 0.213261 +vt 0.279922 0.245271 +vt 0.279922 0.245271 +vt 0.264859 0.213261 +vt 0.308037 0.291333 +vt 0.279922 0.245271 +vt 0.308037 0.291333 +vt 0.377000 0.255623 +vt 0.378700 0.295995 +vt 0.372639 0.156040 +vt 0.377000 0.255623 +vt 0.367735 0.111762 +vt 0.372639 0.156040 +vt 0.372639 0.156040 +vt 0.367735 0.111762 +vt 0.377000 0.255623 +vt 0.372639 0.156040 +vt 0.377000 0.255623 +vt 0.393655 0.410963 +vt 0.467714 0.453591 +vt 0.467714 0.410963 +vt 0.348935 0.453591 +vt 0.321554 0.410963 +vt 0.348935 0.368334 +vt 0.467714 0.368334 +vt 0.486443 0.230599 +vt 0.486443 0.273314 +vt 0.486443 0.122067 +vt 0.486443 0.230599 +vt 0.486443 0.071872 +vt 0.486443 0.122067 +vt 0.486443 0.122067 +vt 0.486443 0.071872 +vt 0.486443 0.230599 +vt 0.486443 0.122067 +vt 0.486443 0.230599 +vt 0.000000 1.000000 +vt 0.312949 0.385343 +vt 0.374010 0.385343 +vt 0.251887 0.385343 +vt 0.190825 0.385343 +vt 0.129763 0.385343 +vt 0.068702 0.385343 +vt 0.496134 0.385343 +vt 0.435072 0.385343 +vt 0.312949 0.498276 +vt 0.374010 0.498276 +vt 0.374010 0.385343 +vt 0.312949 0.385343 +vt 0.251887 0.498276 +vt 0.312949 0.498276 +vt 0.312949 0.385343 +vt 0.251887 0.385343 +vt 0.190825 0.498276 +vt 0.251887 0.498276 +vt 0.251887 0.385343 +vt 0.190825 0.385343 +vt 0.129763 0.498276 +vt 0.190825 0.498276 +vt 0.190825 0.385343 +vt 0.129763 0.385343 +vt 0.068702 0.498276 +vt 0.129763 0.498276 +vt 0.129763 0.385343 +vt 0.068702 0.385343 +vt 0.007640 0.498276 +vt 0.068702 0.498276 +vt 0.068702 0.385343 +vt 0.007640 0.385343 +vt 0.435072 0.498276 +vt 0.496134 0.498276 +vt 0.496134 0.385343 +vt 0.435072 0.385343 +vt 0.321935 0.273341 +vt 0.321962 0.201250 +vt 0.321962 0.201250 +vt 0.321935 0.273341 +vt 0.234927 0.237263 +vt 0.321935 0.273341 +vt 0.270940 0.324298 +vt 0.198849 0.324271 +vt 0.147891 0.273276 +vt 0.147918 0.201184 +vt 0.198914 0.150227 +vt 0.271005 0.150254 +vt 0.321962 0.201250 +vt 0.143227 0.361033 +vt 0.143227 0.144695 +vt 0.135916 0.138034 +vt 0.135916 0.368993 +vt 0.143227 0.144695 +vt 0.359565 0.144695 +vt 0.366875 0.138034 +vt 0.135916 0.138034 +vt 0.359565 0.144695 +vt 0.359565 0.361033 +vt 0.366875 0.368993 +vt 0.366875 0.138034 +vt 0.359565 0.361033 +vt 0.143227 0.361033 +vt 0.135916 0.368993 +vt 0.366875 0.368993 +vt 0.135916 0.368993 +vt 0.135916 0.138034 +vt 0.113352 0.114821 +vt 0.113352 0.390908 +vt 0.135916 0.138034 +vt 0.366875 0.138034 +vt 0.389439 0.114821 +vt 0.113352 0.114821 +vt 0.366875 0.138034 +vt 0.366875 0.368993 +vt 0.389439 0.390908 +vt 0.389439 0.114821 +vt 0.366875 0.368993 +vt 0.135916 0.368993 +vt 0.113352 0.390908 +vt 0.389439 0.390908 +vt 0.113352 0.390908 +vt 0.113352 0.114821 +vt 0.121903 0.123372 +vt 0.121903 0.382356 +vt 0.113352 0.114821 +vt 0.389439 0.114821 +vt 0.380888 0.123372 +vt 0.121903 0.123372 +vt 0.389439 0.114821 +vt 0.389439 0.390908 +vt 0.380888 0.382356 +vt 0.380888 0.123372 +vt 0.389439 0.390908 +vt 0.113352 0.390908 +vt 0.121903 0.382356 +vt 0.380888 0.382356 +vt 0.004820 0.499440 +vt 0.497971 0.499440 +vt 0.497971 0.499440 +vt 0.004820 0.499440 +vt 0.497971 0.499440 +vt 0.497971 0.006289 +vt 0.497971 0.006289 +vt 0.497971 0.499440 +vt 0.497971 0.006289 +vt 0.004820 0.006289 +vt 0.004820 0.006289 +vt 0.497971 0.006289 +vt 0.004820 0.006289 +vt 0.004820 0.499440 +vt 0.004820 0.499440 +vt 0.004820 0.006289 +vt 0.497971 0.499440 +vt 0.004820 0.499440 +vt 0.497971 0.006289 +vt 0.497971 0.499440 +vt 0.004820 0.006289 +vt 0.497971 0.006289 +vt 0.004820 0.499440 +vt 0.004820 0.006289 +vt 0.491654 0.493123 +vt 0.011137 0.493123 +vt 0.491654 0.012605 +vt 0.491654 0.493123 +vt 0.011137 0.012605 +vt 0.491654 0.012605 +vt 0.011137 0.493123 +vt 0.011137 0.012605 +vt 0.482370 0.483838 +vt 0.020421 0.483838 +vt 0.482370 0.021890 +vt 0.482370 0.483838 +vt 0.020421 0.021890 +vt 0.482370 0.021890 +vt 0.020421 0.483838 +vt 0.020421 0.021890 +vt 0.470567 0.472035 +vt 0.032224 0.472035 +vt 0.470567 0.033693 +vt 0.470567 0.472035 +vt 0.032224 0.033693 +vt 0.470567 0.033693 +vt 0.032224 0.472035 +vt 0.032224 0.033693 +vt 0.032224 0.472035 +vt 0.470567 0.472035 +vt 0.459013 0.460481 +vt 0.043778 0.460481 +vt 0.470567 0.472035 +vt 0.470567 0.033693 +vt 0.459013 0.045247 +vt 0.459013 0.460481 +vt 0.470567 0.033693 +vt 0.032224 0.033693 +vt 0.043778 0.045247 +vt 0.459013 0.045247 +vt 0.032224 0.033693 +vt 0.032224 0.472035 +vt 0.043778 0.460481 +vt 0.043778 0.045247 +vt 0.098754 0.100222 +vt 0.098754 0.405506 +vt 0.404037 0.100222 +vt 0.098754 0.100222 +vt 0.404037 0.405506 +vt 0.404037 0.100222 +vt 0.098754 0.405506 +vt 0.404037 0.405506 +vt 0.094840 0.096308 +vt 0.094840 0.409420 +vt 0.407951 0.096308 +vt 0.094840 0.096308 +vt 0.407951 0.409420 +vt 0.407951 0.096308 +vt 0.094840 0.409420 +vt 0.407951 0.409420 +vt 0.087012 0.088481 +vt 0.087012 0.417248 +vt 0.415779 0.088481 +vt 0.087012 0.088481 +vt 0.415779 0.417248 +vt 0.415779 0.088481 +vt 0.087012 0.417248 +vt 0.415779 0.417248 +vt 0.586243 0.413570 +vt 0.586243 0.086583 +vt 0.504496 0.004836 +vt 0.504496 0.495317 +vt 0.586243 0.086583 +vt 0.913231 0.086583 +vt 0.994978 0.004836 +vt 0.504496 0.004836 +vt 0.913231 0.086583 +vt 0.913231 0.413570 +vt 0.994978 0.495317 +vt 0.994978 0.004836 +vt 0.913231 0.413570 +vt 0.586243 0.413570 +vt 0.504496 0.495317 +vt 0.994978 0.495317 +vt 0.052083 0.452177 +vt 0.052083 0.053552 +vt 0.043778 0.045247 +vt 0.043778 0.460481 +vt 0.052083 0.053552 +vt 0.450708 0.053552 +vt 0.459013 0.045247 +vt 0.043778 0.045247 +vt 0.450708 0.053552 +vt 0.450708 0.452177 +vt 0.459013 0.460481 +vt 0.459013 0.045247 +vt 0.450708 0.452177 +vt 0.052083 0.452177 +vt 0.043778 0.460481 +vt 0.459013 0.460481 +vt 0.997798 0.502710 +vt 0.503545 0.502710 +vt 0.503545 0.996963 +vt 0.997798 0.996963 +vt 0.497971 0.006289 +vt 0.497971 0.499440 +vt 0.004820 0.499440 +vt 0.004820 0.006289 +vt 0.366183 0.254192 +vt 0.376207 0.221754 +vt 0.430543 0.221754 +vt 0.410142 0.287774 +vt 0.339940 0.274240 +vt 0.356731 0.328576 +vt 0.307501 0.274241 +vt 0.290711 0.328576 +vt 0.281258 0.254192 +vt 0.237300 0.287774 +vt 0.271234 0.221754 +vt 0.216899 0.221754 +vt 0.281258 0.189315 +vt 0.237300 0.155734 +vt 0.307501 0.169267 +vt 0.290711 0.114932 +vt 0.339940 0.169267 +vt 0.356731 0.114932 +vt 0.366183 0.189315 +vt 0.410142 0.155734 +vt 0.351262 0.242793 +vt 0.357763 0.221754 +vt 0.334240 0.255796 +vt 0.313201 0.255796 +vt 0.296180 0.242793 +vt 0.289678 0.221754 +vt 0.296180 0.200714 +vt 0.313201 0.187711 +vt 0.334240 0.187711 +vt 0.351262 0.200714 +vt 0.350121 0.494170 +vt 0.396949 0.494170 +vt 0.396949 0.469050 +vt 0.350121 0.469050 +vt 0.300793 0.494170 +vt 0.350121 0.494170 +vt 0.350121 0.469050 +vt 0.300793 0.469050 +vt 0.249801 0.494170 +vt 0.300793 0.494170 +vt 0.300793 0.469050 +vt 0.249801 0.469050 +vt 0.200473 0.494170 +vt 0.249801 0.494170 +vt 0.249801 0.469050 +vt 0.200473 0.469050 +vt 0.153645 0.494170 +vt 0.200473 0.494170 +vt 0.200473 0.469050 +vt 0.153645 0.469050 +vt 0.106818 0.494170 +vt 0.153645 0.494170 +vt 0.153645 0.469050 +vt 0.106818 0.469050 +vt 0.057489 0.494170 +vt 0.106818 0.494170 +vt 0.106818 0.469050 +vt 0.057489 0.469050 +vt 0.006498 0.494170 +vt 0.057489 0.494170 +vt 0.057489 0.469050 +vt 0.006498 0.469050 +vt 0.443776 0.494170 +vt 0.493105 0.494170 +vt 0.493105 0.469050 +vt 0.443776 0.469050 +vt 0.396949 0.494170 +vt 0.443776 0.494170 +vt 0.443776 0.469050 +vt 0.396949 0.469050 +vt 0.350121 0.469050 +vt 0.396949 0.469050 +vt 0.396949 0.467794 +vt 0.350121 0.467794 +vt 0.300793 0.469050 +vt 0.350121 0.469050 +vt 0.350121 0.467794 +vt 0.300793 0.467794 +vt 0.249801 0.469050 +vt 0.300793 0.469050 +vt 0.300793 0.467794 +vt 0.249801 0.467794 +vt 0.200473 0.469050 +vt 0.249801 0.469050 +vt 0.249801 0.467794 +vt 0.200473 0.467794 +vt 0.153645 0.469050 +vt 0.200473 0.469050 +vt 0.200473 0.467794 +vt 0.153645 0.467794 +vt 0.106818 0.469050 +vt 0.153645 0.469050 +vt 0.153645 0.467794 +vt 0.106818 0.467794 +vt 0.057489 0.469050 +vt 0.106818 0.469050 +vt 0.106818 0.467794 +vt 0.057489 0.467794 +vt 0.006498 0.469050 +vt 0.057489 0.469050 +vt 0.057489 0.467794 +vt 0.006498 0.467794 +vt 0.443776 0.469050 +vt 0.493105 0.469050 +vt 0.493105 0.467794 +vt 0.443776 0.467794 +vt 0.396949 0.469050 +vt 0.443776 0.469050 +vt 0.443776 0.467794 +vt 0.396949 0.467794 +vt 0.350121 0.467794 +vt 0.396949 0.467794 +vt 0.396949 0.442675 +vt 0.350121 0.442675 +vt 0.300793 0.467794 +vt 0.350121 0.467794 +vt 0.350121 0.442675 +vt 0.300793 0.442675 +vt 0.249801 0.467794 +vt 0.300793 0.467794 +vt 0.300793 0.442675 +vt 0.249801 0.442675 +vt 0.200473 0.467794 +vt 0.249801 0.467794 +vt 0.249801 0.442675 +vt 0.200473 0.442675 +vt 0.153645 0.467794 +vt 0.200473 0.467794 +vt 0.200473 0.442675 +vt 0.153645 0.442675 +vt 0.106818 0.467794 +vt 0.153645 0.467794 +vt 0.153645 0.442675 +vt 0.106818 0.442675 +vt 0.057489 0.467794 +vt 0.106818 0.467794 +vt 0.106818 0.442675 +vt 0.057489 0.442675 +vt 0.006498 0.467794 +vt 0.057489 0.467794 +vt 0.057489 0.442675 +vt 0.006498 0.442675 +vt 0.443776 0.467794 +vt 0.493105 0.467794 +vt 0.493105 0.442675 +vt 0.443776 0.442675 +vt 0.396949 0.467794 +vt 0.443776 0.467794 +vt 0.443776 0.442675 +vt 0.396949 0.442675 +vt 0.350121 0.442675 +vt 0.396949 0.442675 +vt 0.396949 0.436395 +vt 0.350121 0.436395 +vt 0.300793 0.442675 +vt 0.350121 0.442675 +vt 0.350121 0.436395 +vt 0.300793 0.436395 +vt 0.249801 0.442675 +vt 0.300793 0.442675 +vt 0.300793 0.436395 +vt 0.249801 0.436395 +vt 0.200473 0.442675 +vt 0.249801 0.442675 +vt 0.249801 0.436395 +vt 0.200473 0.436395 +vt 0.153645 0.442675 +vt 0.200473 0.442675 +vt 0.200473 0.436395 +vt 0.153645 0.436395 +vt 0.106818 0.442675 +vt 0.153645 0.442675 +vt 0.153645 0.436395 +vt 0.106818 0.436395 +vt 0.057489 0.442675 +vt 0.106818 0.442675 +vt 0.106818 0.436395 +vt 0.057489 0.436395 +vt 0.006498 0.442675 +vt 0.057489 0.442675 +vt 0.057489 0.436395 +vt 0.006498 0.436395 +vt 0.443776 0.442675 +vt 0.493105 0.442675 +vt 0.493105 0.436395 +vt 0.443776 0.436395 +vt 0.396949 0.442675 +vt 0.443776 0.442675 +vt 0.443776 0.436395 +vt 0.396949 0.436395 +vt 0.350121 0.436395 +vt 0.396949 0.436395 +vt 0.396949 0.423835 +vt 0.350121 0.423835 +vt 0.300793 0.436395 +vt 0.350121 0.436395 +vt 0.350121 0.423835 +vt 0.300793 0.423835 +vt 0.249801 0.436395 +vt 0.300793 0.436395 +vt 0.300793 0.423835 +vt 0.249801 0.423835 +vt 0.200473 0.436395 +vt 0.249801 0.436395 +vt 0.249801 0.423835 +vt 0.200473 0.423835 +vt 0.153645 0.436395 +vt 0.200473 0.436395 +vt 0.200473 0.423835 +vt 0.153645 0.423835 +vt 0.106818 0.436395 +vt 0.153645 0.436395 +vt 0.153645 0.423835 +vt 0.106818 0.423835 +vt 0.057489 0.436395 +vt 0.106818 0.436395 +vt 0.106818 0.423835 +vt 0.057489 0.423835 +vt 0.006498 0.436395 +vt 0.057489 0.436395 +vt 0.057489 0.423835 +vt 0.006498 0.423835 +vt 0.443776 0.436395 +vt 0.493105 0.436395 +vt 0.493105 0.423835 +vt 0.443776 0.423835 +vt 0.396949 0.436395 +vt 0.443776 0.436395 +vt 0.443776 0.423835 +vt 0.396949 0.423835 +vt 0.350121 0.423835 +vt 0.396949 0.423835 +vt 0.396949 0.417555 +vt 0.350121 0.417555 +vt 0.300793 0.423835 +vt 0.350121 0.423835 +vt 0.350121 0.417555 +vt 0.300793 0.417555 +vt 0.249801 0.423835 +vt 0.300793 0.423835 +vt 0.300793 0.417555 +vt 0.249801 0.417555 +vt 0.200473 0.423835 +vt 0.249801 0.423835 +vt 0.249801 0.417555 +vt 0.200473 0.417555 +vt 0.153645 0.423835 +vt 0.200473 0.423835 +vt 0.200473 0.417555 +vt 0.153645 0.417555 +vt 0.106818 0.423835 +vt 0.153645 0.423835 +vt 0.153645 0.417555 +vt 0.106818 0.417555 +vt 0.057489 0.423835 +vt 0.106818 0.423835 +vt 0.106818 0.417555 +vt 0.057489 0.417555 +vt 0.006498 0.423835 +vt 0.057489 0.423835 +vt 0.057489 0.417555 +vt 0.006498 0.417555 +vt 0.443776 0.423835 +vt 0.493105 0.423835 +vt 0.493105 0.417555 +vt 0.443776 0.417555 +vt 0.396949 0.423835 +vt 0.443776 0.423835 +vt 0.443776 0.417555 +vt 0.396949 0.417555 +vt 0.350121 0.417555 +vt 0.396949 0.417555 +vt 0.396949 0.404768 +vt 0.350121 0.404768 +vt 0.300793 0.417555 +vt 0.350121 0.417555 +vt 0.350121 0.404768 +vt 0.300793 0.404768 +vt 0.249801 0.417555 +vt 0.300793 0.417555 +vt 0.300793 0.404768 +vt 0.249801 0.404768 +vt 0.200473 0.417555 +vt 0.249801 0.417555 +vt 0.249801 0.404768 +vt 0.200473 0.404768 +vt 0.153645 0.417555 +vt 0.200473 0.417555 +vt 0.200473 0.404768 +vt 0.153645 0.404768 +vt 0.106818 0.417555 +vt 0.153645 0.417555 +vt 0.153645 0.404768 +vt 0.106818 0.404768 +vt 0.057489 0.417555 +vt 0.106818 0.417555 +vt 0.106818 0.404768 +vt 0.057489 0.404768 +vt 0.006498 0.417555 +vt 0.057489 0.417555 +vt 0.057489 0.404768 +vt 0.006498 0.404768 +vt 0.443776 0.417555 +vt 0.493105 0.417555 +vt 0.493105 0.404768 +vt 0.443776 0.404768 +vt 0.396949 0.417555 +vt 0.443776 0.417555 +vt 0.443776 0.404768 +vt 0.396949 0.404768 +vt 0.350998 0.547962 +vt 0.398319 0.547961 +vt 0.398319 0.498824 +vt 0.350998 0.498825 +vt 0.301150 0.547961 +vt 0.301150 0.498825 +vt 0.249620 0.547961 +vt 0.249620 0.498825 +vt 0.199772 0.547962 +vt 0.199772 0.498825 +vt 0.152451 0.547962 +vt 0.152451 0.498824 +vt 0.105130 0.547961 +vt 0.105130 0.498824 +vt 0.055282 0.547962 +vt 0.055282 0.498824 +vt 0.003753 0.547962 +vt 0.003753 0.498824 +vt 0.445640 0.547961 +vt 0.495488 0.547962 +vt 0.495488 0.498824 +vt 0.445640 0.498824 +vt 0.350998 0.737698 +vt 0.398319 0.737698 +vt 0.301150 0.737698 +vt 0.249620 0.737698 +vt 0.199772 0.737698 +vt 0.152451 0.737698 +vt 0.105130 0.737698 +vt 0.055282 0.737698 +vt 0.003753 0.737698 +vt 0.445640 0.737698 +vt 0.495488 0.737698 +vt 0.350998 0.858405 +vt 0.398319 0.858405 +vt 0.301150 0.858405 +vt 0.249620 0.858405 +vt 0.199772 0.858405 +vt 0.152451 0.858405 +vt 0.105130 0.858405 +vt 0.055282 0.858405 +vt 0.003753 0.858405 +vt 0.445640 0.858405 +vt 0.495488 0.858405 +vt 0.350998 0.961982 +vt 0.398319 0.961982 +vt 0.301150 0.961982 +vt 0.249620 0.961982 +vt 0.199772 0.961982 +vt 0.152451 0.961982 +vt 0.105130 0.961982 +vt 0.055282 0.961982 +vt 0.003753 0.961982 +vt 0.445640 0.961982 +vt 0.495488 0.961982 +vt 0.350998 0.996654 +vt 0.398319 0.996654 +vt 0.301150 0.996654 +vt 0.249620 0.996654 +vt 0.199772 0.996654 +vt 0.152451 0.996654 +vt 0.105130 0.996654 +vt 0.055282 0.996654 +vt 0.003753 0.996654 +vt 0.445640 0.996654 +vt 0.495488 0.996654 +vn 0.000001 -0.000117 -1.000000 +vn 0.000007 -0.000119 -1.000000 +vn 0.000004 -0.000642 -1.000000 +vn 0.000290 -0.001097 -0.999999 +vn 0.965539 -0.259953 0.012557 +vn 0.960748 -0.276359 0.024272 +vn 0.995038 -0.099144 0.008333 +vn 0.997311 0.073275 0.000826 +vn 0.384905 -0.746403 0.542891 +vn -0.062420 -0.728758 0.681921 +vn 0.161475 -0.510903 0.844336 +vn 0.298440 -0.528902 0.794478 +vn -0.388088 -0.822360 0.416066 +vn -0.374937 -0.503238 0.778571 +vn -0.967185 -0.253827 0.011142 +vn -0.969696 -0.243379 0.021376 +vn -0.995359 -0.095953 0.007360 +vn -0.997773 0.066697 0.000871 +vn -0.000005 -0.000117 -1.000000 +vn -0.000578 -0.001225 -0.999999 +vn -0.002059 0.162154 -0.986763 +vn 0.036715 0.227361 -0.973118 +vn 0.988150 0.153490 0.000530 +vn 0.997092 0.076202 0.000795 +vn 0.419290 0.355620 0.835302 +vn 0.335340 0.314686 0.887986 +vn 0.476829 0.120448 0.870704 +vn 0.548589 -0.115983 0.828008 +vn -0.425538 0.336785 0.839936 +vn -0.326355 0.383871 0.863791 +vn -0.479491 0.111072 0.870489 +vn -0.546378 -0.151051 0.823805 +vn -0.988094 0.153853 0.000548 +vn -0.996980 0.077652 0.000810 +vn -0.071204 0.307808 -0.948780 +vn 0.134041 0.542848 -0.829065 +vn 0.038742 0.586621 -0.808935 +vn 0.999191 -0.037450 -0.014645 +vn 0.997224 -0.066926 -0.032638 +vn 0.508477 -0.486691 0.710340 +vn 0.518399 -0.586423 0.622391 +vn -0.510691 -0.477362 0.715067 +vn -0.519541 -0.586094 0.621748 +vn -0.999321 -0.034320 -0.013421 +vn -0.997248 -0.066385 -0.032993 +vn -0.208233 0.626135 -0.751394 +vn 0.208454 0.614903 -0.760553 +vn 0.003597 0.581754 -0.813357 +vn 0.994885 -0.089661 -0.046525 +vn 0.994269 -0.101688 -0.032983 +vn 0.510524 -0.657019 0.554699 +vn 0.512927 -0.632907 0.579944 +vn -0.512007 -0.660652 0.548989 +vn -0.514396 -0.638014 0.573004 +vn -0.992961 -0.104288 -0.056137 +vn -0.993472 -0.105450 -0.043510 +vn -0.215729 0.522222 -0.825073 +vn 0.214294 0.359182 -0.908332 +vn 0.000134 0.334072 -0.942548 +vn 0.997269 -0.072312 -0.015018 +vn 0.998775 -0.049471 -0.001064 +vn 0.525393 -0.499573 0.688759 +vn 0.520961 -0.381681 0.763491 +vn -0.527026 -0.502395 0.685451 +vn -0.522284 -0.373646 0.766556 +vn -0.997005 -0.073521 -0.023992 +vn -0.999371 -0.035442 -0.000762 +vn -0.214604 0.292047 -0.932016 +vn -0.000002 -0.996240 0.086630 +vn 0.254654 -0.964745 -0.066466 +vn -0.000002 -0.978728 -0.205161 +vn 0.384905 -0.746403 0.542891 +vn -0.062420 -0.728758 0.681921 +vn -0.388088 -0.822360 0.416066 +vn -0.254657 -0.964744 -0.066466 +vn 0.215116 0.223526 -0.950664 +vn -0.074129 0.228601 -0.970694 +vn 1.000000 0.000000 -0.000000 +vn 1.000000 0.000000 -0.000000 +vn 0.532664 -0.238851 0.811923 +vn 0.525606 -0.243348 0.815181 +vn -0.532938 -0.238769 0.811767 +vn -0.526504 -0.236645 0.816574 +vn -1.000000 -0.000000 0.000000 +vn -1.000000 -0.000000 0.000000 +vn -0.212589 0.222631 -0.951442 +vn 0.000117 0.000000 -1.000000 +vn 0.000118 0.000007 -1.000000 +vn 0.000642 0.000004 -1.000000 +vn 0.001097 0.000289 -0.999999 +vn 0.259953 0.965539 0.012557 +vn 0.276358 0.960748 0.024272 +vn 0.099144 0.995038 0.008333 +vn -0.073275 0.997311 0.000826 +vn 0.746403 0.384905 0.542891 +vn 0.728758 -0.062420 0.681921 +vn 0.510903 0.161476 0.844336 +vn 0.528902 0.298440 0.794478 +vn 0.822360 -0.388088 0.416066 +vn 0.503238 -0.374936 0.778572 +vn 0.253827 -0.967185 0.011142 +vn 0.243379 -0.969696 0.021376 +vn 0.095953 -0.995359 0.007360 +vn -0.066697 -0.997773 0.000871 +vn 0.000117 -0.000006 -1.000000 +vn 0.001225 -0.000578 -0.999999 +vn -0.162154 -0.002061 -0.986763 +vn -0.227361 0.036714 -0.973118 +vn -0.153490 0.988150 0.000530 +vn -0.076202 0.997092 0.000795 +vn -0.355620 0.419290 0.835302 +vn -0.314686 0.335340 0.887986 +vn -0.120448 0.476829 0.870704 +vn 0.115983 0.548589 0.828008 +vn -0.336785 -0.425537 0.839937 +vn -0.383871 -0.326354 0.863792 +vn -0.111072 -0.479490 0.870490 +vn 0.151051 -0.546377 0.823805 +vn -0.153853 -0.988094 0.000549 +vn -0.077652 -0.996980 0.000810 +vn -0.307808 -0.071204 -0.948780 +vn -0.542849 0.134040 -0.829065 +vn -0.586621 0.038742 -0.808935 +vn 0.037450 0.999191 -0.014646 +vn 0.066926 0.997224 -0.032638 +vn 0.486691 0.508477 0.710340 +vn 0.586423 0.518399 0.622390 +vn 0.477362 -0.510691 0.715067 +vn 0.586095 -0.519541 0.621748 +vn 0.034320 -0.999321 -0.013421 +vn 0.066385 -0.997248 -0.032993 +vn -0.626135 -0.208233 -0.751394 +vn -0.614903 0.208454 -0.760553 +vn -0.581754 0.003596 -0.813357 +vn 0.089661 0.994885 -0.046525 +vn 0.101687 0.994269 -0.032983 +vn 0.657019 0.510524 0.554699 +vn 0.632907 0.512927 0.579944 +vn 0.660652 -0.512006 0.548989 +vn 0.638015 -0.514396 0.573004 +vn 0.104288 -0.992961 -0.056137 +vn 0.105450 -0.993472 -0.043510 +vn -0.522222 -0.215730 -0.825073 +vn -0.359182 0.214294 -0.908332 +vn -0.334072 0.000134 -0.942547 +vn 0.072312 0.997269 -0.015018 +vn 0.049471 0.998775 -0.001064 +vn 0.499573 0.525393 0.688759 +vn 0.381681 0.520961 0.763491 +vn 0.502395 -0.527026 0.685451 +vn 0.373646 -0.522284 0.766556 +vn 0.073521 -0.997005 -0.023992 +vn 0.035442 -0.999371 -0.000762 +vn -0.292047 -0.214604 -0.932016 +vn 0.996240 -0.000002 0.086630 +vn 0.964745 0.254654 -0.066466 +vn 0.978728 -0.000002 -0.205161 +vn 0.746403 0.384905 0.542891 +vn 0.728758 -0.062420 0.681921 +vn 0.822360 -0.388088 0.416066 +vn 0.964744 -0.254658 -0.066466 +vn -0.223526 0.215116 -0.950664 +vn -0.228601 -0.074129 -0.970694 +vn -0.000000 1.000000 -0.000000 +vn -0.000000 1.000000 -0.000000 +vn 0.238851 0.532664 0.811923 +vn 0.243348 0.525606 0.815181 +vn 0.238770 -0.532938 0.811767 +vn 0.236645 -0.526504 0.816574 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.222631 -0.212589 -0.951442 +vn -0.000001 0.000116 -1.000000 +vn -0.000009 0.000119 -1.000000 +vn -0.000005 0.000642 -1.000000 +vn -0.000289 0.001096 -0.999999 +vn -0.965539 0.259953 0.012557 +vn -0.960748 0.276358 0.024272 +vn -0.995038 0.099144 0.008333 +vn -0.997311 -0.073275 0.000826 +vn -0.384905 0.746403 0.542891 +vn 0.062420 0.728758 0.681921 +vn -0.161475 0.510903 0.844336 +vn -0.298440 0.528902 0.794478 +vn 0.388088 0.822361 0.416066 +vn 0.374936 0.503239 0.778571 +vn 0.967185 0.253827 0.011142 +vn 0.969696 0.243379 0.021376 +vn 0.995359 0.095953 0.007360 +vn 0.997773 -0.066696 0.000871 +vn 0.000006 0.000116 -1.000000 +vn 0.000578 0.001225 -0.999999 +vn 0.002061 -0.162154 -0.986763 +vn -0.036715 -0.227361 -0.973118 +vn -0.988150 -0.153490 0.000530 +vn -0.997092 -0.076202 0.000795 +vn -0.419290 -0.355620 0.835302 +vn -0.335340 -0.314686 0.887986 +vn -0.476829 -0.120448 0.870704 +vn -0.548589 0.115983 0.828008 +vn 0.425538 -0.336785 0.839937 +vn 0.326355 -0.383871 0.863791 +vn 0.479490 -0.111072 0.870490 +vn 0.546377 0.151051 0.823806 +vn 0.988094 -0.153853 0.000549 +vn 0.996980 -0.077652 0.000810 +vn 0.071202 -0.307807 -0.948781 +vn -0.134041 -0.542849 -0.829065 +vn -0.038743 -0.586621 -0.808935 +vn -0.999191 0.037450 -0.014645 +vn -0.997224 0.066925 -0.032638 +vn -0.508477 0.486691 0.710340 +vn -0.518400 0.586423 0.622390 +vn 0.510690 0.477362 0.715067 +vn 0.519540 0.586095 0.621748 +vn 0.999321 0.034320 -0.013421 +vn 0.997248 0.066385 -0.032993 +vn 0.208233 -0.626135 -0.751394 +vn -0.208455 -0.614903 -0.760553 +vn -0.003597 -0.581754 -0.813357 +vn -0.994885 0.089660 -0.046525 +vn -0.994269 0.101687 -0.032983 +vn -0.510524 0.657019 0.554699 +vn -0.512927 0.632907 0.579944 +vn 0.512006 0.660652 0.548989 +vn 0.514396 0.638015 0.573004 +vn 0.992961 0.104288 -0.056137 +vn 0.993472 0.105451 -0.043510 +vn 0.215730 -0.522222 -0.825072 +vn -0.214294 -0.359182 -0.908332 +vn -0.000134 -0.334072 -0.942547 +vn -0.997269 0.072312 -0.015018 +vn -0.998775 0.049471 -0.001064 +vn -0.525393 0.499573 0.688759 +vn -0.520961 0.381681 0.763491 +vn 0.527026 0.502395 0.685451 +vn 0.522284 0.373646 0.766556 +vn 0.997005 0.073521 -0.023992 +vn 0.999371 0.035442 -0.000762 +vn 0.214604 -0.292047 -0.932016 +vn 0.000002 0.996240 0.086630 +vn -0.254654 0.964745 -0.066466 +vn 0.000002 0.978728 -0.205161 +vn -0.384905 0.746403 0.542891 +vn 0.062420 0.728758 0.681921 +vn 0.388088 0.822361 0.416066 +vn 0.254658 0.964744 -0.066466 +vn -0.215116 -0.223526 -0.950664 +vn 0.074129 -0.228601 -0.970694 +vn -1.000000 -0.000000 -0.000000 +vn -1.000000 -0.000000 -0.000000 +vn -0.532664 0.238851 0.811923 +vn -0.525606 0.243348 0.815181 +vn 0.532938 0.238770 0.811767 +vn 0.526504 0.236645 0.816574 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.212589 -0.222631 -0.951442 +vn -0.000117 -0.000002 -1.000000 +vn -0.000120 -0.000009 -1.000000 +vn -0.000642 -0.000005 -1.000000 +vn -0.001096 -0.000290 -0.999999 +vn -0.259953 -0.965540 0.012557 +vn -0.276358 -0.960748 0.024272 +vn -0.099144 -0.995038 0.008333 +vn 0.073275 -0.997311 0.000826 +vn -0.746403 -0.384905 0.542891 +vn -0.728758 0.062420 0.681921 +vn -0.510903 -0.161475 0.844336 +vn -0.528903 -0.298440 0.794478 +vn -0.822360 0.388088 0.416066 +vn -0.503238 0.374937 0.778571 +vn -0.253827 0.967185 0.011142 +vn -0.243379 0.969696 0.021376 +vn -0.095953 0.995359 0.007360 +vn 0.066697 0.997773 0.000871 +vn -0.000116 0.000005 -1.000000 +vn -0.001225 0.000578 -0.999999 +vn 0.162155 0.002059 -0.986763 +vn 0.227361 -0.036715 -0.973118 +vn 0.153490 -0.988150 0.000530 +vn 0.076203 -0.997092 0.000795 +vn 0.355621 -0.419290 0.835302 +vn 0.314686 -0.335340 0.887986 +vn 0.120448 -0.476829 0.870704 +vn -0.115983 -0.548589 0.828008 +vn 0.336785 0.425538 0.839937 +vn 0.383871 0.326355 0.863791 +vn 0.111072 0.479490 0.870490 +vn -0.151051 0.546377 0.823805 +vn 0.153853 0.988094 0.000548 +vn 0.077652 0.996980 0.000810 +vn 0.307808 0.071202 -0.948781 +vn 0.542849 -0.134041 -0.829065 +vn 0.586621 -0.038743 -0.808934 +vn -0.037450 -0.999191 -0.014645 +vn -0.066925 -0.997224 -0.032638 +vn -0.486691 -0.508477 0.710340 +vn -0.586423 -0.518400 0.622390 +vn -0.477362 0.510691 0.715067 +vn -0.586095 0.519541 0.621748 +vn -0.034320 0.999321 -0.013421 +vn -0.066385 0.997248 -0.032993 +vn 0.626135 0.208232 -0.751395 +vn 0.614903 -0.208454 -0.760553 +vn 0.581754 -0.003597 -0.813357 +vn -0.089660 -0.994885 -0.046525 +vn -0.101687 -0.994269 -0.032983 +vn -0.657019 -0.510525 0.554699 +vn -0.632907 -0.512927 0.579944 +vn -0.660652 0.512007 0.548988 +vn -0.638015 0.514396 0.573004 +vn -0.104288 0.992961 -0.056137 +vn -0.105451 0.993472 -0.043510 +vn 0.522222 0.215729 -0.825072 +vn 0.359182 -0.214295 -0.908331 +vn 0.334072 -0.000134 -0.942547 +vn -0.072312 -0.997269 -0.015018 +vn -0.049471 -0.998775 -0.001064 +vn -0.499573 -0.525393 0.688759 +vn -0.381681 -0.520961 0.763491 +vn -0.502395 0.527026 0.685451 +vn -0.373646 0.522284 0.766556 +vn -0.073521 0.997005 -0.023992 +vn -0.035442 0.999371 -0.000763 +vn 0.292047 0.214604 -0.932016 +vn -0.996240 0.000002 0.086630 +vn -0.964745 -0.254654 -0.066466 +vn -0.978728 0.000002 -0.205161 +vn -0.746403 -0.384905 0.542891 +vn -0.728758 0.062420 0.681921 +vn -0.822360 0.388088 0.416066 +vn -0.964744 0.254657 -0.066466 +vn 0.223526 -0.215116 -0.950664 +vn 0.228601 0.074129 -0.970694 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 -0.000000 +vn -0.238851 -0.532664 0.811923 +vn -0.243348 -0.525606 0.815181 +vn -0.238770 0.532938 0.811767 +vn -0.236645 0.526504 0.816574 +vn -0.000000 1.000000 0.000000 +vn -0.000000 1.000000 0.000000 +vn 0.222631 0.212589 -0.951442 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.706842 0.707371 0.000000 +vn 0.706842 0.707371 0.000000 +vn 0.706842 0.707371 0.000000 +vn 0.706842 0.707371 0.000000 +vn -0.000374 1.000000 0.000000 +vn -0.000374 1.000000 0.000000 +vn -0.000374 1.000000 0.000000 +vn -0.000374 1.000000 0.000000 +vn -0.707371 0.706842 0.000000 +vn -0.707371 0.706842 0.000000 +vn -0.707371 0.706842 0.000000 +vn -0.707371 0.706842 0.000000 +vn -1.000000 -0.000374 0.000000 +vn -1.000000 -0.000374 0.000000 +vn -1.000000 -0.000374 0.000000 +vn -1.000000 -0.000374 0.000000 +vn -0.706842 -0.707371 -0.000000 +vn -0.706842 -0.707371 -0.000000 +vn -0.706842 -0.707371 -0.000000 +vn -0.706842 -0.707371 0.000000 +vn 0.000374 -1.000000 -0.000000 +vn 0.000374 -1.000000 0.000000 +vn 0.000374 -1.000000 -0.000000 +vn 0.000374 -1.000000 -0.000000 +vn 0.707371 -0.706842 -0.000000 +vn 0.707371 -0.706842 -0.000000 +vn 0.707371 -0.706842 -0.000000 +vn 0.707371 -0.706842 -0.000000 +vn 1.000000 0.000374 0.000000 +vn 1.000000 0.000374 0.000000 +vn 1.000000 0.000374 0.000000 +vn 1.000000 0.000374 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn -0.099506 0.000000 0.995037 +vn -0.099506 0.000000 0.995037 +vn -0.099506 0.000000 0.995037 +vn -0.099506 0.000000 0.995037 +vn 0.000000 -0.099506 0.995037 +vn 0.000000 -0.099506 0.995037 +vn 0.000000 -0.099506 0.995037 +vn 0.000000 -0.099506 0.995037 +vn 0.099506 0.000000 0.995037 +vn 0.099506 0.000000 0.995037 +vn 0.099506 0.000000 0.995037 +vn 0.099506 0.000000 0.995037 +vn 0.000000 0.099506 0.995037 +vn 0.000000 0.099506 0.995037 +vn 0.000000 0.099506 0.995037 +vn 0.000000 0.099506 0.995037 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -0.929987 0.000000 0.367592 +vn -0.677867 0.000000 0.735184 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -0.929987 0.367592 +vn 0.000000 -0.677867 0.735184 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.929987 0.000000 0.367592 +vn 0.677867 0.000000 0.735184 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 0.929987 0.367592 +vn 0.000000 0.677867 0.735184 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn -0.000000 -1.000000 0.000000 +vn -0.000000 -1.000000 0.000000 +vn -0.000000 -1.000000 0.000000 +vn -0.000000 -1.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn 0.000000 0.967538 0.252725 +vn 0.000000 0.862856 0.505449 +vn 0.967538 0.000000 0.252725 +vn 0.862856 0.000000 0.505449 +vn -0.000000 -0.967538 0.252725 +vn -0.000000 -0.862856 0.505449 +vn -0.967538 0.000000 0.252725 +vn -0.862856 0.000000 0.505449 +vn 0.000000 0.862856 0.505449 +vn 0.000000 0.967538 0.252725 +vn 0.862856 0.000000 0.505449 +vn 0.967538 0.000000 0.252725 +vn -0.000000 -0.862856 0.505449 +vn -0.000000 -0.967538 0.252725 +vn -0.862856 0.000000 0.505449 +vn -0.967538 0.000000 0.252725 +vn 0.000000 0.967538 0.252725 +vn 0.000000 0.862856 0.505449 +vn 0.967538 0.000000 0.252724 +vn 0.862857 0.000000 0.505449 +vn -0.000000 -0.967538 0.252724 +vn -0.000000 -0.862857 0.505448 +vn -0.967538 0.000000 0.252725 +vn -0.862857 0.000000 0.505449 +vn 0.000000 0.707107 0.707107 +vn 0.000000 0.707107 0.707107 +vn 0.707108 0.000000 0.707106 +vn 0.707107 0.000000 0.707107 +vn -0.000000 -0.707108 0.707105 +vn -0.000000 -0.707108 0.707105 +vn -0.707108 0.000000 0.707106 +vn -0.707108 0.000000 0.707105 +vn 0.000000 0.099506 0.995037 +vn 0.000000 0.099506 0.995037 +vn 0.000000 0.099506 0.995037 +vn 0.000000 0.099506 0.995037 +vn 0.099506 0.000000 0.995037 +vn 0.099501 0.000000 0.995037 +vn 0.099506 0.000000 0.995037 +vn 0.099506 0.000000 0.995037 +vn -0.000000 -0.099501 0.995037 +vn -0.000000 -0.099501 0.995037 +vn -0.000000 -0.099501 0.995037 +vn -0.000000 -0.099501 0.995037 +vn -0.099501 0.000000 0.995037 +vn -0.099506 0.000000 0.995037 +vn -0.099501 0.000000 0.995037 +vn -0.099501 0.000000 0.995037 +vn -0.275482 0.000000 0.961306 +vn -0.187896 0.000000 0.982189 +vn 0.000000 -0.275482 0.961306 +vn 0.000000 -0.187896 0.982189 +vn 0.275482 0.000000 0.961306 +vn 0.187896 0.000000 0.982189 +vn 0.000000 0.275482 0.961306 +vn 0.000000 0.187896 0.982189 +vn -0.516067 0.000000 0.856548 +vn -0.903649 0.000000 0.428274 +vn 0.000000 -0.516067 0.856548 +vn 0.000000 -0.903649 0.428274 +vn 0.516067 0.000000 0.856548 +vn 0.903649 0.000000 0.428274 +vn 0.000000 0.516067 0.856548 +vn 0.000000 0.903649 0.428274 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn -0.049938 0.000000 0.998752 +vn -0.049938 0.000000 0.998752 +vn -0.049938 0.000000 0.998752 +vn -0.049938 0.000000 0.998752 +vn 0.000000 -0.049938 0.998752 +vn 0.000000 -0.049938 0.998752 +vn 0.000000 -0.049938 0.998752 +vn 0.000000 -0.049938 0.998752 +vn 0.049938 0.000000 0.998752 +vn 0.049938 0.000000 0.998752 +vn 0.049938 0.000000 0.998752 +vn 0.049938 0.000000 0.998752 +vn 0.000000 0.049938 0.998752 +vn 0.000000 0.049938 0.998752 +vn 0.000000 0.049938 0.998752 +vn 0.000000 0.049938 0.998752 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn 0.000000 1.000000 -0.000002 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 -0.000002 +vn 0.000000 1.000000 -0.000005 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 +vn -0.000000 -1.000000 0.000002 +vn 0.000000 -1.000000 0.000005 +vn -0.000000 -1.000000 0.000002 +vn -0.000000 -1.000000 0.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.562661 0.423331 -0.710072 +vn 0.704032 0.011758 -0.710070 +vn 0.582173 0.063049 -0.810617 +vn 0.433925 0.393201 -0.810618 +vn 0.206373 0.673207 -0.710072 +vn 0.119934 0.573161 -0.810618 +vn -0.228742 0.665939 -0.710072 +vn -0.239867 0.534192 -0.810618 +vn -0.576487 0.404302 -0.710072 +vn -0.508049 0.291177 -0.810618 +vn -0.704032 -0.011763 -0.710070 +vn -0.582173 -0.063055 -0.810616 +vn -0.562662 -0.423334 -0.710070 +vn -0.433926 -0.393204 -0.810616 +vn -0.206373 -0.673209 -0.710070 +vn -0.119934 -0.573164 -0.810616 +vn 0.228743 -0.665941 -0.710070 +vn 0.239869 -0.534195 -0.810616 +vn 0.576487 -0.404306 -0.710070 +vn 0.508049 -0.291182 -0.810616 +vn 0.745732 0.553468 -0.370886 +vn 0.928631 0.009435 -0.370885 +vn 0.277988 0.886096 -0.370886 +vn -0.295936 0.880264 -0.370886 +vn -0.756825 0.538201 -0.370886 +vn -0.928631 -0.009437 -0.370885 +vn -0.745732 -0.553469 -0.370885 +vn -0.277989 -0.886096 -0.370885 +vn 0.295937 -0.880265 -0.370885 +vn 0.756824 -0.538202 -0.370885 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.951056 -0.309017 -0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.951056 -0.309017 0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.047494 0.015432 0.998752 +vn 0.047493 0.015432 0.998752 +vn 0.047494 0.015432 0.998752 +vn 0.047494 0.015432 0.998752 +vn 0.029353 0.040401 0.998752 +vn 0.029353 0.040401 0.998752 +vn 0.029353 0.040401 0.998752 +vn 0.029353 0.040401 0.998752 +vn 0.000000 0.049938 0.998752 +vn 0.000000 0.049938 0.998752 +vn 0.000000 0.049938 0.998752 +vn 0.000000 0.049938 0.998752 +vn -0.029353 0.040401 0.998752 +vn -0.029353 0.040401 0.998752 +vn -0.029353 0.040401 0.998752 +vn -0.029353 0.040401 0.998752 +vn -0.047493 0.015431 0.998752 +vn -0.047494 0.015432 0.998752 +vn -0.047493 0.015431 0.998752 +vn -0.047493 0.015431 0.998752 +vn -0.047493 -0.015432 0.998752 +vn -0.047493 -0.015432 0.998752 +vn -0.047493 -0.015432 0.998752 +vn -0.047493 -0.015432 0.998752 +vn -0.029353 -0.040400 0.998752 +vn -0.029353 -0.040400 0.998752 +vn -0.029353 -0.040400 0.998752 +vn -0.029353 -0.040400 0.998752 +vn 0.000000 -0.049937 0.998752 +vn 0.000000 -0.049937 0.998752 +vn 0.000000 -0.049937 0.998752 +vn 0.000000 -0.049937 0.998752 +vn 0.029353 -0.040399 0.998752 +vn 0.029353 -0.040400 0.998752 +vn 0.029353 -0.040399 0.998752 +vn 0.029353 -0.040399 0.998752 +vn 0.047493 -0.015432 0.998752 +vn 0.047493 -0.015432 0.998752 +vn 0.047493 -0.015432 0.998752 +vn 0.047493 -0.015432 0.998752 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.951056 -0.309017 -0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.951056 -0.309017 0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.425325 0.138196 -0.894427 +vn 0.425326 0.138197 -0.894427 +vn 0.425325 0.138196 -0.894427 +vn 0.425325 0.138196 -0.894427 +vn 0.262866 0.361804 -0.894427 +vn 0.262865 0.361803 -0.894427 +vn 0.262866 0.361804 -0.894427 +vn 0.262866 0.361804 -0.894427 +vn -0.000000 0.447215 -0.894427 +vn 0.000000 0.447214 -0.894427 +vn -0.000000 0.447215 -0.894427 +vn -0.000000 0.447215 -0.894427 +vn -0.262865 0.361803 -0.894427 +vn -0.262866 0.361804 -0.894427 +vn -0.262865 0.361803 -0.894427 +vn -0.262865 0.361803 -0.894427 +vn -0.425326 0.138196 -0.894427 +vn -0.425325 0.138196 -0.894427 +vn -0.425326 0.138196 -0.894427 +vn -0.425326 0.138196 -0.894427 +vn -0.425326 -0.138196 -0.894427 +vn -0.425326 -0.138196 -0.894427 +vn -0.425326 -0.138196 -0.894427 +vn -0.425326 -0.138196 -0.894427 +vn -0.262865 -0.361804 -0.894427 +vn -0.262865 -0.361804 -0.894427 +vn -0.262865 -0.361804 -0.894427 +vn -0.262865 -0.361804 -0.894427 +vn 0.000000 -0.447214 -0.894427 +vn 0.000000 -0.447214 -0.894427 +vn 0.000000 -0.447214 -0.894427 +vn 0.000000 -0.447214 -0.894427 +vn 0.262865 -0.361804 -0.894427 +vn 0.262865 -0.361804 -0.894427 +vn 0.262865 -0.361804 -0.894427 +vn 0.262865 -0.361804 -0.894427 +vn 0.425326 -0.138196 -0.894427 +vn 0.425326 -0.138196 -0.894427 +vn 0.425326 -0.138196 -0.894427 +vn 0.425326 -0.138196 -0.894427 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.587786 0.809017 -0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587786 0.809017 -0.000000 +vn 0.587786 0.809017 -0.000000 +vn -0.000000 1.000000 0.000000 +vn -0.000000 1.000000 -0.000001 +vn -0.000000 1.000000 0.000000 +vn -0.000000 1.000000 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.951056 -0.309017 -0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.951056 -0.309017 0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.951056 -0.309017 -0.000000 +vn 0.425325 0.138197 0.894427 +vn 0.425326 0.138197 0.894427 +vn 0.425325 0.138197 0.894427 +vn 0.425325 0.138197 0.894427 +vn 0.262866 0.361803 0.894427 +vn 0.262866 0.361804 0.894427 +vn 0.262866 0.361803 0.894427 +vn 0.262866 0.361803 0.894427 +vn 0.000000 0.447214 0.894427 +vn -0.000000 0.447213 0.894427 +vn 0.000000 0.447214 0.894427 +vn 0.000000 0.447214 0.894427 +vn -0.262866 0.361804 0.894427 +vn -0.262865 0.361804 0.894427 +vn -0.262866 0.361804 0.894427 +vn -0.262866 0.361804 0.894427 +vn -0.425326 0.138197 0.894427 +vn -0.425326 0.138197 0.894427 +vn -0.425326 0.138197 0.894427 +vn -0.425326 0.138197 0.894427 +vn -0.425324 -0.138197 0.894428 +vn -0.425326 -0.138197 0.894427 +vn -0.425324 -0.138197 0.894428 +vn -0.425324 -0.138197 0.894428 +vn -0.262866 -0.361803 0.894427 +vn -0.262865 -0.361802 0.894428 +vn -0.262866 -0.361803 0.894427 +vn -0.262866 -0.361803 0.894427 +vn 0.000000 -0.447213 0.894427 +vn 0.000000 -0.447213 0.894427 +vn 0.000000 -0.447213 0.894427 +vn 0.000000 -0.447213 0.894427 +vn 0.262866 -0.361802 0.894427 +vn 0.262866 -0.361803 0.894427 +vn 0.262866 -0.361802 0.894427 +vn 0.262866 -0.361802 0.894427 +vn 0.425326 -0.138198 0.894427 +vn 0.425325 -0.138197 0.894427 +vn 0.425326 -0.138198 0.894427 +vn 0.425326 -0.138198 0.894427 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000001 +vn 0.951056 0.309017 0.000000 +vn 0.951056 0.309017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.587785 0.809017 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 1.000000 0.000000 +vn -0.587785 0.809017 0.000001 +vn -0.587785 0.809017 0.000000 +vn -0.587785 0.809017 0.000001 +vn -0.587785 0.809017 0.000001 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000001 +vn -0.951056 0.309017 0.000000 +vn -0.951056 0.309017 0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.951056 -0.309017 -0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.951056 -0.309017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn -0.587785 -0.809017 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.000000 -1.000000 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.587785 -0.809017 0.000000 +vn 0.951056 -0.309017 0.000001 +vn 0.951056 -0.309017 0.000000 +vn 0.951056 -0.309017 0.000001 +vn 0.951056 -0.309017 0.000001 +vn 0.808878 0.587853 -0.012040 +vn 0.999927 0.000136 -0.012040 +vn 0.928631 0.009435 -0.370885 +vn 0.745732 0.553468 -0.370886 +vn 0.308865 0.951030 -0.012040 +vn 0.277988 0.886096 -0.370886 +vn -0.309124 0.950945 -0.012040 +vn -0.295936 0.880264 -0.370886 +vn -0.809038 0.587632 -0.012040 +vn -0.756825 0.538201 -0.370886 +vn -0.999927 -0.000136 -0.012040 +vn -0.928631 -0.009437 -0.370885 +vn -0.808878 -0.587853 -0.012040 +vn -0.745732 -0.553469 -0.370885 +vn -0.308865 -0.951030 -0.012040 +vn -0.277989 -0.886096 -0.370885 +vn 0.309124 -0.950945 -0.012040 +vn 0.295937 -0.880265 -0.370885 +vn 0.809038 -0.587632 -0.012040 +vn 0.309124 -0.950945 -0.012040 +vn 0.295937 -0.880265 -0.370885 +vn 0.756824 -0.538202 -0.370885 +vn 0.797207 0.577639 0.175482 +vn 0.984482 -0.001267 0.175482 +vn 0.305427 0.935906 0.175482 +vn -0.303017 0.936689 0.175482 +vn -0.795718 0.579689 0.175482 +vn -0.984482 0.001267 0.175482 +vn -0.797207 -0.577639 0.175482 +vn -0.305426 -0.935906 0.175482 +vn 0.303017 -0.936689 0.175482 +vn 0.795718 -0.579689 0.175482 +vn 0.303017 -0.936689 0.175482 +vn 0.805510 0.586917 0.081747 +vn 0.996652 0.001359 0.081747 +vn 0.306690 0.948292 0.081747 +vn -0.309275 0.947452 0.081747 +vn -0.807107 0.584718 0.081747 +vn -0.996652 -0.001359 0.081747 +vn -0.805510 -0.586917 0.081747 +vn -0.306690 -0.948292 0.081747 +vn 0.309275 -0.947452 0.081747 +vn 0.807107 -0.584718 0.081747 +vn 0.309275 -0.947452 0.081747 +vn 0.768673 0.548289 -0.329426 +vn 0.944145 -0.008240 -0.329426 +vn 0.299593 0.895389 -0.329426 +vn -0.283921 0.900482 -0.329426 +vn -0.758987 0.561621 -0.329426 +vn -0.944145 0.008240 -0.329426 +vn -0.768673 -0.548289 -0.329426 +vn -0.299593 -0.895389 -0.329426 +vn 0.283921 -0.900482 -0.329426 +vn 0.758987 -0.561620 -0.329426 +vn 0.283921 -0.900482 -0.329426 +vn 0.726320 0.416280 -0.546965 +vn 0.832289 -0.090142 -0.546964 +vn 0.342922 0.763698 -0.546965 +vn -0.171461 0.819409 -0.546965 +vn -0.620351 0.562133 -0.546965 +vn -0.832288 0.090142 -0.546965 +vn -0.726320 -0.416280 -0.546965 +vn -0.342922 -0.763698 -0.546965 +vn 0.171461 -0.819409 -0.546965 +vn 0.620351 -0.562134 -0.546965 +vn 0.171461 -0.819409 -0.546965 +f 1/1/1 2/2/2 3/3/3 +f 3/3/3 4/4/4 1/1/1 +f 5/5/5 6/6/6 7/7/7 +f 7/7/7 8/8/8 5/5/5 +f 9/9/9 10/10/10 11/11/11 +f 11/11/11 12/12/12 9/9/9 +f 10/10/10 13/13/13 14/14/14 +f 14/14/14 11/11/11 10/10/10 +f 15/15/15 16/16/16 17/17/17 +f 17/17/17 18/18/18 15/15/15 +f 19/19/19 1/1/1 4/4/4 +f 4/4/4 20/20/20 19/19/19 +f 4/4/4 3/3/3 21/21/21 +f 21/21/21 22/22/22 4/4/4 +f 8/8/8 7/7/7 23/23/23 +f 23/23/23 24/24/24 8/8/8 +f 25/25/25 26/26/26 27/27/27 +f 27/27/27 28/28/28 25/25/25 +f 29/29/29 30/30/30 31/31/31 +f 31/31/31 32/32/32 29/29/29 +f 18/18/18 17/17/17 33/33/33 +f 33/33/33 34/34/34 18/18/18 +f 20/20/20 4/4/4 22/22/22 +f 22/22/22 35/35/35 20/20/20 +f 22/22/22 21/21/21 36/36/36 +f 36/36/36 37/37/37 22/22/22 +f 24/24/24 23/23/23 38/38/38 +f 38/38/38 39/39/39 24/24/24 +f 28/28/28 27/27/27 40/40/40 +f 40/40/40 41/41/41 28/28/28 +f 32/32/32 31/31/31 42/42/42 +f 42/42/42 43/43/43 32/32/32 +f 34/34/34 33/33/33 44/44/44 +f 44/44/44 45/45/45 34/34/34 +f 35/35/35 22/22/22 37/37/37 +f 37/37/37 46/46/46 35/35/35 +f 37/37/37 36/36/36 47/47/47 +f 47/47/47 48/48/48 37/37/37 +f 39/39/39 38/38/38 49/49/49 +f 49/49/49 50/50/50 39/39/39 +f 41/41/41 40/40/40 51/51/51 +f 51/51/51 52/52/52 41/41/41 +f 43/43/43 42/42/42 53/53/53 +f 53/53/53 54/54/54 43/43/43 +f 45/45/45 44/44/44 55/55/55 +f 55/55/55 56/56/56 45/45/45 +f 46/46/46 37/37/37 48/48/48 +f 48/48/48 57/57/57 46/46/46 +f 48/48/48 47/47/47 58/58/58 +f 58/58/58 59/59/59 48/48/48 +f 50/50/50 49/49/49 60/60/60 +f 60/60/60 61/61/61 50/50/50 +f 52/52/52 51/51/51 62/62/62 +f 62/62/62 63/63/63 52/52/52 +f 54/54/54 53/53/53 64/64/64 +f 64/64/64 65/65/65 54/54/54 +f 56/56/56 55/55/55 66/66/66 +f 66/66/66 67/67/67 56/56/56 +f 57/57/57 48/48/48 59/59/59 +f 59/59/59 68/68/68 57/57/57 +f 69/69/69 70/70/70 71/71/71 +f 69/69/69 72/72/72 70/70/70 +f 69/69/69 73/73/73 72/72/72 +f 69/69/69 74/74/74 73/73/73 +f 69/69/69 75/75/75 74/74/74 +f 69/69/69 71/71/71 75/75/75 +f 76/76/76 77/77/77 59/59/59 +f 76/76/76 59/59/59 58/58/58 +f 78/78/78 79/79/79 61/61/61 +f 78/78/78 61/61/61 60/60/60 +f 80/80/80 81/81/81 63/63/63 +f 80/80/80 63/63/63 62/62/62 +f 82/82/82 83/83/83 65/65/65 +f 82/82/82 65/65/65 64/64/64 +f 84/84/84 85/85/85 67/67/67 +f 84/84/84 67/67/67 66/66/66 +f 77/77/77 86/86/86 68/68/68 +f 77/77/77 68/68/68 59/59/59 +f 87/87/87 88/88/88 89/89/89 +f 89/89/89 90/90/90 87/87/87 +f 91/91/91 92/92/92 93/93/93 +f 93/93/93 94/94/94 91/91/91 +f 95/95/95 96/96/96 97/97/97 +f 97/97/97 98/98/98 95/95/95 +f 96/96/96 99/99/99 100/100/100 +f 100/100/100 97/97/97 96/96/96 +f 101/101/101 102/102/102 103/103/103 +f 103/103/103 104/104/104 101/101/101 +f 105/105/105 87/87/87 90/90/90 +f 90/90/90 106/106/106 105/105/105 +f 90/90/90 89/89/89 107/107/107 +f 107/107/107 108/108/108 90/90/90 +f 94/94/94 93/93/93 109/109/109 +f 109/109/109 110/110/110 94/94/94 +f 111/111/111 112/112/112 113/113/113 +f 113/113/113 114/114/114 111/111/111 +f 115/115/115 116/116/116 117/117/117 +f 117/117/117 118/118/118 115/115/115 +f 104/104/104 103/103/103 119/119/119 +f 119/119/119 120/120/120 104/104/104 +f 106/106/106 90/90/90 108/108/108 +f 108/108/108 121/121/121 106/106/106 +f 108/108/108 107/107/107 122/122/122 +f 122/122/122 123/123/123 108/108/108 +f 110/110/110 109/109/109 124/124/124 +f 124/124/124 125/125/125 110/110/110 +f 114/114/114 113/113/113 126/126/126 +f 126/126/126 127/127/127 114/114/114 +f 118/118/118 117/117/117 128/128/128 +f 128/128/128 129/129/129 118/118/118 +f 120/120/120 119/119/119 130/130/130 +f 130/130/130 131/131/131 120/120/120 +f 121/121/121 108/108/108 123/123/123 +f 123/123/123 132/132/132 121/121/121 +f 123/123/123 122/122/122 133/133/133 +f 133/133/133 134/134/134 123/123/123 +f 125/125/125 124/124/124 135/135/135 +f 135/135/135 136/136/136 125/125/125 +f 127/127/127 126/126/126 137/137/137 +f 137/137/137 138/138/138 127/127/127 +f 129/129/129 128/128/128 139/139/139 +f 139/139/139 140/140/140 129/129/129 +f 131/131/131 130/130/130 141/141/141 +f 141/141/141 142/142/142 131/131/131 +f 132/132/132 123/123/123 134/134/134 +f 134/134/134 143/143/143 132/132/132 +f 134/134/134 133/133/133 144/144/144 +f 144/144/144 145/145/145 134/134/134 +f 136/136/136 135/135/135 146/146/146 +f 146/146/146 147/147/147 136/136/136 +f 138/138/138 137/137/137 148/148/148 +f 148/148/148 149/149/149 138/138/138 +f 140/140/140 139/139/139 150/150/150 +f 150/150/150 151/151/151 140/140/140 +f 142/142/142 141/141/141 152/152/152 +f 152/152/152 153/153/153 142/142/142 +f 143/143/143 134/134/134 145/145/145 +f 145/145/145 154/154/154 143/143/143 +f 155/155/155 156/156/156 157/157/157 +f 155/155/155 158/158/158 156/156/156 +f 155/155/155 159/159/159 158/158/158 +f 155/155/155 160/160/160 159/159/159 +f 155/155/155 161/161/161 160/160/160 +f 155/155/155 157/157/157 161/161/161 +f 162/162/162 163/163/163 145/145/145 +f 162/162/162 145/145/145 144/144/144 +f 164/164/164 165/165/165 147/147/147 +f 164/164/164 147/147/147 146/146/146 +f 166/166/166 167/167/167 149/149/149 +f 166/166/166 149/149/149 148/148/148 +f 168/168/168 169/169/169 151/151/151 +f 168/168/168 151/151/151 150/150/150 +f 170/170/170 171/171/171 153/153/153 +f 170/170/170 153/153/153 152/152/152 +f 163/163/163 172/172/172 154/154/154 +f 163/163/163 154/154/154 145/145/145 +f 173/173/173 174/174/174 175/175/175 +f 175/175/175 176/176/176 173/173/173 +f 177/177/177 178/178/178 179/179/179 +f 179/179/179 180/180/180 177/177/177 +f 181/181/181 182/182/182 183/183/183 +f 183/183/183 184/184/184 181/181/181 +f 182/182/182 185/185/185 186/186/186 +f 186/186/186 183/183/183 182/182/182 +f 187/187/187 188/188/188 189/189/189 +f 189/189/189 190/190/190 187/187/187 +f 191/191/191 173/173/173 176/176/176 +f 176/176/176 192/192/192 191/191/191 +f 176/176/176 175/175/175 193/193/193 +f 193/193/193 194/194/194 176/176/176 +f 180/180/180 179/179/179 195/195/195 +f 195/195/195 196/196/196 180/180/180 +f 197/197/197 198/198/198 199/199/199 +f 199/199/199 200/200/200 197/197/197 +f 201/201/201 202/202/202 203/203/203 +f 203/203/203 204/204/204 201/201/201 +f 190/190/190 189/189/189 205/205/205 +f 205/205/205 206/206/206 190/190/190 +f 192/192/192 176/176/176 194/194/194 +f 194/194/194 207/207/207 192/192/192 +f 194/194/194 193/193/193 208/208/208 +f 208/208/208 209/209/209 194/194/194 +f 196/196/196 195/195/195 210/210/210 +f 210/210/210 211/211/211 196/196/196 +f 200/200/200 199/199/199 212/212/212 +f 212/212/212 213/213/213 200/200/200 +f 204/204/204 203/203/203 214/214/214 +f 214/214/214 215/215/215 204/204/204 +f 206/206/206 205/205/205 216/216/216 +f 216/216/216 217/217/217 206/206/206 +f 207/207/207 194/194/194 209/209/209 +f 209/209/209 218/218/218 207/207/207 +f 209/209/209 208/208/208 219/219/219 +f 219/219/219 220/220/220 209/209/209 +f 211/211/211 210/210/210 221/221/221 +f 221/221/221 222/222/222 211/211/211 +f 213/213/213 212/212/212 223/223/223 +f 223/223/223 224/224/224 213/213/213 +f 215/215/215 214/214/214 225/225/225 +f 225/225/225 226/226/226 215/215/215 +f 217/217/217 216/216/216 227/227/227 +f 227/227/227 228/228/228 217/217/217 +f 218/218/218 209/209/209 220/220/220 +f 220/220/220 229/229/229 218/218/218 +f 220/220/220 219/219/219 230/230/230 +f 230/230/230 231/231/231 220/220/220 +f 222/222/222 221/221/221 232/232/232 +f 232/232/232 233/233/233 222/222/222 +f 224/224/224 223/223/223 234/234/234 +f 234/234/234 235/235/235 224/224/224 +f 226/226/226 225/225/225 236/236/236 +f 236/236/236 237/237/237 226/226/226 +f 228/228/228 227/227/227 238/238/238 +f 238/238/238 239/239/239 228/228/228 +f 229/229/229 220/220/220 231/231/231 +f 231/231/231 240/240/240 229/229/229 +f 241/241/241 242/242/242 243/243/243 +f 241/241/241 244/244/244 242/242/242 +f 241/241/241 245/245/245 244/244/244 +f 241/241/241 246/246/246 245/245/245 +f 241/241/241 247/247/247 246/246/246 +f 241/241/241 243/243/243 247/247/247 +f 248/248/248 249/249/249 231/231/231 +f 248/248/248 231/231/231 230/230/230 +f 250/250/250 251/251/251 233/233/233 +f 250/250/250 233/233/233 232/232/232 +f 252/252/252 253/253/253 235/235/235 +f 252/252/252 235/235/235 234/234/234 +f 254/254/254 255/255/255 237/237/237 +f 254/254/254 237/237/237 236/236/236 +f 256/256/256 257/257/257 239/239/239 +f 256/256/256 239/239/239 238/238/238 +f 249/249/249 258/258/258 240/240/240 +f 249/249/249 240/240/240 231/231/231 +f 259/259/259 260/260/260 261/261/261 +f 261/261/261 262/262/262 259/259/259 +f 263/263/263 264/264/264 265/265/265 +f 265/265/265 266/266/266 263/263/263 +f 267/267/267 268/268/268 269/269/269 +f 269/269/269 270/270/270 267/267/267 +f 268/268/268 271/271/271 272/272/272 +f 272/272/272 269/269/269 268/268/268 +f 273/273/273 274/274/274 275/275/275 +f 275/275/275 276/276/276 273/273/273 +f 277/277/277 259/259/259 262/262/262 +f 262/262/262 278/278/278 277/277/277 +f 262/262/262 261/261/261 279/279/279 +f 279/279/279 280/280/280 262/262/262 +f 266/266/266 265/265/265 281/281/281 +f 281/281/281 282/282/282 266/266/266 +f 283/283/283 284/284/284 285/285/285 +f 285/285/285 286/286/286 283/283/283 +f 287/287/287 288/288/288 289/289/289 +f 289/289/289 290/290/290 287/287/287 +f 276/276/276 275/275/275 291/291/291 +f 291/291/291 292/292/292 276/276/276 +f 278/278/278 262/262/262 280/280/280 +f 280/280/280 293/293/293 278/278/278 +f 280/280/280 279/279/279 294/294/294 +f 294/294/294 295/295/295 280/280/280 +f 282/282/282 281/281/281 296/296/296 +f 296/296/296 297/297/297 282/282/282 +f 286/286/286 285/285/285 298/298/298 +f 298/298/298 299/299/299 286/286/286 +f 290/290/290 289/289/289 300/300/300 +f 300/300/300 301/301/301 290/290/290 +f 292/292/292 291/291/291 302/302/302 +f 302/302/302 303/303/303 292/292/292 +f 293/293/293 280/280/280 295/295/295 +f 295/295/295 304/304/304 293/293/293 +f 295/295/295 294/294/294 305/305/305 +f 305/305/305 306/306/306 295/295/295 +f 297/297/297 296/296/296 307/307/307 +f 307/307/307 308/308/308 297/297/297 +f 299/299/299 298/298/298 309/309/309 +f 309/309/309 310/310/310 299/299/299 +f 301/301/301 300/300/300 311/311/311 +f 311/311/311 312/312/312 301/301/301 +f 303/303/303 302/302/302 313/313/313 +f 313/313/313 314/314/314 303/303/303 +f 304/304/304 295/295/295 306/306/306 +f 306/306/306 315/315/315 304/304/304 +f 306/306/306 305/305/305 316/316/316 +f 316/316/316 317/317/317 306/306/306 +f 308/308/308 307/307/307 318/318/318 +f 318/318/318 319/319/319 308/308/308 +f 310/310/310 309/309/309 320/320/320 +f 320/320/320 321/321/321 310/310/310 +f 312/312/312 311/311/311 322/322/322 +f 322/322/322 323/323/323 312/312/312 +f 314/314/314 313/313/313 324/324/324 +f 324/324/324 325/325/325 314/314/314 +f 315/315/315 306/306/306 317/317/317 +f 317/317/317 326/326/326 315/315/315 +f 327/327/327 328/328/328 329/329/329 +f 327/327/327 330/330/330 328/328/328 +f 327/327/327 331/331/331 330/330/330 +f 327/327/327 332/332/332 331/331/331 +f 327/327/327 333/333/333 332/332/332 +f 327/327/327 329/329/329 333/333/333 +f 334/334/334 335/335/335 317/317/317 +f 334/334/334 317/317/317 316/316/316 +f 336/336/336 337/337/337 319/319/319 +f 336/336/336 319/319/319 318/318/318 +f 338/338/338 339/339/339 321/321/321 +f 338/338/338 321/321/321 320/320/320 +f 340/340/340 341/341/341 323/323/323 +f 340/340/340 323/323/323 322/322/322 +f 342/342/342 343/343/343 325/325/325 +f 342/342/342 325/325/325 324/324/324 +f 335/335/335 344/344/344 326/326/326 +f 335/335/335 326/326/326 317/317/317 +f 345/345/345 346/346/346 347/347/347 +f 345/345/345 348/348/348 346/346/346 +f 345/345/345 349/349/349 348/348/348 +f 345/345/345 350/350/350 349/349/349 +f 345/345/345 351/351/351 350/350/350 +f 345/345/345 352/352/352 351/351/351 +f 345/345/345 353/353/353 352/352/352 +f 345/345/345 347/347/347 353/353/353 +f 354/354/354 355/355/355 356/356/356 +f 354/354/354 356/356/356 357/357/357 +f 358/358/358 359/359/359 360/360/360 +f 358/358/358 360/360/360 361/361/361 +f 362/362/362 363/363/363 364/364/364 +f 362/362/362 364/364/364 365/365/365 +f 366/366/366 367/367/367 368/368/368 +f 366/366/366 368/368/368 369/369/369 +f 370/370/370 371/371/371 372/372/372 +f 370/370/370 372/372/372 373/373/373 +f 374/374/374 375/375/375 376/376/376 +f 374/374/374 376/376/376 377/377/377 +f 378/378/378 379/379/379 380/380/380 +f 378/378/378 380/380/380 381/381/381 +f 382/382/382 383/383/383 384/384/384 +f 382/382/382 384/384/384 385/385/385 +f 386/386/386 387/387/387 388/388/388 +f 386/386/386 388/388/388 389/389/389 +f 386/386/386 389/389/389 390/390/390 +f 386/386/386 390/390/390 391/391/391 +f 386/386/386 391/391/391 392/392/392 +f 386/386/386 392/392/392 393/393/393 +f 386/386/386 393/393/393 394/394/394 +f 386/386/386 394/394/394 387/387/387 +f 395/395/395 396/396/396 397/397/397 +f 397/397/397 398/398/398 395/395/395 +f 399/399/399 400/400/400 401/401/401 +f 401/401/401 402/402/402 399/399/399 +f 403/403/403 404/404/404 405/405/405 +f 405/405/405 406/406/406 403/403/403 +f 407/407/407 408/408/408 409/409/409 +f 409/409/409 410/410/410 407/407/407 +f 411/411/411 412/412/412 413/413/413 +f 413/413/413 414/414/414 411/411/411 +f 415/415/415 416/416/416 417/417/417 +f 417/417/417 418/418/418 415/415/415 +f 419/419/419 420/420/420 421/421/421 +f 421/421/421 422/422/422 419/419/419 +f 423/423/423 424/424/424 425/425/425 +f 425/425/425 426/426/426 423/423/423 +f 427/427/427 428/428/428 429/429/429 +f 429/429/429 430/430/430 427/427/427 +f 431/431/431 432/432/432 433/433/433 +f 433/433/433 434/434/434 431/431/431 +f 435/435/435 436/436/436 437/437/437 +f 437/437/437 438/438/438 435/435/435 +f 439/439/439 440/440/440 441/441/441 +f 441/441/441 442/442/442 439/439/439 +f 443/443/443 444/444/444 445/445/445 +f 445/445/445 446/446/446 443/443/443 +f 447/447/447 448/448/448 449/449/449 +f 449/449/449 450/450/450 447/447/447 +f 451/451/451 452/452/452 453/453/453 +f 453/453/453 454/454/454 451/451/451 +f 455/455/455 456/456/456 457/457/457 +f 457/457/457 458/458/458 455/455/455 +f 446/446/446 445/445/445 459/459/459 +f 459/459/459 460/460/460 446/446/446 +f 450/450/450 449/449/449 461/461/461 +f 461/461/461 462/462/462 450/450/450 +f 454/454/454 453/453/453 463/463/463 +f 463/463/463 464/464/464 454/454/454 +f 458/458/458 457/457/457 465/465/465 +f 465/465/465 466/466/466 458/458/458 +f 460/460/460 459/459/459 467/467/467 +f 467/467/467 468/468/468 460/460/460 +f 462/462/462 461/461/461 469/469/469 +f 469/469/469 470/470/470 462/462/462 +f 464/464/464 463/463/463 471/471/471 +f 471/471/471 472/472/472 464/464/464 +f 466/466/466 465/465/465 473/473/473 +f 473/473/473 474/474/474 466/466/466 +f 468/468/468 467/467/467 475/475/475 +f 475/475/475 476/476/476 468/468/468 +f 470/470/470 469/469/469 477/477/477 +f 477/477/477 478/478/478 470/470/470 +f 472/472/472 471/471/471 479/479/479 +f 479/479/479 480/480/480 472/472/472 +f 474/474/474 473/473/473 481/481/481 +f 481/481/481 482/482/482 474/474/474 +f 476/476/476 475/475/475 483/483/483 +f 483/483/483 484/484/484 476/476/476 +f 478/478/478 477/477/477 485/485/485 +f 485/485/485 486/486/486 478/478/478 +f 480/480/480 479/479/479 487/487/487 +f 487/487/487 488/488/488 480/480/480 +f 482/482/482 481/481/481 489/489/489 +f 489/489/489 490/490/490 482/482/482 +f 491/491/491 492/492/492 493/493/493 +f 493/493/493 494/494/494 491/491/491 +f 495/495/495 496/496/496 497/497/497 +f 497/497/497 498/498/498 495/495/495 +f 499/499/499 500/500/500 501/501/501 +f 501/501/501 502/502/502 499/499/499 +f 503/503/503 504/504/504 505/505/505 +f 505/505/505 506/506/506 503/503/503 +f 430/430/430 429/429/429 507/507/507 +f 507/507/507 508/508/508 430/430/430 +f 434/434/434 433/433/433 509/509/509 +f 509/509/509 510/510/510 434/434/434 +f 438/438/438 437/437/437 511/511/511 +f 511/511/511 512/512/512 438/438/438 +f 442/442/442 441/441/441 513/513/513 +f 513/513/513 514/514/514 442/442/442 +f 508/508/508 507/507/507 515/515/515 +f 515/515/515 516/516/516 508/508/508 +f 510/510/510 509/509/509 517/517/517 +f 517/517/517 518/518/518 510/510/510 +f 512/512/512 511/511/511 519/519/519 +f 519/519/519 520/520/520 512/512/512 +f 514/514/514 513/513/513 521/521/521 +f 521/521/521 522/522/522 514/514/514 +f 516/516/516 515/515/515 523/523/523 +f 523/523/523 524/524/524 516/516/516 +f 518/518/518 517/517/517 525/525/525 +f 525/525/525 526/526/526 518/518/518 +f 520/520/520 519/519/519 527/527/527 +f 527/527/527 528/528/528 520/520/520 +f 522/522/522 521/521/521 529/529/529 +f 529/529/529 530/530/530 522/522/522 +f 531/531/531 532/532/532 533/533/533 +f 533/533/533 534/534/534 531/531/531 +f 535/535/535 536/536/536 537/537/537 +f 537/537/537 538/538/538 535/535/535 +f 539/539/539 540/540/540 541/541/541 +f 541/541/541 542/542/542 539/539/539 +f 543/543/543 544/544/544 545/545/545 +f 545/545/545 546/546/546 543/543/543 +f 547/547/547 548/548/548 549/549/549 +f 549/549/549 550/550/550 547/547/547 +f 551/551/551 552/552/552 553/553/553 +f 553/553/553 554/554/554 551/551/551 +f 555/555/555 556/556/556 557/557/557 +f 557/557/557 558/558/558 555/555/555 +f 559/559/559 560/560/560 561/561/561 +f 561/561/561 562/562/562 559/559/559 +f 563/563/563 564/564/564 565/565/565 +f 565/565/565 566/566/566 563/563/563 +f 567/567/567 568/568/568 569/569/569 +f 569/569/569 570/570/570 567/567/567 +f 571/571/571 572/572/572 573/573/573 +f 573/573/573 574/574/574 571/571/571 +f 575/575/575 571/571/571 574/574/574 +f 574/574/574 576/576/576 575/575/575 +f 577/577/577 575/575/575 576/576/576 +f 576/576/576 578/578/578 577/577/577 +f 579/579/579 577/577/577 578/578/578 +f 578/578/578 580/580/580 579/579/579 +f 581/581/581 579/579/579 580/580/580 +f 580/580/580 582/582/582 581/581/581 +f 583/583/583 581/581/581 582/582/582 +f 582/582/582 584/584/584 583/583/583 +f 585/585/585 583/583/583 584/584/584 +f 584/584/584 586/586/586 585/585/585 +f 587/587/587 585/585/585 586/586/586 +f 586/586/586 588/588/588 587/587/587 +f 589/589/589 587/587/587 588/588/588 +f 588/588/588 590/590/590 589/589/589 +f 572/572/572 589/589/589 590/590/590 +f 590/590/590 573/573/573 572/572/572 +f 591/591/591 592/592/592 572/572/572 +f 572/572/572 571/571/571 591/591/591 +f 593/593/593 591/591/591 571/571/571 +f 571/571/571 575/575/575 593/593/593 +f 594/594/594 593/593/593 575/575/575 +f 575/575/575 577/577/577 594/594/594 +f 595/595/595 594/594/594 577/577/577 +f 577/577/577 579/579/579 595/595/595 +f 596/596/596 595/595/595 579/579/579 +f 579/579/579 581/581/581 596/596/596 +f 597/597/597 596/596/596 581/581/581 +f 581/581/581 583/583/583 597/597/597 +f 598/598/598 597/597/597 583/583/583 +f 583/583/583 585/585/585 598/598/598 +f 599/599/599 598/598/598 585/585/585 +f 585/585/585 587/587/587 599/599/599 +f 600/600/600 599/599/599 587/587/587 +f 587/587/587 589/589/589 600/600/600 +f 592/592/592 600/600/600 589/589/589 +f 589/589/589 572/572/572 592/592/592 +f 601/601/601 602/602/602 603/603/603 +f 603/603/603 604/604/604 601/601/601 +f 605/605/605 606/606/606 607/607/607 +f 607/607/607 608/608/608 605/605/605 +f 609/609/609 610/610/610 611/611/611 +f 611/611/611 612/612/612 609/609/609 +f 613/613/613 614/614/614 615/615/615 +f 615/615/615 616/616/616 613/613/613 +f 617/617/617 618/618/618 619/619/619 +f 619/619/619 620/620/620 617/617/617 +f 621/621/621 622/622/622 623/623/623 +f 623/623/623 624/624/624 621/621/621 +f 625/625/625 626/626/626 627/627/627 +f 627/627/627 628/628/628 625/625/625 +f 629/629/629 630/630/630 631/631/631 +f 631/631/631 632/632/632 629/629/629 +f 633/633/633 634/634/634 635/635/635 +f 635/635/635 636/636/636 633/633/633 +f 637/637/637 638/638/638 639/639/639 +f 639/639/639 640/640/640 637/637/637 +f 641/641/641 642/642/642 643/643/643 +f 643/643/643 644/644/644 641/641/641 +f 645/645/645 646/646/646 647/647/647 +f 647/647/647 648/648/648 645/645/645 +f 649/649/649 650/650/650 651/651/651 +f 651/651/651 652/652/652 649/649/649 +f 653/653/653 654/654/654 655/655/655 +f 655/655/655 656/656/656 653/653/653 +f 657/657/657 658/658/658 659/659/659 +f 659/659/659 660/660/660 657/657/657 +f 661/661/661 662/662/662 663/663/663 +f 663/663/663 664/664/664 661/661/661 +f 665/665/665 666/666/666 667/667/667 +f 667/667/667 668/668/668 665/665/665 +f 669/669/669 670/670/670 671/671/671 +f 671/671/671 672/672/672 669/669/669 +f 673/673/673 674/674/674 675/675/675 +f 675/675/675 676/676/676 673/673/673 +f 677/677/677 678/678/678 679/679/679 +f 679/679/679 680/680/680 677/677/677 +f 681/681/681 682/682/682 683/683/683 +f 683/683/683 684/684/684 681/681/681 +f 685/685/685 686/686/686 687/687/687 +f 687/687/687 688/688/688 685/685/685 +f 689/689/689 690/690/690 691/691/691 +f 691/691/691 692/692/692 689/689/689 +f 693/693/693 694/694/694 695/695/695 +f 695/695/695 696/696/696 693/693/693 +f 697/697/697 698/698/698 699/699/699 +f 699/699/699 700/700/700 697/697/697 +f 701/701/701 702/702/702 703/703/703 +f 703/703/703 704/704/704 701/701/701 +f 705/705/705 706/706/706 707/707/707 +f 707/707/707 708/708/708 705/705/705 +f 709/709/709 710/710/710 711/711/711 +f 711/711/711 712/712/712 709/709/709 +f 713/713/713 714/714/714 715/715/715 +f 715/715/715 716/716/716 713/713/713 +f 717/717/717 718/718/718 719/719/719 +f 719/719/719 720/720/720 717/717/717 +f 721/721/721 722/722/722 723/723/723 +f 723/723/723 724/724/724 721/721/721 +f 725/725/725 726/726/726 727/727/727 +f 727/727/727 728/728/728 725/725/725 +f 729/729/729 730/730/730 731/731/731 +f 731/731/731 732/732/732 729/729/729 +f 733/733/733 734/734/734 735/735/735 +f 735/735/735 736/736/736 733/733/733 +f 737/737/737 738/738/738 739/739/739 +f 739/739/739 740/740/740 737/737/737 +f 741/741/741 742/742/742 743/743/743 +f 743/743/743 744/744/744 741/741/741 +f 745/745/745 746/746/746 747/747/747 +f 747/747/747 748/748/748 745/745/745 +f 749/749/749 750/750/750 751/751/751 +f 751/751/751 752/752/752 749/749/749 +f 753/753/753 754/754/754 755/755/755 +f 755/755/755 756/756/756 753/753/753 +f 757/757/757 758/758/758 759/759/759 +f 759/759/759 760/760/760 757/757/757 +f 761/761/761 762/762/762 763/763/763 +f 763/763/763 764/764/764 761/761/761 +f 765/765/765 766/766/766 767/767/767 +f 767/767/767 768/768/768 765/765/765 +f 769/769/769 770/770/770 771/771/771 +f 771/771/771 772/772/772 769/769/769 +f 773/773/773 774/774/774 775/775/775 +f 775/775/775 776/776/776 773/773/773 +f 777/777/777 778/778/778 779/779/779 +f 779/779/779 780/780/780 777/777/777 +f 781/781/781 782/782/782 783/783/783 +f 783/783/783 784/784/784 781/781/781 +f 785/785/785 786/786/786 787/787/787 +f 787/787/787 788/788/788 785/785/785 +f 789/789/789 790/790/790 791/791/791 +f 791/791/791 792/792/792 789/789/789 +f 793/793/793 794/794/794 795/795/795 +f 795/795/795 796/796/796 793/793/793 +f 797/797/797 798/798/798 799/799/799 +f 799/799/799 800/800/800 797/797/797 +f 801/801/801 802/802/802 803/803/803 +f 803/803/803 804/804/804 801/801/801 +f 805/805/805 806/806/806 807/807/807 +f 807/807/807 808/808/808 805/805/805 +f 809/809/809 810/810/810 811/811/811 +f 811/811/811 812/812/812 809/809/809 +f 813/813/813 814/814/814 815/815/815 +f 815/815/815 816/816/816 813/813/813 +f 817/817/817 818/818/818 819/819/819 +f 819/819/819 820/820/820 817/817/817 +f 821/821/821 822/822/822 823/823/823 +f 823/823/823 824/824/824 821/821/821 +f 825/825/825 826/826/826 827/827/827 +f 827/827/827 828/828/828 825/825/825 +f 829/829/829 830/830/830 831/831/831 +f 831/831/831 832/832/832 829/829/829 +f 833/833/833 834/834/834 835/835/835 +f 835/835/835 836/836/836 833/833/833 +f 837/837/837 838/838/838 839/839/839 +f 839/839/839 840/840/840 837/837/837 +f 841/841/841 842/842/842 843/843/843 +f 843/843/843 844/844/844 841/841/841 +f 845/845/845 846/846/846 847/847/847 +f 847/847/847 848/848/848 845/845/845 +f 849/849/849 850/850/850 851/851/851 +f 851/851/851 852/852/852 849/849/849 +f 853/853/853 854/854/854 855/855/855 +f 855/855/855 856/856/856 853/853/853 +f 857/857/857 858/858/858 859/859/859 +f 859/859/859 860/860/860 857/857/857 +f 861/861/861 862/862/862 863/863/863 +f 863/863/863 864/864/864 861/861/861 +f 865/865/865 866/866/866 867/867/867 +f 867/867/867 868/868/868 865/865/865 +f 869/869/869 870/870/870 871/871/871 +f 871/871/871 872/872/872 869/869/869 +f 873/873/873 874/874/874 875/875/875 +f 875/875/875 876/876/876 873/873/873 +f 877/877/877 878/878/878 879/879/879 +f 879/879/879 880/880/880 877/877/877 +f 881/881/881 882/882/882 883/883/883 +f 881/881/881 883/883/883 884/884/884 +f 885/885/885 881/881/881 884/884/884 +f 885/885/885 884/884/884 886/886/886 +f 887/887/887 885/885/885 886/886/886 +f 887/887/887 886/886/886 888/888/888 +f 889/889/889 887/887/887 888/888/888 +f 889/889/889 888/888/888 890/890/890 +f 891/891/891 889/889/889 890/890/890 +f 891/891/891 890/890/890 892/892/892 +f 893/893/893 891/891/891 892/892/892 +f 893/893/893 892/892/892 894/894/894 +f 895/895/895 893/893/893 894/894/894 +f 895/895/895 894/894/894 896/896/896 +f 897/897/897 895/895/895 896/896/896 +f 897/897/897 896/896/896 898/898/898 +f 899/899/899 900/900/900 901/901/901 +f 899/899/899 901/901/901 902/902/902 +f 882/882/882 899/899/899 902/902/902 +f 882/882/882 902/902/902 883/883/883 +f 903/903/903 904/904/904 882/882/882 +f 903/903/903 882/882/882 881/881/881 +f 905/905/905 903/903/903 881/881/881 +f 905/905/905 881/881/881 885/885/885 +f 906/906/906 905/905/905 885/885/885 +f 906/906/906 885/885/885 887/887/887 +f 907/907/907 906/906/906 887/887/887 +f 907/907/907 887/887/887 889/889/889 +f 908/908/908 907/907/907 889/889/889 +f 908/908/908 889/889/889 891/891/891 +f 909/909/909 908/908/908 891/891/891 +f 909/909/909 891/891/891 893/893/893 +f 910/910/910 909/909/909 893/893/893 +f 910/910/910 893/893/893 895/895/895 +f 911/911/911 910/910/910 895/895/895 +f 911/911/911 895/895/895 897/897/897 +f 912/912/912 913/913/913 900/900/900 +f 912/912/912 900/900/900 899/899/899 +f 904/904/904 912/912/912 899/899/899 +f 904/904/904 899/899/899 882/882/882 +f 914/914/914 915/915/915 904/904/904 +f 914/914/914 904/904/904 903/903/903 +f 916/916/916 914/914/914 903/903/903 +f 916/916/916 903/903/903 905/905/905 +f 917/917/917 916/916/916 905/905/905 +f 917/917/917 905/905/905 906/906/906 +f 918/918/918 917/917/917 906/906/906 +f 918/918/918 906/906/906 907/907/907 +f 919/919/919 918/918/918 907/907/907 +f 919/919/919 907/907/907 908/908/908 +f 920/920/920 919/919/919 908/908/908 +f 920/920/920 908/908/908 909/909/909 +f 921/921/921 920/920/920 909/909/909 +f 921/921/921 909/909/909 910/910/910 +f 922/922/922 921/921/921 910/910/910 +f 922/922/922 910/910/910 911/911/911 +f 923/923/923 924/924/924 913/913/913 +f 923/923/923 913/913/913 912/912/912 +f 915/915/915 923/923/923 912/912/912 +f 915/915/915 912/912/912 904/904/904 +f 925/925/925 926/926/926 915/915/915 +f 925/925/925 915/915/915 914/914/914 +f 927/927/927 925/925/925 914/914/914 +f 927/927/927 914/914/914 916/916/916 +f 928/928/928 927/927/927 916/916/916 +f 928/928/928 916/916/916 917/917/917 +f 929/929/929 928/928/928 917/917/917 +f 929/929/929 917/917/917 918/918/918 +f 930/930/930 929/929/929 918/918/918 +f 930/930/930 918/918/918 919/919/919 +f 931/931/931 930/930/930 919/919/919 +f 931/931/931 919/919/919 920/920/920 +f 932/932/932 931/931/931 920/920/920 +f 932/932/932 920/920/920 921/921/921 +f 933/933/933 932/932/932 921/921/921 +f 933/933/933 921/921/921 922/922/922 +f 934/934/934 935/935/935 924/924/924 +f 934/934/934 924/924/924 923/923/923 +f 926/926/926 934/934/934 923/923/923 +f 926/926/926 923/923/923 915/915/915 +f 936/936/936 937/937/937 926/926/926 +f 936/936/936 926/926/926 925/925/925 +f 938/938/938 936/936/936 925/925/925 +f 938/938/938 925/925/925 927/927/927 +f 939/939/939 938/938/938 927/927/927 +f 939/939/939 927/927/927 928/928/928 +f 940/940/940 939/939/939 928/928/928 +f 940/940/940 928/928/928 929/929/929 +f 941/941/941 940/940/940 929/929/929 +f 941/941/941 929/929/929 930/930/930 +f 942/942/942 941/941/941 930/930/930 +f 942/942/942 930/930/930 931/931/931 +f 943/943/943 942/942/942 931/931/931 +f 943/943/943 931/931/931 932/932/932 +f 944/944/944 943/943/943 932/932/932 +f 944/944/944 932/932/932 933/933/933 +f 945/945/945 946/946/946 935/935/935 +f 945/945/945 935/935/935 934/934/934 +f 937/937/937 945/945/945 934/934/934 +f 937/937/937 934/934/934 926/926/926 diff --git a/ObsoleteDemos/ConvexDecompositionDemo/main.cpp b/Demos/ConvexDecompositionDemo/main.cpp similarity index 100% rename from ObsoleteDemos/ConvexDecompositionDemo/main.cpp rename to Demos/ConvexDecompositionDemo/main.cpp diff --git a/ObsoleteDemos/ConvexDecompositionDemo/testFile32Single.bullet b/Demos/ConvexDecompositionDemo/testFile32Single.bullet similarity index 100% rename from ObsoleteDemos/ConvexDecompositionDemo/testFile32Single.bullet rename to Demos/ConvexDecompositionDemo/testFile32Single.bullet diff --git a/ObsoleteDemos/ConvexHullDistance/CMakeLists.txt b/Demos/ConvexHullDistance/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/ConvexHullDistance/CMakeLists.txt rename to Demos/ConvexHullDistance/CMakeLists.txt diff --git a/ObsoleteDemos/ConvexHullDistance/ConvexHullDistanceDemo.cpp b/Demos/ConvexHullDistance/ConvexHullDistanceDemo.cpp similarity index 100% rename from ObsoleteDemos/ConvexHullDistance/ConvexHullDistanceDemo.cpp rename to Demos/ConvexHullDistance/ConvexHullDistanceDemo.cpp diff --git a/ObsoleteDemos/DoublePrecisionDemo/CMakeLists.txt b/Demos/DoublePrecisionDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/DoublePrecisionDemo/CMakeLists.txt rename to Demos/DoublePrecisionDemo/CMakeLists.txt diff --git a/ObsoleteDemos/DoublePrecisionDemo/DoublePrecisionDemo.cpp b/Demos/DoublePrecisionDemo/DoublePrecisionDemo.cpp similarity index 100% rename from ObsoleteDemos/DoublePrecisionDemo/DoublePrecisionDemo.cpp rename to Demos/DoublePrecisionDemo/DoublePrecisionDemo.cpp diff --git a/ObsoleteDemos/DoublePrecisionDemo/DoublePrecisionDemo.h b/Demos/DoublePrecisionDemo/DoublePrecisionDemo.h similarity index 100% rename from ObsoleteDemos/DoublePrecisionDemo/DoublePrecisionDemo.h rename to Demos/DoublePrecisionDemo/DoublePrecisionDemo.h diff --git a/ObsoleteDemos/DynamicControlDemo/CMakeLists.txt b/Demos/DynamicControlDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/DynamicControlDemo/CMakeLists.txt rename to Demos/DynamicControlDemo/CMakeLists.txt diff --git a/ObsoleteDemos/DynamicControlDemo/MotorDemo.cpp b/Demos/DynamicControlDemo/MotorDemo.cpp similarity index 100% rename from ObsoleteDemos/DynamicControlDemo/MotorDemo.cpp rename to Demos/DynamicControlDemo/MotorDemo.cpp diff --git a/ObsoleteDemos/DynamicControlDemo/MotorDemo.h b/Demos/DynamicControlDemo/MotorDemo.h similarity index 100% rename from ObsoleteDemos/DynamicControlDemo/MotorDemo.h rename to Demos/DynamicControlDemo/MotorDemo.h diff --git a/ObsoleteDemos/DynamicControlDemo/main.cpp b/Demos/DynamicControlDemo/main.cpp similarity index 100% rename from ObsoleteDemos/DynamicControlDemo/main.cpp rename to Demos/DynamicControlDemo/main.cpp diff --git a/ObsoleteDemos/EPAPenDepthDemo/PenetrationTestBullet.cpp b/Demos/EPAPenDepthDemo/PenetrationTestBullet.cpp similarity index 100% rename from ObsoleteDemos/EPAPenDepthDemo/PenetrationTestBullet.cpp rename to Demos/EPAPenDepthDemo/PenetrationTestBullet.cpp diff --git a/ObsoleteDemos/FeatherstoneMultiBodyDemo/CMakeLists.txt b/Demos/FeatherstoneMultiBodyDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/FeatherstoneMultiBodyDemo/CMakeLists.txt rename to Demos/FeatherstoneMultiBodyDemo/CMakeLists.txt diff --git a/ObsoleteDemos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp b/Demos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp similarity index 100% rename from ObsoleteDemos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp rename to Demos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.cpp diff --git a/ObsoleteDemos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.h b/Demos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.h similarity index 100% rename from ObsoleteDemos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.h rename to Demos/FeatherstoneMultiBodyDemo/FeatherstoneMultiBodyDemo.h diff --git a/ObsoleteDemos/FeatherstoneMultiBodyDemo/Makefile.am b/Demos/FeatherstoneMultiBodyDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/FeatherstoneMultiBodyDemo/Makefile.am rename to Demos/FeatherstoneMultiBodyDemo/Makefile.am diff --git a/ObsoleteDemos/FeatherstoneMultiBodyDemo/Win32FeatherstoneMultiBodyDemo.cpp b/Demos/FeatherstoneMultiBodyDemo/Win32FeatherstoneMultiBodyDemo.cpp similarity index 100% rename from ObsoleteDemos/FeatherstoneMultiBodyDemo/Win32FeatherstoneMultiBodyDemo.cpp rename to Demos/FeatherstoneMultiBodyDemo/Win32FeatherstoneMultiBodyDemo.cpp diff --git a/ObsoleteDemos/FeatherstoneMultiBodyDemo/main.cpp b/Demos/FeatherstoneMultiBodyDemo/main.cpp similarity index 100% rename from ObsoleteDemos/FeatherstoneMultiBodyDemo/main.cpp rename to Demos/FeatherstoneMultiBodyDemo/main.cpp diff --git a/ObsoleteDemos/ForkLiftDemo/CMakeLists.txt b/Demos/ForkLiftDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/ForkLiftDemo/CMakeLists.txt rename to Demos/ForkLiftDemo/CMakeLists.txt diff --git a/ObsoleteDemos/ForkLiftDemo/ForkLiftDemo.cpp b/Demos/ForkLiftDemo/ForkLiftDemo.cpp similarity index 100% rename from ObsoleteDemos/ForkLiftDemo/ForkLiftDemo.cpp rename to Demos/ForkLiftDemo/ForkLiftDemo.cpp diff --git a/ObsoleteDemos/ForkLiftDemo/ForkLiftDemo.h b/Demos/ForkLiftDemo/ForkLiftDemo.h similarity index 100% rename from ObsoleteDemos/ForkLiftDemo/ForkLiftDemo.h rename to Demos/ForkLiftDemo/ForkLiftDemo.h diff --git a/ObsoleteDemos/ForkLiftDemo/Makefile.am b/Demos/ForkLiftDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/ForkLiftDemo/Makefile.am rename to Demos/ForkLiftDemo/Makefile.am diff --git a/ObsoleteDemos/ForkLiftDemo/main.cpp b/Demos/ForkLiftDemo/main.cpp similarity index 100% rename from ObsoleteDemos/ForkLiftDemo/main.cpp rename to Demos/ForkLiftDemo/main.cpp diff --git a/ObsoleteDemos/FractureDemo/CMakeLists.txt b/Demos/FractureDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/FractureDemo/CMakeLists.txt rename to Demos/FractureDemo/CMakeLists.txt diff --git a/ObsoleteDemos/FractureDemo/FractureDemo.cpp b/Demos/FractureDemo/FractureDemo.cpp similarity index 100% rename from ObsoleteDemos/FractureDemo/FractureDemo.cpp rename to Demos/FractureDemo/FractureDemo.cpp diff --git a/ObsoleteDemos/FractureDemo/FractureDemo.h b/Demos/FractureDemo/FractureDemo.h similarity index 100% rename from ObsoleteDemos/FractureDemo/FractureDemo.h rename to Demos/FractureDemo/FractureDemo.h diff --git a/ObsoleteDemos/FractureDemo/Win32FractureDemo.cpp b/Demos/FractureDemo/Win32FractureDemo.cpp similarity index 100% rename from ObsoleteDemos/FractureDemo/Win32FractureDemo.cpp rename to Demos/FractureDemo/Win32FractureDemo.cpp diff --git a/ObsoleteDemos/FractureDemo/btFractureBody.cpp b/Demos/FractureDemo/btFractureBody.cpp similarity index 100% rename from ObsoleteDemos/FractureDemo/btFractureBody.cpp rename to Demos/FractureDemo/btFractureBody.cpp diff --git a/ObsoleteDemos/FractureDemo/btFractureBody.h b/Demos/FractureDemo/btFractureBody.h similarity index 100% rename from ObsoleteDemos/FractureDemo/btFractureBody.h rename to Demos/FractureDemo/btFractureBody.h diff --git a/ObsoleteDemos/FractureDemo/btFractureDynamicsWorld.cpp b/Demos/FractureDemo/btFractureDynamicsWorld.cpp similarity index 100% rename from ObsoleteDemos/FractureDemo/btFractureDynamicsWorld.cpp rename to Demos/FractureDemo/btFractureDynamicsWorld.cpp diff --git a/ObsoleteDemos/FractureDemo/btFractureDynamicsWorld.h b/Demos/FractureDemo/btFractureDynamicsWorld.h similarity index 100% rename from ObsoleteDemos/FractureDemo/btFractureDynamicsWorld.h rename to Demos/FractureDemo/btFractureDynamicsWorld.h diff --git a/ObsoleteDemos/FractureDemo/main.cpp b/Demos/FractureDemo/main.cpp similarity index 100% rename from ObsoleteDemos/FractureDemo/main.cpp rename to Demos/FractureDemo/main.cpp diff --git a/ObsoleteDemos/GenericJointDemo/CMakeLists.txt b/Demos/GenericJointDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/GenericJointDemo/CMakeLists.txt rename to Demos/GenericJointDemo/CMakeLists.txt diff --git a/ObsoleteDemos/GenericJointDemo/GenericJointDemo.cpp b/Demos/GenericJointDemo/GenericJointDemo.cpp similarity index 100% rename from ObsoleteDemos/GenericJointDemo/GenericJointDemo.cpp rename to Demos/GenericJointDemo/GenericJointDemo.cpp diff --git a/ObsoleteDemos/GenericJointDemo/GenericJointDemo.h b/Demos/GenericJointDemo/GenericJointDemo.h similarity index 100% rename from ObsoleteDemos/GenericJointDemo/GenericJointDemo.h rename to Demos/GenericJointDemo/GenericJointDemo.h diff --git a/ObsoleteDemos/GenericJointDemo/Ragdoll.cpp b/Demos/GenericJointDemo/Ragdoll.cpp similarity index 100% rename from ObsoleteDemos/GenericJointDemo/Ragdoll.cpp rename to Demos/GenericJointDemo/Ragdoll.cpp diff --git a/ObsoleteDemos/GenericJointDemo/Ragdoll.h b/Demos/GenericJointDemo/Ragdoll.h similarity index 100% rename from ObsoleteDemos/GenericJointDemo/Ragdoll.h rename to Demos/GenericJointDemo/Ragdoll.h diff --git a/ObsoleteDemos/GenericJointDemo/Win32GenericJointDemo.cpp b/Demos/GenericJointDemo/Win32GenericJointDemo.cpp similarity index 100% rename from ObsoleteDemos/GenericJointDemo/Win32GenericJointDemo.cpp rename to Demos/GenericJointDemo/Win32GenericJointDemo.cpp diff --git a/ObsoleteDemos/GenericJointDemo/main.cpp b/Demos/GenericJointDemo/main.cpp similarity index 100% rename from ObsoleteDemos/GenericJointDemo/main.cpp rename to Demos/GenericJointDemo/main.cpp diff --git a/ObsoleteDemos/GimpactTestDemo/BunnyMesh.h b/Demos/GimpactTestDemo/BunnyMesh.h similarity index 100% rename from ObsoleteDemos/GimpactTestDemo/BunnyMesh.h rename to Demos/GimpactTestDemo/BunnyMesh.h diff --git a/ObsoleteDemos/GimpactTestDemo/CMakeLists.txt b/Demos/GimpactTestDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/GimpactTestDemo/CMakeLists.txt rename to Demos/GimpactTestDemo/CMakeLists.txt diff --git a/ObsoleteDemos/GimpactTestDemo/GimpactTestDemo.cpp b/Demos/GimpactTestDemo/GimpactTestDemo.cpp similarity index 100% rename from ObsoleteDemos/GimpactTestDemo/GimpactTestDemo.cpp rename to Demos/GimpactTestDemo/GimpactTestDemo.cpp diff --git a/ObsoleteDemos/GimpactTestDemo/GimpactTestDemo.h b/Demos/GimpactTestDemo/GimpactTestDemo.h similarity index 100% rename from ObsoleteDemos/GimpactTestDemo/GimpactTestDemo.h rename to Demos/GimpactTestDemo/GimpactTestDemo.h diff --git a/ObsoleteDemos/GimpactTestDemo/TorusMesh.h b/Demos/GimpactTestDemo/TorusMesh.h similarity index 100% rename from ObsoleteDemos/GimpactTestDemo/TorusMesh.h rename to Demos/GimpactTestDemo/TorusMesh.h diff --git a/ObsoleteDemos/GimpactTestDemo/Win32GimpactDemo.cpp b/Demos/GimpactTestDemo/Win32GimpactDemo.cpp similarity index 100% rename from ObsoleteDemos/GimpactTestDemo/Win32GimpactDemo.cpp rename to Demos/GimpactTestDemo/Win32GimpactDemo.cpp diff --git a/ObsoleteDemos/GimpactTestDemo/main.cpp b/Demos/GimpactTestDemo/main.cpp similarity index 100% rename from ObsoleteDemos/GimpactTestDemo/main.cpp rename to Demos/GimpactTestDemo/main.cpp diff --git a/ObsoleteDemos/GjkConvexCastDemo/CMakeLists.txt b/Demos/GjkConvexCastDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/GjkConvexCastDemo/CMakeLists.txt rename to Demos/GjkConvexCastDemo/CMakeLists.txt diff --git a/ObsoleteDemos/GjkConvexCastDemo/LinearConvexCastDemo.cpp b/Demos/GjkConvexCastDemo/LinearConvexCastDemo.cpp similarity index 100% rename from ObsoleteDemos/GjkConvexCastDemo/LinearConvexCastDemo.cpp rename to Demos/GjkConvexCastDemo/LinearConvexCastDemo.cpp diff --git a/ObsoleteDemos/GjkConvexCastDemo/LinearConvexCastDemo.h b/Demos/GjkConvexCastDemo/LinearConvexCastDemo.h similarity index 100% rename from ObsoleteDemos/GjkConvexCastDemo/LinearConvexCastDemo.h rename to Demos/GjkConvexCastDemo/LinearConvexCastDemo.h diff --git a/ObsoleteDemos/GjkConvexCastDemo/main.cpp b/Demos/GjkConvexCastDemo/main.cpp similarity index 100% rename from ObsoleteDemos/GjkConvexCastDemo/main.cpp rename to Demos/GjkConvexCastDemo/main.cpp diff --git a/ObsoleteDemos/Glut/GL/freeglut.h b/Demos/Glut/GL/freeglut.h similarity index 100% rename from ObsoleteDemos/Glut/GL/freeglut.h rename to Demos/Glut/GL/freeglut.h diff --git a/ObsoleteDemos/Glut/GL/freeglut_ext.h b/Demos/Glut/GL/freeglut_ext.h similarity index 100% rename from ObsoleteDemos/Glut/GL/freeglut_ext.h rename to Demos/Glut/GL/freeglut_ext.h diff --git a/ObsoleteDemos/Glut/GL/freeglut_std.h b/Demos/Glut/GL/freeglut_std.h similarity index 100% rename from ObsoleteDemos/Glut/GL/freeglut_std.h rename to Demos/Glut/GL/freeglut_std.h diff --git a/ObsoleteDemos/Glut/GL/glew.h b/Demos/Glut/GL/glew.h similarity index 100% rename from ObsoleteDemos/Glut/GL/glew.h rename to Demos/Glut/GL/glew.h diff --git a/ObsoleteDemos/Glut/GL/glext.h b/Demos/Glut/GL/glext.h similarity index 100% rename from ObsoleteDemos/Glut/GL/glext.h rename to Demos/Glut/GL/glext.h diff --git a/ObsoleteDemos/Glut/GL/glut.h b/Demos/Glut/GL/glut.h similarity index 100% rename from ObsoleteDemos/Glut/GL/glut.h rename to Demos/Glut/GL/glut.h diff --git a/ObsoleteDemos/Glut/GL/glxew.h b/Demos/Glut/GL/glxew.h similarity index 100% rename from ObsoleteDemos/Glut/GL/glxew.h rename to Demos/Glut/GL/glxew.h diff --git a/ObsoleteDemos/Glut/GL/glxext.h b/Demos/Glut/GL/glxext.h similarity index 100% rename from ObsoleteDemos/Glut/GL/glxext.h rename to Demos/Glut/GL/glxext.h diff --git a/ObsoleteDemos/Glut/GL/wglew.h b/Demos/Glut/GL/wglew.h similarity index 100% rename from ObsoleteDemos/Glut/GL/wglew.h rename to Demos/Glut/GL/wglew.h diff --git a/ObsoleteDemos/Glut/GL/wglext.h b/Demos/Glut/GL/wglext.h similarity index 100% rename from ObsoleteDemos/Glut/GL/wglext.h rename to Demos/Glut/GL/wglext.h diff --git a/ObsoleteDemos/Glut/btGlutInclude.h b/Demos/Glut/btGlutInclude.h similarity index 100% rename from ObsoleteDemos/Glut/btGlutInclude.h rename to Demos/Glut/btGlutInclude.h diff --git a/ObsoleteDemos/Glut/glew32s.lib b/Demos/Glut/glew32s.lib similarity index 100% rename from ObsoleteDemos/Glut/glew32s.lib rename to Demos/Glut/glew32s.lib diff --git a/ObsoleteDemos/Glut/glew64s.lib b/Demos/Glut/glew64s.lib similarity index 100% rename from ObsoleteDemos/Glut/glew64s.lib rename to Demos/Glut/glew64s.lib diff --git a/ObsoleteDemos/Glut/glut32.lib b/Demos/Glut/glut32.lib similarity index 100% rename from ObsoleteDemos/Glut/glut32.lib rename to Demos/Glut/glut32.lib diff --git a/ObsoleteDemos/Glut/glut64.lib b/Demos/Glut/glut64.lib similarity index 100% rename from ObsoleteDemos/Glut/glut64.lib rename to Demos/Glut/glut64.lib diff --git a/ObsoleteDemos/GyroscopicDemo/CMakeLists.txt b/Demos/GyroscopicDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/GyroscopicDemo/CMakeLists.txt rename to Demos/GyroscopicDemo/CMakeLists.txt diff --git a/ObsoleteDemos/GyroscopicDemo/GyroscopicDemo.cpp b/Demos/GyroscopicDemo/GyroscopicDemo.cpp similarity index 100% rename from ObsoleteDemos/GyroscopicDemo/GyroscopicDemo.cpp rename to Demos/GyroscopicDemo/GyroscopicDemo.cpp diff --git a/ObsoleteDemos/GyroscopicDemo/GyroscopicDemo.h b/Demos/GyroscopicDemo/GyroscopicDemo.h similarity index 100% rename from ObsoleteDemos/GyroscopicDemo/GyroscopicDemo.h rename to Demos/GyroscopicDemo/GyroscopicDemo.h diff --git a/ObsoleteDemos/GyroscopicDemo/Win32GyroscopicDemo.cpp b/Demos/GyroscopicDemo/Win32GyroscopicDemo.cpp similarity index 100% rename from ObsoleteDemos/GyroscopicDemo/Win32GyroscopicDemo.cpp rename to Demos/GyroscopicDemo/Win32GyroscopicDemo.cpp diff --git a/ObsoleteDemos/GyroscopicDemo/main.cpp b/Demos/GyroscopicDemo/main.cpp similarity index 100% rename from ObsoleteDemos/GyroscopicDemo/main.cpp rename to Demos/GyroscopicDemo/main.cpp diff --git a/ObsoleteDemos/HelloWorld/CMakeLists.txt b/Demos/HelloWorld/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/HelloWorld/CMakeLists.txt rename to Demos/HelloWorld/CMakeLists.txt diff --git a/ObsoleteDemos/HelloWorld/HelloWorld.cpp b/Demos/HelloWorld/HelloWorld.cpp similarity index 100% rename from ObsoleteDemos/HelloWorld/HelloWorld.cpp rename to Demos/HelloWorld/HelloWorld.cpp diff --git a/ObsoleteDemos/HelloWorld/premake4.lua b/Demos/HelloWorld/premake4.lua similarity index 100% rename from ObsoleteDemos/HelloWorld/premake4.lua rename to Demos/HelloWorld/premake4.lua diff --git a/ObsoleteDemos/InternalEdgeDemo/CMakeLists.txt b/Demos/InternalEdgeDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/InternalEdgeDemo/CMakeLists.txt rename to Demos/InternalEdgeDemo/CMakeLists.txt diff --git a/ObsoleteDemos/InternalEdgeDemo/InternalEdgeDemo.cpp b/Demos/InternalEdgeDemo/InternalEdgeDemo.cpp similarity index 100% rename from ObsoleteDemos/InternalEdgeDemo/InternalEdgeDemo.cpp rename to Demos/InternalEdgeDemo/InternalEdgeDemo.cpp diff --git a/ObsoleteDemos/InternalEdgeDemo/InternalEdgeDemo.h b/Demos/InternalEdgeDemo/InternalEdgeDemo.h similarity index 100% rename from ObsoleteDemos/InternalEdgeDemo/InternalEdgeDemo.h rename to Demos/InternalEdgeDemo/InternalEdgeDemo.h diff --git a/ObsoleteDemos/InternalEdgeDemo/Taru.mdl b/Demos/InternalEdgeDemo/Taru.mdl similarity index 100% rename from ObsoleteDemos/InternalEdgeDemo/Taru.mdl rename to Demos/InternalEdgeDemo/Taru.mdl diff --git a/ObsoleteDemos/InternalEdgeDemo/Win32InternalEdgeDemo.cpp b/Demos/InternalEdgeDemo/Win32InternalEdgeDemo.cpp similarity index 100% rename from ObsoleteDemos/InternalEdgeDemo/Win32InternalEdgeDemo.cpp rename to Demos/InternalEdgeDemo/Win32InternalEdgeDemo.cpp diff --git a/ObsoleteDemos/InternalEdgeDemo/main.cpp b/Demos/InternalEdgeDemo/main.cpp similarity index 100% rename from ObsoleteDemos/InternalEdgeDemo/main.cpp rename to Demos/InternalEdgeDemo/main.cpp diff --git a/ObsoleteDemos/MovingConcaveDemo/CMakeLists.txt b/Demos/MovingConcaveDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/MovingConcaveDemo/CMakeLists.txt rename to Demos/MovingConcaveDemo/CMakeLists.txt diff --git a/ObsoleteDemos/MovingConcaveDemo/ConcaveDemo.h b/Demos/MovingConcaveDemo/ConcaveDemo.h similarity index 100% rename from ObsoleteDemos/MovingConcaveDemo/ConcaveDemo.h rename to Demos/MovingConcaveDemo/ConcaveDemo.h diff --git a/ObsoleteDemos/MovingConcaveDemo/ConcavePhysicsDemo.cpp b/Demos/MovingConcaveDemo/ConcavePhysicsDemo.cpp similarity index 100% rename from ObsoleteDemos/MovingConcaveDemo/ConcavePhysicsDemo.cpp rename to Demos/MovingConcaveDemo/ConcavePhysicsDemo.cpp diff --git a/ObsoleteDemos/MultiMaterialDemo/CMakeLists.txt b/Demos/MultiMaterialDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/MultiMaterialDemo/CMakeLists.txt rename to Demos/MultiMaterialDemo/CMakeLists.txt diff --git a/ObsoleteDemos/MultiMaterialDemo/MultiMaterialDemo.cpp b/Demos/MultiMaterialDemo/MultiMaterialDemo.cpp similarity index 100% rename from ObsoleteDemos/MultiMaterialDemo/MultiMaterialDemo.cpp rename to Demos/MultiMaterialDemo/MultiMaterialDemo.cpp diff --git a/ObsoleteDemos/MultiMaterialDemo/MultiMaterialDemo.h b/Demos/MultiMaterialDemo/MultiMaterialDemo.h similarity index 100% rename from ObsoleteDemos/MultiMaterialDemo/MultiMaterialDemo.h rename to Demos/MultiMaterialDemo/MultiMaterialDemo.h diff --git a/ObsoleteDemos/MultiMaterialDemo/main.cpp b/Demos/MultiMaterialDemo/main.cpp similarity index 100% rename from ObsoleteDemos/MultiMaterialDemo/main.cpp rename to Demos/MultiMaterialDemo/main.cpp diff --git a/ObsoleteDemos/MultiThreadedDemo/CMakeLists.txt b/Demos/MultiThreadedDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/MultiThreadedDemo/CMakeLists.txt rename to Demos/MultiThreadedDemo/CMakeLists.txt diff --git a/ObsoleteDemos/MultiThreadedDemo/Makefile.am b/Demos/MultiThreadedDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/MultiThreadedDemo/Makefile.am rename to Demos/MultiThreadedDemo/Makefile.am diff --git a/ObsoleteDemos/MultiThreadedDemo/MultiThreadedDemo.cpp b/Demos/MultiThreadedDemo/MultiThreadedDemo.cpp similarity index 100% rename from ObsoleteDemos/MultiThreadedDemo/MultiThreadedDemo.cpp rename to Demos/MultiThreadedDemo/MultiThreadedDemo.cpp diff --git a/ObsoleteDemos/MultiThreadedDemo/MultiThreadedDemo.h b/Demos/MultiThreadedDemo/MultiThreadedDemo.h similarity index 100% rename from ObsoleteDemos/MultiThreadedDemo/MultiThreadedDemo.h rename to Demos/MultiThreadedDemo/MultiThreadedDemo.h diff --git a/ObsoleteDemos/MultiThreadedDemo/main.cpp b/Demos/MultiThreadedDemo/main.cpp similarity index 100% rename from ObsoleteDemos/MultiThreadedDemo/main.cpp rename to Demos/MultiThreadedDemo/main.cpp diff --git a/ObsoleteDemos/NativeClient/bin_html/bind.js b/Demos/NativeClient/bin_html/bind.js similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/bind.js rename to Demos/NativeClient/bin_html/bind.js diff --git a/ObsoleteDemos/NativeClient/bin_html/dragger.js b/Demos/NativeClient/bin_html/dragger.js similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/dragger.js rename to Demos/NativeClient/bin_html/dragger.js diff --git a/ObsoleteDemos/NativeClient/bin_html/httpd.cmd b/Demos/NativeClient/bin_html/httpd.cmd similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/httpd.cmd rename to Demos/NativeClient/bin_html/httpd.cmd diff --git a/ObsoleteDemos/NativeClient/bin_html/httpd.py b/Demos/NativeClient/bin_html/httpd.py similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/httpd.py rename to Demos/NativeClient/bin_html/httpd.py diff --git a/ObsoleteDemos/NativeClient/bin_html/index.html b/Demos/NativeClient/bin_html/index.html similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/index.html rename to Demos/NativeClient/bin_html/index.html diff --git a/ObsoleteDemos/NativeClient/bin_html/trackball.js b/Demos/NativeClient/bin_html/trackball.js similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/trackball.js rename to Demos/NativeClient/bin_html/trackball.js diff --git a/ObsoleteDemos/NativeClient/bin_html/tumbler.js b/Demos/NativeClient/bin_html/tumbler.js similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/tumbler.js rename to Demos/NativeClient/bin_html/tumbler.js diff --git a/ObsoleteDemos/NativeClient/bin_html/tumbler.nmf b/Demos/NativeClient/bin_html/tumbler.nmf similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/tumbler.nmf rename to Demos/NativeClient/bin_html/tumbler.nmf diff --git a/ObsoleteDemos/NativeClient/bin_html/vector3.js b/Demos/NativeClient/bin_html/vector3.js similarity index 100% rename from ObsoleteDemos/NativeClient/bin_html/vector3.js rename to Demos/NativeClient/bin_html/vector3.js diff --git a/ObsoleteDemos/NativeClient/callback.h b/Demos/NativeClient/callback.h similarity index 100% rename from ObsoleteDemos/NativeClient/callback.h rename to Demos/NativeClient/callback.h diff --git a/ObsoleteDemos/NativeClient/cube.cc b/Demos/NativeClient/cube.cc similarity index 100% rename from ObsoleteDemos/NativeClient/cube.cc rename to Demos/NativeClient/cube.cc diff --git a/ObsoleteDemos/NativeClient/cube.h b/Demos/NativeClient/cube.h similarity index 100% rename from ObsoleteDemos/NativeClient/cube.h rename to Demos/NativeClient/cube.h diff --git a/ObsoleteDemos/NativeClient/opengl_context.cc b/Demos/NativeClient/opengl_context.cc similarity index 100% rename from ObsoleteDemos/NativeClient/opengl_context.cc rename to Demos/NativeClient/opengl_context.cc diff --git a/ObsoleteDemos/NativeClient/opengl_context.h b/Demos/NativeClient/opengl_context.h similarity index 100% rename from ObsoleteDemos/NativeClient/opengl_context.h rename to Demos/NativeClient/opengl_context.h diff --git a/ObsoleteDemos/NativeClient/opengl_context_ptrs.h b/Demos/NativeClient/opengl_context_ptrs.h similarity index 100% rename from ObsoleteDemos/NativeClient/opengl_context_ptrs.h rename to Demos/NativeClient/opengl_context_ptrs.h diff --git a/ObsoleteDemos/NativeClient/premake4.lua b/Demos/NativeClient/premake4.lua similarity index 100% rename from ObsoleteDemos/NativeClient/premake4.lua rename to Demos/NativeClient/premake4.lua diff --git a/ObsoleteDemos/NativeClient/scripting_bridge.cc b/Demos/NativeClient/scripting_bridge.cc similarity index 100% rename from ObsoleteDemos/NativeClient/scripting_bridge.cc rename to Demos/NativeClient/scripting_bridge.cc diff --git a/ObsoleteDemos/NativeClient/scripting_bridge.h b/Demos/NativeClient/scripting_bridge.h similarity index 100% rename from ObsoleteDemos/NativeClient/scripting_bridge.h rename to Demos/NativeClient/scripting_bridge.h diff --git a/ObsoleteDemos/NativeClient/shader_util.cc b/Demos/NativeClient/shader_util.cc similarity index 100% rename from ObsoleteDemos/NativeClient/shader_util.cc rename to Demos/NativeClient/shader_util.cc diff --git a/ObsoleteDemos/NativeClient/shader_util.h b/Demos/NativeClient/shader_util.h similarity index 100% rename from ObsoleteDemos/NativeClient/shader_util.h rename to Demos/NativeClient/shader_util.h diff --git a/ObsoleteDemos/NativeClient/transforms.cc b/Demos/NativeClient/transforms.cc similarity index 100% rename from ObsoleteDemos/NativeClient/transforms.cc rename to Demos/NativeClient/transforms.cc diff --git a/ObsoleteDemos/NativeClient/transforms.h b/Demos/NativeClient/transforms.h similarity index 100% rename from ObsoleteDemos/NativeClient/transforms.h rename to Demos/NativeClient/transforms.h diff --git a/ObsoleteDemos/NativeClient/tumbler.cc b/Demos/NativeClient/tumbler.cc similarity index 100% rename from ObsoleteDemos/NativeClient/tumbler.cc rename to Demos/NativeClient/tumbler.cc diff --git a/ObsoleteDemos/NativeClient/tumbler.h b/Demos/NativeClient/tumbler.h similarity index 100% rename from ObsoleteDemos/NativeClient/tumbler.h rename to Demos/NativeClient/tumbler.h diff --git a/ObsoleteDemos/NativeClient/tumbler_module.cc b/Demos/NativeClient/tumbler_module.cc similarity index 100% rename from ObsoleteDemos/NativeClient/tumbler_module.cc rename to Demos/NativeClient/tumbler_module.cc diff --git a/ObsoleteDemos/OpenGL/CMakeLists.txt b/Demos/OpenGL/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/OpenGL/CMakeLists.txt rename to Demos/OpenGL/CMakeLists.txt diff --git a/ObsoleteDemos/OpenGL/CommandLineArguments.h b/Demos/OpenGL/CommandLineArguments.h similarity index 100% rename from ObsoleteDemos/OpenGL/CommandLineArguments.h rename to Demos/OpenGL/CommandLineArguments.h diff --git a/ObsoleteDemos/OpenGL/DebugCastResult.h b/Demos/OpenGL/DebugCastResult.h similarity index 100% rename from ObsoleteDemos/OpenGL/DebugCastResult.h rename to Demos/OpenGL/DebugCastResult.h diff --git a/ObsoleteDemos/OpenGL/DemoApplication.cpp b/Demos/OpenGL/DemoApplication.cpp similarity index 97% rename from ObsoleteDemos/OpenGL/DemoApplication.cpp rename to Demos/OpenGL/DemoApplication.cpp index 3baaca44c..e373a08e3 100644 --- a/ObsoleteDemos/OpenGL/DemoApplication.cpp +++ b/Demos/OpenGL/DemoApplication.cpp @@ -4,8 +4,8 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -43,7 +43,7 @@ btCollisionShape* gShapePtr[maxNumObjects];//1 rigidbody has 1 shape (no re-use extern int gNumClampedCcdMotions; -#ifdef SHOW_NUM_DEEP_PENETRATIONS +#ifdef SHOW_NUM_DEEP_PENETRATIONS extern int gNumDeepPenetrationChecks; extern int gNumSplitImpulseRecoveries; @@ -75,7 +75,7 @@ m_scaleBottom(0.5f), m_scaleFactor(2.f), m_cameraUp(0,1,0), m_forwardAxis(2), -m_zoomStepSize(0.4), +m_zoomStepSize(0.4), m_glutScreenWidth(0), m_glutScreenHeight(0), m_frustumZNear(1.f), @@ -220,20 +220,20 @@ void DemoApplication::updateCamera() { aspect = m_glutScreenWidth / (btScalar)m_glutScreenHeight; extents.setValue(aspect * 1.0f, 1.0f,0); - - + + if (m_ortho) { // reset matrix glLoadIdentity(); - - + + extents *= m_cameraDistance; btVector3 lower = m_cameraTargetPosition - extents; btVector3 upper = m_cameraTargetPosition + extents; //gluOrtho2D(lower.x, upper.x, lower.y, upper.y); glOrtho(lower.getX(), upper.getX(), lower.getY(), upper.getY(),-1000,1000); - + glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //glTranslatef(100,210,0); @@ -243,8 +243,8 @@ void DemoApplication::updateCamera() { glFrustum (-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - gluLookAt(m_cameraPosition[0], m_cameraPosition[1], m_cameraPosition[2], - m_cameraTargetPosition[0], m_cameraTargetPosition[1], m_cameraTargetPosition[2], + gluLookAt(m_cameraPosition[0], m_cameraPosition[1], m_cameraPosition[2], + m_cameraTargetPosition[0], m_cameraTargetPosition[1], m_cameraTargetPosition[2], m_cameraUp.getX(),m_cameraUp.getY(),m_cameraUp.getZ()); } @@ -254,32 +254,32 @@ void DemoApplication::updateCamera() { const float STEPSIZE = 5; -void DemoApplication::stepLeft() -{ - m_azi -= STEPSIZE; if (m_azi < 0) m_azi += 360; updateCamera(); +void DemoApplication::stepLeft() +{ + m_azi -= STEPSIZE; if (m_azi < 0) m_azi += 360; updateCamera(); } -void DemoApplication::stepRight() -{ - m_azi += STEPSIZE; if (m_azi >= 360) m_azi -= 360; updateCamera(); +void DemoApplication::stepRight() +{ + m_azi += STEPSIZE; if (m_azi >= 360) m_azi -= 360; updateCamera(); } -void DemoApplication::stepFront() -{ - m_ele += STEPSIZE; if (m_ele >= 360) m_ele -= 360; updateCamera(); +void DemoApplication::stepFront() +{ + m_ele += STEPSIZE; if (m_ele >= 360) m_ele -= 360; updateCamera(); } -void DemoApplication::stepBack() -{ - m_ele -= STEPSIZE; if (m_ele < 0) m_ele += 360; updateCamera(); +void DemoApplication::stepBack() +{ + m_ele -= STEPSIZE; if (m_ele < 0) m_ele += 360; updateCamera(); } -void DemoApplication::zoomIn() -{ - m_cameraDistance -= btScalar(m_zoomStepSize); updateCamera(); +void DemoApplication::zoomIn() +{ + m_cameraDistance -= btScalar(m_zoomStepSize); updateCamera(); if (m_cameraDistance < btScalar(0.1)) m_cameraDistance = btScalar(0.1); } -void DemoApplication::zoomOut() -{ - m_cameraDistance += btScalar(m_zoomStepSize); updateCamera(); +void DemoApplication::zoomOut() +{ + m_cameraDistance += btScalar(m_zoomStepSize); updateCamera(); } @@ -292,7 +292,7 @@ void DemoApplication::zoomOut() -void DemoApplication::reshape(int w, int h) +void DemoApplication::reshape(int w, int h) { GLDebugResetFont(w,h); @@ -324,7 +324,7 @@ void DemoApplication::keyboardCallback(unsigned char key, int x, int y) } #endif //BT_NO_PROFILE - switch (key) + switch (key) { case 8: { @@ -337,7 +337,7 @@ void DemoApplication::keyboardCallback(unsigned char key, int x, int y) btRigidBody* body = btRigidBody::upcast(obj); if (body && body->getMotionState()) { - delete body->getMotionState(); + delete body->getMotionState(); } delete obj; @@ -345,7 +345,7 @@ void DemoApplication::keyboardCallback(unsigned char key, int x, int y) } break; } - case 'q' : + case 'q' : #ifdef BT_USE_FREEGLUT //return from glutMainLoop(), detect memory leaks etc. glutLeaveMainLoop(); @@ -418,44 +418,44 @@ void DemoApplication::keyboardCallback(unsigned char key, int x, int y) m_debugMode |= btIDebugDraw::DBG_DrawNormals; break; - case 't' : + case 't' : if (m_debugMode & btIDebugDraw::DBG_DrawText) m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawText); else m_debugMode |= btIDebugDraw::DBG_DrawText; break; - case 'y': + case 'y': if (m_debugMode & btIDebugDraw::DBG_DrawFeaturesText) m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawFeaturesText); else m_debugMode |= btIDebugDraw::DBG_DrawFeaturesText; break; - case 'a': + case 'a': if (m_debugMode & btIDebugDraw::DBG_DrawAabb) m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawAabb); else m_debugMode |= btIDebugDraw::DBG_DrawAabb; break; - case 'c' : + case 'c' : if (m_debugMode & btIDebugDraw::DBG_DrawContactPoints) m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawContactPoints); else m_debugMode |= btIDebugDraw::DBG_DrawContactPoints; break; - case 'C' : + case 'C' : if (m_debugMode & btIDebugDraw::DBG_DrawConstraints) m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawConstraints); else m_debugMode |= btIDebugDraw::DBG_DrawConstraints; break; - case 'L' : + case 'L' : if (m_debugMode & btIDebugDraw::DBG_DrawConstraintLimits) m_debugMode = m_debugMode & (~btIDebugDraw::DBG_DrawConstraintLimits); else m_debugMode |= btIDebugDraw::DBG_DrawConstraintLimits; break; - case 'd' : + case 'd' : if (m_debugMode & btIDebugDraw::DBG_NoDeactivation) m_debugMode = m_debugMode & (~btIDebugDraw::DBG_NoDeactivation); else @@ -516,7 +516,7 @@ void DemoApplication::keyboardCallback(unsigned char key, int x, int y) if (getDynamicsWorld() && getDynamicsWorld()->getDebugDrawer()) getDynamicsWorld()->getDebugDrawer()->setDebugMode(m_debugMode); - + } @@ -589,7 +589,7 @@ void DemoApplication::shootBox(const btVector3& destination) // printf("shootBox uid=%d\n", body->getBroadphaseHandle()->getUid()); // printf("camPos=%f,%f,%f\n",camPos.getX(),camPos.getY(),camPos.getZ()); // printf("destination=%f,%f,%f\n",destination.getX(),destination.getY(),destination.getZ()); - + } } @@ -604,7 +604,7 @@ btRigidBody* pickedBody = 0;//for deactivation state btVector3 DemoApplication::getRayTo(int x,int y) { - + if (m_ortho) { @@ -613,14 +613,14 @@ btVector3 DemoApplication::getRayTo(int x,int y) btVector3 extents; aspect = m_glutScreenWidth / (btScalar)m_glutScreenHeight; extents.setValue(aspect * 1.0f, 1.0f,0); - + extents *= m_cameraDistance; btVector3 lower = m_cameraTargetPosition - extents; btVector3 upper = m_cameraTargetPosition + extents; btScalar u = x / btScalar(m_glutScreenWidth); btScalar v = (m_glutScreenHeight - y) / btScalar(m_glutScreenHeight); - + btVector3 p(0,0,0); p.setValue((1.0f - u) * lower.getX() + u * upper.getX(),(1.0f - v) * lower.getY() + v * upper.getY(),m_cameraTargetPosition.getZ()); return p; @@ -654,9 +654,9 @@ btVector3 DemoApplication::getRayTo(int x,int y) vertical *= 2.f * farPlane * tanfov; btScalar aspect; - + aspect = m_glutScreenWidth / (btScalar)m_glutScreenHeight; - + hor*=aspect; @@ -676,7 +676,7 @@ btScalar mousePickClamping = 30.f; void DemoApplication::mouseFunc(int button, int state, int x, int y) { - if (state == 0) + if (state == 0) { m_mouseButtons |= 1<rayTest(rayFrom,rayTo,rayCallback); if (rayCallback.hasHit()) { btVector3 pickPos = rayCallback.m_hitPointWorld; - + pickObject(pickPos, rayCallback.m_collisionObject); - + gOldPickingPos = rayTo; gHitPos = pickPos; @@ -801,7 +801,7 @@ void DemoApplication::mouseFunc(int button, int state, int x, int y) void DemoApplication::pickObject(const btVector3& pickPos, const btCollisionObject* hitObj) { - + btRigidBody* body = (btRigidBody*)btRigidBody::upcast(hitObj); if (body) { @@ -860,15 +860,15 @@ void DemoApplication::pickObject(const btVector3& pickPos, const btCollisionObje p2p->setParam(BT_CONSTRAINT_ERP,0.1,1); p2p->setParam(BT_CONSTRAINT_ERP,0.1,2); */ - + } - + //save mouse position for dragging - + } } - + } void DemoApplication::removePickingConstraint() @@ -979,21 +979,21 @@ void DemoApplication::mouseMotionFunc(int x,int y) if(m_mouseButtons & (2 << 2) && m_mouseButtons & 1) { } - else if(m_mouseButtons & 1) + else if(m_mouseButtons & 1) { m_azi += dx * btScalar(0.2); m_azi = fmodf(m_azi, btScalar(360.f)); m_ele += dy * btScalar(0.2); m_ele = fmodf(m_ele, btScalar(180.f)); - } - else if(m_mouseButtons & 4) + } + else if(m_mouseButtons & 4) { m_cameraDistance -= dy * btScalar(0.02f); if (m_cameraDistancesetContactProcessingThreshold(m_defaultContactProcessingThreshold); #else - btRigidBody* body = new btRigidBody(mass,0,shape,localInertia); + btRigidBody* body = new btRigidBody(mass,0,shape,localInertia); body->setWorldTransform(startTransform); #endif// @@ -1039,13 +1039,13 @@ btRigidBody* DemoApplication::localCreateRigidBody(float mass, const btTransform } //See http://www.lighthouse3d.com/opengl/glut/index.php?bmpfontortho -void DemoApplication::setOrthographicProjection() +void DemoApplication::setOrthographicProjection() { // switch to projection mode glMatrixMode(GL_PROJECTION); - // save previous matrix which contains the + // save previous matrix which contains the //settings for the perspective projection glPushMatrix(); // reset matrix @@ -1063,7 +1063,7 @@ void DemoApplication::setOrthographicProjection() } -void DemoApplication::resetPerspectiveProjection() +void DemoApplication::resetPerspectiveProjection() { glMatrixMode(GL_PROJECTION); @@ -1189,7 +1189,7 @@ void DemoApplication::renderscene(int pass) wireColor += btVector3 (1.f,0.f,0.f); } else - { + { wireColor += btVector3 (.5f,0.f,0.f); } } @@ -1207,7 +1207,7 @@ void DemoApplication::renderscene(int pass) btVector3 aabbMin(0,0,0),aabbMax(0,0,0); //m_dynamicsWorld->getBroadphase()->getBroadphaseAabb(aabbMin,aabbMax); - + aabbMin-=btVector3(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); aabbMax+=btVector3(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); // printf("aabbMin=(%f,%f,%f)\n",aabbMin.getX(),aabbMin.getY(),aabbMin.getZ()); @@ -1235,7 +1235,7 @@ void DemoApplication::renderme() updateCamera(); if (m_dynamicsWorld) - { + { if(m_enableshadows) { glClear(GL_STENCIL_BUFFER_BIT); @@ -1300,7 +1300,7 @@ void DemoApplication::renderme() #ifdef USE_QUICKPROF - + if ( getDebugMode() & btIDebugDraw::DBG_ProfileTimings) { static int counter = 0; @@ -1320,7 +1320,7 @@ void DemoApplication::renderme() #endif //USE_QUICKPROF - + resetPerspectiveProjection(); } @@ -1358,11 +1358,11 @@ void DemoApplication::clientResetScene() m_dynamicsWorld->getConstraint(0)->setEnabled(true); } numObjects = m_dynamicsWorld->getNumCollisionObjects(); - + ///create a copy of the array, not a reference! btCollisionObjectArray copyArray = m_dynamicsWorld->getCollisionObjectArray(); - + for (i=0;ienableTexture(enable)); } bool setShadows(bool enable) { bool p=m_enableshadows;m_enableshadows=enable;return(p); } bool getTexturing() const @@ -145,9 +145,9 @@ public: { return m_debugMode ; } - + void setDebugMode(int mode); - + void setAzi(float azi) { m_azi = azi; @@ -157,7 +157,7 @@ public: { m_ele = ele; } - + void setCameraUp(const btVector3& camUp) { m_cameraUp = camUp; @@ -170,7 +170,7 @@ public: virtual void myinit(); void toggleIdle(); - + virtual void updateCamera(); btVector3 getCameraPosition() @@ -199,9 +199,9 @@ public: } ///glut callbacks - + float getCameraDistance(); - void setCameraDistance(float dist); + void setCameraDistance(float dist); void moveAndDisplay(); virtual void clientMoveAndDisplay() = 0; @@ -217,12 +217,12 @@ public: btRigidBody* localCreateRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape); - ///callback methods by glut + ///callback methods by glut virtual void keyboardCallback(unsigned char key, int x, int y); - + virtual void keyboardUpCallback(unsigned char key, int x, int y) {} - + virtual void specialKeyboard(int key, int x, int y){} virtual void specialKeyboardUp(int key, int x, int y){} @@ -232,7 +232,7 @@ public: virtual void mouseFunc(int button, int state, int x, int y); virtual void mouseMotionFunc(int x,int y); - + virtual void displayCallback(); virtual void renderme(); diff --git a/ObsoleteDemos/OpenGL/GLDebugDrawer.cpp b/Demos/OpenGL/GLDebugDrawer.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/GLDebugDrawer.cpp rename to Demos/OpenGL/GLDebugDrawer.cpp diff --git a/ObsoleteDemos/OpenGL/GLDebugDrawer.h b/Demos/OpenGL/GLDebugDrawer.h similarity index 100% rename from ObsoleteDemos/OpenGL/GLDebugDrawer.h rename to Demos/OpenGL/GLDebugDrawer.h diff --git a/ObsoleteDemos/OpenGL/GLDebugFont.cpp b/Demos/OpenGL/GLDebugFont.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/GLDebugFont.cpp rename to Demos/OpenGL/GLDebugFont.cpp diff --git a/ObsoleteDemos/OpenGL/GLDebugFont.h b/Demos/OpenGL/GLDebugFont.h similarity index 100% rename from ObsoleteDemos/OpenGL/GLDebugFont.h rename to Demos/OpenGL/GLDebugFont.h diff --git a/ObsoleteDemos/OpenGL/GL_DialogDynamicsWorld.cpp b/Demos/OpenGL/GL_DialogDynamicsWorld.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/GL_DialogDynamicsWorld.cpp rename to Demos/OpenGL/GL_DialogDynamicsWorld.cpp diff --git a/ObsoleteDemos/OpenGL/GL_DialogDynamicsWorld.h b/Demos/OpenGL/GL_DialogDynamicsWorld.h similarity index 100% rename from ObsoleteDemos/OpenGL/GL_DialogDynamicsWorld.h rename to Demos/OpenGL/GL_DialogDynamicsWorld.h diff --git a/ObsoleteDemos/OpenGL/GL_DialogWindow.cpp b/Demos/OpenGL/GL_DialogWindow.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/GL_DialogWindow.cpp rename to Demos/OpenGL/GL_DialogWindow.cpp diff --git a/ObsoleteDemos/OpenGL/GL_DialogWindow.h b/Demos/OpenGL/GL_DialogWindow.h similarity index 100% rename from ObsoleteDemos/OpenGL/GL_DialogWindow.h rename to Demos/OpenGL/GL_DialogWindow.h diff --git a/ObsoleteDemos/OpenGL/GL_ShapeDrawer.cpp b/Demos/OpenGL/GL_ShapeDrawer.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/GL_ShapeDrawer.cpp rename to Demos/OpenGL/GL_ShapeDrawer.cpp diff --git a/ObsoleteDemos/OpenGL/GL_ShapeDrawer.h b/Demos/OpenGL/GL_ShapeDrawer.h similarity index 100% rename from ObsoleteDemos/OpenGL/GL_ShapeDrawer.h rename to Demos/OpenGL/GL_ShapeDrawer.h diff --git a/ObsoleteDemos/OpenGL/GL_Simplex1to4.cpp b/Demos/OpenGL/GL_Simplex1to4.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/GL_Simplex1to4.cpp rename to Demos/OpenGL/GL_Simplex1to4.cpp diff --git a/ObsoleteDemos/OpenGL/GL_Simplex1to4.h b/Demos/OpenGL/GL_Simplex1to4.h similarity index 100% rename from ObsoleteDemos/OpenGL/GL_Simplex1to4.h rename to Demos/OpenGL/GL_Simplex1to4.h diff --git a/ObsoleteDemos/OpenGL/GlutDemoApplication.cpp b/Demos/OpenGL/GlutDemoApplication.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/GlutDemoApplication.cpp rename to Demos/OpenGL/GlutDemoApplication.cpp diff --git a/ObsoleteDemos/OpenGL/GlutDemoApplication.h b/Demos/OpenGL/GlutDemoApplication.h similarity index 100% rename from ObsoleteDemos/OpenGL/GlutDemoApplication.h rename to Demos/OpenGL/GlutDemoApplication.h diff --git a/ObsoleteDemos/OpenGL/GlutStuff.cpp b/Demos/OpenGL/GlutStuff.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/GlutStuff.cpp rename to Demos/OpenGL/GlutStuff.cpp diff --git a/ObsoleteDemos/OpenGL/GlutStuff.h b/Demos/OpenGL/GlutStuff.h similarity index 100% rename from ObsoleteDemos/OpenGL/GlutStuff.h rename to Demos/OpenGL/GlutStuff.h diff --git a/ObsoleteDemos/OpenGL/Makefile.am b/Demos/OpenGL/Makefile.am similarity index 100% rename from ObsoleteDemos/OpenGL/Makefile.am rename to Demos/OpenGL/Makefile.am diff --git a/ObsoleteDemos/OpenGL/RenderTexture.cpp b/Demos/OpenGL/RenderTexture.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/RenderTexture.cpp rename to Demos/OpenGL/RenderTexture.cpp diff --git a/ObsoleteDemos/OpenGL/RenderTexture.h b/Demos/OpenGL/RenderTexture.h similarity index 100% rename from ObsoleteDemos/OpenGL/RenderTexture.h rename to Demos/OpenGL/RenderTexture.h diff --git a/ObsoleteDemos/OpenGL/Win32AppMain.cpp b/Demos/OpenGL/Win32AppMain.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/Win32AppMain.cpp rename to Demos/OpenGL/Win32AppMain.cpp diff --git a/ObsoleteDemos/OpenGL/Win32DemoApplication.cpp b/Demos/OpenGL/Win32DemoApplication.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/Win32DemoApplication.cpp rename to Demos/OpenGL/Win32DemoApplication.cpp diff --git a/ObsoleteDemos/OpenGL/Win32DemoApplication.h b/Demos/OpenGL/Win32DemoApplication.h similarity index 100% rename from ObsoleteDemos/OpenGL/Win32DemoApplication.h rename to Demos/OpenGL/Win32DemoApplication.h diff --git a/ObsoleteDemos/OpenGL/premake4.lua b/Demos/OpenGL/premake4.lua similarity index 100% rename from ObsoleteDemos/OpenGL/premake4.lua rename to Demos/OpenGL/premake4.lua diff --git a/ObsoleteDemos/OpenGL/stb_image.cpp b/Demos/OpenGL/stb_image.cpp similarity index 100% rename from ObsoleteDemos/OpenGL/stb_image.cpp rename to Demos/OpenGL/stb_image.cpp diff --git a/ObsoleteDemos/OpenGL/stb_image.h b/Demos/OpenGL/stb_image.h similarity index 100% rename from ObsoleteDemos/OpenGL/stb_image.h rename to Demos/OpenGL/stb_image.h diff --git a/ObsoleteDemos/OpenPL_Demo/CApi.cpp b/Demos/OpenPL_Demo/CApi.cpp similarity index 100% rename from ObsoleteDemos/OpenPL_Demo/CApi.cpp rename to Demos/OpenPL_Demo/CApi.cpp diff --git a/ObsoleteDemos/OpenPL_Demo/OpenPL_Demo.c b/Demos/OpenPL_Demo/OpenPL_Demo.c similarity index 100% rename from ObsoleteDemos/OpenPL_Demo/OpenPL_Demo.c rename to Demos/OpenPL_Demo/OpenPL_Demo.c diff --git a/ObsoleteDemos/RagdollDemo/CMakeLists.txt b/Demos/RagdollDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/RagdollDemo/CMakeLists.txt rename to Demos/RagdollDemo/CMakeLists.txt diff --git a/ObsoleteDemos/RagdollDemo/RagdollDemo.cpp b/Demos/RagdollDemo/RagdollDemo.cpp similarity index 100% rename from ObsoleteDemos/RagdollDemo/RagdollDemo.cpp rename to Demos/RagdollDemo/RagdollDemo.cpp diff --git a/ObsoleteDemos/RagdollDemo/RagdollDemo.h b/Demos/RagdollDemo/RagdollDemo.h similarity index 100% rename from ObsoleteDemos/RagdollDemo/RagdollDemo.h rename to Demos/RagdollDemo/RagdollDemo.h diff --git a/ObsoleteDemos/RagdollDemo/main.cpp b/Demos/RagdollDemo/main.cpp similarity index 100% rename from ObsoleteDemos/RagdollDemo/main.cpp rename to Demos/RagdollDemo/main.cpp diff --git a/ObsoleteDemos/RaytestDemo/CMakeLists.txt b/Demos/RaytestDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/RaytestDemo/CMakeLists.txt rename to Demos/RaytestDemo/CMakeLists.txt diff --git a/ObsoleteDemos/RaytestDemo/Makefile.am b/Demos/RaytestDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/RaytestDemo/Makefile.am rename to Demos/RaytestDemo/Makefile.am diff --git a/ObsoleteDemos/RaytestDemo/RaytestDemo.cpp b/Demos/RaytestDemo/RaytestDemo.cpp similarity index 100% rename from ObsoleteDemos/RaytestDemo/RaytestDemo.cpp rename to Demos/RaytestDemo/RaytestDemo.cpp diff --git a/ObsoleteDemos/RaytestDemo/RaytestDemo.h b/Demos/RaytestDemo/RaytestDemo.h similarity index 100% rename from ObsoleteDemos/RaytestDemo/RaytestDemo.h rename to Demos/RaytestDemo/RaytestDemo.h diff --git a/ObsoleteDemos/RaytestDemo/Win32RaytestDemo.cpp b/Demos/RaytestDemo/Win32RaytestDemo.cpp similarity index 100% rename from ObsoleteDemos/RaytestDemo/Win32RaytestDemo.cpp rename to Demos/RaytestDemo/Win32RaytestDemo.cpp diff --git a/ObsoleteDemos/RaytestDemo/main.cpp b/Demos/RaytestDemo/main.cpp similarity index 100% rename from ObsoleteDemos/RaytestDemo/main.cpp rename to Demos/RaytestDemo/main.cpp diff --git a/ObsoleteDemos/Raytracer/CMakeLists.txt b/Demos/Raytracer/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/Raytracer/CMakeLists.txt rename to Demos/Raytracer/CMakeLists.txt diff --git a/ObsoleteDemos/Raytracer/Raytracer.cpp b/Demos/Raytracer/Raytracer.cpp similarity index 100% rename from ObsoleteDemos/Raytracer/Raytracer.cpp rename to Demos/Raytracer/Raytracer.cpp diff --git a/ObsoleteDemos/Raytracer/Raytracer.h b/Demos/Raytracer/Raytracer.h similarity index 100% rename from ObsoleteDemos/Raytracer/Raytracer.h rename to Demos/Raytracer/Raytracer.h diff --git a/ObsoleteDemos/Raytracer/main.cpp b/Demos/Raytracer/main.cpp similarity index 100% rename from ObsoleteDemos/Raytracer/main.cpp rename to Demos/Raytracer/main.cpp diff --git a/ObsoleteDemos/RollingFrictionDemo/CMakeLists.txt b/Demos/RollingFrictionDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/RollingFrictionDemo/CMakeLists.txt rename to Demos/RollingFrictionDemo/CMakeLists.txt diff --git a/ObsoleteDemos/RollingFrictionDemo/Makefile.am b/Demos/RollingFrictionDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/RollingFrictionDemo/Makefile.am rename to Demos/RollingFrictionDemo/Makefile.am diff --git a/ObsoleteDemos/RollingFrictionDemo/RollingFrictionDemo.cpp b/Demos/RollingFrictionDemo/RollingFrictionDemo.cpp similarity index 100% rename from ObsoleteDemos/RollingFrictionDemo/RollingFrictionDemo.cpp rename to Demos/RollingFrictionDemo/RollingFrictionDemo.cpp diff --git a/ObsoleteDemos/RollingFrictionDemo/RollingFrictionDemo.h b/Demos/RollingFrictionDemo/RollingFrictionDemo.h similarity index 100% rename from ObsoleteDemos/RollingFrictionDemo/RollingFrictionDemo.h rename to Demos/RollingFrictionDemo/RollingFrictionDemo.h diff --git a/ObsoleteDemos/RollingFrictionDemo/Win32RollingFrictionDemo.cpp b/Demos/RollingFrictionDemo/Win32RollingFrictionDemo.cpp similarity index 100% rename from ObsoleteDemos/RollingFrictionDemo/Win32RollingFrictionDemo.cpp rename to Demos/RollingFrictionDemo/Win32RollingFrictionDemo.cpp diff --git a/ObsoleteDemos/RollingFrictionDemo/main.cpp b/Demos/RollingFrictionDemo/main.cpp similarity index 100% rename from ObsoleteDemos/RollingFrictionDemo/main.cpp rename to Demos/RollingFrictionDemo/main.cpp diff --git a/ObsoleteDemos/SerializeDemo/AMD/CMakeLists.txt b/Demos/SerializeDemo/AMD/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/SerializeDemo/AMD/CMakeLists.txt rename to Demos/SerializeDemo/AMD/CMakeLists.txt diff --git a/ObsoleteDemos/SerializeDemo/AMD/premake4.lua b/Demos/SerializeDemo/AMD/premake4.lua similarity index 100% rename from ObsoleteDemos/SerializeDemo/AMD/premake4.lua rename to Demos/SerializeDemo/AMD/premake4.lua diff --git a/ObsoleteDemos/SerializeDemo/CMakeLists.txt b/Demos/SerializeDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/SerializeDemo/CMakeLists.txt rename to Demos/SerializeDemo/CMakeLists.txt diff --git a/ObsoleteDemos/SerializeDemo/SerializeDemo.cpp b/Demos/SerializeDemo/SerializeDemo.cpp similarity index 96% rename from ObsoleteDemos/SerializeDemo/SerializeDemo.cpp rename to Demos/SerializeDemo/SerializeDemo.cpp index f98f1227d..d6deddf78 100644 --- a/ObsoleteDemos/SerializeDemo/SerializeDemo.cpp +++ b/Demos/SerializeDemo/SerializeDemo.cpp @@ -4,8 +4,8 @@ Copyright (c) 2003-2010 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -95,7 +95,7 @@ void SerializeDemo::keyboardCallback(unsigned char key, int x, int y) } if (minDist>0.) continue; - + btCollisionObject* colObj0 = (btCollisionObject*)manifold->getBody0(); btCollisionObject* colObj1 = (btCollisionObject*)manifold->getBody1(); // int tag0 = (colObj0)->getIslandTag(); @@ -133,13 +133,13 @@ void SerializeDemo::keyboardCallback(unsigned char key, int x, int y) for (int i=0;i<6;i++) dof6->setLimit(i,0,0); getDynamicsWorld()->addConstraint(dof6,true); - + } } } } - - } + + } for (int i=0;istepSimulation(ms / 1000000.f); - + #ifdef DESERIALIZE_SOFT_BODIES if (fSoftBodySolver) fSoftBodySolver->copyBackToSoftBodies(); @@ -192,8 +192,8 @@ void SerializeDemo::clientMoveAndDisplay() #endif //DESERIALIZE_SOFT_BODIES } - - renderme(); + + renderme(); glFlush(); @@ -209,7 +209,7 @@ class CachingCLFuncs : public CLFunctions public: - CachingCLFuncs (cl_command_queue cqCommandQue, cl_context cxMainContext, cl_device_id device) + CachingCLFuncs (cl_command_queue cqCommandQue, cl_context cxMainContext, cl_device_id device) :CLFunctions(cqCommandQue,cxMainContext), m_device(device) { @@ -220,14 +220,14 @@ class CachingCLFuncs : public CLFunctions cl_int pErrNum; cl_program prog; - + prog = btOpenCLUtils::compileCLProgramFromFile( m_cxMainContext,m_device, &pErrNum,additionalMacros ,srcFileNameForCaching); if (!prog) { printf("Using embedded kernel source instead:\n"); prog = btOpenCLUtils::compileCLProgramFromString( m_cxMainContext,m_device, kernelSource, &pErrNum,additionalMacros); } - + return btOpenCLUtils::compileCLKernelFromString( m_cxMainContext,m_device, kernelSource, kernelName, &pErrNum, prog,additionalMacros); } @@ -237,8 +237,8 @@ class CachingCLFuncs : public CLFunctions void SerializeDemo::displayCallback(void) { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + if (m_dynamicsWorld->getWorldType()==BT_SOFT_RIGID_DYNAMICS_WORLD) { #ifdef DESERIALIZE_SOFT_BODIES @@ -293,7 +293,7 @@ void SerializeDemo::setupEmptyDynamicsWorld() btGImpactCollisionAlgorithm::registerAlgorithm(m_dispatcher); m_broadphase = new btDbvtBroadphase(); - + ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; @@ -301,7 +301,7 @@ void SerializeDemo::setupEmptyDynamicsWorld() #ifdef DESERIALIZE_SOFT_BODIES - + #ifdef USE_AMD_OPENCL @@ -309,16 +309,16 @@ void SerializeDemo::setupEmptyDynamicsWorld() if ( 1 ) { switch (solverAccel) - { + { case kSolverAccelerationOpenCL_GPU: { btOpenCLSoftBodySolverSIMDAware* softSolv= new btOpenCLSoftBodySolverSIMDAware( g_cqCommandQue, g_cxMainContext ); //btOpenCLSoftBodySolver* softSolv= new btOpenCLSoftBodySolver( g_cqCommandQue, g_cxMainContext); fSoftBodySolver = softSolv; - + CLFunctions* funcs = new CachingCLFuncs(g_cqCommandQue, g_cxMainContext,g_cdDevice); softSolv->setCLFunctions(funcs); - + break; } @@ -334,21 +334,21 @@ void SerializeDemo::setupEmptyDynamicsWorld() } }; } - else + else { - if ( solverAccel != kSolverAccelerationNone ) + if ( solverAccel != kSolverAccelerationNone ) { } - else + else { } fSoftBodySolver = NULL; } #else - + fSoftBodySolver = NULL; #endif - + btSoftRigidDynamicsWorld* world = new btSoftRigidDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration, fSoftBodySolver); m_dynamicsWorld = world; @@ -380,7 +380,7 @@ class MySoftBulletWorldImporter : public btBulletWorldImporter btHashMap m_clusterBodyMap; btHashMap m_softBodyMap; - + public: @@ -394,7 +394,7 @@ public: virtual ~MySoftBulletWorldImporter() { - + } virtual bool convertAllObjects( bParse::btBulletFile* bulletFile2) @@ -413,8 +413,8 @@ public: btSoftBodyFloatData* softBodyData = (btSoftBodyFloatData*)bulletFile2->m_softBodies[i]; int i; int numNodes = softBodyData->m_numNodes; - - + + btSoftBody* psb=new btSoftBody(&m_softRigidWorld->getWorldInfo()); m_softBodyMap.insert(softBodyData,psb); @@ -462,11 +462,11 @@ public: { printf("no mat?\n"); } - + node->m_n.deSerializeFloat(nodeData.m_normal); node->m_q = node->m_x; node->m_v.deSerializeFloat(nodeData.m_velocity); - + } for (i=0;im_numLinks;i++) @@ -501,7 +501,7 @@ public: face->m_ra = faceData.m_restArea; } - + //anchors for (i=0;im_numAnchors;i++) @@ -526,7 +526,7 @@ public: psb->m_pose.m_bframe = (softBodyData->m_pose->m_bframe!=0); psb->m_pose.m_bvolume = (softBodyData->m_pose->m_bvolume!=0); psb->m_pose.m_com.deSerializeFloat(softBodyData->m_pose->m_com); - + psb->m_pose.m_pos.resize(softBodyData->m_pose->m_numPositions); for (i=0;im_pose->m_numPositions;i++) { @@ -547,7 +547,7 @@ public: psb->m_cfg.diterations=softBodyData->m_config.m_driftIterations; psb->m_cfg.citerations=softBodyData->m_config.m_clusterIterations; psb->m_cfg.viterations=softBodyData->m_config.m_velocityIterations; - + //psb->setTotalMass(0.1); psb->m_cfg.aeromodel = (btSoftBody::eAeroModel::_)softBodyData->m_config.m_aeroModel; psb->m_cfg.kLF = softBodyData->m_config.m_lift; @@ -619,7 +619,7 @@ public: psb->m_clusters[i]->m_selfCollisionImpulseFactor = softBodyData->m_clusters[i].m_selfCollisionImpulseFactor; psb->m_clusters[i]->m_vimpulses[0].deSerializeFloat(softBodyData->m_clusters[i].m_vimpulses[0]); psb->m_clusters[i]->m_vimpulses[1].deSerializeFloat(softBodyData->m_clusters[i].m_vimpulses[1]); - + } //psb->initializeClusters(); //psb->updateClusters(); @@ -641,7 +641,7 @@ public: psb->updateConstants(); m_softRigidWorld->getWorldInfo().m_dispatcher = m_softRigidWorld->getDispatcher(); - + m_softRigidWorld->addSoftBody(psb); @@ -742,7 +742,7 @@ m_fileName("testFile.bullet") SerializeDemo::~SerializeDemo() { m_fileLoader->deleteAllData(); - delete m_fileLoader; + delete m_fileLoader; exitPhysics(); } @@ -754,18 +754,39 @@ void SerializeDemo::initPhysics() setCameraDistance(btScalar(SCALING*30.)); setupEmptyDynamicsWorld(); - + #ifdef DESERIALIZE_SOFT_BODIES m_fileLoader = new MySoftBulletWorldImporter((btSoftRigidDynamicsWorld*)m_dynamicsWorld); #else m_fileLoader = new btBulletWorldImporter(m_dynamicsWorld); #endif //DESERIALIZE_SOFT_BODIES - + m_fileLoader->setVerboseMode(m_verboseMode); - + + const char* filename = "testFile.bullet"; + + const char* prefix[]={"./","../","../../","../../../","../../../../", "SerializeDemo/", "Demos/SerializeDemo/", + "../Demos/SerializeDemo/","../../Demos/SerializeDemo/"}; + int numPrefixes = sizeof(prefix)/sizeof(const char*); + char relativeFileName[1024]; + bool fileFound = false; + + for (int i=0;iloadFile("testFile.bullet", "testFileSwappedEndianness.bullet")) + + + if (!m_fileLoader->loadFile(relativeFileName, "testFileSwappedEndianness.bullet")) // if (!m_fileLoader->loadFile("../SoftDemo/testFile.bullet")) { ///create a few basic rigid bodies and save them to testFile.bullet @@ -773,7 +794,7 @@ void SerializeDemo::initPhysics() // btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50); btCollisionObject* groundObject = 0; - + m_collisionShapes.push_back(groundShape); btTransform groundTransform; @@ -846,12 +867,12 @@ void SerializeDemo::initPhysics() btScalar(20+2.0*k + start_y), btScalar(2.0*j + start_z))); - + //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia); btRigidBody* body = new btRigidBody(rbInfo); - + m_dynamicsWorld->addRigidBody(body); //body->setActivationState(ISLAND_SLEEPING); } @@ -869,14 +890,14 @@ void SerializeDemo::initPhysics() for (int i=0;iregisterNameForPointer(m_collisionShapes[i],name); } btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*(btRigidBody*)getDynamicsWorld()->getCollisionObjectArray()[2],btVector3(0,1,0)); m_dynamicsWorld->addConstraint(p2p); - + const char* name = "constraintje"; serializer->registerNameForPointer(p2p,name); @@ -892,7 +913,7 @@ void SerializeDemo::initPhysics() //clientResetScene(); } - + void SerializeDemo::exitPhysics() { @@ -931,16 +952,16 @@ void SerializeDemo::exitPhysics() m_collisionShapes.clear(); delete m_dynamicsWorld; - + delete m_solver; - + delete m_broadphase; - + delete m_dispatcher; delete m_collisionConfiguration; - + } diff --git a/ObsoleteDemos/SerializeDemo/SerializeDemo.h b/Demos/SerializeDemo/SerializeDemo.h similarity index 100% rename from ObsoleteDemos/SerializeDemo/SerializeDemo.h rename to Demos/SerializeDemo/SerializeDemo.h diff --git a/ObsoleteDemos/SerializeDemo/Win32SerializeDemo.cpp b/Demos/SerializeDemo/Win32SerializeDemo.cpp similarity index 100% rename from ObsoleteDemos/SerializeDemo/Win32SerializeDemo.cpp rename to Demos/SerializeDemo/Win32SerializeDemo.cpp diff --git a/ObsoleteDemos/SerializeDemo/main.cpp b/Demos/SerializeDemo/main.cpp similarity index 100% rename from ObsoleteDemos/SerializeDemo/main.cpp rename to Demos/SerializeDemo/main.cpp diff --git a/ObsoleteDemos/SerializeDemo/testFile.bullet b/Demos/SerializeDemo/testFile.bullet similarity index 100% rename from ObsoleteDemos/SerializeDemo/testFile.bullet rename to Demos/SerializeDemo/testFile.bullet diff --git a/ObsoleteDemos/SerializeDemo/testFileCloth.bullet b/Demos/SerializeDemo/testFileCloth.bullet similarity index 100% rename from ObsoleteDemos/SerializeDemo/testFileCloth.bullet rename to Demos/SerializeDemo/testFileCloth.bullet diff --git a/ObsoleteDemos/SimplexDemo/CMakeLists.txt b/Demos/SimplexDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/SimplexDemo/CMakeLists.txt rename to Demos/SimplexDemo/CMakeLists.txt diff --git a/ObsoleteDemos/SimplexDemo/SimplexDemo.cpp b/Demos/SimplexDemo/SimplexDemo.cpp similarity index 100% rename from ObsoleteDemos/SimplexDemo/SimplexDemo.cpp rename to Demos/SimplexDemo/SimplexDemo.cpp diff --git a/ObsoleteDemos/SimplexDemo/SimplexDemo.h b/Demos/SimplexDemo/SimplexDemo.h similarity index 100% rename from ObsoleteDemos/SimplexDemo/SimplexDemo.h rename to Demos/SimplexDemo/SimplexDemo.h diff --git a/ObsoleteDemos/SliderConstraintDemo/CMakeLists.txt b/Demos/SliderConstraintDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/SliderConstraintDemo/CMakeLists.txt rename to Demos/SliderConstraintDemo/CMakeLists.txt diff --git a/ObsoleteDemos/SliderConstraintDemo/SliderConstraintDemo.cpp b/Demos/SliderConstraintDemo/SliderConstraintDemo.cpp similarity index 100% rename from ObsoleteDemos/SliderConstraintDemo/SliderConstraintDemo.cpp rename to Demos/SliderConstraintDemo/SliderConstraintDemo.cpp diff --git a/ObsoleteDemos/SliderConstraintDemo/SliderConstraintDemo.h b/Demos/SliderConstraintDemo/SliderConstraintDemo.h similarity index 100% rename from ObsoleteDemos/SliderConstraintDemo/SliderConstraintDemo.h rename to Demos/SliderConstraintDemo/SliderConstraintDemo.h diff --git a/ObsoleteDemos/SliderConstraintDemo/main.cpp b/Demos/SliderConstraintDemo/main.cpp similarity index 100% rename from ObsoleteDemos/SliderConstraintDemo/main.cpp rename to Demos/SliderConstraintDemo/main.cpp diff --git a/ObsoleteDemos/SoftDemo/AMD/premake4.lua b/Demos/SoftDemo/AMD/premake4.lua similarity index 100% rename from ObsoleteDemos/SoftDemo/AMD/premake4.lua rename to Demos/SoftDemo/AMD/premake4.lua diff --git a/ObsoleteDemos/SoftDemo/CMakeLists.txt b/Demos/SoftDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/SoftDemo/CMakeLists.txt rename to Demos/SoftDemo/CMakeLists.txt diff --git a/ObsoleteDemos/SoftDemo/Makefile.am b/Demos/SoftDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/SoftDemo/Makefile.am rename to Demos/SoftDemo/Makefile.am diff --git a/ObsoleteDemos/SoftDemo/SoftDemo.cpp b/Demos/SoftDemo/SoftDemo.cpp similarity index 100% rename from ObsoleteDemos/SoftDemo/SoftDemo.cpp rename to Demos/SoftDemo/SoftDemo.cpp diff --git a/ObsoleteDemos/SoftDemo/SoftDemo.h b/Demos/SoftDemo/SoftDemo.h similarity index 100% rename from ObsoleteDemos/SoftDemo/SoftDemo.h rename to Demos/SoftDemo/SoftDemo.h diff --git a/ObsoleteDemos/SoftDemo/bunny.inl b/Demos/SoftDemo/bunny.inl similarity index 100% rename from ObsoleteDemos/SoftDemo/bunny.inl rename to Demos/SoftDemo/bunny.inl diff --git a/ObsoleteDemos/SoftDemo/cube.inl b/Demos/SoftDemo/cube.inl similarity index 100% rename from ObsoleteDemos/SoftDemo/cube.inl rename to Demos/SoftDemo/cube.inl diff --git a/ObsoleteDemos/SoftDemo/main.cpp b/Demos/SoftDemo/main.cpp similarity index 100% rename from ObsoleteDemos/SoftDemo/main.cpp rename to Demos/SoftDemo/main.cpp diff --git a/ObsoleteDemos/TerrainDemo/Makefile.am b/Demos/TerrainDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/TerrainDemo/Makefile.am rename to Demos/TerrainDemo/Makefile.am diff --git a/ObsoleteDemos/TerrainDemo/TerrainDemo.cpp b/Demos/TerrainDemo/TerrainDemo.cpp similarity index 100% rename from ObsoleteDemos/TerrainDemo/TerrainDemo.cpp rename to Demos/TerrainDemo/TerrainDemo.cpp diff --git a/ObsoleteDemos/TerrainDemo/TerrainDemo.h b/Demos/TerrainDemo/TerrainDemo.h similarity index 100% rename from ObsoleteDemos/TerrainDemo/TerrainDemo.h rename to Demos/TerrainDemo/TerrainDemo.h diff --git a/ObsoleteDemos/TerrainDemo/main.cpp b/Demos/TerrainDemo/main.cpp similarity index 100% rename from ObsoleteDemos/TerrainDemo/main.cpp rename to Demos/TerrainDemo/main.cpp diff --git a/ObsoleteDemos/ThreadingDemo/CMakeLists.txt b/Demos/ThreadingDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/ThreadingDemo/CMakeLists.txt rename to Demos/ThreadingDemo/CMakeLists.txt diff --git a/ObsoleteDemos/ThreadingDemo/main.cpp b/Demos/ThreadingDemo/main.cpp similarity index 100% rename from ObsoleteDemos/ThreadingDemo/main.cpp rename to Demos/ThreadingDemo/main.cpp diff --git a/ObsoleteDemos/UserCollisionAlgorithm/CMakeLists.txt b/Demos/UserCollisionAlgorithm/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/UserCollisionAlgorithm/CMakeLists.txt rename to Demos/UserCollisionAlgorithm/CMakeLists.txt diff --git a/ObsoleteDemos/UserCollisionAlgorithm/UserCollisionAlgorithm.cpp b/Demos/UserCollisionAlgorithm/UserCollisionAlgorithm.cpp similarity index 100% rename from ObsoleteDemos/UserCollisionAlgorithm/UserCollisionAlgorithm.cpp rename to Demos/UserCollisionAlgorithm/UserCollisionAlgorithm.cpp diff --git a/ObsoleteDemos/UserCollisionAlgorithm/UserCollisionAlgorithm.h b/Demos/UserCollisionAlgorithm/UserCollisionAlgorithm.h similarity index 100% rename from ObsoleteDemos/UserCollisionAlgorithm/UserCollisionAlgorithm.h rename to Demos/UserCollisionAlgorithm/UserCollisionAlgorithm.h diff --git a/ObsoleteDemos/VehicleDemo/CMakeLists.txt b/Demos/VehicleDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/VehicleDemo/CMakeLists.txt rename to Demos/VehicleDemo/CMakeLists.txt diff --git a/ObsoleteDemos/VehicleDemo/Makefile.am b/Demos/VehicleDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/VehicleDemo/Makefile.am rename to Demos/VehicleDemo/Makefile.am diff --git a/ObsoleteDemos/VehicleDemo/VehicleDemo.cpp b/Demos/VehicleDemo/VehicleDemo.cpp similarity index 100% rename from ObsoleteDemos/VehicleDemo/VehicleDemo.cpp rename to Demos/VehicleDemo/VehicleDemo.cpp diff --git a/ObsoleteDemos/VehicleDemo/VehicleDemo.h b/Demos/VehicleDemo/VehicleDemo.h similarity index 100% rename from ObsoleteDemos/VehicleDemo/VehicleDemo.h rename to Demos/VehicleDemo/VehicleDemo.h diff --git a/ObsoleteDemos/VehicleDemo/heightfield128x128.cpp b/Demos/VehicleDemo/heightfield128x128.cpp similarity index 100% rename from ObsoleteDemos/VehicleDemo/heightfield128x128.cpp rename to Demos/VehicleDemo/heightfield128x128.cpp diff --git a/ObsoleteDemos/VehicleDemo/main.cpp b/Demos/VehicleDemo/main.cpp similarity index 100% rename from ObsoleteDemos/VehicleDemo/main.cpp rename to Demos/VehicleDemo/main.cpp diff --git a/ObsoleteDemos/VoronoiFractureDemo/CMakeLists.txt b/Demos/VoronoiFractureDemo/CMakeLists.txt similarity index 100% rename from ObsoleteDemos/VoronoiFractureDemo/CMakeLists.txt rename to Demos/VoronoiFractureDemo/CMakeLists.txt diff --git a/ObsoleteDemos/VoronoiFractureDemo/Makefile.am b/Demos/VoronoiFractureDemo/Makefile.am similarity index 100% rename from ObsoleteDemos/VoronoiFractureDemo/Makefile.am rename to Demos/VoronoiFractureDemo/Makefile.am diff --git a/ObsoleteDemos/VoronoiFractureDemo/VoronoiFractureDemo.cpp b/Demos/VoronoiFractureDemo/VoronoiFractureDemo.cpp similarity index 100% rename from ObsoleteDemos/VoronoiFractureDemo/VoronoiFractureDemo.cpp rename to Demos/VoronoiFractureDemo/VoronoiFractureDemo.cpp diff --git a/ObsoleteDemos/VoronoiFractureDemo/VoronoiFractureDemo.h b/Demos/VoronoiFractureDemo/VoronoiFractureDemo.h similarity index 100% rename from ObsoleteDemos/VoronoiFractureDemo/VoronoiFractureDemo.h rename to Demos/VoronoiFractureDemo/VoronoiFractureDemo.h diff --git a/ObsoleteDemos/VoronoiFractureDemo/Win32VoronoiFractureDemo.cpp b/Demos/VoronoiFractureDemo/Win32VoronoiFractureDemo.cpp similarity index 100% rename from ObsoleteDemos/VoronoiFractureDemo/Win32VoronoiFractureDemo.cpp rename to Demos/VoronoiFractureDemo/Win32VoronoiFractureDemo.cpp diff --git a/ObsoleteDemos/VoronoiFractureDemo/main.cpp b/Demos/VoronoiFractureDemo/main.cpp similarity index 100% rename from ObsoleteDemos/VoronoiFractureDemo/main.cpp rename to Demos/VoronoiFractureDemo/main.cpp diff --git a/ObsoleteDemos/premake4.lua b/Demos/premake4.lua similarity index 100% rename from ObsoleteDemos/premake4.lua rename to Demos/premake4.lua diff --git a/Demos3/CMakeLists.txt b/Demos3/CMakeLists.txt index aaa6a1713..b1f54a968 100644 --- a/Demos3/CMakeLists.txt +++ b/Demos3/CMakeLists.txt @@ -1,2 +1,3 @@ -SUBDIRS( GpuDemos SimpleOpenGL3 AllBullet2Demos ) -#SUBDIRS( SimpleOpenGL3 AllBullet2Demos ) +if (BUILD_BULLET3) + SUBDIRS( AllBullet2Demos GpuDemos SimpleOpenGL3 ) +endif(BUILD_BULLET3) diff --git a/Demos3/ImplicitCloth/stan/Cloth.cpp b/Demos3/ImplicitCloth/stan/Cloth.cpp index e713f8eec..35859e686 100644 --- a/Demos3/ImplicitCloth/stan/Cloth.cpp +++ b/Demos3/ImplicitCloth/stan/Cloth.cpp @@ -66,7 +66,7 @@ int cloth_tess = 20; float3 cloth_spawnpoint(0,3,5.0f); - +/* static void ClothDrawSprings(Cloth *cloth) { static const float3 color[3]={float3(1,1,0),float3(1,0,1),float3(0,1,1)}; @@ -78,7 +78,7 @@ static void ClothDrawSprings(Cloth *cloth) Line(X[s.a],X[s.b],color[s.type]); } } - +*/ int cloth_showsprings=0; void DoCloths() @@ -93,4 +93,4 @@ void DoCloths() // ClothDrawSprings(cloth); // debug visualization } -} \ No newline at end of file +} diff --git a/Extras/CMakeLists.txt b/Extras/CMakeLists.txt index a92f64720..24fc0f159 100644 --- a/Extras/CMakeLists.txt +++ b/Extras/CMakeLists.txt @@ -2,6 +2,6 @@ SUBDIRS( Serialize ConvexDecomposition HACD GIMPACTUtils ) #Maya Dynamica plugin is moved to http://dynamica.googlecode.com -IF (USE_GLUT AND GLUT_FOUND) - SUBDIRS (glui) -ENDIF () +#IF (USE_GLUT AND GLUT_FOUND) +# SUBDIRS (glui) +#ENDIF () diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index 9fdc05848..b5e96ab3c 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -16,9 +16,9 @@ subject to the following restrictions: ///todo: make this configurable in the gui bool useShadowMap=true; -float shadowMapWidth=8192; -float shadowMapHeight=8192; -float shadowMapWorldSize=100; +float shadowMapWidth=16384; +float shadowMapHeight=16384; +float shadowMapWorldSize=1000; float WHEEL_MULTIPLIER=0.01f; float MOUSE_MOVE_MULTIPLIER = 0.4f; #define MAX_POINTS_IN_BATCH 1024 diff --git a/data/testFile.bullet b/data/testFile.bullet deleted file mode 100644 index a444865a1d9131a548cafb0c0d53c3b0bf732ff8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73336 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 AKL7v# diff --git a/data/testFileFracture.bullet b/data/testFileFracture.bullet index 1413f2d7cf46778a4684e07a0d7816e47a49f279..ae161a54cc59d29dce0119b159c0f8ecb7368142 100644 GIT binary patch delta 3265 zcmb`IYjjlA7035Exyjr-X2^s*7!V~1q)-SZfna#$9RV9cBtfJ~O>81bTOoiCT#7R) zy8PCrqrHSui+za7bmOnowp8h3h1@cgxs{aHd}8 z4wg)h;p-08Uwz(Sm2=JvL^$(o>I+oHYG=y}*~qOZ{Ca8usSFNC@9Mk^qf9{Wc!lV$^FcZu=CDtu5B~0#<8ulL>={N31^||{5gDU){H7&eDr|9Z_ zrc&utZdGaFkFAt>q5a0K)b%w*Y>kZ@b@~z{`b>YQ>gHf9i^PtZT>g(Gl;!dj~5NixSCngo<(EDg0EiskQ{&012 zw%6o-k@?$%FkEE*9GtWH)A)bppZ{g+-!i|ZnN1P*BXd??sRDc|7Dv)I^M?bsRwY0o zX|EK{HShYSn$n&kkyPpib3)AOwb0R2v#_Bd^68WMG0Ssn&w`a5o$Df-x9iW6(|X!F zI=WY`xNiD#r*Dt`C_UaT#Sq!>jLubo_I2HB7p$z2n{SBKYN@ShzomOs#EIyDCq-J9 zH8(7c?AfRPtCLo(?2J5eKsPIAbW~?JZw%<75po^GbgH3(~L*U54t-# z*Eolxy1*DSta+X7Yn;re&W+V@&v8D8>KC1759(3DOev8}e&cwzNj0B9HnnCfZSo_^ z3Vzu#Uo3t$RG@68-9|YMz4>L*ZkAIjQ|*i2mnqx%&!8StY{{K&=#nq- z^yBHr(~GAUPp@;rczRsVg$d76(NZRN5qrH%qduLwmwLJ6uvd4>2no^-!98#<+z0Dn z1KbY}5P8`VU0Cj6D=g`i8IsFX?q=nKgbl$xa4*~k>tO@j4-YV%owx?=xU1QQE6Bo< zA48ZE;U$xY;9++)Ecpp`2R1?%Z69qP?aFw6qFsf`=(A+RR*GMe`LEz{ zv7Gj!IxpWN+sJD>M?I$V%T_k@d|5Cdt6>l`To$r(qRA7a{A+j;egnUSr(hdwXI*zl zt)!jfYs*ghcEQtdR%^>{sgra!?RYw7?RLU0cp9F9Sl%AQ!ZE7nK%03c^7qOfX7mh1 zU@uet9sFJz&<&q}51kL451ntA?n*wNdieuB&oWl<%VK=OTgRmM7!C`nF2H^-Cg<~)T$KeHdk*I%!6Yvte41aRRn@()@KS~0-VHF&N z)o=(7!}Bl*N8l(NgCRH$FTjO^H!_Sz{tSPCS7*< zpO5+j>>s-Qi^V&d#z!>%4ZEFVL%NhD`5%o>;WPLgM0rFhOEe^b1<7z5cXCXT!_+SLKcifCxxxW39iQW%cai5XAvmqx)kqdb^jlwCwdo+xJOK6XU zOQ~N5@NDY^7pUTvS;TJRccoDYvb?N z+h8y_p{*3!(x5G7aRJ_72;*ZGFXpC1MfspARANoI?(7+V4sGbT!QgVenEC9PGe-P6 zW^p@Icf$A7`$m7eAUiDrVP+WGFw;^z4ymsLef`=cp@V5rMQOCD?VQyHWFJOifhv>- zw6R6kH9TxNPS>lo_UdSV)hD$*W~rOO&@XeRjwvmv9AP}%&tEA8j}hMf-xW1CH3w_^ z|6OF4>#OUabHqp8l=DW(L)AV#3QudF4y2>zOjokjVIS7Ew%XA#Q+tj5)b0P*o*pF@ z?K2_=TKfz%K&N)$TPySNyQi84q@SNM?`&zBdY#rEBxA!+byt`y^BzOgd5_lsJnz*t zZ(P`F0hyqje6dOZ703|V@7L5>w^3}EpXEHYjKNyBB{KB2tj#zd9G^AboAhY~mBpex zzDCg6XHuQX-jbuGI`z652fexc{U)0FXWIKm+H3tSQEk71W9z8)U!rT7tmBNHh_AP> zOmA9DQwLk97R=9<_N4+d$!cq5Z_ys-gX6QtJ6deMpt4xB&w?7$+Gkds$v$+g zVRy$`!uC=tOiP;#5|rbP`okz%3y!U$+Gi+`Dht)tra9oJT{4$}K+pr-DSJVsMz?Wfo;g4|pO&UyJrQ9~_@GUX$fJb!ndi z1*Wyn4idq+TbI=9>ZBbbY}~ijlz3vQpm?R;7E+aVT7TF|YhgciW4qVGjMT38JFcnc ztR>Q*C+#(3@Q*NEQ)ls@U#Yn%{j=n%+6KdjH~xoc4}-y?JE zN0<6(>cqYgnmTJg#a44u`e(^iwb9r|9h9N3MSGkNj?Wq|y07J0#G-v}6qwdN7f8gC zqoq3ay08D-;*PwGG)1MUoO1r9-qymyuatILf7nWEVLx?qT>B(*Pr*9Ir-h9*b(1Dk z*3?=1DYlxM(mzYCs%)w zdRq$*zf#(1{b4Juh5gjcaqX*K+#p!TSUD#~Q+IdhAx)jNpJJ=IDgCqLs@euaI&knILE$pXmj%#l!^G2|aQMmODP2Kyx-!ygBeu}N;ru5H}t7;nzclJie(AP5WaXvUc zYrGrH3JNNVMf<|2F|BJJ(2LS+ARc(XeMbJVS`dYNd`QZ4h@y`8~ zK~PyN+Pk5~wDv_*XR^2CXsJ%U?%;+-!lMTBO*0?-K$_r^dRyhV`mfSX>#rV9ZIAub z&2jB({J0=kN9vZz@~lifHfYQL?s~ta?{rz^Dtn9eI3FCJHJ;P0oPx??(cS|!rnPrh zoylIGcH43m7Dl&QVDkFnCny+4{XsG|3{`g}j-$_Z)|PLclD8$)gUCotU5h)~b`}r% z70l0ao?6Dmv*}rx_MqS2<9u*@)_6|g$5ZAU{+!qT=XjndFs*%2kccHmOLgjX?F-(J zmP{OGDza*!q_j`Ht%ZkQDebiWu$9)re(L7eJ%4I=Y!+3#@pDim7ua%v@ebt)7lqPoyp#kqoq3ax}lTv@jrqm znPT@{N;&^hZ)@S^G8#?Y{cC9Is@5-{snh0$Yt-D7{%LK4 zq0x%~8TwkZ$NAv+tno%=SJzv%d0!F*rnN5t5>a!eD^suIdw9v!?{+s$+>%ySJW_8< z6IJcC{;-wS!hCgeTzlj8iGp>EXSb_q>S9XI*3?=1DYlxMIu6#h!BDsK78&|lw8#12 z_^k07On;R!=h(Ezy3^X@?+;munzN-w)rqcA>+*PHl0%#IGu@o`K~j!8>JOu6EjX5r zUhjL1ETWmurG?jmb=+Eg8fw~Ew^3}EpXEHYj7!y}rDf=A(H`f6S(vRKyq zvZyhweHqo6>@7K3s#CA4{;s6FZFgJKw6rV#NPDfnC93ULaBLmb-p$2Dqv`Y&=kx<*=w;C!=Y!+3#ygR_yr8mJv@eeu)7qC)oyk6Rok6pd>-ENA z=>+G8GfWkWmKBuaj{3tWS__V?quOtqeJ3SvOQeP+_f zwBPx6C+Xdai6*zi{+xnw)E^{c!+>M!=)4dA#B0{~?Cw6Ax)JFjHFY+ULsc+8t&P4* z;9Nk4z839qJ~%#Wyq(u42`Y<4`zok0t$k(Hne6px=ia`)SWlQ_@@!W4kF?kNgJf(N zaBLmbK6^p!dp!RK+Vf%jdiVdC_Eoz3$gpD;?QuRhK5M+i{o4sDi$(jYs4=a*x9Uvx z`m}#EGDNPnyOHVquracNanv6qW5f90YX75C6^*7R+gH%k6)WFEQ)eSNR0Z?X+6KeG zW|d^wQfW znAW}qNJO7@*C)N?{kzRK8Qtp&3dT`?kcbCFq*VI`& z=vOd5TiOr(l={6M&IiY5jaTeMk}mCQqf}|_YtgBvymtdt|3_VP&wk?9+u^1)13!t1 zk3Q|S{xGuEf@ABb_G@45(X8b~mrm8xrTer%Q>V=h*TDR=w!u)~%^eB)TIM~@2ghfP z=Q7Lk*)q$TkALt-YhMQ>qEEYiBiHfY!e^SU1pV2Xuk{DX*f8MOI;wrOnU?!xHCU-> zO9l0{y6;hSnx;-Y2KO*OTiW+@KOsXOi}pAl9G^Ab=6}xUn)mpIoYvk5649r%h1=N zJl{I4vCMninAZOHi9;azw99m*iQH#rD^re}-%{2wNBz~Fq_&4+>!|j( zyM+nXkqTWMrm36gQCCxE?Wfo-lNuMM`UyJrQ9~_@GUhAmszvW}m-WLU?wTCCP zKJB`eh>(vRtZX{6YD!9f9QB8zqP5`II;#Dz6aW1lJ2lp?uJM{W_v7gW_4xn2hxysk zzLK2%5M)@i$NAv+tno60ME}l}MSDLKnAW~7NJO7@r^7nS@`whe#sjj*3dT`?kcHVScu>cdfBdhQ1cM!sP>0t?dNz>E*sz7U8wzB*G6)v3g)M^ z4Th=jB4y}n(H`f6;}>R(*ZXKbL1nSb`-Z47t$hR4ne6px7kIj&eC&M_)3>2jWd-A? zKS;)g0ms%+?bif+60C!a?{Yv>_gBVD@X~1Q^xKB{+0s5Rbh7-rIeB5x9_NGOv&MU0 zTA%ifQ9N4vMj#P=+Wq%+zT9+@$>hDenXF(O^#{q=FyPoas{Qjbu7Y(C&)eGH>Xcto zNYl>RPqATswzSW@8Twl0 zJD_A|BXCrb*(QGbw(4Fis?quQ@& zb5gJlav^D%rtZI~r!;leeu@qAv!#8Tk*UAO!};L&tns|7>wAya5+zA%-vV?(pLPY0 z9pslho@UzHzLa3;I{+dhb*9$e+Sl5KW9z8)wQ981%;!u~rfKT7Wbdb`v(8MhVScu> z-+nNk41F#09_NGOv&L)k&GH)}mU-VA1*Wxc1rkYJC(tZK&qF_WIlEU|Q~q`xWaYS{ z{xFKxf@ABb_6gsO_%SCa@A6gD)J=QXNmB=$ej6}9TiUNno|>{os!kT|aXvUcYdoKz zT))pr7VX=jkhJz~)D*~GpLWqN>qjmo^y*@bAA|za+IIkn=+n+14i;9a6_~ z8|G(A`^ux2$w$4U&TCHKe*kx~v_>{3y0T%6XJ|sS4yiwzB z3Mz#~`);T)t$kP3ne6pxm$~?C$vxc=)65cSWCi1>KS;)g0msr&?He7_&he-=M+ED@ zi}qjC)LFMtY?z<+TtMI3DH0_^UyJrQ9~_@GUZ3H41(n63eK2ZFYu{aUCVPF_9d!|k8 z)dB?TAphAe+E1}zezvr4{4DkFY~g%xeAal+?`-4MJXo~vjT+P1_fnn7 zUY~Y%v#ycFZM97s){T%AjHCV_85;&1TSv8Tn7x}|9b{{h6`H!f-$!cdto;-l=4VU$ zNsBhh(AP5WaXvUcYrIbrEr0WyMf<)eFs*$bkcd9*&OQy2oliC~?TM+A(jQ0tK{7TB zIJS;zf9#Z#X3ZZP{Zz0HT=5@+rk!;g#fJIW(tc6RVKVf!Xpi&3@mb?V?p2?qvpw7C zj{?)$_XCOO({4*_KRIeQXPP#6UP^x)^#{q=FyPoas(tQTme0Y|U|YLsKfm{^to`n; z+8*vss>%qQJEF13)7BwDa6QO;{AP%+$X}UqQh* z>JO5!VZgCllQ;J*wWJ0E0~`x?Kj5dKLkB3+T(n1eAak% zis<|NelQA5Yd;7iqEEa2#eeZL=1(_OPB$TCY#j9m$=ER9*gC5H#q*w;wfx7}>YBRs z{X1*wY$S)OV18QLVE8(xy$pRV+T(n1eAalQd(;tB7R&X12x?4g|F`N)_WHD&UL#um zHNUPY_tPP=f^pOzBxA#XW9z8)aWz9VnvU3dQd2knYfnv`jpR@j%uj0@4BInhmZ7gj zdz=rB&l<0Z|6D<3v1mUGHKw&6sydUsKJEH{I3OjI>uh?Rsj8%49Q6mu*f8MOI;#Dw z4$C!~2Hqa0sS}c)Y3ghwhpJ$HTH9b~SpHecSg8by_BbCLpEcgU6?X_Kg+==js4=bm zaMhXY^=UWn-e)OvOAFJ=eO|JHanv6qW5a-B>!|jzoi_^BL7J|5uBkgT`+xUa%q*)` z$S|fwdz=rB&l<0F6T|OZS+oy9fobhWf<*Lbm!o?nVN|;%rb@YsrsUwLKS;)g@xRqR zLDYT^uWN0~Tv8L5Kk98t|J0h)_AozN^FGbb;WG5LXpi&3@mb>qhnEyo7K`?yQDa*B zQK~c9>(lOBrz@P#uSnCVk$pr3I4S|0KnF zKU>;oa%n0EhELaDbv~-rHE~MgAO`Wx$V#EAwX}{#*J{kI2w8#12_^k1MOudsb z?rhI?#-YHp_G3XJ`m`@PX9*YZeu61JP1!%X*VFogWNa94Y#r5pM}~g|>mbc;rPa*) zglF2%e60Nx8|G(A`+akRW$0_s9_NGOv&PF^#amEWEb~4LHKw&6uR4>xKJDME5#-73 zd`-qd;j)5p)E^{c!+>M!sP=D0#R}FzhIBZkseAZlxu(wAPqATswzMBrW|jDR2GZ&;ixgK{RGvS?Dc84c~c{P{>w1a%t@91=z6d92g%ql;Mh81Ov3wWWMp9H2%+HqgPI5V! zazHOF+T(n1eAakFLk9{fi)G$NqQH2*QZ^U#Dmhv-Q7%wTa}O%jHCV_85;&1 zTSv9uJfN;%9b|6&dQDyDwLY3UYd^(?`PtHb^H#GAeJ$GKd~kf$cP+(g7 z$siGZ+U<$;7yF+LGu<}-*?qp&A0%VLfMe^Z_Mt!eXy&-QvzV`S;9fo3YuZ`2QEZr> zE$wgobt&b(SS47r$NAv+tnq#wIV`9YmU%xFHKw(nqB@hkKJBN>FD4YoJ;n6Tv;`^W zpQHXD85;&1TSv8j)wQuk=Vt$SYU+&RI%?`{B!{YCep=gLD7R!ps@mgxaD3Ky_4Akf zeNM7yKOJRAYd;NiLZ5c+e)W*M?BY%HgG$Q^#!-Kej12>ht)tp+idy}9?9^Zzd{$`c zik;u8sZ-m-Ja|u6a z%Vg8T0~rMcM!sP>=M ze@V&P5^8ai?V7saTn9CE77zLr%+Hqg1Di(5vx>s%`d1d7VYPt#!|j950%ke$4{2_(A2FAt)i*3ksPXm z`Dtx~A>i_+RIm3q9~_@G-jf8&b4eEM=b;Q~?dO6{=+myogN8!$y0c7CHD3PFy`I(| zBxA#XW9z8)lae+I)`H$wk)*mEe!+>M!sP?TscnQ`)YCS5WsoPXh z{fyeWwY3fNv!#9P{m(M=vS^R!|kmwocaEzsGz$tf@PT zKBu;kjEyRopDpe8cE}(@M~n729~_@GUeI3)1(n5eyJVDb=JqGtMKU>;+y_qjVAB*-l z9~_@G-l0Y6duz7q{c;qT)_xgCM4xtFr~w>An2#!-Kej12>ht)tra@zj2A zXZD$6DSfeoZ+t`hzRz-$eg*ThrG2OrB-0-Bdpw*Ej?Wq|%Zyrr%3_)Kv8XYv{R-8Y z?Dc8)eA+kezpmp<{Tr))r^Hczkco-Ma|tYjywqXqcu>JqGtM zKU>89YsIh=xV)E^{c z!+>M!sP=8Pwim2}EL+rCQ}=UzGfkbfpJK!OY-zuy#U&Z~TC~Uc;P|ZZVnuy_Pj?Lp zOl!XyB%)8ddbgX)C)d|8ZJXULr9Y1PgJf(NaBLmbepBTD%{|=WBOaPM|F*?6bvBYi zRWLuTZ7?jFVw9n;MSGkNj?WtJQNgx?%3@jb*P+I=_G?vVve&2Gsr{p*_uhj|!lQP7 zH1DA599u`V-{rbPunschLAa*w)t-5pI%_}0hWXjje)ZZI8TwkZ$NAv+tnrKk zE#Et0(S8F8Ol!X$B%)9I;RiGFSA1uf{(AW=<+|gjKS;)g0ms%+?VG%n1?wR1!p~~z zf|B-V>a6_~8|G(A`-n|rWaw+r9_NGOv&QRu$Wu^REZT2EjcM&Ss?KDuPrD;CDhRvg zEijFJm0M6Sj{1XSY#4BC9o7E(?UyNeTSEP{_qe8R;BD<^J{Ax970l0;_Almz$+QQ3 zpO5pw@mb^Ts_!nSEEetmL5*qcH>=KMuTQ&=9g7Ji;-;Ghmz?`Y^Iq!@lCfdHv2|4Y z!R7a9uH*k@-mIxRzcWcwXCpaO1@qI|216~^cM|lq%zK;S*?X~_O85;&1TSv7IFLh3^4s!6B_Pu=InmA26Yd^(? z`PtImt!nC@<=}j9eAak7C+hnwXFE!g)_xo4gg)(eaoOZ|`vXjmqBF>rz5^gKQfF%Y zt$nR+IJS;zADWz2GoMZUKM2-Q53YTysk3gQ*f2j^+E))AD??w)yvOjavm=ouSTTpoS8uIZF>BUw4_s6ULNwcyw~s{QPl+Ieq?nk-ny z9hp&k4`AI!v0;9;v@daKmJEF@+LL@xeAajoeX|NGi$(i5)R@+Om+DOR`m}3$`+&6T zV;j@i#1|>oFh~7CGByl2wvK8)Aw>I3_e8Dinzf+&#Cn=K8_A(6n4i`*7-m;$B12z` z_BbCLpEcg01&sui#iIQl)R@+Ox9Uvx`n2LEg^ks;PV2zrUu=+E1}zezvr)z2mtIeJ$GKd~kf$c<<}!`}=zPP+(g7y&w^N z+WWYC68BXcV|sbM#vf^~^#{q=FyPoas{O#s+TY(VXkpUK@#UxgchB{9^37$~F^l#% z9~_@G-Vmv-pt4xz{Q=aN)_%Y0O!oS;uO8k+yghB4$*teEKhj?750bHA{BN}%R{5@A z9pqKJv>NUAExM#>XYHrhFh5)KzUPZz8TwkZ$NAv+tnq5SsUoN>7VYCvV_N%zsx#T^ z)84t!NB(inNYjg-HFyQ%s6R-?h5^Uc(RuH?TdQep`K(|a_|dc+n)AWBjbg+6Y-wNl zuL&~rwP=s?!SPw+#dUWRR2GZ&B5F))Z&sbjUY~Y(S42xAqsE%*`o>mXwnPt??12-u*hv-VSLn4c}}KPN1ap|3@IoDYuA8n1qcv!JqAw8w#I z?Nb)(6ofwQi$zS3yl0Fs{p~vFkJfyxzuJ@3_Hb++)qeQGY=U*9psdeR)-cPFs7NPG zJIhh}70l0;_L-w{AEG_zXSz5a9G^9w`@<=}b7j%~FbYg-4-?U+{nNqex(!wzR$JQ^h~~`+8b`kca6_~8|G(A`=e*-rpyzSV9_4ugX6Qt8(z7&Nu{vN`vlaO*8Z64O!oS;PYmcL zgx6eRdRI&RUW=ptAQ>A599u`VueAEa?|GvJJLX+cP+zP2i~I{sJM|dc!~AS%KPxH+ zTxzMmy@2z<@mb@A@0{^FFBa`jpk!(7kAvj(X_uU^N}6A*yQz43^*7~?`h#R_7;tPI z)xMMegx~W<4Hi6oyr!;T)n%GGwLRR!{A_7Iy;(6C`dH>Y&IiY5jo0`5XhCJMXnzVd zrnNt*I+MLV?FOxzELZccWh$T6M^-S7`h#R_7;tPI)js5b_BS|-Z;cnM1MmE|h^EfE zjbg+6Y-#WG_P7jvE!yLJaD3Ky74MwUHSf=$z_j+KK_dFJ`z1G%#hOh`b!GLlDM$T5 zGByl2wvK8)zo_MJ7pTEn7S=w`UpLh4e>U$sH%R@t9?l2HXN~8#udblx%`)%Lp~kfK zXH{pi*Qec@xPfv)>FTDFCr8Q(#!-Kej1A*|tNq%L^cqd?q}?r82R{Acyr#~&jbg+6 zY|Z;N9VW`q*D~*MJ~%#Wyavw;2`cOV(!Or9rY)+XhUd{%4sB`BmIG~B(1uH9wEapc zqyqgDvv@Iw+qt1FwCo%Kzg9UH&})_Bie9sF{CYM4oQo7EH+t=YHeBrGbK_nbz`2Bc z)O-q}*ZDC76?>edBTsp{Uzd@O$|;Oqi?w9IO>9=gO}0fRjjZ zuzwS^RJhzIY4HtX;nmcYP$mcHdQTv6@Wme9>jj&($C=Q+%telX_IY7Ve zQyee!x(eEGvDdFHGowJi9v~mJUpOCD&ak{$Kt2yC4qkhzq74^&`TW>(807N^`KbBe zb&QoW!hbv9Jf=7v=yi3p;bJeJ>RG)&zn&l;H6OedvT|1D&kHzDDGpv&SvirT3IfhE zii6jmnrOqtUcV|Gs}DFy$Vcs$2YSuQ88jh3;5?@|cpYQqyr1_P==Fl);IU!l6c2#c zi1fHqw0afZG11mpY;`KTP+F9B`1 z*yH>tSO{?5BOjH6uNMN^aIweP<_h!qfP7RAUVHLl2rBkC!S_#qasG&WRE{rt&B__p zr7GyxCyFDW*M4Zj#a=$=n-lFmb?KR z1A5b@O*ZnICy+mIYSP>`#NWegYSP>IUQSO0{u!$ zaoiBcA8okU8|SWz;eAUwii7W4SUL5R;eAVbijxCzn&M04 zd~_7xWTZIwK7p0}$ zgNnU;t_?p4I5{XzdF0Q^$sWE8aB@-{yw11A$)I8{pEB}fz;UHGcpYQqyzjOMaB@)` ze7#`hWSLY7aB@=|tXEsK;bN~}rLVyE?|CQ=o}=vv#Xjdi-dJ!R=A}4z{bA)i?6ezj z@=+YT7P4}LW$^i7eu{$`L5%&{baXJtrvSyl>oY6oen$9wtRTg~{bJ?J>y;7YQ;6c= zb)yqwzjpL20XT&zj(`|l7&!$S-2>-g5sFh*2dCxz2*7cpIQZU&HJ`It=Kzj7#liOp ztQ_yv%K^uO;^4Kg8`^NOJHPhq2b`i52d~epoKdae^A=BvgXcRdCr3{B{J9v#!D~h^ z+HkSgud(xgf_@dJI5;0x&c1p#0jC7Tsf{>2aWbgb%V*eb*sqcl2VdJ+IsS2J!MrF% zajNLx9KHsh8<(ayc$``DY2B+l$fpd&!S|}Y(T0n?@rlh1pCgr}IC+sjE9XV^bReH{ z6vtNw=g_t4fK#60;C}T*8!q{*AW)ry9j6sDtw+@igF6r#SdL?2k5F?48dwzg`EN8Wac5Q&vut zzYCaOH7O3Br>vY#uj&9!EsBH3hm}(--4D>O+7t)hXAVRgF80Rf)U=@>pE?u=-`BBn zK97d?t3DJ5->wQq z;bL!`%>&_c2@F*^_`Me^XVIxdpu36Ul-I$zHOv6|);fc`~~Dwm*P~{!HGz& z0P^vpI2m9aZ7yJ54AKUJqG0!`V^LvMreX-#qPvklgMwQaKpaN1Cu+K4k6ZMfJQ=a87O zfYX-ZR6+i%oF>QM^TT!&C$|nx&E;^M+fy8T{R%}JF82C0sx>^HJ5U^aO=jhsHNejc zf+!9?e^@zHAC>~=Pe+P_KL=suyl{i>mpf6M!a6wT$EOGRbf!31^Kody#ojo_-Pi)o zpDq*!pNFiRLKoq4Xj3`0<{$LYHO>fVFmaL7LlLr}5DDc@u>=vPmQQxN%wVF)VrIIa`! z08TH8gU_FELb1>Js|wVsH^sr4vvQ1a@V=!F#p$Gjb1c~%%!|Gh2cL(m`SdBt0Zu=P zgV#e=PT`*LbK(9JCm3-e(1wdWz1E+BpPLV$IQYJWl{5OD8R$Nc;$TK3P6icw`4k%h z-|q~fIQagDl{3`aQHdMFp5)B2PeT3eh+Op#lg>wqtJ$nJ>9c583N9q5frB<@@M5#?e-XOMp7IX z9h?!#Ccp`yIC!42=CkMl{Jza7ii7W4rlJiOd*f5RVi%ClXo`ccU(*T2KBp7<|5lOf z@81QCp*VgzI6p4K>w750!Pg7cd@f~J0rDA3aatlyG}>^nH$FWtgaXbuic=o>vvQhE zUIjSgDUOd0&W-aA04I#%6xYF7(_lW}OrSU!b#S=zaD5J^I39>I3vIaA8|T_LGJxyX zM2dsQnUxde3*RqCP#iZMoW{rDx;lyC`0Lfrdq!{=<1DNb3$nS(Z5 z?2R+uWdhJWisInwAS za6ZqXIQZOIfHqw0>2+ii9Ou~-2cOTZ9IgYrADcsQ@cGQjY4M;m=+|6|GfW33I{pJV zf96pfPaT{$rQ!D&=TjW~{E)R@^?t(VS_>#npbk#=*6@AGLW)xpaTcKs7kj$5NejQ{ zxrpL;Ab(a)-$U?w?~5r8UN=}detY2eC1NNJUN=}dNx44)-Iq`tyl${^dM$w8e_l#) z@Vddu8T=Z)?_Nf62J7H7+xY_YYdOWi_dcxoWchvta8^(peE-AB*|!ybpFfu3RM)|A zn+2bbt)w`3Eo9ASLNfe4$SR71*JoDF)idyStg9)GfH*N|!^PhG8gk@cFwScz4t@{E z%31yhe$Qbo#lh<;E9Y8I_`9}s6sNupj#~kE|Gb{!jL^Y}ytx~U&jyOqPzR@Y6wGHM z#li1$S;xnJvkdatL~+6pXDQlnv8Q{{`tbSlW{QJ#XXUiDx)1+{;$Xd4ITfEi0{z-T zaq!r%at7yx_nBKM4%VHOvtS*(|Jg=yTI=A9G0z44+D>se9h~V&+W=<=#lhzxYrm?s zg3l#(QXG69vT`c=!1ZSr#c7W?%h865z4I{N`yt>yDvsjhK>n;8zx)A!vzy{%(ZTs^ z3jChl9*R>_2j^oB`1_r`6vsmcr{FaBeVct0CqxIQ%1-z>{(g!Rq=VC%`v;td2Pn>H z#EC^4F7|X!3VjVY2Pw`t9lq z=W>+d;OAqp7=nsDPVd!kKt9JPPHyBMiy^4kzdo z{Q~g0-xZ3}5^*-54HtX;${hs1hjx|X;P>6EoR(eJf%E4Y#qrU>N$d(gue?ri@H)?$ zkKdvtAfFo)2d~epoJn=|0nSZ|lTio9{m6a5xkYjCd}qz4xd?y9ahu|JAkHSV;bKqs zbkXqpb%_*b7V>B1jBW<6r*|k0ekQ@nxm6Ud^LHsubsd}oLGbh3dlbh_2j_kj_&xml z6bIiwv-ZogF8m$q1Bz2v2WQjAd*J+eNOAD>{U5a9Vo&#$?neRV5yhE`{8>4#q?~~B znBw631Xj+~HSqgUPbdyPe^@zX#~cCqJf%4Eba0}c!S5eFqd0h+x1tRfd*j^L2d>Xa z6bFwFD<{uS_yv=%F5YQ8$Q>1Lvipr&&p}q5eCeM@oh z=U=Rx>6766dPi}}>fqFy4cCqL6sMvN&Y)%Qz&!mxabk3EzK)02_m323gbt3o)$^85 z6sL<0&dPMtK)*gyoQ66$qIeN-zEGU$h_e%IxY#>?{@$|zaK2KUzQ~`I6Fm)nU-TQr z!S4xJIUhH}`}t&w6Q+Z+vl9F~_dCVGbAmOWnCkF%$3G~}QXQNeXW_c>AH~7vA!|M* zXTi^Ne^MMy2dD6*%|Q2G6bGM&tobBx@P5_cWcmGEAV#{X(-Md#EC;2F80pn zmh4CU83OiJsrgf*1_4*c?TGu z^b}{94$kbf;{hiF#aW<()3H1Jo@YjigXbyh_)J_0@5eGx96Y~RIXS*x0R3{IICz}* zpbZy$=i!A&cwd*9;*3N7tQ?=paD1{*oNyhSN+aR-v9nSf{9J-HpWdtCbEIq(r>zc7 z;eGIPkn9vEPzR@W4*2_&925tS^FFlUVo$G5Md9aPIVlc)&d1~bEPwYZtogWAg5PJ$LvirA!^&CN0`@B}#p#AP2hfI#J-y`N z@b5b2qc~W1Ru2CQt{eF&4%VHObNmCme=b0A@Yt|&T>Rj9Sdil2ac1Sr@rCO~A&P_N z7b~ZZ8GcWuFvY>|x#Q7>i#@&0tX~M$)glxJKTlxgxE6%-%Z=g;*1>sqR|NUEQ=C{G zoc$*FKF)*UtkS{x_a>YdMJY}v9h|29;pf7h6lVeAh-kybo?h3o!}s0AD2^xcXXQi< zhR?N%Q=9-D9FN_nfnFsjP8A)TEXl_KrzFL}>oaS=o`t~Y^Q9;bUY}VxUoXSo$Caiy zQ93y0t?;>e8H%$`2j@ZSuV8%2QXIUFvGz*{g!fV9C{8!TkcGFxUy zP_f5ZH6Rb*cu^dzm5d>%*yCLCgr9p>ra0@6zlt5O_%KFb(_iak!kKk#$CY7_@wmt_n=#U7`{UoC-N z)hQ0XF3T8#iak!}KJat=8Wd*^@;^){_Bq+>#)J7@lj7j#eyp4mO}_z7EsBHRd$DrT zcZSbNYEvBiewmdssseoeT!-Rx)4@4C4*vZFABuz5AJ%-9vFm?%z38SUEXYIs;BUii6KXR!(wm z_&l>d#c7H-324K`-uSpV4FKn11Bx>c`LlB7or0W(6sNroj(hcGAfHAQCx;GB^^?;8 zr!mD@u7e{dz~84dp*UG|aE3V#1Nrz<91k6wI0^o}ufHhHEFGNw?aF|Bno=A$9US-5 z~3 zWDf-Sw4^w$Iyie)!{>*sC{85eoIo2c_STJ$IpO-#n&Lzte^ySd^pRjaY(sJI{RS(C zUpxnJ+EN^Rzro5WHy{2!r5(iy*1-ws55H&Cp5k=V!MRWa{!XC-#lhDd)_#?8>kP&x zh~nVu4lCzyA9x?tk>VWI!MWHE{tmhm#VM_W6L&NM^s6()!S^k!{c1cOe(${t#c7N< zr_hFry?L>s23&u-QXKqwE-RW3*^2yGIX}|C`_;cG&R`v! zH-q7G>>(50acmn=Ct8o+uUzb@q;ZNg0 zKI17)m=2E67yccyFpAS(2dDWP_`U846eq6^&e&`4ej}XXoYKLW8Ug=*hlv!&R|hB0 zH2D5Bg5u!o1*=}Od@mEdS~N5T;OnO|+H#@|Kcj*L{y*O?*Bkh%8*b-vy_ga2RZcqe znuSv)$lVmU@24>H@Ngdc(;R%?lmTtU(5B{-7QI#q%m?42mqA-uw3S1f%9(`51s7b8 ziz(35E*90{dfZoB|Eu~D&f`XH^QYcbNDkx5^yJoM7|jhU_ZDBm4bQ93=9*@56PJBf zj*pysimTb7z4`Q!N~HbHclEeOW5Y$iQQpKZD|hBXKZJ8pVK0e)i&7`Jog*ij-76{W zyOw;$C2r|&9DM3BIquir#8q~hB*uD z*g+IF=HRb=Tul69w-n}*Ru`ALq>aIsJ_Gm8Lwfr@UHmhz?4*6tO+k9oAQxxYpYI?( z-g(m#&Tyqxt%#nVMQk51v=iHyMf!ez%NCKzrV*s^Sh(b+{(J%#O|H1w0X+8NG`5#RbtQIBy)osRTd4sixa!S zs;gYcc(YI9-v(lD=-JzBs6LaMlC~PL-@fe-zbfls&NWEk;W>rpLMF7a%mwxTwO9A* zT!>7W3wW;Jg69HWS8+X_3%LGa#qZp^s++{ao3|1zN5A~eomlmc7;d^s?1VRoocrr6 zV!9e$WNcP@`-)5I)#eZFDM{?c-v4pliQC1?URj71^`kZ!rM30Mv6ExS@qm+)#5tE* z@RgUBAU0B*-@5IfxYfHGXVCEHv(@&_K-DVkv1q>-b(D*BqD3 zt6ME5_WNDS#IvJ=`43Nv6Z_W1DcsWb^TiT1zHzvZE!Xei+V*`a?wQb<@HSLj=Cj(j zCigW{G&z2F#0F6mTJt})^~Se1hF5cX8YkVGBp%EiL3l#3?_$Qu0elswk;Hz{cDXoV zeRuwO?!v@A{Bolhw7VBy=X@Drx5=N2D|DobxoA&iuJ}i%5qD&%BDp0gbM5QgH|7&( zDoZh2uabP)=jv|m*uYC_?OKi4PhH=MhZ+v!>nzDic=fv`i$kuI;J^H%@MooQmfmvh z`La>N$nmnB-iZ%;4davDvJpFGmXmbi+<1OZ@213VHa?r=nYJf?*u68cyM!l->pv%Q zd-8oTUv*(U6aA2ecjO+q_ls9@vbjT#NN>?trXTV zjCVWVjMyEo=9F%BAHqK!(1+NeQ*ugvr-t+ETJ$Hj$HHt<(YB-bbvuKI?e{p76jLOW zce~z!*asW9O8e#x=c_F2OKkOA$M-!f=Q_UU%7Zq1EzgHG^<1Bva<1dgym7(jIzGv9 zJwDfQeg3HQKAZLx;iC&>=W&}$AM2Z6i&goM(@w4&@}|f02rpvbWpl55Jb&5gHL*)S@5c#| z31YP#wFrOJb3gt_&|Gfz1!djqI>DPS66(q4NLWF58(eboN1T26r!STf`$BF%Dc#q# z=KuD8Ahyr7D!g%T3BJ%gB|bkrtF$h>s&rw+j5@eKo~~ii$3_*zZvjV0dpC1hY0o<^ z>0_N-q(8pqaopo#$HW!&tC4)3?)Kxoip}OW&IlyObNoCRAC=o#dXg=Tgn5zoWHc9x z@n?%~BD`M{2S^uM)DhE^{7LNQwLSRAD;fFj-aCjr@Ouua=Ywj}+v3h-Zo1XaD*e;5 zsw75Y_%|zNa46SQkdEZIOa9XkXPT8b>Vm0Y&zau2y%d0r4Q^J2@;uK}Ai~7WySMMq+ zRqOSb#P{w|nwQ(J6EpcJ`Hp)WWNtayQ<^X#i5!m{z1UngAg44wo5FWL9V|Wd8zJ7g zf0rC@F|WN;He|4PGpjPbM{73}<61aLwK}+v{DQLAlk#7S7dN5}k4M)EEkrr6v=kq& zoWJT^%ZiS%%r(qFf61Cx_LjL8l`_`?QVx*0hHe0HJ)Ud0e(vIm{L&b2uHd*B4mT@O zp(LNbKy5DM@fczcT3(UAyTF^95v?4*)L@x0dq5s3K<@U~bLF}vR zi}4Yee7Nc7`x5`EIYln`#dj`mHi6iAR#)OTovFf^oR$-N@U3(4g>QRF6$leL&*un3N=D2lU(&b*t+OTH3$^2-Wr}S**>JnAnGhU*W#qT*mbrq}*dpJ@Ap6 z_4ggF*)FBOhk8}#hg_<`m8@$fyjf!gnO8=6Nk?ZcCGq{s-4&zmrIWJo2h3Q1`R6cm zljQ}aOtYVo<8`lR68r8?D_sv$=H9)r1^Ey;Js11cjmPaTZyYOTJM&O9KD$Hs&7Rff zxn_yRVjZp%d+(Vh;)Mg(jKvGLAo2#@dN!^bDQH-1^5=wEATEk3?M zUT(_n^W=EC0^P*8mRUKue^bIcmOEJN&|(KyHK8Q2Z@LTOl~;+}@K_I5(^j$kz7kUG z%zsJ$ZlM0PK>Zt>(!Wvl>WRUR%wpWvTqNGXr^CgzkurB*Qm&;#>Ma#Ri(eK86;$+e z`7cUbAhhOw2KkZp(>qTWKgR}hODp;k+x1d{_~TS|<1y#|NPnLM3S!{5Ph71KWq!{~ zJTAWdH&=YK2FiV3d*QTLI>RuZlfGX`d;jQrVxv#aQrIJ9{L`PDCbm4im^-yA3+Yd{ z$J52~CAx7B_oc*}b3!a#{GN}g{14(^IGxDFV;ge~@75;yt7~m`GWr zShH86`A~1gE`B9O4BNxkX|Z4!IX-*&SaDd@Z9c0zjv@A`i*xxA^NUDJzpN&G_w{aQ zPRI~0j=A?2IUbijQoP`N%bcd8!s}ZH-SdCHV;Dufq5Z=X52%RzDIsq)0;mFuo+r^{T=d)4@|qc)KCKl{z&Jw$iu@4V|sd@VyY(eqFReqC+lJ~cTd{`i#mKagD<<{v| zVx`0}JnoOH{Mqai{9U{mlAiRx*z@N6Jm12S&~GB)N1CFfw_RQ0!!9o*@sF1pDV4la zSd8sl%m@1qc8Zc_`CmEMw%|N+JpX`Ue9NmYQZLUW(*L7t=I~B2?$VepD~O$Wq6>F3 zI!J8c6GGw_Z+AGp$q0Y(d($9di=qFSy>=&y-Cv|5`Roc9$Gzw>NgVpC2RW|J75w~& zWv;02bJe{%SEi=S73=rAxE{|HTpuwt4PX3wX8wSGXOg?mnC$$5u|GMv*9c;-oba7< zYURR<<(m>apz;Re5W`n4;c{M*>-6{NxyAYKobR;|a@v7HHlzRfPh8bm`3UcXcS)(vE`d9kbrU)MJbf&e zYvN_GZM8QdO4rcyV-B7>^POvbQ;9cl&obk;=Q~8FfyGI@@oslEo7-HCCi#wYbLG!%`o`TlKAQBmOXfWM z;E;d0&U+^jJIX!Q_@vA(aokuXU+%>TaqRJO((;%xB%kV?yBJG0i4n&&Q1VYSmy_C# zEypzt;mGlr_^Q(4f+e|+Yut(bw0LHz%b`k=SM^2Yp8I5)ZJha)9~afDF3Gq4h-&=F z=b_xxuMbH4{Ou#mO_nwm<2dEI(>Gg$xpah^RPmQ`PhKT9FQ4zSmpL(D6XBUwZZdam z;4UTYNhI<1bSTPyjcDzYZ3S<{dW_idNz55gNjl$RKk0wczs`~@dP#5Mh7-GB$+S|p zyr{=vjvb<>02aHp(Ku81ncUp?1zAr{NIjwd8`#GSz%RL}KkDd)OBs>6j`7tq5} zT#wInTz{c-KIzTQBK*caiDWGL+Nm z`Q?9yi#Vr=(RHM|6|?ZoPb%?VEpe5$FLUOl?#eYaTiW;H`bsxB=d#Ykzx>;p+|;7g z_*rKb5dSgbDoM3+9OTj-T1VEUcRh^K+#|QR&ow)c_x%gjXE$QCV%x3J%>BbO@0_5F6^(w+Ys8Bt9~z&v}%Hq&&u(BlJ|z6T=%}px!LYZQCgla<7NFmjIAa6)G3z}02M-cYKA@u-lIUn#yO zc2ePSM(&?%{Io*<5_{sH8q)EsC%AyoH#n@%&Ws|Lt%;N5we1bDV?17QMK*jF%RYWY z?D{wVu^NfogX6L6xye0PS zGE>Dx&2vkS=dB_3%}-UNa-DW_b530&{B~m>nIng0mL}x9MUM9$A0hVNl}j4mOu23k z-2abx=Z>_}q!o9_@t_h@#XT)@OWS-DUY#kG#mMsoq%Dp15Zp2b1zNe5IbSc6Ry;l+1&O8%352d z)edv`taQ@C7E1nUx{njrOei1~=zE%+f16A65Iv6+lzz2}FU!A|+a`!YH_j`{CzmL}9XfM{ zwEwndr1&#`At^bqFX3k`oq@l);;|T4DJ?lJxz^xMTzzYt5wVcii^GcZwHp=Tiu5{8 z>=qS@@&`61ie=o^l6+=9_Tn3vZ-{3+{~>Gb%T*=#oplOwubUnt?f2g*#>ZTaGfyc! zN%2p44vwGqv8in4Su64Pzj489WfxS3>+xEN>$jJ0Wo$5K zroSfD6wVJSuXMM zF|!YMg4p?gZsE$lY9eM^q41to%_6?u{ZxEAUwJ=dJac-cF~v`~i>6 z1^rGE|CL{oxhy62a`9;ol5^!rts9(N|5&_O;|Mw4>hekM%<7lsMFkUxy=r$kZga*J zV)>2AXEfQzqW1(@vq~rWv?Tr^Iqn+&9*07F#E5;r!R9CGidJ_r=3~ z)^n>{D*c_g=?>=+R@W!nKAG^{lGF1e-sR?Nc2?ex`A7UR{#|#Acws^r!aJ63x#(0h zn-tJCBZ>Fz*f4QK4RpV_IF_6{Z=1F-h7HNe|G2HprEE>|NYjhYH+u!-5V0N)T^eu~ zO1tqMHj%?t4_sG^9cNY|@q&KlmEva|Fh8wVi5#!#otyIw z${-f5*_#}fj})xa+VG0&^m+!#|8Rvu+>LHy&7~KOCCA_PIw1x`Y%+7NlyiOin;Sj> zk+ypo*eEf|?X5;wGJxRQ~d3%coJ)Nc8jSdlQ4W~|Vx4fEg+3pn}V^h5% zx+ck=IH6VYLENXo^%H%%=4)iU@?H77^GRYf=e@KUw|Lh(5^qtVM4zdd8X0H(P>z?I zH(#9o<+Zr`(oAyPDY2ipc!RSveNqC6=b3zlTXvuU7gIYwi5IsgA204&ZLB|Y49PEZ z;f0)+K^Ai_QQj}DJavT26IhFD@8V9{A2PXdr5?KSckcg7_~BpMao&LyxJB8OxtH(I z6wZBIAa`-7^6bE4d43<$wSvYM13h`%pRDC##D@)Eh~EY+BmNs7Jr#Ft8YZ4xw2#Dp z=^7?xGbD>4W0lXqW_J(cz9*a%!`FNz$FnTV$3MH#T(~iKzH(pi zW8W^W>({knKxXCr=ExEYxWK-$7*I>JVkooBe9#KS};^p3BU0pUg1MOF2Hx zcdl68_nx?a?;3Kv)|;hb(4uGJ_=d5>?*96Lxc}RDv1V`_>CcY9=i=XPgT$X34iJ0z zwsM|po4lK#&> zypQ`_wg^|ULMdVwF4DvJ`o>&yXjbKTm*5k|k*o9b1IyBOnmDg<@5a{ zr=e!4Y!?1Rx^m=r?|^US8@p@N8DT0$>>kcX#C#JEi&-Zr*NUdUJf%X#gc^3=B0bSS6ozhr&y!pCBi@8Sx&0DrG>e4cn)IkUj9xjf$lL+Y(GT! zkxn_KM+-8EwY>@}_TFMrzgLURUx)W6^XJ*858{xsO~f+SPLksRqq9r$-9g6pD?$jb zK$~yk_t8y6v9O|ty4Dpyxv;EtSx`ItnM5|U;pb)QS{I$N*7>43T<}`wfz~=)kJma} zpC+~!*LKov&f{f6<=IK7kxT#NA=khBUGkox+&=WIVbpcbV_gYyPY^g@At&!H?bD#n zE7F(2+dmm2Bi?Wi8cia79i3%^n8RZ;7nS5e#*@N7^>8rR! z4e}8GGhb$Lh8OqtN1Rgb0V8|;-y~v&0z}4PYl*FG}J2QW*Mn|sd$)#pI27%kdxqx-Y z;!oUB=0@vR)%d8K%Z+9H_L1W``g`*^i=Q{T&A37APKj^Ch6kMa6M@4?yle{+#HpEY zaIsmHwXArr&Enx!aa_;M%5&~p|0IY@J~&CyZLbplA)D5r?`o{)w)iM(S+OBi`Jg-p zjb+=OCdcR8-pe(8u~dARS9woz^FS!Ky_CT`C+R=Z|Kp#l^YxcbF`hc7Jl}ZL{GI5* zec+NGG$#4XMyh!t)fq&IY~YjE-V#azT9UFN*+)A2jA-;R;;+g z9GLedvBj);#VL(Ci`ToM=b@-_n)%XB~9Hcekh(^;=IQYe(pL8MKS9V zE?t0fe!WjGo1K?CON%lElKE2Sep&u*q3*`Gn%Bws{`mC~^PsEFQq8q}$nhNCuNv#U z8Yw2Hn@95Vo-<9{9x|63d{DU-uTL(ihs7t`^>Gw zD{x+}xk&plBMe;9!dTLzJU4wr z6jw1>d9HgfYbL(rwn%QlEamx3qv~$l(G%0T(U+C6$a#9LC~r8=iO$N}&>D!IT)%e3#BRFpI0%A8SR71L-wEZAgZ;FU>Y_+&Bx6XYkCvQ@C9!WdI$D1y3 zyZ==_<7{853jZ0scT5aHYZxlyvb5!5f9w(`3{?2N>UH4cQ*q*dyFQcS3lnnktp{h5 zI={(E>`S$MrP!{I>OA3Ak$AJ3RF-nM`^Fy`8ba)B2Vd4Hx~Yvg^|kUDQoiLGTj7E7|F``l#99+E9Y$xgEG35i0IY)J^A zP_|U}xgnLULXwC|cCsZR^}qKy{6D|>&irT0{O?S|>pbf@_nhaR{T*wR2kENE>0KA7 zcjSxGq?QPhP41O zdd^Z|v1$$JH=W%aFgXEdCNTNN@5*Aj&rP9v&nRjuN6S>jpCylk*HhRUVB~fUNPB%4 zR}W?RKfpVQajiZG7tNWyT^~A&<8OQvlvY}ieE5{kVz^u4uBe$X0A!9M&Lt|9YEj}m1f08ZnyPVb(o4dV0o0Dy*uFP(tElylt zhH;f_z4FE{2QkCl6Z2davAWU6UJM=H9d~&L6F&RY6O$c|K0oq)9sBj^h;=e9eXUt4Ds6_K`iujnW#VOm8)yi&&=Ofz~?>$iCqU4bgGQ z9Z)oUM)=FwUpRcH6f=9VHMuP&1rTFB8{$Sb;br-nk^y|;lKHM~P3%cu9$Mw>IS8$R1e` zYrh;~oizx%XFP)Z%`t*&O=rUUJknug)*7g;Vf4RkwYB8?zqD0#iBH~7sww@+d+q+V z)g6D@s=JgXKY#n!a=P4B<@9xzree&44D4`#jVHeswBnzf&&gcVE1UWhej(QU8h1PV zbow3DO-uVN*uVNZuKB7h$~s?MZOI27TA1mqa)bD5O|1E|%T(}7Xc+M?t+wG8g|tR5 z^CyIBdt38^+B={}U^U?(a0~f}E`6UA?+n37LyitQA`ZoVe^lf>u zXfe1KBvu=d{wmEwct7zp>RK8S_B1?zlTzQ~A=`S=zak+90|uM`6&uFyZmz=5^PB*o zk6RHvVSElW&btE%=~ndaN6rv{_jw0z=O&XqBi&2F{CkN|sm%PjH#%O>8nqqN7PCH% zVjF2s%*L7cBDo#O&$%3nLG3@_h_1g#|2)OxIDK~_8ed`di%s{V&9yMlu4UNE=n!t% z^Bx^z82_hhd-2QV6Hxn|(T_~;1QW7#`8|^klRqWljnIGTGFa%RMEZk5Gr{lSdpOIeB-GkT1mnP3Z+d29`} zBy^3d;rbDxc#-uX`|mL0GfP%s@tMxVAI*)!-z$v8xYKOjT50Zkob^G#m&Hw}{NGw1 zz#PBLFe8fje>LR=u6=tOyE!2V)2jEqVp+&8cYFAVO>_r2js{gj;LCEVIUTH^Sw zY`m{<^BrvIuO>Q|isb*NiEA=PT=Nz;oZmtCc)2okJ838md1}kc?ZIcYqM)BWN*s1% z9nn2f^91f{A92P|6~b5Nea7^Pec1LSYj0ca48@GS520rei=<@a{B zp~&TG^F38qextJ$MZ>ht{G4l3P_}0m{{vTwJ^9}$mV|G;HWnY6sqx9BY|N^;`89WW zfRQ+44 z#G>}i6tgZZRqNff?x>1F%m4ZfQGa65|DN5D)8$wsr+c)m1CQO|ii^cC)AGhdB2%Og|!0a{sNq&W*Ib5AyiaBE*6UO~}u*EqqNdGyK^kp_^ zLhR`v9J6^NNbV{Wg=_Jl0|jX3m_q#Kj;X@u&h{8?-<`^K%o;;jRl5w|K3+@wn_8@d zkvnc-){kDqpXPWXGt2c3=I>|g`5l7J2n`3uW4&n?lGhAO2h#!9VeC5=TLYuw@w4hQ zP_rIO{yen`<%XpX!N-AnNdL*zH-rT(x?=FN9whHMAs1Kt?Cn~yij6_MrM>jNrjxM$ z^qpkCj4I%s*PrqWK8aD>Z0K(~j_l1DosMxKlR&L#1YxZw z`r^=Tnh-seedpXO?+f!PyI@5s>u1fpVj(6i)Q29cSnS)^>^u5DOclH|+4y|LVpXx$ z=V7K-O%}b+`HL4}SmiUgo!67}k6p3}pQ=R11TQnE9-t7hR%-H2h0; z)0O=DD*c{q_X~Dn23H$0e@E=S#rdvF zN27o%q(8d4Eqq*SARgASA-qhjGp_HKilb}TcjKr=Yw>cHIY0aen`?Z^&k_<+55x7W zYh<6VXeSQcq|W!)qfPQx_jiK9&-KN|PELe<(yU>4zJWN%tOMaqo2*2&1T8+l6&o}B zt;<$YUjF~o<>)_knKs)=y5v4)yi|$hbh$3e={J=1P|0^aCRCM@?_=ibVD$A3I7zFR z@aW#UIKMIk(*hn7KGs}S9HwuMYwK7a#HimuA=&H!mKP~fUUZ5$zNz^&uIZ&6$`xAu%*>kDp5#qDT=3-`6S(c| zLwIuWRB_&Zdu;9QOZ;6|O%Z1qTVtPb(+ICr1-$u2I%n5;BJrR8)JwQ?s07y*F#F|i z9%i(jpO2x#JCXgbUp@FQgY&pW?XMGVBlN@SKKo%vF|*f0=OoPA9?4lR5lDYolMeXm zpdP4fW^sG@h6$o;*&wvr@`GZ*)~%l6jL%nu;P5Eof4$^`u(f>&_BuF(^dEKT#>YFW z39}tppX%sm4}Oo;4enwPv%e`~2u^(*4=Mo@$p6`@V?-m3Ntl(elJv)qh{U>wFQ7PP zAkkyjrEo%EI3`{%CjBQd4%6M_u|jD35Q!c0|}el?!&9)pMc%&tRHbj3-J>E@%ZdNC8 zbHjJSnH6~uVc*Dks_mn?Kk(5{a4Sy`zF+=9^8Wr;z(MUW_B}L|_>*(1U`eSq+?+5a@*J@(!Z4H=mnFBgyYFeTA$eK;(>!un9DenyyCa~^wUu(`8i>#qw% zj~+p5h33RRZ|eZi-kL1ocj7-9S%k;O9e|30 z9)yRSG87fNuZFN{*7jGeGsPZp=dg2^U*wbxt=CN4p*fay@ zZCQ_**N>8XT9SuYD#Qp{lbFAM>$-ft{GaOjl8h#9OQm|gQ2JZ*UtN#+Q`f08BejhM9(ZG{?0X?u=AMLg2lX6ym8m_#J@Oo1_aM3f=_m2PC<8p3mh^W z44SibiT_xQx%BR9L0HAwT3ARe*Im>>?8o{@?ymY`R-G!}FM{E4&VK#)RoQH= zAY-EehK4)wJFfUpS=JS7fSk`az}Y;UvK?L?0)cmK!TFn;2#@HZz}r=ZqfIVryCJP& zV4~9mObU%5e{#V{Owu_BX3qTxf841E$@)vNwB$75;igJ(0-Ivu2lm~y`1U^iskEMA z?wd^Z{hIk>u$L?UaJmuUV;T1aqZ5w&ry0S7d+3LQ`KN2}`t>gIM>nOOTQypNAA0&8 zC%q1Z=x;gTWO$9M-M@j#FIP`$+o$93g+7Y~r3Q_z_8lD&+!M&3R{JW@Q!g8XH)Rt4 ziosf-;Slb8}PWo#NPcd0WaU zVbWI{{z%i!L|-r^9<&#o0oQHm~cr29@JVa8|p>!Vt%fmoGP8YKjTe!Z`l~M@f7#ESo2UzF43SRtqPDA_11 zYu8FRp<_jHO_^)PkB{at@YYk5$O=VoP77zPy)#$mu{gV+O?xaHrYxG>o=)`e>XvvU z-dx<>wTkeJeWv_X&%W5Wg3asrhX)AD4urYRyu-%EsxLgTr<(?j?qW{%^!K*I3k6NZ z-(hD+zR8VNSi9L=>^k~6;V(v;1XCqz(PX2ADEp(-zX~q*I*2{1nh=iAYs-foaz>NV z&&1zXXQJS7Fw%8x9J6QfA{h_+RdVNz8$gy1-gyy+YBhn-HE#%CpS=*jD1N{WMQq+{ zhDJ5Ky}1Y5)TxpF$2V+vs~g&A^Wg#MH<{a-&#LN=6OtMT4=D+SvgT&6TAHtx_50Q- zii4!P8Ma@ZM0Fv_=@l-z5)9+4=a4^-}Z}y(U$Gtjyii^Zij#3mPZfa)yv6bFVtMxXR+e} zTsq6_2X0ppmEPQi`))w=t8JzI^)c6=rf_wp>~GT5IGpn;0yp}xKBe)RZ1_|@%{8uP z2HC4~UIyL=_Jf9s7vVt@4}g_zduX%7g7RDYc|QyewuRNT3>Wq|>bmb$0qpQ-4YGdg z?LUR#9!h-gGfT<-legLU^6YUzKZ?b&;KX=g>J4SyKYJa~e>~52J!z)Q7hOF_xUVC} zMSWA^Yn_h~jx)^`j=faoGyInm{@Yd@C0qZ}R(eQ$J*7W+d?;@w_}hov^QW!2OKI}+ zcg;dhm)nY*K4XSD+?Uo@9b9uMZ=a7J0#l7noPPc*!cC9-=1z=gDqf7dPWZTf9(?TZ zi5q(2AmP(LFT>EOY20Rubi&=PEQKKN{+!;x?}Ur|KXRAUnu>c(nEvLyG{8n%PyEpQ zGSPp(&4$(IpL08+Ss!Cs(S7J2pa%xqSX^(JJBUj*4d%w&XX{0A8y|D}aeCq{?gq(g z)T@ZrS#9y!m>`t%IIv|oWVF7AqnEIE{bIWo-)`4C?wF|#(T^=u#`)0~xicwjp6dL< z+mQ9F8baE2A^ORzUxMoQGh9MzcD}Z4`AuQx&tR@=F2ha3lzZ(i*^En56sWFbHA~~v zpX-WmwC{jye_N*$s2e1r_OC#~!)K|9`J6dk_Y5ZeSGgcC2sn?;wqGEuvE>yQTVBV> z3D*d_XlV22p1kD}z8eru-QOT2C#G;Km6`p+AC}@T|owxz9MW3ZTmFzon z=cg}MU#lsOP|X3^pPA?&zT0)2d$S>o@ZiqL_%weIYTSw<{j(gJh)Xqgi2rH)g4w;!6- z*by$Te#+&I-UH*k*nV)k6m{seIu4e(I1s)1vjX3*AqEGgmXp4^byLyr-8~q(cM{n% z@1_Ns_YcALQB0qCt|f*@=hbKaXhU=_9d)QzItXLEn7+TUsH2qke~CqIQ>5?qH0duu z`kVRRcYE)jSkzW7MCqYeB&Eseax9Y5A;<-{`-frlg5H!D?Mp70usjUgE@b%2NiSiA zDv!3lK=i;xCS1Uhi&)&KM>y!-7|c7e4WGL5gw;no;@Wb=c{^EN6GqJCt`u$+W?8l& zdg&v3;cbQocF^xd*lEox;eJde?it&Tuz^^^b!mAH^XID)ZYa8s6(`cMJg_5S=VDb+ zXHo>7Yr^I^v-|bH@D#+n8_eF8dnP#A6w$+iz02`E4aHSM=HQoG6X@OKgskH__X-h~ zWV9xIx~Z-(;K4~8TF?3&g^QCjQyY9R+K$c5_-P%1$De|+;M@yp8@DF4gwf(@oK{s! z`l`mOi?2F`VS#rt;k>Ml+{@l;h45f4UM_Q$aTemsi*EQ?eyBNVi0&UeaY{i1=EryyXm9v}bs0?7IdM~l#D5s#BbO(y+1m)pXt zpyvEjBen*zSNSvqB^&S)T(gM(Z(Wr4o&8H)tdR~6hW=`7)R7kS<$Kcpei!#ibxwZ% zcg;Xfm+PXOesc0uY-RQqujp?l-;N~*U^@2-7q;I?IL^imUrF~=ZK?JloU_80>-k7S z?0;h!;YAez_^YN0Kd7=hR?gf?#LbsgMZ0nzD!X;tvV@O@Dq=|TbmG6-qaU>ItS7ed z*g$w?+c>Z|e;ak58BpHc^XH=NuNdq$MThXvMHg|@v?k)b>PXTzF*5-C#uE*Pe2O&HDCMvyW0X?%V(c>C%2@&rhVEcc>ID zc30qUb^l5F*4h?>OE%((acpi!r(LxW?61t*9IGe#yUtxP_CYng3jau0&o>MMYV)A= zyJEsEw>Dy@d!cx7C zOWB&uEopCaKi!MCzJu+7#i=yH+uE5=wi5nE(>Z4>L$;sx zc*{*#SnnjvTUk&3|Eb#)XkSyf7q@U)_rH|X+I|%%?$8-2;+VZp}O*7?{a8zubBI`s*13eX)ny& zaSnYt^(1-odp|JsQzS%Y=#qY8!$hIgl|pc>Tt)or7B#>~sm~UX#`e{eoJ`H!XI26i z`mnL~j(um)qre(;gIS#FYPJq+T0h__+B_%ubB|A=QRM=`_a5u>p0WIbJxUhBPiwZn zm0wD-|7`swaT`J7Z&>F;0aTJG^}u@3Go?AwHe@d|YkTH^4NduP%W)yIQ+QxlSp z%3Xy6Hx;6Xoc8CFUDoI0S#UzGf7sIVd2e(81Lov6xhd!a-2o1E$*h7BG9 zi^7>dzxN)*1sg>?8^-+I7N?Goje%devzG%l! z(toUMG+@ndHAG z=wmA*n=iVbdy=WuF&|`mWy(Fp(h4_t@|pSD+0;pVDcyC}cPJYV?a5Mf zy*l+5c60hn`r^gplICd_Zhc6aPx>M`M(=DKD6&a@XXgFd{;e4{Qa_(Ffb;M{JXrtMYIaCMDuBE zZ~OW34VmRWH8}szIS`3tsM!Ro_|ercIbo4=sTeumTDKFRd#^%))V6iNP2jG^egx*wJT>yut?a1mD~ zDdVRpp449ces{V{W%)0$;Alf*<0EZpzEp|@dP@Jrf&+hI0ZsNvy5v}pB?SRFU5*8E zdia>b+;-p9e3f)|S%M0kOvg$02Cm^1-!CNG$4(V~xh&!*-C})^kxdV9!v@XaEk?~D zwH~2+I6v#zyhYmv`lc(qA98tZ_8LCkWIf5-I=6z3y=L(2p3ma^NkBW;4|kwgd=x{3PE4n@&O<3lYClzxZtp-4IlFRA>l$N2hsb( zUU;f}g>e4pGFZCkEeyHO;{N2t74W&Z6b{X7OZp;KwBx&Mc#jLZdJuNbu;y3lRO6W} zmY;4h%eXgJ!*RUTcha}-nWK1eajKANev9xBS7R|%yAXfcvNe;&R~G!r?9V9N=tufo z@+|pvFTUZFDp$h&S1#v9hDTtI6Vq4h)@vK9~Wq3AuE`JXe{Se!Vo z0Jr!t{Xu3%Vs`i=EIxXe_&ulViC>47<4fOtga=CZ0VFnd7UNs#lRedS?RYLO`L5?6tW%ZfzxIeMtf7i0*bU9YY>HALY5)%67 zpz^iBl=qy7816)870A6;OTG?zy@=9a%$uC1yc!yOFptrjF#BxNQYH-@_Qfv$=u3L+)`s<91_Y&(B16d76$N0ydy(!D_+* z-R|Jopm3ZX=|#9&Egw&=>@6%T*n!gPQ?TCq45J<|!>u7!L~njnRh;Ro!L68dpX$~$ z?J4N7aVng;F`r^{dj4m0s$b7#g*6gANA;YveiV*Rel(@F-Qw^bc%E<&{nj!ZIzI!) zk6DjTyRbg`(;L?@ad#N{^_@oc44st4@=I;FA(gByUwl%BW9zedxFjPfwuVuEZN8U+<)u3{Gs`mx-REg`l67p^8fzU^@D%v`Vcu$dg!|-oyC>Y z<+?7XKlN>m=?afA0cMf!^-6c(e1xUwc6ex}Ec5Z$6Nm{i7Tu2CrLwx|(hGCCJj8mQ z%_#@Y?uBNxY6|6xKlU_q=&5Z(o437Ox2Nl3&xk zsTdP>4AdQ$qU>)%w}A*H8K}FK^;weIH%B#PbMbW5C(@VR$qmm*an`BJO~TXqd?9#;?K%f!V$Oh#aXA=Tue;* z8H^kqgHLy`@6!FQ;lj;s4XCGdo8+s%*TO!i$1~Qf&!xR%3Y=WB8|p`@(fi+%pu?}# zRu?@3*>~G@*F@NJYd4G^z|Qj(OuGy!>B-XlF&oML)|-{WO@%1%++t7i4z~5{H&f$mA;CDQ_v^h!meb5EC+OZA|maw^rZeOaw z`tf(Pmd?$|?>EZA7do8V4XZA*F~KFbZ*b}D7*MNYvAMImHos*~1*)h%Cw<-aOoYQN z_kd?7mVcK{6CtAgR;cd7+8&}0I2f-3#pA4P2c)$F$1P*PZW-%mnY1hs)V*V1(tQUi zpOfYWV&Bm(p?th0)t?T}y5KJ9&Y@Ui)^C{k^9n3`yAd>hzajerr1^Mpkw0`QX8i)4 zR?+Ad8IjRcyAkC46sXrhn6wvRln=|_w#0Tg^tw9lXvxZVM`1l|(Rs`z9{NT4N_92( zY|YuIaO*c=6|)hrM7jetaSzL1=p+u3FVBMGHf-Ndzh~P8k2BJm=5agn-}{a-9xFNv zzdzUz-rq!D9DLb??{tZ^mvOC?#O+^g`LQ>Tl7Cvq>#;z}d&H+C!e$F%F>h9*Yl7Vm z!c*Qh;q44tVdE(_2K!j{89v|BBk*#hM{u?VfsVx5` zRuu;=#{}U_a^-KAYV`Z=uB;|BDR?6wc>dK;p#T?k+IDl;b z;&bq-X%pz@ca5-jw262xYcC9PTr0byFhx2`YUv#bYf@(u-Z1$k21NLifQrM32d93Ns>Vpyjp~DEl{Jw}PmwDa~z- zGZJK+SiD9Evj2pJ8(xwArpbc@qy7hQ#*0ZLA9gbc*Zg?EZJ%(TaOiP;&^=xQZ%Uay z?OW@(+WEKOVKrN$2wP;vjh(M6TCGVZeZhVEyKbl!vCz_k%O)_3A|U)2&X*|9rpel++9 z@dJ!AttQ_geQmFdL(}}*obtB^gu7jC4w2H?!*}hO{`9gAfcXk=$mki_OH&%aZ8Fgl z>$imS<=yf7PRJe=?K*zEU3BF`6v1uk5wc&rwF|U;ejOg{-bnV8Qwu;{>Qha9zL@ZbR%xJMcpe9giX>cb zC360Odg2VVkz{{mi>J`v_C0o6r7g(iGogJ2jGgli-S@KhcPV=-^jJNUn=&ex>@Bfe z4ZB0lAT5{mONL+F3{MmjxtlS|iN3|IC!8tIgz=-+l0BVM4eV=EmZu}6U)D-(!9Rdw*oF+d55P5nUFuHO1DFaZdb1A6YCoY$8zCq?OqJ~ z=0|;rmE9gg{qctwGQ@@SHO=S=)m6G;C&en#_b%cExR})80_i?SIe(AezJM^dpEz1f zCH%Lo%Youw+WIT$f|9pQ6%^d0`2wZ?bJqFL|3|+_PM6!d+%NL`RffUSMrS^V%OPJ^ zbaE8cA35US&mn{}>?+aMCaqVGdD(=Q%xI2LV@BepQdXB-pIM1zKV7iUKa}V(ue*pH zRW0$@BGymIQ6C^4jyVfgOQrTIJuknt5^uXp_jgZ=CcMvI6T7vXfCuZ?_{UQ^Lq2B+ z;;z1ziS97IkJw_q4#s$R6SfZSCw6IOD4o+EML4R<05R!l1}u^87M1nuzUVLB?s^=u zR7Vmnnb1ZY>+}rlpYI@?{kA~}T{#tRysaP{qUtVY$2LW;Brn45kGtT{UpLTYrbsyb zvb$*PrH5Y47(Gfqo*Nvu62A>(bB$`g14RF$xiCJE*$>*a21jmH6aCvR1KA(b9v0HQ zlI1YqFtb18K&{aK>J+^7oY}w8;~bn0>?U?l97Oi|Ts;dpJ5 zZ)PvnI)+QRHWhdJvG2;wYCX|phB+VX-X~qQ2TzBi@;E&)en%wPpE1l_e7))gY`woNu4c-c( z#o0EzZ^9H#wwGymM+pCF#n10oO!gwXXo+oH+wgmQ!f1?fps5nP?pX}mLl2PtK1%P= zZnq|1%7qa&tk?*P?&rcmVn+V?UMUpLRa^000v{0F;=m=LZFejFTNsPQ zHSfGYH}VcREs7_9maYten9X_c!eC7T%rc#!pmuFDG@e)ATZG`(gJ(a~)6NO8V_1OmdoGK>%mX0sr=c*`aE_^EC6?T?<3n7%_Co}oE zZBn4<r@wrBWKpAn)) znXY)H?=qt2bbSK_tGePO_jQyPtNUZ{SM?zHmdVx?igV7R^|}Kv;RIVFdpb5Bug*Qm z-Er(s@@snz7Iorv#jM>62>a!a6ekVW7HiusC46GMAHQ&tbe167oXV!b=?wm`xd69K z*t$vojpxwJ`Uu#4WNmvSJj1%B{kT1GZ0^#*^#T`vK~+4~L6N>gj(f+68q)8j?6M3Z z{q~Di@IE`=3J!h?Nqh>8@n}J#qi2d%`Vefi)w=bEEHK zqcD?jpx6d#UvGf|uce~=&Tr&R5Qlz#hdUR{Ao}|sBVe$b65noOB$Y>Z$)Ag_ZwmQq zm_MhTAK{Ck0_c8EAbWN`#Tb7dp|=OapGNe^oM&RpN2ZUWSd^_$%4ypifcxDRl0AF- z4d5Ootx?YNCEP2{L|nNv6pX@5QTFHB@mYMQ!#i9}3wILE%J0uvzHG@Sc&AZ6Bk{N` zH~o`2zf5fc;bFFyg)=WIL3O?#>1*EBmrplT{7aU;!h|?tB-DwsS2P|qWu6U`59&1d9-!H>WjFrwwS?^d!IHd9#{&;N4$9QK^ z-3Y$mCLZqZ0v+v-5`A2KAUIWMT5Sh)s!;!Tu zxPntVLE+we(q9!32P@BShEC0p^!uD0C|-1)2%XZHywc}jxNqDXHNMu6zJ=-2(fLU; z(O`cMlHd4zzO)`^EEYcC2;Z6L%11W0&74=6OZqA%_2*0c7Yn#|3*oT^t$Fq3rCba1 zV#2+~c)(4Q7TBs88{a$j_l2C%jl%1TY`)^n(G;$3e=wX4QKYu&(cunQwD=`V%Ss}D z;ujZ#db0=k^X5Flxzzz!D&0H3qXqNNYIJ+ve{vEx(xw%a|8IiwzW2JjAV zPYcU-yd%6cpbziaB}JH_;X?NQwl(=4)qiPgiHZ*5Rzua^7V`c8-T&4E6aKWd|J@%T zr^{_kPJbl*-k{m(Wc+pNCY8mDPAdG4%6J^R{RZKpL-mm5aUTOK&Jqs1rowl(DZ%n_ zg@kXfu7Q9G1>SQdtDELc7D8+7WDIoc36gq+x8C1jJ>JFT3M|gt`l!fn{#J^+Hk6Qj z?7%`OZtRCCA!-zte!Tw*-HO!s=tT)cH%PMqbA!X!v+)G!+gJDo%7fvtUk6Myq;Zy=~Zmar_ihsevc@_B>`+qqON)m>MM_-=VG>A?BJCLUd@Xj zv*6!FKEjuyNJ=HZX#EY?jb2oPL~a`5p}_I~T!PvEEHI|Z+n{fVF3 zUxb}*mvZr*%pd*smm%kBq4YZqWkfe`wggtq%z(fhb|Am+Jw1xykctj(_Hh`|pDEqr z{AZ7Xkm;|8UinlG@<4+X%)hx`mBnWZhvDVyWTGFMs3q35bHXpi*9muC-b1Vjnh7|zhVbKHNAav* z2sq!YCA>C&16-_CLZ2Am63@FR?)TePg4&bSXoo)RFza z_az~%6Zc6moL9c`jn#J(B7n8S?_O{2jP60)&%S6}k2@~Fw zn@H=`W)!Dy#|oLBynAvk)0+?;4f_R$b=M)zJDd2;mkh%ZV&~DjA*t?d^EkzoZWZu2&gg+D5zOARVl{hvnj_Z@~ zr*1$q*EfzfnAC;QE!FzLcH>cyX||p8d5m&F@$L$Uj5&H!P^|DM>WRgVSHSWlW`D)}KCtg-B3!@7>VBN5BZSq3gU2p5 zPyY3@kqGVE!qCG{NZ(4GJg(_GY0YvVvu_-{np626g-XL14uj9|CBGXsm+q~W%NI+0 zz;CJ>XmjC&gI5iMFNgR$Fmw6vJ09gkVtj)A&K$NB*wtXTm#9HNfQRtOm$G?8e_H<@`)Wsv~e?jfmSjwAD%nY~@+@IfY z=m_Z>sB{c^h1u~l_Ha}dOMiZWeyX2fN#sX*7saC!Ky`s7KW8VqPu0WzFdQv6;NRCa zCwns&4@W<za zz(<6$2MWo)duW~O*y{`UoLkSxUc1$gK_~V!MqBnHx>j}#lr8=M9zlP;1G!&e@#bns zN@U-GI|+wi;jC6XuiTNB-^Zl<&D<)J8Nvz=B>5Vx`_M(X99QTcB;4agBpNn74~P9q z2}i$jbG`X|4xe|c7-acZ7rw${?g_kZ`I2x&s}k_)_yWJxZ72RSsUP80yD!r3Ff{bK02Q5#Tq;)9})|i z@FgW|5AU&$cLehx`eOB#P2``7S_;fR(u^05btV6MhaK_ICs*;*2eyu*-|ZaCJfg*~@86C1 z$Gu5`wieC!J?aeiHgp3&2V?Q#1~w)-x>^t7&zgvH?kS3Lc}KkRbM0C;P<;K8<)_o< z%P5}NFBUFlzkQ|}z8O`mc8iH!6UqM^V^?9Q(K^v~)(G;~w(54T8>fbf^S<6BTxg;V zDH}b-Ch6-5*H5_yuCdyD2MtH^?{BObEZP2-SR;iG1$hrqp>+3|n*M)djN^Y|je|s! zA34@!NojJr9BbtCrVI43{i`10iSv4tSA)*Ggpt3-i)&u8_50Q5w&I(hNupQBX!3QW zjw_D#Zzh@=vbmpxb^UqIJJznol`$aOFg+ZD{d-Iji(|uxUp>Ab+RfAvXV#dI{`9dP z*h>1nEtl17kLZ%G{rR!QeO!m6?I!u>=MwP5JDeH*F zIcG4)n|+rfb#=t5F3A{Hx{>%-JaEVIMT+9Y7c7680mFH-PuID7TNBB@hRhk*byYcj zmhQ%r{d4Cp;!}Ic-?1FY$CPS_&(}JL@24&yf3NI{z{~F6am)-h*Jk9ZES~Mc;lue$ zi9dL|i;&RwG+6X~MmTj@E}mO>0PGiZBm7CTqp)H_iu4;;WrUsG9r&kfHTjf&Q$eI z>-i}in7p-_5BQ|c(&Dbg!QY!`G?#&F7S*IeMd7^ZRPbg?&W&)8A|%^jH*V% zI1o+pN=U!v^ci?3tQfUdy&-wMlJ$IS#Ruv3jpl@3EPandPjTYI+-Jo9?crwrvqKSQ zTg}d}IW3vR*J+*LcF&$g{C(FuixXVSaq6MlWbfz6xj3-;F4nt#Ao|o}9Yw#`Qrx;( zk#Nt#pRlA}5469&B+Qqeg0dgGxNK`5s;jRKZ{`oIdnoNo9YFR=Ck61&Lz20bH9^F` z?^jo`_3|g!HlvvAr99n+1#dF&efRG~Utpw${SyPg-K)PSzf0}a;XjREB zaTP`=e&zC>1(3bs-dJWf7>>k+&LXvH2p!i=(QtS z>jZ+P;{ejHx+@m~VwB-*CpHfq>=Mems5g<$@o9o=zh?3r@$M8YKCdU!cW%~oIO(JX zQwOkl>5cQ(^R;7I!j^lZh`(*@bTPw9i#LIlWY0)C)0mw36N3Ki84k7`Aa)4X;8QeN zefnG1hfB8prLG(1S@ScivmjW$6VvFw@4|^cb^U+83v&A3?}GmK6Bu=_J#QqPZ<6yi zd36%@cyGb?u<<3VrG5fq9qsu1^y!4v9_ZuCbW8s29UFRA%g;U#xcCW(>)Bk-f}6z{ zd3XYM!0k7^>qYO|qI;<~-yL#De(&sk!ujnkymyaTMDHl|<;xZXz}xCcDBB-D*Hg$Y z=*C;zwV?I5qx0?wMHa!R@5bT^f4TyV##|A8sI&1%*y`4pcXaCcogzM}o$-eW#Rv7Yo4F6zk9?2Ja?H0zC?L;kU zzDnljrep}U(NlPT{hLJJFfKdO^mljOB1n<++3~{!pH*k1xhXd9+^^s+?(X1-9qZUW z!@{V!=;V|FHOuysyv1i-v>h~_Z^&l$Muzql;!KX=()-WJUgyU(!tGHL`KQBg5dX6; zci_0E1;*ZVBAlsnI5YENSKjSjI;|&PPA(PF?l_7Iv>sD_P}K)p&QcZQ&*&3BH#Hf1 zc%DYr7QG19UjXzBXgRqJ@!zp8f;aZ# zaO}hj#NP(f1U0)3;(%xtdp6qS!QNIYu-!U==qIXTpzZD~d{Fk3@P(_{aIDW^9J{0$ z=^MSc0L)qh;Gu14M89`stFSMwgE)Bc1M>g%+DI^VzKy=mZxMat%}-q1Nhk49EZb}2 zUZ(&{u6GbWCx;UM-?lPB%FDmB6}L+1?vyI&9QJeR-)H}w#Xk9`t@M`*MSA2ul&{p` zlGEk3BBy^#uYtY~nsHr!KBc@opHc%q6pgsTWo*1L`u96{?S9SGeMkk-!`IbAr)1z7 z-rOggJK-F9n)PvwTH21{)VRB$FfqSD=sf&8(GBc%d1v!;oK5&K!V!bKana20i1lnP z=Kmq>%cFYwy8lyYl8{PKB$Z4}QmOYnw~{#|nG!;hOi`i~NfMDHMM5PBsZ2?|@4g{q zC}k=MAt6&jlA+(d`|y3%de-w>>$BG9{ZGBl-e>Q9&fVwSeWrW1=beSRQb&nN8qNQn zJqP9%8zr}{(|BErT?k9B)xh?7bWZ-crz7Ytcn{(C=~<33vAtN+`0q^4tZAAk_$Po-ld@hUf@<-{hA18Gnd+UP`I~#RoBga&d+h(ySzpwry zQatY~QB}H%IHSA=AGf+)y6ouy#LlWyVX&r9pB-uW{L2?WRMHoi??lU&uu+lkWv4)F zHq#iYC8Z;u&|v{^*S4X)hcjNmII;`QrqCEv!YlJhwf)GhSlT!6Df`HsgqP$@%YM|? zN56_Z_xnO3f-WPzws<2PT>KV%#wuZX<*yE63v<$mR)jp#88=g!;lQpRRx3+9#UJN@fDh`#t2fcNfIoEAknqBfxlS48!;C^c$Pt-Qi$vX;)puH3PKy8I>i{&b$Qq z6Mt#)3EH!m@!fo|JW5MPuoKKZ$!t47?7Mjdb6Yt3zpr2)@^7>4!ngLXm%eCNjCk(_ zO+NB;DC4eghWsyAoB;KtJ!JajYm8VwdsjQKxsGmR!-9KA_p^y%9{BBGe9i389?$ce zVDH&r&PSKpXQi}(88!PP#H!Kf{p2>w_R(@BzIG2W|Jl2{7ze9p=K1R3nBVllM#l7W zHdF>u{>Kxt$;(da!Xe@xXy4zyY>HsZKk3W9%(}!Rz0V_tiWNk(|8Ih-=Lh$g`|Q{>%@&#M?uTjT=j2*1`=rq%L_86I4Ra{6*#mLT?x0 zPRL@qp11x=963769O|UoP!h3cH70C#}aLIZ=O` z?JqEOy1_jTw?cgf8ykC( zL6J8}`tTYe$}@jg3{f>YVMKsRqGmgT{b$FReoCwN&G;rKavc?XbOKjHhm@rb7x)PeShSHc-)8bh_dtA)ayAGr(87g3(VjlCpU8U$)aJs7b} zHw}VG76)XhyA0+}IDZ>H7|D>82QDEVn>dp^ywZdDS)`2Z*kyGtsZUu6gZI<#0NzkP zO71k3lg-aLl=u8s1W{z2nC0`jA^+cJFKMgZZ4s`{ea18jnABl5q0Ez0Rh=cafeN z<0>r?-nZ#ziV#248pgZ#zeC!x+7XwU3HNpQIFbhKt5_G8<@H$A)JbG))<|;@np>_GiUyi-Ltdg;Ku8MWx8)L|iT`GKQ`9p73EW?8?eOdqa zqsV#1D=2Sp*bT<_cqcZen-9u+{`DKto^DLK)_ew$KW*I|xV9>nS>T?E_{Aj&uWM*V zCNxK3er=7PejJSA%0-M{vnweNmN__V-Gs2WyBO_x$B}>Ao<7{}?@IjPW4VZ@#w)Ok zW>zuhKT`Q)t^4y|2iHKQ5nZ2ps^`G#HpaoAKX=X8DK20mlID};sVb=NWCP1aeA!P@ zlzJjgXlx^2hCLuYBpdA?805f*jVXX}ZxpcpUEVtL5FZKW%IUmSVEGi7akB=bIW+$M zYP1&9JY~|6C!=9Y|v`$G7byLH-_5 zn{^89?`-A3dyXyw_Z~Ecv;1rfPgehc-V!?gNLc0v9VS&k)|OJ#Kl*VzR12RZovfRO z__xbK_Q)(B&L#de;%EKiU`mxT?^7DaiT+i$+??P4^&Ln;sC{8;4R|}FW_a=KClTp? z+wx4||9{e!|9|H^a{jbs@vb=WhyAM1h{bfVEsN=0(>_Aa)1rOPi)fq=t1iF-NSFV^sC4(YZ) ziwuI2>vT?8k1C2p+b6xo_Z>3z9ssyyh=hYOx#P$>yP@Ij}Ws^T2y}m>uGm>Eb z`ucTz>CPDDW)h9>g)eN7s+mpDK6MM~)6>~UCQj|iZ;$gv94Xv)(V#gRO#C_#(LUM0 zv*dN89G~`WBhnv?*h8Mk>hMi_7bDgVUMSqPSpZ5WKO_I(#ixny9(jIs5akbEGM1#K zb>`z1%s_q@&oX9=iY#yVY82wXZE=>M>z}kmabL!imiG3=N-{FSr-S}4#>xHD77azC zg`e0K9fUM7U2KbD`rH}9+E)?}O1J48<^CbUJ*y+`fz_KfT9>Zf*a121%)M#!%+mDB z!v2z~tz^Q94_LNo{wv7|=ezLw(>Ua}w@fC^CY6x6MGNbCg;p*+mx+caPIRm=W4ji6 zL(`1>c2UCovzo$*)x2$_Xnhmn@Zr|d`jiS#n4p0;$#Nk0kGc+ELFb7yw-4gCy2Zc` zGdgecc}5B$=}tnZXIgnrE-UFL5r?7 z$}cW?E!}eSHe5Q~1F?RFKg^fE3VwksV)@mk{5Ih%^oy-@JP~lWmNZ{iV8eBzaGtDF z(L3VvN{!XtpoIFm?~Wh|7IN&A69+NBtxkW&%3p;om7(h`q2FVf(4W_c`QR>SkKdCe zVB?(+vN4m8|NV0d-h5vS49?C3(f-F}tH4Yc+D~*Hjr7cV3x4X}7?91Q^pB1gh-$MM z`{9%>(q$|?<#!c#YD{i+CKnnTXrxX5~#fXsrF3o{BfXULFH|qd5+9} z*qJr4mBF@A>!}4#io3D5+IM4qlTJsA#xK)kZyn!>*zQ9ZT(ME*+qTm2!ki^5K_Nz& z$PTJQ`e7RlcBGCvNLOkhp82T@YuB%kb9hSI(jKi-U4=yS6XWfPmK>D-PTey}1ut9ZTo6V&{88 zdAFgg^UDCF*FzX&9qz)pnnpN7@bZ3a<5O3}CQsMEZ5l1<;mn16JXCn`p(XMzKJPf~ zj){171cuZ%p*>Hm6!>E8IH~uTY8)Fc@A?z8pT$eUhX!Fk*}Y~BTso0N29~Zy`HimG zcM&GZ8;Od4W@J0*KY<3^I>lo<7PU~VZ7=V185k+=ceZaB>?Q_l|?G-Zb6{e?3}iEV1OK zU8env)7@VDcKLrE#trE8*^w6%(nntq_~ znDK{t^Fh*{T#1(!^4IIQGVMA_ti7;rNGwIE;xP8A;IH-hmyxcK+>1N)=_zPjf5C}# zJI7S`G$sS$f77w?K+}E1^r$xbV98d@Z_!(iZ}>Hr^K5d!{J}GO^NG2AxyX~Uh&Nh` zcNX7c%Fog7aRfM8v29;;Nk%n~bi<+}5ccXeoS#SENh!}1x%bv}P-;)VAt5=O2KM7} zVOxiDsLyU(I;{F}7;;SLSlaJn5&1b-kJW2ii1bO*mH5?hyMZyI@%@}5)v(0A1K+A} z70c7mrolV5T;t-Mlt3(>e)d2%Z}tgB^(tMftF8ILbz5oUx*?_d2UD@*j~=foJM> zxMX3@L@ZC;v2b$V>nL1WMdSH~M|CjTs1;;N)UmB*=58XVq#sBKu#CtLKD8is@fX}X zMd$GB>YhQ^H{ni$9}7_5INvC^^RgG*n@IcV*4XhdBT82IhKw=l``gwQ2(tc7TRZco zt^N19ub3{jH8Gvno@?RVhYcRkWWh4br0 zsm5rdC+LG7he%wIlzuf$Dti)L)?X zxewxljUS+B?|L{6^sL;iuO0aFle4({`@bMvwmgGKM#-=#S7)OMzd*G2N%$>D*A~vZO{Q(*Y=RnV z`89@kBvF0-AD!3?X#z>toQe6vLLJ%ie$gav@gT&1+sZ;g*1u^hXaBSn578*$CyxD6 zg-v#1y4Y64^psVa;N3o%^ckg(&wjao9#;rmSo80@u-#jkYs0kTjzl(%#?vnJ=RXtLij=zFH5Bfzu1J2=Ii1E?=e?E^p0nUfdKX*@jZU>u_yX-X1e z4Uj$}aVyEasmQ+CMEjXT2XdI@m&X#fWpr((d_yNrGp0Mcg6N{Yshfe@q@c-~uBT_b zUB+`TB54OVEQrd_v6#r~kJ2uj>3R>JMY!}lT+`ac_4TkoeV#h~;CxAca=z~n#J%H# znG?p>7_;qGi0#von3K<}$jdKu4mIHTR?>D&k?ogFXnm->AU!Vw8FlOfC)Vkzb4SVP z5wdL9H@Z*xJ2Qcg?zPAMq|JTQKiy|D*q5oX$L1#^{xVg#W5`;azo66~aiq>rzR@n8 zJF}o3@u5y#DI``e!4q_&k*u3uoKDrB6ouBJ~R6 zmH8OX`GgX&etb3?a&9WGgzvc?Kzhtf6aE3*`K^hp@yjO4 z7wLOhrTPTf5Z-~+8%ozjRnwB7|L;z0*!c6v-xB4(JErYnhL3%Qc=zT*T! zP`-7$CP^IDnSVTfDbj08rjgpqn*7$0Zit7ia^`kt+rZ&v^qg{nZUz^za1w@I zmq$Xk8Fb#t;bWk^TkTaccRMX_TNelBbI$^z+>7GDtsU8e-PFjuyhOB5OZNcS=BTia z7J&G>=P3xR?8x$IRfxN1>+>-YA>>A6J7SwLIZ(9E7X}#6IsLVMfn>x)4ZdnJou|vW zvW8KE0&rYT%cH%03vrg64&~qJyQBH-dhSZ$P&i*n{d51$GT2YtLC%53Ezyg+u$6mu zGVLSxpuU7YBiJU*eUJ)U5X)HF+TC1rjhs3{%kzEgd2*y?8aeDk{cUFb8zxjUjV$)N zh5Sk5710tm???W`DR0T+{>uF44609O#TiED9)O1{?dxSv4`4r6sXwzNo}a?_ zrybSMcirx7XOivK^Bbnq@l&y9C+2m~B0jCG8`49Tb^(`-!}$KG^u4CFD~$>N62z~X z{ho+AU_k;Ce=?N6T}#JnD)rjLdX6XGQcCH8qve=wR^I%SASzGKZXnITs}RSJ zTKo4yL!}1$(Iy?`&5iEImn+U9_kT{owkb6~&S-rM;9+w;(#w~hAc2o$`EwVRAYR^Z zmrP%J0j@>Um|HS%27Kr|gl(^-bKWag8S+09R}!yVw{X9i%)+-4cj3I@>;dC=(f)Vg zzKm_bC}I808FB84V`R^SNHBd&=is--bYM@vaS*;6z7XT6CanqJ95#f#qJ0DPXY{_# zkg(ybVvo*3@B3v5@zl_~KXRrMyFoaDFOWm|N-apShKM!RN%E6a7PdQP__rri;EPrmq*?L(Ji` z#O))Ep&oMwNx^L?dA@8O+FrV2CQ<0|n3OD}G33ZK)kL@N9^#a|4C(3TR9Lm_Sco;G zF|pauIAUFXm296q2kARLM3EbV%ZU17PsG{}Er{#DH)QY$Q^ao%za*2pZYLhz{)jVE zGq|A73T)-!LL!>2)?JlddpHJ`U#9JxOj2Nj0`@{(B8`EaKTKqLu+F4M=3UHRG1G#K zIdq>$53N8v*w2EHe$~Wp#3IDOfx0}$gbBxdpOrdBCIq+T|c`16&*5|c{Jn)bNVxV&xVgTB@-*|5X&Bc zs4v{$yd>Vb3-K&^jd;#7fS_5o$&lqVE-N@#&A2%7B>7m4|MxC(vKf0Yf1KX?(GS#y-9>GGV^ ztN@U-QhRfAYKi6hVsPeZ{jI7r<$t#3a$63jA-~eROo`(oRTA6b4cdER;6)ghSVpP` z_e1?_Z!Tig?oJ{3@^o!A`uB2X5j&m?%A@w0dp(ujn;$}~G-%%j(>5`sYI3~BDjk%! zct%HJaaWEPCPNV$m~`f+kN1QOyCBs6+29dbRa*jg&S~;u{TpoEPrkfr0L7;?Zune% zg?yNG7t$njz0i5NCBLo56K;xZGUgv;^#evL%_nP8X??jhG;w1N#7UQK_<{PC8g}8& zbej%V#=*!R*YO2cF}e=C>(^r2jQ}#6tC7odzWtcAnd{K0O@z>nCO++B~qh$AJPxd_94Htf;g`&hm_lt zUv|+@-grYJ=hl*h_G}-d&TnX#2zxJtAs+m?mDBb=C@s(Zj`o4xJ6^ZZ?X z@Nl+8Y+a|%uiQ#NUzo!b>;G?Gv_$y-pY%myp8qv>cm7XbG>|gTF_Mrbri*=%nBH2E z2|;R7ZumGJbr-mH;xcSb3o*}h#6hu#U{mj%T>Hs8h~vD@KvHR&yWNC~g zFZG>|ZK1U1PPk)tM0z&mH>I=9Fjv?Qn^o%$q8WC%vE*!fUp~W~&V{+pk!L-c%y_Rc zbpMvEBo@w=@06|yqVLtl1q|F5@7LP>7Uf@G*NwM0y$$qt^}=U==1e#Km~bZ5Ae8Ry z3lAw|T${S_rT2HCzNB0O_JjHW{`jcLXphg2eMJ6BXGkrhW2T<>CxAijIqAArv~6cO zMna~sH}m`TSLAouqX!R*%~;(BebHCfuj~)XhJ)FqlcNzknyK@flVc!fQ*X4#WZrqW z)cOE=?lMDsPuH4VoNdUbXl+M%Z3|};qYqA8&*%}XSRZ?momhjazWlO!8VA&z>qvHV zo4%FJZ@No?0MLHHiGb9)Hs>eI+LGrC^6 zsI((*I(}1;=@YtFVfg|@GV$9eR>9l_#PX}&P-F6qC$QlfcZ)>q@J)v?cr}srI&mK5 z{cQ`&1lqr83k84L!hf$7i|Jxp5Yzn*t!BLnMoZt6k3!pw;s33z1UGY2KcPWYBiZE0Ao?v8#cq#*iJQW2vIs(Xs$mwa!U^OG18rV=OQ+{^a|WPtl8f6T8P7hd80!^3W?We8pE=WlOg+#7JHP}M|*TnO@zqX zYV3q<6fZ114@t3SK;4nfSL};?3eNM~_`~acP~O~YJlW7Mmwf$mhQ1us*yF2*5YIUJ zo@`Jb24A8(u~Uqwyj738^JO7s{N(0EM0h+hJDi(Awv!1v>h>}8_4=L4{Goj<#Na_Q zBhm+}sPo5&1%DyV75Qs?<#_oi_3(2Vo!?PCBEvUzapLn1((g%nUpD0ZFEJp~m&VxJ zTDADq!Grm2Pq$!x`Qf^JUg#Bx^Uhqvu0)wX8!N}#{!+r{JLZ8AZ&5e{w75p3|Mk@s zf-V2VSKU9gx7U4dZ=c%K-Y#t4{J(t-7ykIFxR*%$;dn-HQZZfhRWaRp&Tx?5uM9tw zXuPjKK^f}D)G!yqZlf)yH7meQh_BUB>D)-`_$+SKR|jy|L}RSM{qJ)!i#8MgWfjP8 zUQo#mG}=kl%Tal;CJhiL9RWQ%`+{hL*Rq3L!_g7&w1M_J{uA$U1;RHRM7qqV z8=Svo2Dx{$6!F@N^&L2SLU9-702yHQ3_dD6HF?(oul60%W>^um(I@I+xDvUGk%~0d7^%eF)s^eq>)uJtX;RqCQu(Q>1WR2vKvSYgB>eqY2aYnndZ)80^%^ zIFJmKVS69%g7TWq)N<1w7LcZIXHcJv-VSMpm8sBL@h65=y#VJti(qHKG31YtDv=e> z-a?~<&K+p=8AWytuZHAD^#1mhJ}IQ_yDhi8{Ts@&KAlJ0O+$&^T3VkUKH8GUS#OBW zLOOR=*k>XcapX1GxZo|yk9eNRY%SOeb1wG4wx~Y)J##p)5!|xrJbI5RMRL2>JE%ye zfLm9)V)?Hu-Ary8N+E4I#gc&E%-cj^OnQ*c9XPlhBBg3aNl3&fY+L3H z_ZcS#BRI*^@!`*>o+S9tOVV0F?R)p+7{l)03sv8#J*&PblexPa;dsP%ET7^B61NG{)2||IQ5RoDBJY_IynW-Ad+0)sTz%bZ$Z`VFUT-b)1~G zqH{Zb7E)$b(_V0YO=H#t&os#5=3_AZd@k0{-?q3?@P&WU7Db==UolkSpSEaB8L%yS z329=w*cQd~=}M(!)U|Yo$=!y!wG(nkmjDjD_isWxdF?Hd+G_$lu!=+68gh-qJ06F* z?OPH1?&(av7AWxH@8~?^m~nM5CantzF;qu-*_&Hrl)58yyhQVR^|B{{UP^pZnK2Q~ z(igsuH_%qf9A_whwTmhl*{Z-B@1^owHJ(9XTz3*^KT*jLC=ebi%zC*DH5&3&e{QE3o+ zbHoe8e|ZiGDF zE7CD_+E_NYdmIX4KQq?jJ0g9;NM&ws#dxxD@+ib!$;-HHizGy|a3taram3EHkNKq$Vxg@o68L4#$M*eJ#3R0Rilhpp8ae#BtP0~739$r1}hdCiI^_76*0Xgq?V}t3S(w`UP}ZhGjLflDVY^U4qVJdJbt(l zYs`hhv=u4n8;XuY*k};$x48EK#TwoVBj;E>Qlv^_E*WxyYgz8aD)G0F-&%-6HPSva zZxXMeya959*cQ2+@Z_66(vNzZvK@vb!kA+VP~M8x!R!H}-C$Xzfb^8}!9?A^x3IsC z$`5%JPI`H1lDP+HKjT|?k~7&nmj#(h_-F#~!+!g;?eF7m|4?8GN6wME!3E z4q&ZrMnbsUEF7zOytqu{dg}0=XQDwYe{-~yEW6r^_vjgeIDAGdG|x;SdqQcy8r|s* zcOthZ-(8Y}^6Mj1VSg`MHgk+K%2yh2lIw7C9y_}*8R^CwK9h?#_e1_0f241F@`Xqa zSTR?}^hNoz1N*Z%ZR;U5cmdke^16)3KKKBxfgwouv&tu_>b?1>K|2s{-@g_t7gQ40 z6hL_!j_m<2|Lw$5_^zO6|IhswIkVNeeBqvBsK52xEAGxrZC=&$EaEY5^SE_7-fYFM z7g*o=6RU}K>O*18CKBg9_kN4pZ9;NHyUgIMqU#A%Iw^koOeqY~RWcSiR z{J}x{kbj0_F_+uAjBVluBEIqAJVbIwNcU3*5!Y!b^2SpGAgiAn5$z59uFSjkzsHT( zcpB*;F-pAO=OLhHypNVIIF!6!K9Dcj8H)5#N91|=;%8i2leJ9QPv z*}7m|Xl=0utBL8H^CCxHr2FaFu&dY1B|2d$$nSM@C>yCap9I{X?^V|itH{e6ry)zO z0O@m>?tHTBa<~_>8ReC}8%y?7=fXRelSpqC))VxvUE$X24@UW|&>vieZ|0T{qw`4C z!8UA|r8gO_)(QF7jJILC)%g;Gqn!~CdRs--s1-8u%7ut~JwC%o6|Zw@w|nAy``MoH zyndWNm-Xu~ww0)^{z=q#qzjd9O(P zWpBjCs;Zg2PTt(?2ef>>*hHpw=6UY9gz9f!5lyzX)REkE6Oms@%bve>7K$QgK*IL&fu6r8u zs(EzY<=u{XP_@C9e;-Zr8@tX0o6R=-*xhH5|Em62K61b^FyMQEXk&*S+Ti+5hfk=a zcXi^X4iJoWl%BF4Rb2Fm17n7^rv?aKkD&}{9e3=bnLSoaf-0NPU_T)pLcF1;_%>Z zY;jc)X*iMxqC9OyB{p+yC7Ceq65{x%?xdyvNv3}Z{f1Ra+AF3@hyoj^P21|PuyRtE zm`(CkccHxeL>U;Vqr#@%PEP zy@2=|mrKf~%^?O+YS^|XhD;;t*S%$Sd(%1d+OJK_r{4-}K^Tphf8X{bi~Fmy@nOeN z-`Lh|WZ(Gi!gq1{V1B0uYOL{u)1+nCd6eJ&v7St96YilcFhl&;7uN}8|2MwK|M5jT zu@Z%!=!>a>6N>4gFN*03GkWlrft%rQydUZ=9&@hOx&iK(L?M6FojPdoy$U(q7a`p>qk`)_I|X8%(Y3PVv)U{P0??YW4cm%UKqK?Z zN{+9;cmVlp^gqDfA3H#)?;*q`y);0{FA<*hr{f#H308d9ho;>1E4xr%p_3J#?cI;t z|D47M9(8S;htggco2Qrm-oK`ucKSg zo|yYGM5k7kH|=A@Wq={K%s2_e`Y@@I zf&8gS@N+7ihjBNs;=OBRIBio}KYNdq5%=}xY|TJ=CcL8Dh`mxdkyI?9_T|+Xv5tuo zh;16hq&%6F=C{I4uVbk1&RiqXQ)M%k@r14iWu(QE4^Mx97v_^GofBS| zK82LD#By7O`wc|?(C1r-N!ukT`?LSD)Ts|~-R>@RvQR*Jw=xYzyYoHCtHy7rKf~RU z&$l?qSqR)Czaqo_Iy)aevxc@)-punTfg2F@MO56k_n5Wk>BA zjQsL4zsT34maOy4X%ewKt#3QCg+;oouURC@e=tJ$-t%XB*1XOh`PH`wJEB$$W#_+f zLHxHb2ov)Do4!E&E~5DR?{f%Zy4V+p=~`CGV63i;6E~wjg z1z7Wa4&;uuNBR*NVK3g$^>ECV;-12{3%GH|;Lt=mSJB`6BJr(mCV{UKv8=VHBDjM4 zjog?EMws9H`gri$8UbDQS|RRW^cK8?vGZg14_Nk#7n-@{H_w5VWB}!Vv!9t!l*4S? z-Gubq>UQ$xd0)0;`DsopoAZ$QT*;sc&Z*r1`GqqdoRXU=oJywa7tUM1g6WS8_{7&^ z{%yh@`O66#{c&gZ2YVgu={;0~_lb++^qgKIR!Qv0{~B~0T5eXLesAI1 z?D4aT!7->3u|tm)+=^~0eBT>C5W9@+&Rp&<%U8N&BbHOSOs*`x0dYeABHE+;S-1<~ z$WZoB*G-6T`X!JPW)|$s(s0CI>JKrgkKU8Hoj)UfVirao{M-+V&(ZNhUZ^I|1vzo$ zf5uZK50&_fBez5Gl08I}|JnN%M4T`N_w^Q-KVi!aP*`FFh39M#@1Gn+4%wx_o>wOj z@AFO}hh|u^+tzMIY?&ECrfwX-zFb6cYSu~n1^2Fz-D;h9QGSU)KcT-L%Sil9UEl#3%G`LC<_c;oP=0;sGy9;bA{xa7(mBER$#{S(Dv?y|mx}V%ODkq?7iQ zkjh-TrqE*d1q^+P80`vLACDbQKydC3((hU^@)xf-%)J?LfoRQ@L3{qTwGD!8|D>%= z8>z*oebOOoV}%u^uK(G?bn#DH`|s~ni0NWm6Vn?@55Tq`rtI=(v@Seb9Jvo0j}n!( z-b5hFWEma=qiJUByBInTIOFa?@b))jg$vlxR{0)3q#dKQNQnb&D-my35Sxu1+2_AD zqOYx2>_ndT=*%88qcNV=L+NmpXNohem z&G$7K*Y6Fn?WBY_Ahr)%Gwmdan;3_<=1CjqMd+|=N7NxK#`Fnedy`rZ7_fb}|SMN(Go zM*5&?16Hf&IAWVaafMZPa)5K=QyNF2{>BID{O`fS9X>X6UUKcF(@qA_w&8rm+*nSmufJ`1qwxPfY0FJ^*_?5&jYL~)%iaIemM{Hj%m00MftW6~ zWikD%R+gmC_i5|}?>ptC=w9ijQx`%cRxU>!=@ki`vL0NY7sL4P4CZ8K0$d5ht%z6wbg-lO6;*K78~#oMdg^)YlUH(^E~iJ2YE9$T0UB0VzoBh2a*#f&H$hw?7v{(|>+zDjOiTY-4k z4tYM$`k-BIBema@SLFA-j+0(`5R3FBapC0ajV0v1mO1KcTO2`T&_{@c!%&L4Rwkli}eZL?|==W!K zfYUERF~9X2MgEqy5x0LijVX&X!pWI#mSpCuL8xD`aTnQXwwb*hOxse=3Gw8BK@@A0 zc?9Lh9bIUXp_(mD~&XgTmEXDks1My!LAGiLCfYiP{qY#KzC zcBq7JM`_HiBt0&*_CLq1v@%3_zGFklto)gLz|I=fr@L914~dP2qZ`~%-tsBVT;j|l zF#8~#i#q;Pp7;En490z3k^VC?4777+^Bvd8A}*YaGJ$-|i|oOcA?|B*jZZ8J>Ln=jlWwHE2IJHuhPiw}Re_)p)} zPnG**;m5yPvl!*wIy!_Ly1Yy{b4JJC6@50@58nL|)-?9T@~zJ_;nsG_g)Vl35I0U= z2)fsO_{e@`7(@HG4eWzDcn4pR{$cO#f@G`tqN)u1y(myc{l^>lV|+ zwl1b`m_JGSdafCq@_dMOwZh&&x-ZxWWYenV%(cgplS-T#57nEcEs|xcO)1+|l??&;kwc14c;}ud+v>54qi&e=J-iZw; zGs66f@0M}S-6VWLY%SvZr`pL?Jy~$QL*s_U_kNI7W91<(yffx+7$V0XKC(rhxYrO?D?|h3HB7%jdVf@ATNZ9a`rl{0St$FzdDbO=p0%@B ziNa5u8*vc!nTzS-vli1c7Z|bHIo;XwQS_ZtRc*x93;R#*4xw14*sHL1_AO#6d@ELz zQL{ps^}eXYsupD-Htk@{-dfk4{j`Ge4?5U`bJ|4HyE z@=Unr@@;Y%(r1ouBpnz3B%TZCoN(Xver(WF1$OQ$+Al}l%!C%#!{jyTiS17&O5a#H;jdH90ryC{2|)Yom| z>vEm(%)^+=Lz#4$@qByo0hE`Je4dfFCG6qQ8HihQ3c$F_E|PQ10QGy7D3OZ1vFxn= zrbus%y290ITqSw4?x6nExg}h9TM5}VgqAn1@@50Jhv;S6yyeM(kbr@mLx z*8^@(9!J!D>yX~ouYeRReo6ZM`7TlSZlz?n=Vrb&YB;W6#b2st;N>EIBTM7`)ZIZ6 zwey5Os(BpkxwlJ+Z+x zc!qdl%@uO_{bqi9|L170!=!Bc)9TkCr&|%y_i8UDBQv-2m%GyECv*Nc$X_y-+>K5^ z{W3D+3))86@`DcMfv9hIjuM{`yp`;~N6S;)B+my|B$7K%tC8**rNY~I8dITb|Ay&T|j)##|N_2`>;=iJqx0|5a|n0cu+(1=J_N2!}}_@dC!1IH0gWd^w*8> zbj?trH-*N)89G^c?K|&nh$cOn5_p4@FQ`A&@dt#j*>oYHf}Y>|@~9o$)0awa`Xy2Omdo)MeH@u? z@B5&AOQlMD=-n-3M_wc1bI!_qSp5oe;OtYxjZIb1y=OmCcD@7JXUYA9kU2jk@7~Qv zdEH#s68)WV{D1-15c|h&=dy)wIx1N`MgASv{K!Q8SU$s;&M)}>s^NTB==1lT=zDw4 zbQ#{VHbydHJzZ~W_#n%_2^qrVuUAL?fBUK}Lf!nEzUs=KzREzXWa0OBO+ic-`zkTr z^Atl={Xc_>ZY0{i>TV>rCfJ&P{ChPc=4tO2PUctLg~HVbk)AxUPC7Ztm@hNXM0_nf zlFN6u=Jjp_Ab0mu{ z2g}M2MqHRTo*4JO57rl`{DT%7K|QDopPN4y^J|$(rGbstL3Q6cly5J0mB>7(WnNAX zK)QCn8L)ob4tCf{Do>{B+lAfAlUWrzDbCaFyL$t=E;!4%Ru01azm?-b%UywIhSIyw z8%?fB10P+7^&6=C@Stx+W6}Zg+}0xh_ygBSwEI`))bDMmPrmCErg_nBu)4Yg>D5^? zf$zGVJyT+Y<*{`OmLwRBWAppoM*ZOpUG2kkT-oD_ml5}gErZt5HZDuv67z?ICc{L& z1OGCR`sU!Za-41Cb@<&Ff^@Sl$4T3jcg*QqW{CSZ-G;n*-QmECVTer}LLt+r7zTdw zL;Tklw+heV-}vIyKfc&oe5k@t^u;daJ3VAky-(z9l51&98nl1`OZ5wEPA2~8){B*Q<}B7gEYU$S@DXj10?8gYkvT1t@Z=r zZ=t+yN7g`iqk=^Fc@1LkiSwDkJ7mbU+q7S;U!+Mqtc=J*^A@CgNY6mf_YUxJHGR*7 z^9A5m6VI*AJc)FJ+2`RzL@IYB?fcV20Oh^;cMPCxr%`7*Qb{89RawdINtw(~08L=Uwd(d}UY{ztB zlC+o9NgiX_0w!)I9c!&gXFJOO^ZZ%JaC$~6#)cq$k>_%9!N!J|9iz|sM*9UgJGz0? z8PmOq=f-A``OOI=^W$ygzufmKDM{SRWzAj*qK)z5H|t-wNOIFUVO>nSodMeo?hx~9 z^xHU(tEYm)j%*TpVFB{L>M()y(6u28+ioE?ExQV>ollXHluSmH=P|gI3$9g#$P0A+ zV{X=Cl01DNJUAyo{(eutlNlY(NwykwM|~&KG~s+l9n$#r7}85W#X#%&Lh@S6331|& z0c1_PHL**%i}-+H4Rlj;B)8RKFn{p(@gToJ72a>^!ixIujkE?`Jza3`q>dQOzmtlS zJ0+@0w0v#>HALUv6dKYPls9QsAXhxb%iezVBg6s8i#eHbk%fa=Y7z6s&*69UPlj1_ z2KA*WOQ8CY9%O%`^8E*F4uPhpRLt9UL|{y)B2`o~xQ`z)B4F8ZpN-r2>4OK;$~(RXP-VRT9!Hf`$2 zmmQ<=T4j&^T<^EXxf4U*qwUW+z6ZAqIX=#O3)((HSnpW8yCdH#^E{UQ*B~X%$7nw{ z@&Rq<*8VblxT~*y&)RXw|M}oo&Y@P0w=t#sEzx%*{;m&U%G{%vKVnrOaX!-j~iRU2N(A zsi_~xsz)>)%WY@|^Ub3fnGtkPPw}!tkUI7PQ*J#L<#l{I7V_>qmOL}siMaj9A#UoB zWKy0++g9Fb6E;@;6O;bMo!T>F1nb>Bkuh~KL4MO)*^=p75{O%855%6my0We(5=e#D zcYNm#4OE6Yy>}!aK#2&CPv*Sx3$9N03o)o`KzWzP9RREHOHA7YYR}VxS6u$|Lqs-e z0?O;AE}Yq@IYibka7SD?d<0vqyN@}$!w~VMt3BAJ`~Q!$H;?M+`~Jr(iPD6SB$cU1 zLXzt4n|VqyC1iM+GfOg)q>>D!G9`*qB+68D_X$aoA|VMONoFNU^1IJ{Sl_kY>+@Ud zwbtwTPd(1wXYYN^*=HW^d?-g#!go?Pg2BN6FfblWc=|Ujar5B)VEpHOkhJL~(&zr) zU{>Q7q<>XOiIg`j2JDV;eWCd+#f67FU?gz)F9i9$g#1t_n>s~O*q;!jCHDKi9||p1 z3Ag^e#Ub;j{3gl1lO*qNUDz%2{+qg>kokYDlid1K7yfrIQ4y}F3ySbHVi(bHXd)cF zx!ztOCDPqatd9tUDX-d+ZP^>N#lfv^Kt`8a9|6}jLG7V25qn& z#NQrKTVWxt%ZmjcRem4;b2n}A{K6ZcyX-c_zwP!JIySgK^U=J|6uURTw{jQQcjp-> z^jBAn5?wpT2@Nm!_$ctCi`cWc0|dEPkv*9g`-u-MUBI_zPvRHY4@l~H0jx{6kgxRK zHw9+q|AvgWvxwg3_7muDJQkK#^7}x;B?Ix(b{BY&9ZB?umHOgh&rQ-7uT`kf-}&H9 zbX*W1S^iX`xpJgwZy0CtSje;F_Y`*wi$miPrRkOvl!-nrU?LRWY=G7iW|BP1UNfL_ z^mk~{kMB=Z$2^9W9mhgmAHF78)8~#9XRXU_zkf^mYESe*v%qT1zxbW7>8wzUZ5kx) zxz>c_hpy@dLE9b*X4yv6?$4YNkM;NR(@WO#y|D7RePJBbf=lHX(r<5d867q)#D%B$ zc`2UVD`1pm+yR5VP8|5{a7mOiVg&}!~D(qGzdCN4bx z1WlgQ68`l0DLM*|9Qtj2Ksfh!HQpJXA@*4tN-{YyBasPrG%$^ZR@t4lphZ76}z_|PY zVZZ!1sW{Ug_O}~G@#}uR6pqXKpP6(0`krs#{Vj7T<4Pd$s|*g8GUGmAigz6GzyD+{ zjg#+1y|g<*xC|2|?Kz*&sQod*BOgDM-fw@6j@rJ2uk;*;K^_;-aTZ^%-nVQ59-Vp? zBNNvPa`q~D^-sV}mI2TdRS7?zz8uyJ@dw)@V<^7&s8fhm0dVy85Te(AsuiqO`a9^x zlz}4tFZ1=FKfoXAvUoq@-2I?5Q1v5vUXP{t-RiuArhCoO(-J-qe@@UD9BCZ@;_+CL z_i@*0Oz9l}fvf!qk15?L6drXH`o{kx{`w0)TiQazp zY8XtO>68#!?PHevNJdUzjL`kM$2(s_aO%o3g7PGV+0|ZmQQ0;MhnSxveS^PU!tUW++2l_esGv`n-&Tx1+xadG@(2pg5=bNsJh>9rQBz8J9I{#|w=Y zHfK*9<#Dq7i)odHqZf2$(PLT?KAJlq-DX__=1%`WIBA3y(+>@RmQUIcUUCg-x!MROGjy_p9=~ zHPaYPRv+yHg%0gWetEk5#@N)uaCHVhcWYcyZQo*BW6>;!+p8VlM=V%+UHDSN`x%v^ zrg(4cG-=6seje{^k%Yrv8L%F^Oh}&J$x5lJWmEBPbFOdX@vo?w(FW(%9p>qKx=1`3 zb_`h7Jy7IF;nS&NV2c;vA}<6hu>O=)F#N!8fa#-&-!^!TIQMuMto(hQ=oUTAv8ScB zG^!E5pW|ly75nvVkM8QcEs4@HL(`R)(mTfT^LmT@7KypExTT;Jci6fW!fFLf#R zPhFazFk1f6+*p2}PZ6%DON#I+zox9&-5Lyp@!OX|rzc`T3cTgR9YKn-254!TW{$ z?zZfovqsd8U_`f4J}jGls% zmTV<@pKB&isincHRC_Q*9^EZ}DMTpgvMY65f5ECRxYS>V4ZU@d`0qcPjCqm{^UdIQ z&&nO_uqo4FKEW=ee@LHha8gs3eIM1CLN&p)ydx&_ML*Ok9-rqHM6 z<|G9i86jF^))76sPXTs(JWh;TZAN%!vNw$Mb;V1E_<6sbQ@cU$c*$4NKiw@9(oekwyVp(>zoGAOoUi3B`m6IX^^aFA#hiJw!64^5 zmG`tn2iQHU0gv=Fr}CMZ`5e|mF6K<-W88q-)}m)KcTBioLGnHhQ-y}%p1^LKP=35^ zvH~7w>4~{h`2O9Rn|;$y6gY_!R4T|G*ByrPIb{z~)8P(bD;6&7K5ZesFXi*$^2R4& z@s#@jmzRp3{~6y>{2Dk9EZcE=4JIUk&8U1()%7O+&kG(wQ>!IX z%(4c;{SFz6<`;M2{1o0Eyi4yY4s_jy`Wpg?u5{ATzAAczXt?M#$v4iZad@?IkeK>U zDd8(IO~ezEgTcpi8s*Qjgm$=A$wTy?!tL*#W{BJSdWeo@9Al7~^bA#^_~#tD zWAu$hqFrVdVV|Tz2r@kdAMN&`qCAstYKw)h*MU_EBl(pRE`krc3EkiM5Z!m-1!dS>5*@6R(2}P(B=1#dxaH9b$jJ^eogq<-C&my7-{Y5srr^KtN9Q3cm-d62w!+3PX2-FX3}_(960BBHOeYRST`GBBLU z$EgkBEm_m}J1{u9HRboA9&BXu!qSTn+(w@$`Qi$8(q4Q~IUniFtz!zb`1d(GL$ z%B139L)gR#`zSqg{I{a-q@Cz>B!lD)JH7{7W;THhNBG!b_?eb0`{s4<@n}o-1(j;C z`rG^ywT7oRZ)PHR>lcBS<0i7laGt7o*6JeWbFJc!MD(@!g?{75 z5xvQdcGxQbn4|6YGzEQl-E(P&>k#&OY%--UA$m6sXZ1qh;ws{QuyrGrl|ID{QHg|$ zbd;Dz-*Dl0rx&1zZ+UeCb{SoU&D2g2{n`LmSYCeLUbW>b!ngEKL&bY|iR4G`9G8=m=iF)Rq;-M-X-~-Qlpt zZ#Wz0HUpRsB_1E?buW)^Kz8^8hHb7drJ{=VHeLKD$2cP1>?M{_Ceu1K3W%m&#fO08V_@c?$T9Fbb9p}ozrWwWG6VMwS_h_(3nNdWKlixw!6P$-bBexKKQSJ;GOGl-94SYd(pvwo? zVEhZGto0(?^xJd0yEr{x+f*!P!&yiUd7jgIz;MAJ)LZr(FNW&UUa{6rHxX5 zc3~bLi$>e3rN3Ei%Un-!>}32wa5`tguB3*N{AsUj9lpo)WgVMrC;YcBI3VZszv&AC z9<~*m>2-!8#kWDU{@;2{-k-kUf8U5uge&?2MR?}vE$OdZs-Q(p4(W~=qbV)w{~ely zUn0E!$?Ej{ZdIUs?l$3*aXm1j#A#oF%_Zmq>8v^(KVufF8t{bv0O#eKf$r) zs$_>bcmO}W<8!pljRJ9kraO#T^qtDGrgL+_FjqyK^YAK4gYfWzG3BrsQ3g zKM8<6RUZ(2 z5ZdpaNcq3)&0aiTeM*=GT>hZ@yRc8rNle@uPW&F}*CBt$bC}ZSv4cY1M^A0((zf=j z`STV;PnN&C+fl0m7dfmV+<5MFXxHf}9PX=6@}GU5igyDBrF(yTO7!WMr{YZC;prd0 zb3Cl_0zBCwuWirf?-T^@3Kt@OUc*cBIah_g!7q=dS44VA^(Xi|Ag1RCu&sS9-Ltzu z^uKlGkj(pU>WV_<|FvF}|EI1{B4rN6xG6)fB#LlFT~UO0io6E{CM{y`tEwn%>3!6M z{U4UGyW3`?OjfF_Rufa+c(BwV^U1d3@f}e#n9VLf+)4D|IR?_s?B#6OW?t_fR@{^3 zHe13@_T%kR)R`vY2i3W3!J&l|zf{c&UZ{>|$5&YqJ{#T*jc3kgmMnziMeHyVCk@<( zU&0cI-r%1o#ks9uD>Qk#Y_qE?Cb79pyWK(JFN@F;7cUlA)E&Ow<*;TQjx6%Vlz`?G zfA_uKa42*TE7a*mSaXIwp3-w==j8J)iu660)=4z&)dD-0UnKg-c}=k0+ZAla7$o`{ zUlZ)HVIe#4@Fd}PZJl83?!Kb=TO@wBpX)F#$QjcsTNBotyAE}8HlRVeE@71xtFdCX zgcbw%7(G?Z4-Zam%ifQFNOjr0^*g-WE=<4>6Q;0dU!b{|-L~?|sLOl~q94@`2enKdX2R-s+x?QI=f) zvqx*NJXpqh9A}nAVoBvI^y%50`t@{w`He2O{(|}*ZqLA$@A352Z-QqS$0fVtq0oGZ zm_3E>;oWU#iusQ{*z&vFp4t>4;Agx+-!x1CBN z`yT8K!BY>7MHT0ngxfzz!%6-DXl9*3_Pn$|hK~31vDA1oxp9u`Fq~xI#8LwIIIu;r zGj7!%%IG<-^daQ`3r1&vY^RZz=Ux;qb*Sl;NXW`yQKf$HKgZ$m|{7wi^ zT`Vr0YEJrHj=vZBv>Gj5{fDoQdb&3U)o(81fl!WTSMS1t`zE5-_*uliu_gpJhZ~Fj z`ZEY8AHR(KKl zseWAwnm9x(T*BL`v=?pQrnQGS{Z|C>w_9B##D171j=#k5-?rkg>^uLZt+@NAtuRwK zq5M;{6+Uv9B3#i{D8lO+Z(#=gccR+-VPs3tF<%A^d(m*aK4H5;ALe}{7}xb1MR>vu zU)Ew+2sSnCOxV_E3v(TR3f7ULu6od4{G!f%(cA4IY`5(s-e}L~uj>j_*rLf(@Mzk8 zROCs9y8D$0-V-IyBwebjN~gjxx=4xHbm&R)BVAO`H~1G$SlWm1>!v0mLwoU(ODy47 zqbB006l?M6x*LQqYn_p@#+P7mtVnp3lB(GLaUXH&IzQ`(B}YD~lxB|JZ>kF z&-lHPDeYgtm|tGVO86M?$wLr5mNgdLzulzr3UKW#Caai<;x;aS#W-_u#*D7wi0Bif z|9W0;v3c9xVoCz{522-<*tfH#XfYy_;varBNF4H8{$5`tA6NbL^&@iH|BJ8R`{V2X zyY{OHSNOUje40)(@r&_R=yZnff2!%(i%V-affqYOw)fs7zkk;3BRC7b)Go#6%HM-N zy%mZ}`FkI&=5`Y@6*fTlonf!6+;iNhXosX-FXt{s+NLlms}XMzLfO6)C`A{V|v4^?fj0;%FQ8It!jYA?R${?38&n}tmkXt z&O|WU*9@rl-O+bDG2NrPI)_ciz`G0U4TZn`C49*`g1t@?Kbqh z$n~8x_kpb2rjS|0*Zz{_{kl#}K>a)m(&t+>9W*!SfbJPi4>y=5Cf!*Ji5>X-X#yH}R1=Rr5Wp3>`jaWFXF zI|rJjzX&HbpN(4vg@EBj?#qunuc49dOpK4~O!jQ&G@M_KP5`Q<>5$n^G(84;H_+Q617rT$CfQW}h z)V8#k;x4wx^#$*36_kG$_e~XrKK`J&oA-nBCiRE+Z&SeR8qd$c`)A?U?xA4Xg4;WD zN@rF%;0rF?_MG(V&JIcMRNR)`UCH~U(UBE`-jdVMyW%6!BV#WJXt-e5Z4RvHDyhr2qUxIP!2u78o=}UN8Ac_N89v$TrDm19Z>u zaYy4Vv660dF51=`Ge!B#UU3lBJMM$Bx3aJ5NBx zm#>7!JnO(5TUyKa?fHGo0lxciaB7Le&}!axH+2rf&}E(AcqG?b`UO=b(sHw-r>yyxRg)Gc+# z+%}1Xr&}1q*K?Vu{`xrKnTK7ZPb=E6&ap+LZ`aZYs9dJc=CqxF3i&hN??=x@X*kWu zfqcJ4F9yf=RA%cEEJ=T!b39HsoP+v9d43Gba$weh5z>(f4MZQ*wj0~8^iwd@;Nv={ zWn;1E*;Mq(9@Z48y8Hz zj-{?{#Gjij-)}3Ale~NB5}v1G!OAbc5i)=AanYt22c}!z;LzWlQThTh9aw$k4k^J= zK9M2++Rrv;d4qlnFAey(@pG$L!q?D|c<^KiDCl~f4Z+|{1}+}O#~s#Ti6GW!vCQq= zNS|QcTHMqSgUv4ok$l~+>DaAxG&cG*itM$Bs6&;h@)}2xAMu~QCEIJ0B-Pw$L-<&N zC42uhSLhba=d@#9*s!~|R|+|el}Z2FT0=2+<54f_;fU0QzOsC>u)K+iLrM4Fgv$(#(NyCy zD7D{9c=DWC5V5@qR^3uYMVf;jbwIdzO*raxitzTV&+<2_f8+GJ)ueB&fr_+d&|RoC zJx1{xhU&nst6Kz@Y`%{aC0&-*eJBK{$9#VK&@x--t@Hs(1b$z2obo(SORItB-sf%rzJdM)GmMjg_J} zymzKU;6@(*uP?>QdGT+2Ns(v&*VLb!tPHknd7Z3w8zn-cVkvET7IkRX(`da*XuI14(o-TTX-K{5R@q-m3zXmu{ec>NTdr%Oiy|$t)J2LAYR_^adc$b^6X)2bu%#`0eolf<3)7!CZ z%*^f3^U8UmgY!0FNV*S9(C6~Hi|v`qNfWp)zd5Ez?~K)^nDrqK63#p){Bhb4(M2U+ za+KfrRnU*?l!N}Qt#EhqD3V{C?97zj?|>CEuMofU>$WVzYcE8p^ZD|i1J@`*PDbolrt58j{-?Mv zS$1`1DgJ%1U;rO)yWh_NC-d1bqi;L%l?PfXV$qco*t_a2$-5!rg=X=%BAL(U^0lp4 zak3^BXY#W-rHfse%Xe!$+D(mo|7GP!R#ej)2j=tnk)Z3sx|Q_7Q2EXo`ClV z1E^?cO8TO-RYdy((b!_UCZ*@r3uSRmP&}HXaeWa5UD&hvo6%(_A3txM>&UzdHsX$~ z*OcEj_Z*l*p&t(0%Im^09Tib!?*UvmxjV@lSXlxMmU<9(hU+`u{1Oay*^aGl^ZjHi zqwk=4^deRjzM=Gnu586(TkXMD9=!aHUol~U+XAuX7*F5Oj%V@G*w;8If#1zt7~hqd z=AS_CKX?AL+o*`;&x|lkoA*=RDH1Ggu@N8rFx#jBJkzt(1~mV(Y}v&8Y{#9w{AseF#egr!;V_dw=v#^dV^J&jox^|hcK?1;P4rtlqv&-M!u+(Onv)3$MhJ&G-% z=)!Ouc>F8j>X&c8W$6LQ?jSFFz0f^E?(YpyTO3RDshcL@811w8a@ixoH^bWDl01 zZpwF|-xGefU;?)Iod&w0p9uTZ#A4&p%c%Y94q^R-BY17{S)93;pHH4;a{%9aN>Z_P zbCQoOQ*i2?lQ=Jqw*`NF;k0b)zwrgbk{ju(@0Ea?Vs6p)|IICm{`kWGo@-EqD||r_ zULBDS^Q~q0C1Jwyz6(K)uJo>G zIr#Lg#g{hMi9hL|ulNAl;jUJOl(xusQBdRi3~m_35Z$q33@qKNAsU|IcXiRewOF!t ztT4UWgXH<8wi1nsE(kTd78AbrWerqM{*I29(ZT$Q$75UqAspVa>5*?`COm;MxA<_L9l1udcrnO zPC(faEzyZJA^zcC-hzu+DK@>XMRcEGuJ#)$ zJ0x%6l{&B*QG%L{<`PaCTLV^m4}ssbK*GbjV|vpGFVV{GG~qFgP4Qx^dUrl)N+7VLe z{zqt8aF+1EK|NRtwX?#lU5yBrU$bJK2Ydv#B{xX^`iYI%I{S0bx63c0FZbVuOH6$5 zTH8FrN1L6%xQ-*Ssxxm3{??TB#LlFT~UM&U*L;Beb2$!l51p(m-QV?8lfu2HsSjNjekPNnlzH9_V6DpFE}nldh)z~`JfZ7i`xfB z2Un84ManATqv;2rSk;Q;83);>?{8HObz7Qq`Hgqr5wjgq%Mq!B4U6UVY|q8gXvYhL zy$V!W6P-F?{<1BED}P(z`Nms?amRRB4L&d%ZzvrWcF*DIaTw{OTpF zt>t4FU7c5$-LeqZ6!)O~n`7Mx{8q#{ygtUq^A-b!LYFN)gh|f)9#W}uUno7;28J1P z`*RG2fN{MZ3|zv;028(X7}u5K3$d2;_kS;+H~hT?B6J22PTV5jEwC)Z0e|jyURtWm z*0gdoCE|&_Gn=hxYS|NQr!htvdZ6eb)=sMd!C( z@L<AMaM>2FuOy}$=&4ns*W%|S-)3JlEbbiaaC{Y?kLiB3 z5d+jqrAHHv6Wx4nN3nK|ImYBC6CScM2$$^FVS|*B^i`W2#8t0#*_J-r3IA;ilI6Vk zH*J9;&;GA7IOwj!pEH3gah5r zqtnl|LXbAcF~cf^Jz*~}-%P%1A^+Uwnz0Sf#!AKm#|jEuenW*NJ-Cg}a1SW()oby% zDX&;)(TeLoHS{D7Y@aP$yv@fX7w<2DCWmk0PHWyz)hP{ztnGI(R-ey3x3=Ae6`_Tg zeZ+yaKOgo5| zU%wD)0{FU2-nrG#{?uepw&r8Jw@U+{*9|8)t;X|XWURY5@r4JR-Q0!JUv)y26|~L9 zEh>jezn+dMbGkKE&|WVQ?o#Y7S`FF)M~$_pAHFtsI4*fQ7~*>H^PR@~DjiHrT%q$` zzNT0yzjY+~wFd8@rDSjXG8^ek%0N(g!|O`fX&d-Zx)CeC4C8D>;H)0!NrweAM?~?pLZzE<=HC?!UiTADNj%s4u@?4?O zjhQ50RY^_s8+r&{-RJA~@d53{nL1(6yWuLuFYyi$4%9lp)&ytbw<}W-2L>E~#0|AX z*L$JOyr=mIzwAB}wz`@sU0u@xdir}1e|<$`F{axgc&uH;=|eTey2JZGYZmY8wtTz@ z2L1dX>$4H@3n|wiY+L|bUBKJs>6#K)=4^wCue@#k+g6>E^Wwj>RZsr3RpfNCEXBAb zLvExL;fl6O5&pr`16AewKt4Z%$o4yxv+(o#XRszPf^aY8**HzUCpEvphj7K}P_%t~ z4F=TmaZaMcR!kX`4J%&c5dB-bAy_cF2t2Ad?(x+fpIbeLAd!y&oy#k5Y=9wNzIUAX zmn#KgMMxI(T)=&$?vpQOPtTUm2Hz(7tM|58Vf_#$1@N*q|2h_{Iz0oI{-cTBB}Pfy zJ9R1;Z{TBg_eph_JbxR8q(>25<@HwKq2&RgQ!el4;#@jodcSPAW%ior&(RWxcoo7j zE8fox8?GWY>NFYjjQJcRuV1WW)uaFt_wjMZnX|nxsNkcN5d0S9>{HsaW)FOe*bBjd zA>^xx!|U;Q@D5y{&Gna?9+qCJcaYYpHm0)ovGEg@ErZ!xLf^6TvCX=CiXUbk0naPP!Fwk@PH|OggBM<8!?vMZe|IBQyk~F+bS`q- z{%Eey|Hui@&Q>M+$2ETkSDpWX2RFHW$NZX!SZW1oT60K#ml4OLjZWE+GGjd1vrMo= z>y&b-t@nGvDG~J!!wfuy{k1Nk^ANti;Np@BRod&I zd^xwbU+fBD^tdDlF5-K0R;zBn{n(YD;iO6Sb(t@J&%?<8WRJzi&zNL?>o0LzR` zB>(YvC2TmUDW#P0wzge#BSCGpDyv<|?Wta)ELs=r5EgG8N97r0bwujW@f=K<#qBd| z^hr8eeK>vLxW-IT{x%bXB)yUHHzD=;x-WYr2z$OZV!0)JzV4ZG1~Sbr--V&E%B&!fuay;51w&TsQ;b+;OZ2Q4(_pQ2 zJ!)(nO89SEaY44_zqA!4f7*)wedAscu4pS1;f`;1UeRlL25rv$@#SW*_FeQkvZOZr zorhZMAaEPf1Q*UT6=ilM=VlKuaAs$0y^Yr`$KFZyvnF?D&T&7fpRnD$6S5psa7l}f z#BW#h1Y0lafcZD?Q`spU^0kX(o!GKBoL{NO8hJU#-)8TA&o zde=}tmHPS_8h3br_8!J0FIV|F8aFM*&dN4~%R+9T!s8KI`4OUZtRYdiTphcufW;`G5**wk(Z@wb@y6*^A*45Qxg zbyKAQs~qO(o(6kYKIb}UKN_8ltwfbrzGraXAPU#UH4^=WiDXaZ&uDb(KLdNs8ASR% z#$7|RXHRk3I6h~{SvDGj$`bMLK)&wnlG7hk3(leW7aQWgn0Fb*DK`_3v&%EvO~K1NuuBX)BzuCC`R{Q z;e^u)Y@yqg0W5W5S5(9gmfuBnH+c?T^LbgV>2VxZWbcD*-#QZA+2@&1lv)X^-@T!- z+>`JGZ^nNW^42Diyl@Ruc)xite#OhG_f2)S z@MENqo$pTaV{R)ktL`(PrNHN-{p7oHcBe8#Yvv6m+3BFL{d)>oo3bD6ZG+dd%>-w%dcfqbjPgt_zEycgPC|2ke<;0Q> z1X6sRELAY70hV%oG2yb)sY1>~edsss4e{swQem#wze_{nZxX%jn{s5nrxSb9Q#73lV&(_P>!qyzw1U^Pfbe@Oj4db9) zYd)VdJ(J~7dQ<)$VbeH@@8x_!8r;(l#vJ1F$xCCE&~u~_3+-7+`X|ilDsBkblRhqL zJMoukSc*;e?Q@73&*xNY+h0KJV}#*3ok@RqW;@($v>y(M--!Q~ZM=|?-b{?%%-1*8 zX|%KBw#CRY1j&?&8e*d~ZFeSsd1vHAth*@iFHUopUhwxT&ZeV@C4+`nsai z|2Mww@2<+8d+4*m$9(_s?>hMN{~uphg#Yz*yO(>wFg^pyI;)fJc?0)ALk5HRy?TWA zi1E4LI3N|lY)fSpSTxU2Fp*gW~&YuDA!AlfOM=yC06yLzO zrD$xiIo;5@ANjg|-5z)^*ZYIJT!{bq%bxJL_8HV}jBYMwdY(7SpqBj_^NRJsboFo12lMV`L?rQ9L>|>Hw_`5Z_Ebay)d+>hZxK*h1 zC?OwG|BRU~J@}4$F7yV?h`q%B+UGJp5-afGwe_G#Z?q7K@)d9Rr`ZWffmaWx!cvu1 zEX$>o^xapI-*uR&#{yE%5{Auscs||~YESd@_tB_B$I+J1^(8M~<>%k=(mFlXrQL7h z@9z5pe-CahpA+Nl^p2+AF<)MXeDa&G1${{Pfgf94z|YH~Xbk(r=Lb$&+Ja@}@$-y- zeO+PPzwvcN8vd_!-qJt5{=aJ{ig1OmE5a`swGkav4RFuIepEKY&ECOBx5HTPXHU4l zkAc|qWtHSOtS8}^m6~FV$!5GGxe$)B`3M)L9>PYS9SEOno+*D{{32%lV@}vM%s?Dy z@mccOWl6Z?av6L`DivxLaQ;*Nb6LjZA5zbKKd7vH`edY=9Vn8&Va&%so)HmM zBl)}8WY#-r7mD595FT-(H&aUajy*hhpKshM0WzGjQK^KlV=Z>S18Qa?;mQ5W#BY7- zAZVpjLQzXTKgo!D1U;O`!mtsih`wlXH*xYJAF%uIjC^5i+HCf9R<6|U<2Rz)?-ht2v0mu_~qUM^82D6U`}*< z%AZ`92AJ4wF-*_;hv@rUyNi81c7Xo4gJi#Yzo~4&H-BmTyVpdI?mC1mPxX*`FKbHn zEsGt;)MHNKj>uZz!slQtLjQ#ktoG!Np5_ zKHA2%9gJ`M9H2=JDCqTTYjC4_40yS4{zcDK;B3q3((LpqvgcaYBPjIh17>aXDL?e5 zR0$D_1Eu`nFGRO-Plc`__RxJhx8Kb2qA)$6GlaJ1>)heE5Sz}o0=L!t?1ZuHUYs|# zH_SQ8&prLtZ4O6Mb)--2zLUIU_g3K8^mFdzmuWyM=gqfx%E%UCv1=~Y8+pi(7d@7p5~}x z8^-0?H6JG4oxC3J`}4e6aK}dccv+hj4?9d{=~9!DzF4=v=+h8P^4AQWDrt;z5DnA$ z{HxLFj@T|IOxV$-3+eM-WF)MR_u?m>=K4PwHHJW&TIq=~KaY2?>0LDF?v3yE>kqmVMT zK}ry~eKnDdnBn9A{Jx3r&+cqATnygsgU*AveYFJzus!k+w4THJ{g=#9OkdNOt-QSg z754gT*o!p}TCsya%gElVW&@ygL`N~APg|mYk-zo!`uzjQoW;j@t(1+~-nE~>)$0S< z>%T7%cWrJj78mmQa>-A9sqnLb_%e;JOZ!+nxKg=NNmN<;llZsx7MS-eKdIMbp1wKt zm(jJPt*DXlgy_pF9oXVo{!)99)7c9{R#0b+O=5Xl`*4jidwO>VuJCF>`C*ghB6ja^ z1mopfmWuQ&Iygk!VO5D!2l2I=#p_(eb4*@4*5vkwJ?$oDn2f@wiQ|d?ZDI$^U2n*I zdp#5s@jt&E0P#KKb-$v{l>Uh>^I&+_beQBkkoZ-l3C!8_3QXV3(^K^HIW`T_6$d7i zlKoa81KGpdL!^n*c;6JM>B<~ptQ{V7H6eS|t;foH!>w5x_m;%JePlb)_(nUNTsM#8 zw{z%^=T8~3Yo}h4J&$u*ikBC^m3mE^OY}R@t`OM%GMHzHgo_uY!LH%9@Z!f9!j|R^ zY-+_tm@<<4*TWQdc5vG~xIeO)s7POj5GPjBEi}E=DZYnQq&1K2FZL3K^lwM>#jEGA zy1XgEX>-26yHoav;_tj_ZHr;JDRl7biPhm>!;?QMQR3q~0D zNXt3dD|PanzI^&q572+P;(qJua;4Hm862SbmxBfkgrGa zcz0ncYQv zyRQx(c1$Mvu@9;qla`A27U z3ti_Hi1qOx0bVi)!rYcKwC;$>UdV*u03-zHot70K7K*3HC6 z8vVsrb)5gT&pzy5XD>Dx$Hz@0jkUxLdNHtkIv;lp4zXjRts3;V=J$)NP7h_NcPt$) z$lr2M*ra)7GIs82E56p}@`|lZS!Us0oZu5ebi)${qKR>PXe__=q2M1j_Ar`wIEdl$ z_eB+0end;G{=5yYKJp}f-7(#;`I}y1|1w_pd)FJXZs#9^%Wpp4WutH5&PiRw*Q)9i zU!(t6{8rUM49qvC_!fhPv%CFIT)BI)BjMu33$fIv4U0D~rs40k%>!|we8=mNHXnyt z`ugLe#(J#il!c(M$8cX)w*1sC%=!{Q@n$(VE16@!NQO zzObb@D39CgGtmIIA5#~N0&kH$a4-?NZW@aLQGLjl9osrHwFg@y^@W;bkI|-HID1)J z=90koD8BhpP4KYo#HznvA>UlOayV;wVm3ZjRigNs{hin`gGspH zo)%$vGMc3($4jU7bNQKF&BQ}3JHwsEyziPPwH4jGTY<&iU1YzNvAI}q`G*v2*opKB zGp~ZO{7sbf9ekYY;`fhK*7Pg5Smx3k=gz}VFyUAY1}9u4d)__21<5;&*tjLFNS-95 z!?_eU`D{*qO7E!O!Faa&KJ4=464Bo-PlA^ZeQ^G7zRsQ6$X@#JtUWuz8k4;Gv=*$Q z^KE>n$tY?zEL*oWEz>szClZT&f^LmW@9lWiN(_IZ$y z{f^IB;fSXAq*r@*=o&}*kD8i`p$C3T3-pXAy)zz{gO|@8ho`%Z$zGE)?_kfbc>6{x zd0*4I$UyX{@<63dXHymavE)h|oUrN2X4&%e8nZOek=HrHc5Eg2`Ps?fc+dyGG!jT2 zTmBh*&Mr=u26Q7_`m8N9U;sXM;p-#ylNzz4gbeilq(t%097=;RGuyHW?*h0yi%579 zZO-~uwjsQ5V+ed1YtFV`&?elwLpyQ8;`qd8l%R-&ehm^FEN&w7<-H@MvdivXXY;K z8o%$!_x$i2_MS55oH=vmOkr7q-&x4V|oAe9xBLpM;7PwEZvVIbSRi`}7Uoo5`SwRh8P)=JEEfTDSv!|Np6lzp1sbItwDc zSS<|4`@I>R)j~$k*guD?92n_b^}IY`GWx1ZNkN-=#qASYaeQpp+^~;Z9;a0|e#U)! z`0EYl@yS|p=udI?_V@j!WYh8#vT>96e49r2y={Z5b;2&LP3P^CH`Q_)Y^UkAJ>q^R ze6HMmO`A0|agMlONS*!I89phM49XPxR=>F7tTaBAe71K2x3_OwD%qE|h;)4}*5!6# zYssn+{$$R0aW{DP)I?&qJC1aXJHYLQtkU3rNbD+pdVMj+zYEN!1ATs{a`8-_%P;mX zri{$FPD&?W0&#vYm26m{B343`tM^Le}9(N z8P$Ic30(h}=dx?8b|H5EWvqN+exh|M^&^c|ihZ=}ZtaRXR>^D-@WtP&finc7v$10I zO@WWY4xg>9B!4T`=zD-9WLHK-mUU- zXL0Xy#S6X_XO{4+qOAchWD@&S{0)_d={BID{g$8$6M32&1e01xxt1Y-dbg zEsOVr4!6i3tuwS2PZV(fs_VN_YtJmjIO8_oH@u6#iTNubTsgF*r<2KdJAatos8LH< z67(ULua+q(P3J3g)Jk#2I(w^j@u>0R$j$GBKSk+via%U1j!0h%yj|EABw^7+?ajaI z^7g&DY|*TqR*}>`9nbwa7<*K+cZ?T_{3n6q1=Fr;9$dSvDGp2Ic&~(;r0e!9?dDq_ z@b>E}uczNvi&Pq(?#lgZoN$cB)or58y%NmvlyWmlgf=J-%J($h0B3q_r}g6OYeIrtiMYO7m`rRhuX=P#hGwZw=J5`Pbw0t>TipL zuQk&L`jK&42Xg;T54@pyd)+}|VY8QWfjQ6j7lardE7YC8`L1KJ6KdV62j2%aQ`7xUNQ=#)B5`21`)=(yi zu=bPoG*Y7LccPY0bGbiH{ohi)O5E?<^oRI=pFRb3l-mc^7Trgm}7 z!`%MZ6%v_TxPthc5%;BIR#zgQXs2ikF0|(Q4<*hdgLm1r*O$!Z`1ubylALUB?efE7 zpZ-ggBHTld*Ln|5;rxOTEw)@+o2}g&E%e8Eg_4+{nc5#s;*5H-_8?M!ZI7 zQ#s|x;=t+JvMaM?~zKiqqGa(5by7(J1Iu9tMeG`k9Ti! z|5Lr2lf98Mw5ub<-*n#D97P7rDAX>W9?jcNJm61`7Eaf0>+i>L*IKa$vHLG;MR@;# zl^Q&Wt2F)c7_YT%pGo?=x>n#XdiWQ=Z^9zM=xnWE^y`|T*eE$gh;NZb!p`8bI@8nA~N=bqrcE|wRQE?*y|KTN61n zWv*}fmrLo;q``D;y_OtL`}i`c)90q9`n-l*Uu<$T*?(+m@$Mz5cp%<;pyh16S@MB8toy#4V7J8AN;Nc#9#EU!gR%TK1}#ArIK!7k44 zcKa-e9_~Y`jBd~Ik>~2t@7nDl+or`7GyPBN*CK~|{L}r!AEGuV?>^@2Qz4Fg_;4$? zw{g=7n(viN7ki1haQcH;^qb1@G%!i*Yetv*n3gY-Ko{5B#`O>CiT`PLC!B^S7V3-+@|2Cp+u>{1ZuxpThYg|LjIL+Rl@T4Qg{dsf|Lr z6vU9-7exCfbGB;YRv#l1hKlwX8$YM@T5cr6hKupK<7s^s zYJ#UYw5`T`!SQ(iwq)n&WbMLJ^Ep1}RspHsbda_t&M~b0-iJ5C*4`bZjlC-7LeGU3 zQfW$*_SDl%p|8gunx7jr()N2M?p`ZNGs(j%k=l&k#NF8Adh0ZPb91x<=Jn+AMUU=; zeRgP+HaJn}YuD>)Sm^Ch+C$w}aQ?Gze6^0F%SoAks#0b@V0$%f)4A)M`7udbX?eBY76`!g2qcd*zc5biMs4;}BtE#zB zAnrq^?;q#v^2P_+f+`odJiW1yG)Nk&d35_4*IzirS99=j56!O0VjnjDhlYxDAD<0T zdoSl7{3KBOW#BpI+E%T({;O?|IYWjnqeEwW&-Im=+LRu8(Or8xc@@X|99ck4?#|ZC zJ0j-F>W4GQ%@l)XUh*GYpIk;yH?01IZYb}=`=fo{UU^x)kFtvF;QTRTqm}T;0wurh zRE|G-|0^=`$bLHM(ISrDDvVPeSR6_@f3eT`bX;F0sZYFe{=-?EfB#7#ZQJ!*TCu8l z|HR0a+in(^>ec{ddEMPye$t^v%Bl_BmDJ_OI6l{_uTp*Hc;#`@T#i>g zaZ&T|yq{A0z-o^FFr%w-+2>s)_>#i$qpzd|SH|9Ym6 z5qHT1)j^6PzzK;&+yJPGvirXb;omu=RXy)tvRX z`1Gfj=nrxAx%|)D3uxc918IdDS2=!T!wPyj^pP`Ae~aT^4wy%aC+{J}?|&=gkK#SE zHTROc`69P>&R$KQl}T}S8dZVk!qQ7C=+LGgJ8v}+XO;(_{_1SkW_wu9&L*5cef`<3 z3p11MbkA%oPh_lh3~_w!K{#Uy6+HTJ8e>a5&#%(B$ z>G7Q7FDCS++x}|Q{fkX34c1BSWSX&+@TrU zc5wMFof~NTNs&}ay}y;|>!7_-grAIi+rmQAB_3l9S=<+V7-mzu7{LZ;$8g z#}`bZiFL1$o3i*F;h+WhpOe!cY33e3$LGq#Resw1M`?7$(KoriwNIbW1}le?Jmo{e z^gW+YNSDT5C(%c;xxRV9ZIqZY7c^lV%W%GKcxUD6oBni6tXLNwJPy)2PmiY+uQuiS zV&46ShQBnClj{4_)W5I#(Uh}{8|3W`tR;&&P-j#`6mMXv^!Ha(1E{*+VXwX z4$A0Rp>#y$V$L5tAX=;0+KOtwILF&JdFuh4UUw)-?IP~>vKw`zvE8#t$E*9f{K;7( z>Eju&7yb^HuNrZeCSSQvk1jaO`IFD~qz5ODrPD&h?}W!3tfIW|e?p(p7o1OT^weJ0 zSD^kw#JVwb;T^gudnkE6aS7)q%;-j|r(}`4Zy(~g@=Ify+j7`!ZhAbrxN^!9GH2k&~j=*>#L$HX02!gV_|HrL)L3cgldYVRE`%kW4na zRc9~(Yms5F+U!ybqYgiFQZkHYo!vI1<9m3PjYB%H*EF5Yz?zw@hD?JA4_33;-rua3 zdzht6cjqdr2Hme$W;5=uO&x_m*^36TNTOsL_AE?*$B4ZU-> z5T~;;2klma&Xj2^;aGHf)!Whr1FQ+JNTuawsop?^3(+y(feaK5>+A>{DCrKXd*>WB z`4s_^BPYs?E@nE+4qL3O%V6RxKwzk%vc6P8a4|&bC5<>K&TeG`R}z?4TBvNqHUY8i zZOSk+3JZWPSGL-8#(uCWjK+)j_mXvbaF|k)E{E}KEC~`uSlBZHr8k%|MX)^6BwFN- z(VVU`#seV68W?pZxxd+(qcgfNxM;Iubb%XkEJg#8kLOvmAxAc`tn)~?embkj7u7V= zVrCLno!;OOqNZFqzqiRQTTL*{yyd>22i%!Bv(3OpCBkaejS$`cH(gD;T%FOO_H#&k zmbRQ=6L|&?SXdA^yCGe+b;$6*IL~0xb5?uC>Y!pFq3&20hLm#nfV(nH9sfkt0+Y;< zZCNa9ZNhWpry5!0Nk114jxsqOgA84|%o>)YL=2mak-1qO#Avf4%_ytX(&><4?x(Y` z5bN|E#2|ymRF{U8Cy&XNfiYzo)3XdlJ?ElXDWc{JC#XZ{AuM{sCP7Ji)_I2|BA=Iu z45KcS5oCR)oY*cgB!W#>7ao$>-UDx+*iPUuk)^X`CFsyMW&yZK&bOF;KFUy=W;N^d7C0sM(wX!KHE5pmn^9QJj`CO>pefI6HR=bG;0fA(uOofLw-=jMAo7)*Dl%n=*{7-C%d9sdlg?)b)6~&Mq?n z9$gf=k{KqaXY(=9%YzN}EJ)bQM${-)?15yW(u>fR45wJb)p~6(<@PqQdZSA~^)*}h zc%dDl;yE(9*9-<9o)|c3W@#pxl%T3*^dVg~%2wCPSZXkqEfr{IH`{f_7_$|1OGOgQ z*5SMkLl}#Z+)rm?vq2b$*5z2l;-b3bM!@RC#zALPX(i6EbxUw!dB;?K$$-TVXFVvD zQd95$CRSoiI2v!1W#(y#5oSR|@wKcH7fUTcLv60ZHWky?dd1`&q8*Hqq zmdt)zq-@WVWfQ`gE$buAdIK+AW{j8BpqKkQa^giAq89L>X9JjqdYFxfs7BlaW3crw zF#{~??bvLTc0o;4iy_x+?`?_zUwvd^Nk*TTRN*<#U13&=}2mvNhI_V_=&Yhs9Eg7#T6%oMAVi z5`md!(Ai4T!YUhe`8*gUBwHTB5sw+qrgjO^9*8{;iwfi5SznU!BD3E1G|6Uath-BU zS3Sg3nui?XB&Nf^qXpK0j0~G>$HXih3s-xolU*D^51am_V=AXLpeVht<@B>vGLpGgF+Wv*uu7M{&do;i_`* zrsoK&*_O^1A+>6;MaL+!y~`la1;stZF`0Y2&jwMa)g3rrc1)QFHCxICl`cZ=8gdLK zLyl`^Me6M7S?cU`?+hGQd*KQ-DC+2!L?5JFv(dp~td0jOCplPSaOmM%b#>PaL5o$+ zHQf^0VhCF$+N&eUCoA2pdwBJUKF;)^NEi}ZH*!FT*3d)Yn)XHZtN zSRqi=@H40mdp0&6EC6XbM@}Zjo|i(ajvZ!lTIxTy9St+Fm-VUM&tNg))v3|7O@wK>kg|4l~Pab!*SW2C=S0867r^+$*fUs`}S5 zS&e#qGk1;Z6pCll3H@LOJ+;0@z)kZjTuhyk@!|8E?POUL)ok*Z9f%)au|0@-D~7;> zk}i7ZL9?2YbVwE$*S-W&*h>2*kxsC!nYf+$8 z$NEE3ePr7r{%p|ah#itaeKnPM!Fp5T14l~NlG0^GSNez=fKwZvg&41R*_ctX=BvXA zEwHcw!bW2A}<)%lJ!;{ z8xAq^I796Lf957i#zK@%6~(d&jXaYO7uSF#lxpQH5g}DhosBBihoA3w@JtzoOex`= zxE`^%!%NT7StSSmi4!PpvmD|Dot1EI&6FJcC%=M|^!$`B<(dt8iLb=6l^=MeG<#gu z2%90@7C!=oBS(tGULz8RKQIz;zh|~~;3rGI#Fvo7ky53hv{?=L9r8T{ONbt#C1*o- zoh3vMQCvu<_fYKkqM90DL9t+Wf#9<2cUSW&&qG_uJ(}83)#pxj*X2(4&{Hx2N^e2Z z?Cd~hNRMOpTkd3(?bqH$A>yukD3e}2Ii}hBIgECLI8C}M>21PJ7uTYy!|`mO|2G=$ zk1UuUs(2Jqgg5sjyKakIN-=(HwPj@JmaQ!JRUR5*!(fyd&)qKrbg@lXu zYMUq=Xw43jp6lVaJuWxh87|rgOhw#3x*LtsS!@oYN042%+>)dxiW4?Y|F+JCqnE?z zb}^V%dWWGNh50mbx!}6r5Ipw;i582zjh~TU$q>G6Q;$3>b=_5Zv~yReuJNVK+?jkG zjznF2Ez!dO^r&Y<7LgFlVpjOr^|4A;`&Ob-#d%F=&wrN6x|@5gfQRW`NFn#bntQ)r z;khe@IXQuya7yi}KJ~ulVoAi|5CVe@Vm}arksQuyCbpN5TS$^2E2d z9z<4AJP53Gdk|Ow_aN{xUP9qP6_vb%#;n0N6mAa^N`R*(wdQjnloZuZUi)96l?D(0 z6Ee0(e=o^P^2WE1`prI*xRTUZ@{AF`@89%gR|B2ErC3~HhPD;=4dJwXD zXlsn0$&lOzT9)*USA4>ts0c_`z;9adRwsa$R33g-1kPv`K&c>=g*V=ymjn3XU#ffI zr=JvnS3i7L#;ZR#fp`tTYZb^=Mk{}4sfy=7JO|*p8g%(UlMguFpfIWG(CH5ef3)&} zv=5hJf6Wkt?{bg|1pJ%#27Ghr@R8n-YCx|)e)=Oa{`hcoAAAD7k5mUx7f=s&f+1BO z+8Y3G2xtV!O3+;cP!sU)HbH6|mpp4*3wGIWyL}KzNqP%b%7WGeHk$&PAui3i?{z%r zEkJLHHm%@|H{@CaZv(HGhiyS?ho=y(FBmcO!Mi@|L(ZGO`?CYAvS&7?9pE{BLCBvw zp$C4@6$;-w!_zL1>k581wCxTZVE_&Hw2?$0rv)C)Z8U~;=JT6U1bQEd-bbM)(cDK# z>H&^7dKZH>P4Vr6==X$tFFf^zOds^phqrGk^~F;xZ`T}gVSVwD`f(dAUcp)KeWd=7 z9RP>}41~=9&;|kG5uF6Qz72XJU@#yF@DAWz(1!q$0q+5Za{aB;__97QKSg{~5ZSWa z4}Z+407(b=G{~nT+O?3GdVq|l4A9<0wq*jcAZGv!17stjMnDe01TX_EfZ+fuzy^JG z0RG#qlnclMJQ7*rjm-D}dPgENf-nlBFtbJj9|I@=j0KDXj0B7aOaM#-dQ@{*lvOh9;Cg3wZMn2N#pw9x#2F!s!a{=@4 zJRh(C&tKqmAu_)V+J1@FMSw+^1p*HM9ss;MsEl7#S`1i%HcJ7^0L!6c1z;uME5Iti z*MM&T-(nVtc2&@>%KxFA2KA2FbG7r8Rzu$!z*<15eqV`wiggfXXn7BLe`y^oe-Bs> z*Z@B_0)D_OE(_UBc-{;>TL4=D#hBTi?S0YS7wvt~-q)>t2*%M*ass{supFlVmg5Rw z8(=%&N5BriPQWg}ZonSEUcf%s-VZncI0!fdILvdu19baBH|vwgYl>Hv*9u@8U_0PP zzz)Dpz%IaUz#hO}!2hf}0#lTW5D{Oa#g_WKaTjE0GtGz0-Oe%feg#*vyl4< z&adSb99RhF(m=2yV) z$kVH!U*r6qe9gIz=NkYPgPVX`fZKpS0Cxa?0`3Ct0qz4H03HJV0z3lz4R{QA0(c7e z2l}4@o&#P0UIHAb#+BfQzv8`ATKI@EOSfUw|K=JZP8ErW2}n9pqyL z$X5hZQrr0BH2_c<5D2J(HdWE48eXddf&gy-uK}ou=URZ;c&-De3#bPO2Gj>M0IwmS z5#UX)KJc-;)Yz-M^cM6s0lz7LjLNs=mzKx2m@%mdP>CW{{fJMCv^Y- From 9ab755fc07c0ef5d277db4a1d6f649e0554b6133 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 13 May 2014 12:59:32 -0700 Subject: [PATCH 044/116] fix build (missing glut include path, #include for std::max in hacdICHull.cpp) --- CMakeLists.txt | 14 ++++++++------ Demos/BulletXmlImportDemo/CMakeLists.txt | 1 + Demos/ConcaveDemo/CMakeLists.txt | 2 ++ Demos/ConvexDecompositionDemo/CMakeLists.txt | 2 ++ Demos/SerializeDemo/CMakeLists.txt | 2 ++ Extras/HACD/hacdICHull.cpp | 2 ++ 6 files changed, 17 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca08f5a19..d88eb378f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,18 +39,20 @@ IF(MSVC) IF (NOT USE_MSVC_INCREMENTAL_LINKING) #MESSAGE("MSVC_INCREMENTAL_DEFAULT"+${MSVC_INCREMENTAL_DEFAULT}) SET( MSVC_INCREMENTAL_YES_FLAG "/INCREMENTAL:NO") - + STRING(REPLACE "INCREMENTAL:YES" "INCREMENTAL:NO" replacementFlags ${CMAKE_EXE_LINKER_FLAGS_DEBUG}) SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "/INCREMENTAL:NO ${replacementFlags}" ) MESSAGE("CMAKE_EXE_LINKER_FLAGS_DEBUG=${CMAKE_EXE_LINKER_FLAGS_DEBUG}") STRING(REPLACE "INCREMENTAL:YES" "INCREMENTAL:NO" replacementFlags2 ${CMAKE_EXE_LINKER_FLAGS}) + SET(CMAKE_EXE_LINKER_FLAGS ${replacementFlag2}) - STRING(REPLACE "INCREMENTAL:YES" "" replacementFlags3 ${CMAKE_EXTRA_LINK_FLAGS}) + STRING(REPLACE "INCREMENTAL:YES" "" replacementFlags3 "${CMAKE_EXTRA_LINK_FLAGS}") + SET(CMAKE_EXTRA_LINK_FLAGS ${replacementFlag3}) - STRING(REPLACE "INCREMENTAL:YES" "INCREMENTAL:NO" replacementFlags3 ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}) + STRING(REPLACE "INCREMENTAL:YES" "INCREMENTAL:NO" replacementFlags3 "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") SET(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO ${replacementFlags3}) SET(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/INCREMENTAL:NO ${replacementFlags3}" ) @@ -179,8 +181,8 @@ ENDIF (OPENGL_FOUND) -OPTION(BUILD_OBSOLETE_DEMOS "Set when you want to build the obsolete Bullet 2 demos" ON) -IF(BUILD_OBSOLETE_DEMOS) +OPTION(BUILD_BULLET2_DEMOS "Set when you want to build the Bullet 2 demos" ON) +IF(BUILD_BULLET2_DEMOS) IF (USE_GLUT) IF (MSVC) @@ -222,7 +224,7 @@ ENDIF(USE_GLUT) IF(EXISTS ${BULLET_PHYSICS_SOURCE_DIR}/Demos AND IS_DIRECTORY ${BULLET_PHYSICS_SOURCE_DIR}/Demos) SUBDIRS(Demos) ENDIF() -ENDIF(BUILD_OBSOLETE_DEMOS) +ENDIF(BUILD_BULLET2_DEMOS) OPTION(BUILD_BULLET3_DEMOS "Set when you want to build the Bullet 3 demos" ON) IF(BUILD_BULLET3_DEMOS) diff --git a/Demos/BulletXmlImportDemo/CMakeLists.txt b/Demos/BulletXmlImportDemo/CMakeLists.txt index 486b69027..175c52964 100644 --- a/Demos/BulletXmlImportDemo/CMakeLists.txt +++ b/Demos/BulletXmlImportDemo/CMakeLists.txt @@ -18,6 +18,7 @@ ${BULLET_PHYSICS_SOURCE_DIR}/src ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletFileLoader ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletWorldImporter ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletXmlWorldImporter +${GLUT_INCLUDE_DIR} ) ADD_DEFINITIONS(-DDESERIALIZE_SOFT_BODIES) diff --git a/Demos/ConcaveDemo/CMakeLists.txt b/Demos/ConcaveDemo/CMakeLists.txt index f180492fa..e065ccf57 100644 --- a/Demos/ConcaveDemo/CMakeLists.txt +++ b/Demos/ConcaveDemo/CMakeLists.txt @@ -16,6 +16,8 @@ IF (USE_GLUT) ../OpenGL ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletFileLoader ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletWorldImporter + ${GLUT_INCLUDE_DIR} + ) LINK_LIBRARIES( diff --git a/Demos/ConvexDecompositionDemo/CMakeLists.txt b/Demos/ConvexDecompositionDemo/CMakeLists.txt index 979c792bc..08045bd4f 100644 --- a/Demos/ConvexDecompositionDemo/CMakeLists.txt +++ b/Demos/ConvexDecompositionDemo/CMakeLists.txt @@ -19,6 +19,8 @@ ${BULLET_PHYSICS_SOURCE_DIR}/Extras/HACD ${BULLET_PHYSICS_SOURCE_DIR}/Extras/ConvexDecomposition ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletFileLoader ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletWorldImporter +${GLUT_INCLUDE_DIR} + ) IF (USE_GLUT) diff --git a/Demos/SerializeDemo/CMakeLists.txt b/Demos/SerializeDemo/CMakeLists.txt index 4a85fd275..9cf57df25 100644 --- a/Demos/SerializeDemo/CMakeLists.txt +++ b/Demos/SerializeDemo/CMakeLists.txt @@ -20,6 +20,8 @@ ${BULLET_PHYSICS_SOURCE_DIR}/src ../OpenGL ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletFileLoader ${BULLET_PHYSICS_SOURCE_DIR}/Extras/Serialize/BulletWorldImporter +${GLUT_INCLUDE_DIR} + ) ADD_DEFINITIONS(-DDESERIALIZE_SOFT_BODIES) diff --git a/Extras/HACD/hacdICHull.cpp b/Extras/HACD/hacdICHull.cpp index 4f99c4d64..4ab5cfaf9 100644 --- a/Extras/HACD/hacdICHull.cpp +++ b/Extras/HACD/hacdICHull.cpp @@ -14,6 +14,8 @@ */ #include "hacdICHull.h" #include +#include + namespace HACD { const long ICHull::sc_dummyIndex = std::numeric_limits::max(); From 934df75ea602f9aee398b26b5ced8e0a791f1f31 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 13 May 2014 21:52:46 -0700 Subject: [PATCH 045/116] more fixes in the build, related to CMake and some error (don't delete a void* pointer!) revert BasicDemo.cpp to original Bullet 2.82 state --- CMakeLists.txt | 8 +- Demos/BasicDemo/BasicDemo.cpp | 10 +- Demos3/CMakeLists.txt | 4 +- btgui/CMakeLists.txt | 2 + .../opengl_fontstashcallbacks.cpp | 2 +- btgui/OpenGLWindow/premake4.lua | 1 - build3/findOpenGLGlewGlut.lua | 8 ++ build3/premake4.lua | 95 +++++++++---------- 8 files changed, 69 insertions(+), 61 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d88eb378f..cb0f07560 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,7 +226,13 @@ ENDIF(USE_GLUT) ENDIF() ENDIF(BUILD_BULLET2_DEMOS) -OPTION(BUILD_BULLET3_DEMOS "Set when you want to build the Bullet 3 demos" ON) +OPTION(BUILD_BULLET3 "Set when you want to build Bullet 3" ON) +IF(BUILD_BULLET3) + OPTION(BUILD_BULLET3_DEMOS "Set when you want to build the Bullet 3 demos" ON) +ELSE(BUILD_BULLET3) + unset(BUILD_BULLET3_DEMOS CACHE) + OPTION(BUILD_BULLET3_DEMOS "Set when you want to build the Bullet 3 demos" OFF) +ENDIF(BUILD_BULLET3) IF(BUILD_BULLET3_DEMOS) IF(EXISTS ${BULLET_PHYSICS_SOURCE_DIR}/Demos3 AND IS_DIRECTORY ${BULLET_PHYSICS_SOURCE_DIR}/Demos3) SUBDIRS(Demos3) diff --git a/Demos/BasicDemo/BasicDemo.cpp b/Demos/BasicDemo/BasicDemo.cpp index fc38f27dd..c8dcfcc5c 100644 --- a/Demos/BasicDemo/BasicDemo.cpp +++ b/Demos/BasicDemo/BasicDemo.cpp @@ -15,9 +15,9 @@ subject to the following restrictions: ///create 125 (5x5x5) dynamic object -#define ARRAY_SIZE_X 10 -#define ARRAY_SIZE_Y 10 -#define ARRAY_SIZE_Z 10 +#define ARRAY_SIZE_X 5 +#define ARRAY_SIZE_Y 5 +#define ARRAY_SIZE_Z 5 //maximum number of objects (and allow user to shoot additional boxes) #define MAX_PROXIES (ARRAY_SIZE_X*ARRAY_SIZE_Y*ARRAY_SIZE_Z + 1024) @@ -81,8 +81,8 @@ void BasicDemo::clientMoveAndDisplay() MyOverlapCallback aabbOverlap(aabbMin,aabbMax); m_dynamicsWorld->getBroadphase()->aabbTest(aabbMin,aabbMax,aabbOverlap); - if (aabbOverlap.m_numOverlap) - printf("#aabb overlap = %d\n", aabbOverlap.m_numOverlap); + //if (aabbOverlap.m_numOverlap) + // printf("#aabb overlap = %d\n", aabbOverlap.m_numOverlap); } renderme(); diff --git a/Demos3/CMakeLists.txt b/Demos3/CMakeLists.txt index b1f54a968..edc1c06dc 100644 --- a/Demos3/CMakeLists.txt +++ b/Demos3/CMakeLists.txt @@ -1,3 +1,3 @@ -if (BUILD_BULLET3) +if (BUILD_BULLET3_DEMOS) SUBDIRS( AllBullet2Demos GpuDemos SimpleOpenGL3 ) -endif(BUILD_BULLET3) +endif(BUILD_BULLET3_DEMOS) diff --git a/btgui/CMakeLists.txt b/btgui/CMakeLists.txt index f95d9cc8c..1bce7969e 100644 --- a/btgui/CMakeLists.txt +++ b/btgui/CMakeLists.txt @@ -1 +1,3 @@ +if (OPENGL_FOUND) SUBDIRS( Gwen OpenGLWindow ) +endif(OPENGL_FOUND) diff --git a/btgui/OpenGLTrueTypeFont/opengl_fontstashcallbacks.cpp b/btgui/OpenGLTrueTypeFont/opengl_fontstashcallbacks.cpp index 1ef12906f..d15485219 100644 --- a/btgui/OpenGLTrueTypeFont/opengl_fontstashcallbacks.cpp +++ b/btgui/OpenGLTrueTypeFont/opengl_fontstashcallbacks.cpp @@ -180,7 +180,7 @@ void InternalOpenGL2RenderCallbacks::updateTexture(sth_texture* texture, sth_gly glDeleteTextures(1, id); //delete id; - delete texture->m_userData; + delete id;//texture->m_userData; texture->m_userData = 0; } diff --git a/btgui/OpenGLWindow/premake4.lua b/btgui/OpenGLWindow/premake4.lua index be45bbe0d..e98cb5105 100644 --- a/btgui/OpenGLWindow/premake4.lua +++ b/btgui/OpenGLWindow/premake4.lua @@ -43,4 +43,3 @@ "../OpenGLWindow/MacOpenGLWindow.mm", } end - diff --git a/build3/findOpenGLGlewGlut.lua b/build3/findOpenGLGlewGlut.lua index dd72ae923..b8fe64664 100644 --- a/build3/findOpenGLGlewGlut.lua +++ b/build3/findOpenGLGlewGlut.lua @@ -1,3 +1,11 @@ + function findOpenGL() + configuration{} + if os.is("Linux") then + return false + end + --assume OpenGL is available on Mac OSX, Windows etc + return true + end function initOpenGL() configuration {} diff --git a/build3/premake4.lua b/build3/premake4.lua index 9f3c22fde..359600dbb 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -4,10 +4,10 @@ -- Multithreaded compiling if _ACTION == "vs2010" or _ACTION=="vs2008" then buildoptions { "/MP" } - end - + end + act = "" - + if _ACTION then act = _ACTION end @@ -18,9 +18,9 @@ trigger = "midi", description = "Use Midi controller to control parameters" } - + -- _OPTIONS["midi"] = "1"; - + newoption { trigger = "bullet2gpu", @@ -32,19 +32,20 @@ trigger = "enet", description = "Enable enet NAT punchthrough test" } - + newoption { trigger = "gtest", description = "Enable unit tests using gtest" - } + } + configurations {"Release", "Debug"} configuration "Release" flags { "Optimize", "EnableSSE2","StaticRuntime", "NoMinimalRebuild", "FloatFast"} configuration "Debug" defines {"_DEBUG=1"} flags { "Symbols", "StaticRuntime" , "NoMinimalRebuild", "NoEditAndContinue" ,"FloatFast"} - + if os.is("Linux") then if os.is64bit() then platforms {"x64"} @@ -57,7 +58,7 @@ configuration {"x32"} targetsuffix ("_" .. act) - configuration "x64" + configuration "x64" targetsuffix ("_" .. act .. "_64" ) configuration {"x64", "debug"} targetsuffix ("_" .. act .. "_x64_debug") @@ -65,7 +66,7 @@ targetsuffix ("_" .. act .. "_x64_release" ) configuration {"x32", "debug"} targetsuffix ("_" .. act .. "_debug" ) - + configuration{} postfix="" @@ -78,45 +79,46 @@ } end - + flags { "NoRTTI", "NoExceptions"} defines { "_HAS_EXCEPTIONS=0" } targetdir "../bin" location("./" .. act .. postfix) - + projectRootDir = os.getcwd() .. "/../" - print("Project root directroy: " .. projectRootDir); + print("Project root directory: " .. projectRootDir); dofile ("findOpenCL.lua") dofile ("findDirectX11.lua") dofile ("findOpenGLGlewGlut.lua") - + language "C++" - if _OPTIONS["gtest"] then + if _OPTIONS["gtest"] then include "../test/gtest-1.7.0" -- include "../test/hello_gtest" - include "../test/TestBullet3OpenCL" end - - + +if findOpenGL() then include "../Demos3/AllBullet2Demos" include "../Demos3/GpuDemos" -- include "../Demos3/CpuDemos" +-- include "../Demos3/Wavefront" +-- include "../btgui/MultiThreading" - include "../Demos3/Wavefront" - include "../btgui/MultiThreading" include "../btgui/OpenGLWindow" - -include "../Demos3/ImplicitCloth" -include "../Demos3/SimpleOpenGL3" - +-- include "../Demos3/ImplicitCloth" +-- include "../Demos3/SimpleOpenGL3" + include "../btgui/lua-5.2.3" include "../test/lua" - + include "../btgui/Gwen" + include "../btgui/GwenOpenGLTest" +end + -- include "../demo/gpudemo" if _OPTIONS["midi"] then include "../btgui/MidiTest" @@ -124,58 +126,49 @@ end -- include "../opencl/vector_add_simplified" -- include "../opencl/vector_add" - include "../btgui/Gwen" - include "../btgui/GwenOpenGLTest" - include "../test/clew" - include "../Demos3/GpuGuiInitialize" - - include "../test/OpenCL/BasicInitialize" - include "../test/OpenCL/KernelLaunch"-- +-- include "../test/clew" +-- include "../Demos3/GpuGuiInitialize" + +-- include "../test/OpenCL/BasicInitialize" + include "../test/OpenCL/KernelLaunch"-- -- include "../test/OpenCL/BroadphaseCollision" -- include "../test/OpenCL/NarrowphaseCollision" include "../test/OpenCL/ParallelPrimitives" include "../test/OpenCL/RadixSortBenchmark" - - include "../src/BulletSoftBody" + + include "../src/BulletSoftBody" include "../src/BulletDynamics" include "../src/BulletCollision" include "../src/LinearMath" - + include "../src/Bullet3Dynamics" include "../src/Bullet3Common" include "../src/Bullet3Geometry" include "../src/Bullet3Collision" include "../src/Bullet3Serialize/Bullet2FileLoader" - include "../src/Bullet3OpenCL" - - - + -- include "../demo/gpu_initialize" -- include "../opencl/lds_bank_conflict" -- include "../opencl/reduce" - include "../btgui/OpenGLTrueTypeFont" +-- include "../btgui/OpenGLTrueTypeFont" -- include "../btgui/OpenGLWindow" -- include "../demo/ObjLoader" - - -- include "../test/b3DynamicBvhBroadphase" - + if _OPTIONS["enet"] then include "../btgui/enet" include "../test/enet/server" include "../test/enet/client" end - if _OPTIONS["bullet2gpu"] then - include "../src/LinearMath" - include "../src/BulletCollision" - include "../src/BulletDynamics" - include "../src/BulletSoftBody" - include "../ObsoleteDemos/HelloWorld" - - include "../Demos3" + include "../src/LinearMath" + include "../src/BulletCollision" + include "../src/BulletDynamics" + include "../src/BulletSoftBody" + include "../ObsoleteDemos/HelloWorld" + include "../Demos3" end From 6f3abe414cab14feda8f8c2b4028c88924261a5d Mon Sep 17 00:00:00 2001 From: Jan-Philip Stecker Date: Wed, 14 May 2014 19:44:23 +0200 Subject: [PATCH 046/116] fix gcc warning message in public header for c++11 - missing whitespace lead to msgs like: include/bullet/LinearMath/btScalar.h:100:41: warning: invalid suffix on literal; C++11 requires a space between literal and string macro [-Wliteral-suffix] - this error was visible in projects using bullet when using c++11 mode --- src/LinearMath/btScalar.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LinearMath/btScalar.h b/src/LinearMath/btScalar.h index da3e88313..e02f99abc 100644 --- a/src/LinearMath/btScalar.h +++ b/src/LinearMath/btScalar.h @@ -97,7 +97,7 @@ inline int btGetVersion() #ifdef BT_DEBUG #ifdef _MSC_VER #include - #define btAssert(x) { if(!(x)){printf("Assert "__FILE__ ":%u ("#x")\n", __LINE__);__debugbreak(); }} + #define btAssert(x) { if(!(x)){printf("Assert " __FILE__ ":%u ("#x")\n", __LINE__);__debugbreak(); }} #else//_MSC_VER #include #define btAssert assert @@ -125,7 +125,7 @@ inline int btGetVersion() #ifdef __SPU__ #include #define printf spu_printf - #define btAssert(x) {if(!(x)){printf("Assert "__FILE__ ":%u ("#x")\n", __LINE__);spu_hcmpeq(0,0);}} + #define btAssert(x) {if(!(x)){printf("Assert " __FILE__ ":%u ("#x")\n", __LINE__);spu_hcmpeq(0,0);}} #else #define btAssert assert #endif From 5c1fc2e3a4c964349e210d32abd07f6c4ea5cd44 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Wed, 14 May 2014 11:03:53 -0700 Subject: [PATCH 047/116] fix OpenGL detection on Linux, and re-add TTF project to premake --- build3/findOpenGLGlewGlut.lua | 2 ++ build3/premake4.lua | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/build3/findOpenGLGlewGlut.lua b/build3/findOpenGLGlewGlut.lua index b8fe64664..dada07921 100644 --- a/build3/findOpenGLGlewGlut.lua +++ b/build3/findOpenGLGlewGlut.lua @@ -1,6 +1,8 @@ function findOpenGL() configuration{} if os.is("Linux") then + if os.isdir("/usr/include") and os.isfile("/usr/include/GL/gl.h") then return true + end return false end --assume OpenGL is available on Mac OSX, Windows etc diff --git a/build3/premake4.lua b/build3/premake4.lua index 359600dbb..7c2d48ce3 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -151,7 +151,7 @@ end -- include "../demo/gpu_initialize" -- include "../opencl/lds_bank_conflict" -- include "../opencl/reduce" --- include "../btgui/OpenGLTrueTypeFont" + include "../btgui/OpenGLTrueTypeFont" -- include "../btgui/OpenGLWindow" -- include "../demo/ObjLoader" -- include "../test/b3DynamicBvhBroadphase" From d65089e8e00141460cfd8d1a6651823ea753aee3 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 15 May 2014 15:39:26 -0700 Subject: [PATCH 048/116] cmake improvements --- Demos/premake4.lua | 10 ++++++---- Demos3/AllBullet2Demos/premake4.lua | 6 +++--- build3/premake4.lua | 8 ++------ 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/Demos/premake4.lua b/Demos/premake4.lua index 65c3ab34f..c488759b7 100644 --- a/Demos/premake4.lua +++ b/Demos/premake4.lua @@ -8,9 +8,14 @@ function createDemos( demos, incdirs, linknames) kind "ConsoleApp" targetdir ".." + + configuration {} includedirs {incdirs} - + links { + linknames + } + configuration { "Windows" } defines { "GLEW_STATIC"} links { "opengl32" } @@ -31,9 +36,6 @@ function createDemos( demos, incdirs, linknames) links {"GL","GLU","glut"} configuration{} - links { - linknames - } files { "./" .. name .. "/*.cpp" , diff --git a/Demos3/AllBullet2Demos/premake4.lua b/Demos3/AllBullet2Demos/premake4.lua index 436e1fa8d..c7002808d 100644 --- a/Demos3/AllBullet2Demos/premake4.lua +++ b/Demos3/AllBullet2Demos/premake4.lua @@ -13,11 +13,11 @@ "../../btgui/lua-5.2.3/src" } - initOpenGL() - initGlew() links{"gwen", "OpenGL_Window","OpenGL_TrueTypeFont","BulletSoftBody","BulletDynamics","BulletCollision","LinearMath","lua-5.2.3"} - + initOpenGL() + initGlew() + files { "**.cpp", "**.h", diff --git a/build3/premake4.lua b/build3/premake4.lua index 7c2d48ce3..6b679d976 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -162,13 +162,9 @@ end include "../test/enet/client" end + include "../Demos" + include "../Extras" if _OPTIONS["bullet2gpu"] then - include "../src/LinearMath" - include "../src/BulletCollision" - include "../src/BulletDynamics" - include "../src/BulletSoftBody" - include "../ObsoleteDemos/HelloWorld" - include "../Demos3" end From e579fa9488b417865778b2e66cae8240214cbce3 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 15 May 2014 15:44:22 -0700 Subject: [PATCH 049/116] fix/workaround for gcc internal compiler error See also http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=9636&hilit=compiler+error+gcc and https://github.com/bulletphysics/bullet3/issues/174 https://github.com/bulletphysics/bullet3/issues/39 --- .../CollisionDispatch/btInternalEdgeUtility.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp b/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp index 73fa4e87e..f97d11db7 100644 --- a/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp +++ b/src/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp @@ -114,6 +114,7 @@ struct btConnectivityProcessor : public btTriangleCallback if(numshared >= 3) return; } + switch (numshared) { case 0: @@ -202,7 +203,6 @@ struct btConnectivityProcessor : public btTriangleCallback ang4 = 0.f; } else { - calculatedEdge.normalize(); btVector3 calculatedNormalA = calculatedEdge.cross(edgeCrossA); calculatedNormalA.normalize(); @@ -213,7 +213,7 @@ struct btConnectivityProcessor : public btTriangleCallback isConvex = (dotA<0.); correctedAngle = isConvex ? ang4 : -ang4; - btQuaternion orn2(calculatedEdge,-correctedAngle); + btQuaternion orn2 = btQuaternion(btVector3(calculatedEdge.x(), calculatedEdge.y(), calculatedEdge.z()),-correctedAngle); calculatedNormalB = btMatrix3x3(orn2)*normalA; @@ -301,11 +301,6 @@ struct btConnectivityProcessor : public btTriangleCallback break; } - default: - { - // printf("warning: duplicate triangle\n"); - } - } } }; From 7f3cbc066ff8e72c48e8b292b0b0d6fc415d401c Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 15 May 2014 22:55:54 -0700 Subject: [PATCH 050/116] Remove @workaround for sticky convex collisions in btGjkPairDetector, it suffers from many artifacts, We still need to do more work on GJK when using very small collision margins... Fix premake build on Windows --- Demos/premake4.lua | 11 +-- .../btGjkPairDetector.cpp | 77 ++----------------- 2 files changed, 14 insertions(+), 74 deletions(-) diff --git a/Demos/premake4.lua b/Demos/premake4.lua index c488759b7..89ad341de 100644 --- a/Demos/premake4.lua +++ b/Demos/premake4.lua @@ -18,16 +18,17 @@ function createDemos( demos, incdirs, linknames) configuration { "Windows" } defines { "GLEW_STATIC"} - links { "opengl32" } - includedirs{ "../Glut" } - libdirs {"../Glut"} - files { "../build/bullet.rc" } + links { "opengl32","glu32","winmm"} + includedirs{ "Glut" } + libdirs {"Glut"} + files { "../build3/bullet.rc" } configuration {"Windows", "x32"} links {"glew32s","glut32"} configuration {"Windows", "x64"} links {"glew64s", "glut64"} - + + configuration {"MacOSX"} --print "hello" linkoptions { "-framework Carbon -framework OpenGL -framework AGL -framework Glut" } diff --git a/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp b/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp index 887757949..4c8ff2fab 100644 --- a/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp +++ b/src/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp @@ -26,7 +26,6 @@ subject to the following restrictions: #ifdef __SPU__ #include #define printf spu_printf -//#define DEBUG_SPU_COLLISION_DETECTION 1 #endif //__SPU__ #endif @@ -81,17 +80,18 @@ void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result& #ifdef __SPU__ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw) #else -void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw) +void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input, Result& output, class btIDebugDraw* debugDraw) #endif { m_cachedSeparatingDistance = 0.f; btScalar distance=btScalar(0.); btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.)); + btVector3 pointOnA,pointOnB; btTransform localTransA = input.m_transformA; btTransform localTransB = input.m_transformB; - btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5); + btVector3 positionOffset=(localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5); localTransA.getOrigin() -= positionOffset; localTransB.getOrigin() -= positionOffset; @@ -102,17 +102,11 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu gNumGjkChecks++; -#ifdef DEBUG_SPU_COLLISION_DETECTION - spu_printf("inside gjk\n"); -#endif //for CCD we don't use margins if (m_ignoreMargin) { marginA = btScalar(0.); marginB = btScalar(0.); -#ifdef DEBUG_SPU_COLLISION_DETECTION - spu_printf("ignoring margin\n"); -#endif } m_curIter = 0; @@ -143,37 +137,13 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis(); btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis(); -#if 1 btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); -// btVector3 pInA = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA); -// btVector3 qInB = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB); - -#else -#ifdef __SPU__ - btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); -#else - btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA); - btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB); -#ifdef TEST_NON_VIRTUAL - btVector3 pInAv = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA); - btVector3 qInBv = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB); - btAssert((pInAv-pInA).length() < 0.0001); - btAssert((qInBv-qInB).length() < 0.0001); -#endif // -#endif //__SPU__ -#endif - - btVector3 pWorld = localTransA(pInA); btVector3 qWorld = localTransB(qInB); -#ifdef DEBUG_SPU_COLLISION_DETECTION - spu_printf("got local supporting vertices\n"); -#endif if (check2d) { @@ -217,14 +187,8 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu break; } -#ifdef DEBUG_SPU_COLLISION_DETECTION - spu_printf("addVertex 1\n"); -#endif //add current vertex to simplex m_simplexSolver->addVertex(w, pWorld, qWorld); -#ifdef DEBUG_SPU_COLLISION_DETECTION - spu_printf("addVertex 2\n"); -#endif btVector3 newCachedSeparatingAxis; //calculate the closest point to the origin (update vector v) @@ -274,7 +238,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject if (m_curIter++ > gGjkMaxIter) { - #if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION) + #if defined(DEBUG) || defined (_DEBUG) printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter); printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n", @@ -307,6 +271,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu { m_simplexSolver->compute_points(pointOnA, pointOnB); normalInB = m_cachedSeparatingAxis; + btScalar lenSqr =m_cachedSeparatingAxis.length2(); //valid normal @@ -318,6 +283,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu { btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); normalInB *= rlen; //normalize + btScalar s = btSqrt(squaredDistance); btAssert(s > btScalar(0.0)); @@ -380,6 +346,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu pointOnA = tmpPointOnA; pointOnB = tmpPointOnB; normalInB = tmpNormalInB; + isValid = true; m_lastUsedMethod = 3; } else @@ -413,6 +380,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu pointOnB += m_cachedSeparatingAxis * marginB ; normalInB = m_cachedSeparatingAxis; normalInB.normalize(); + isValid = true; m_lastUsedMethod = 6; } else @@ -431,36 +399,7 @@ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& inpu if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared))) { -#if 0 -///some debugging -// if (check2d) - { - printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]); - printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex); - } -#endif - if (m_fixContactNormalDirection) - { - ///@workaround for sticky convex collisions - //in some degenerate cases (usually when the use uses very small margins) - //the contact normal is pointing the wrong direction - //so fix it now (until we can deal with all degenerate cases in GJK and EPA) - //contact normals need to point from B to A in all cases, so we can simply check if the contact normal really points from B to A - //We like to use a dot product of the normal against the difference of the centroids, - //once the centroid is available in the API - //until then we use the center of the aabb to approximate the centroid - btVector3 aabbMin,aabbMax; - m_minkowskiA->getAabb(localTransA,aabbMin,aabbMax); - btVector3 posA = (aabbMax+aabbMin)*btScalar(0.5); - - m_minkowskiB->getAabb(localTransB,aabbMin,aabbMax); - btVector3 posB = (aabbMin+aabbMax)*btScalar(0.5); - - btVector3 diff = posA-posB; - if (diff.dot(normalInB) < 0.f) - normalInB *= -1.f; - } m_cachedSeparatingAxis = normalInB; m_cachedSeparatingDistance = distance; From a22e129f8b8e60c90feca4685e8f4cffe8694de9 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 15 May 2014 23:25:00 -0700 Subject: [PATCH 051/116] remove unused/uninitialized data in BulletWorldImporterDemo --- Demos/BulletXmlImportDemo/BulletXmlImportDemo.cpp | 2 -- Demos/BulletXmlImportDemo/BulletXmlImportDemo.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/Demos/BulletXmlImportDemo/BulletXmlImportDemo.cpp b/Demos/BulletXmlImportDemo/BulletXmlImportDemo.cpp index e1338dbc7..dba805a5b 100644 --- a/Demos/BulletXmlImportDemo/BulletXmlImportDemo.cpp +++ b/Demos/BulletXmlImportDemo/BulletXmlImportDemo.cpp @@ -142,8 +142,6 @@ void BulletXmlImportDemo::setupEmptyDynamicsWorld() BulletXmlImportDemo::~BulletXmlImportDemo() { - m_fileLoader->deleteAllData(); - delete m_fileLoader; exitPhysics(); } diff --git a/Demos/BulletXmlImportDemo/BulletXmlImportDemo.h b/Demos/BulletXmlImportDemo/BulletXmlImportDemo.h index 53c163ec4..234291f0b 100644 --- a/Demos/BulletXmlImportDemo/BulletXmlImportDemo.h +++ b/Demos/BulletXmlImportDemo/BulletXmlImportDemo.h @@ -49,8 +49,6 @@ class BulletXmlImportDemo : public PlatformDemoApplication btDefaultCollisionConfiguration* m_collisionConfiguration; - class btBulletWorldImporter* m_fileLoader; - public: BulletXmlImportDemo() From 01ce7a0288e8733c86042f949e73d9ed237bf304 Mon Sep 17 00:00:00 2001 From: erwin coumans Date: Fri, 16 May 2014 08:59:34 -0700 Subject: [PATCH 052/116] remove a few unused variable, and add casts to avoid warnings --- btgui/OpenGLTrueTypeFont/fontstash.cpp | 28 +++++++++---------- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 14 +++++----- .../shared/b3ContactConvexConvexSAT.h | 4 +-- .../shared/b3FindSeparatingAxis.h | 2 +- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/btgui/OpenGLTrueTypeFont/fontstash.cpp b/btgui/OpenGLTrueTypeFont/fontstash.cpp index a43b7ff5f..803e155e1 100644 --- a/btgui/OpenGLTrueTypeFont/fontstash.cpp +++ b/btgui/OpenGLTrueTypeFont/fontstash.cpp @@ -494,10 +494,10 @@ static int get_quad(struct sth_stash* stash, struct sth_font* fnt, struct sth_gl ry = (*y + scale * float(glyph->yoff)); q->x0 = rx; - q->y0 = ry + 1.5*0.5f*float(isize)/10.f; + q->y0 = ry + 1.5f*0.5f*float(isize)/10.f; q->x1 = rx + scale * float(glyph->x1 - glyph->x0_); - q->y1 = ry + scale * float(glyph->y1 - glyph->y0)+ 1.5*0.5f*float(isize)/10.f; + q->y1 = ry + scale * float(glyph->y1 - glyph->y0)+ 1.5f*0.5f*float(isize)/10.f; q->s0 = float(glyph->x0_) * stash->itw; q->t0 = float(glyph->y0) * stash->ith; @@ -637,13 +637,13 @@ void sth_draw_texture(struct sth_stash* stash, q.x1 = q.x0+width; q.y1 = q.y0+height; - v = setv(v, q.x0, q.y0, 0,0,screenwidth,screenheight); - v = setv(v, q.x1, q.y0, 1,0,screenwidth,screenheight); - v = setv(v, q.x1, q.y1, 1,1,screenwidth,screenheight); + v = setv(v, q.x0, q.y0, 0,0,(float)screenwidth,(float)screenheight); + v = setv(v, q.x1, q.y0, 1,0,(float)screenwidth,(float)screenheight); + v = setv(v, q.x1, q.y1, 1,1,(float)screenwidth,(float)screenheight); - v = setv(v, q.x0, q.y0, 0,0,screenwidth,screenheight); - v = setv(v, q.x1, q.y1, 1,1,screenwidth,screenheight); - v = setv(v, q.x0, q.y1, 0,1,screenwidth,screenheight); + v = setv(v, q.x0, q.y0, 0,0,(float)screenwidth,(float)screenheight); + v = setv(v, q.x1, q.y1, 1,1,(float)screenwidth,(float)screenheight); + v = setv(v, q.x0, q.y1, 0,1,(float)screenwidth,(float)screenheight); texture->nverts += 6; } @@ -703,13 +703,13 @@ void sth_draw_text(struct sth_stash* stash, { v = &texture->newverts[texture->nverts]; - v = setv(v, q.x0, q.y0, q.s0, q.t0,screenwidth,screenheight); - v = setv(v, q.x1, q.y0, q.s1, q.t0,screenwidth,screenheight); - v = setv(v, q.x1, q.y1, q.s1, q.t1,screenwidth,screenheight); + v = setv(v, q.x0, q.y0, q.s0, q.t0,(float)screenwidth,(float)screenheight); + v = setv(v, q.x1, q.y0, q.s1, q.t0,(float)screenwidth,(float)screenheight); + v = setv(v, q.x1, q.y1, q.s1, q.t1,(float)screenwidth,(float)screenheight); - v = setv(v, q.x0, q.y0, q.s0, q.t0,screenwidth,screenheight); - v = setv(v, q.x1, q.y1, q.s1, q.t1,screenwidth,screenheight); - v = setv(v, q.x0, q.y1, q.s0, q.t1,screenwidth,screenheight); + v = setv(v, q.x0, q.y0, q.s0, q.t0,(float)screenwidth,(float)screenheight); + v = setv(v, q.x1, q.y1, q.s1, q.t1,(float)screenwidth,(float)screenheight); + v = setv(v, q.x0, q.y1, q.s0, q.t1,(float)screenwidth,(float)screenheight); texture->nverts += 6; } diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index b5e96ab3c..e214c3220 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -178,7 +178,7 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData if (deltay<0 || m_cameraDistance>1) { - m_cameraDistance -= deltay*0.1; + m_cameraDistance -= deltay*0.1f; if (m_cameraDistance<1) m_cameraDistance=1; } else @@ -234,8 +234,8 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData } if (m_rightMouseButton) { - m_cameraDistance -= xDelta*0.01; - m_cameraDistance -= yDelta*0.01; + m_cameraDistance -= xDelta*0.01f; + m_cameraDistance -= yDelta*0.01f; if (m_cameraDistance<1) m_cameraDistance=1; if (m_cameraDistance>1000) @@ -1205,7 +1205,7 @@ void GLInstancingRenderer::getMouseDirection(float* dir, int x, int y) float farPlane = 10000.f; rayForward*= farPlane; - b3Vector3 rightOffset; +// b3Vector3 rightOffset; b3Vector3 vertical = m_data->m_cameraUp; b3Vector3 hor; @@ -1270,9 +1270,9 @@ void writeTextureToPng(int textureWidth, int textureHeight, const char* fileName { //printf("val[%d,%d]=%f\n", i,j,val); } - pixels[(j*textureWidth+i)*numComponents]=orgPixels[(j*textureWidth+i)]*255.f; - pixels[(j*textureWidth+i)*numComponents+1]=0.f;//255.f; - pixels[(j*textureWidth+i)*numComponents+2]=0.f;//255.f; + pixels[(j*textureWidth+i)*numComponents]=char(orgPixels[(j*textureWidth+i)]*255.f); + pixels[(j*textureWidth+i)*numComponents+1]=0;//255.f; + pixels[(j*textureWidth+i)*numComponents+2]=0;//255.f; pixels[(j*textureWidth+i)*numComponents+3]=255; diff --git a/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h b/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h index b3d0c8031..65b333902 100644 --- a/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h +++ b/src/Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h @@ -370,7 +370,7 @@ inline int b3ClipHullHullSingle( B3_PROFILE("overlap"); b3Float4 normalOnSurfaceB = (b3Float4&)hostNormal; - b3Float4 centerOut; +// b3Float4 centerOut; b3Int4 contactIdx; contactIdx.x = 0; @@ -461,7 +461,7 @@ inline int b3ContactConvexConvexSAT( //printf("numvertsB = %d\n",hullB.m_numVertices); - b3Float4 contactsOut[B3_MAX_VERTS]; +// b3Float4 contactsOut[B3_MAX_VERTS]; int contactCapacity = B3_MAX_VERTS; int numContactsOut=0; diff --git a/src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindSeparatingAxis.h b/src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindSeparatingAxis.h index 039130016..d7fde0501 100644 --- a/src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindSeparatingAxis.h +++ b/src/Bullet3Collision/NarrowPhaseCollision/shared/b3FindSeparatingAxis.h @@ -149,7 +149,7 @@ inline bool b3FindSeparatingAxis( const b3ConvexPolyhedronData& hullA, const b3C } } - b3Vector3 edgeAstart,edgeAend,edgeBstart,edgeBend; +// b3Vector3 edgeAstart,edgeAend,edgeBstart,edgeBend; int curEdgeEdge = 0; // Test edges From 08369dbd0af4f00cb9b6c0e7e3af735af67a4deb Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Fri, 16 May 2014 11:56:43 -0700 Subject: [PATCH 053/116] fix uninitialized data in btMultiBodyPoint2Point, thanks to Valgrind valgrind --track-origins=yes --log-file="dump_valgrind.txt" ./App_AllBullet2Demos_codeblocks_x64_debug --- .../Featherstone/btMultiBodyPoint2Point.cpp | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp b/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp index 84f6f39fe..d2ebf29ef 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBodyPoint2Point.cpp @@ -4,8 +4,8 @@ Copyright (c) 2013 Erwin Coumans http://bulletphysics.org This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -26,7 +26,7 @@ subject to the following restrictions: #endif btMultiBodyPoint2Point::btMultiBodyPoint2Point(btMultiBody* body, int link, btRigidBody* bodyB, const btVector3& pivotInA, const btVector3& pivotInB) - :btMultiBodyConstraint(body,0,link,-1,BTMBP2PCONSTRAINT_DIM,false), + :btMultiBodyConstraint(body,0,link,-1,BTMBP2PCONSTRAINT_DIM,false), m_rigidBodyA(0), m_rigidBodyB(bodyB), m_pivotInA(pivotInA), @@ -95,15 +95,23 @@ void btMultiBodyPoint2Point::createConstraintRows(btMultiBodyConstraintArray& co const btContactSolverInfo& infoGlobal) { -// int i=1; - for (int i=0;igetCompanionId(); pivotAworld = m_rigidBodyA->getCenterOfMassTransform()*m_pivotInA; } else @@ -134,20 +142,22 @@ void btMultiBodyPoint2Point::createConstraintRows(btMultiBodyConstraintArray& co { if (m_bodyB) pivotBworld = m_bodyB->localPosToWorld(m_linkB, m_pivotInB); - + } btScalar posError = i < 3 ? (pivotAworld-pivotBworld).dot(contactNormalOnB) : 0; -#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST - +#ifndef BTMBP2PCONSTRAINT_BLOCK_ANGULAR_MOTION_TEST + fillMultiBodyConstraint(constraintRow, data, 0, 0, contactNormalOnB, pivotAworld, pivotBworld, //sucks but let it be this way "for the time being" posError, infoGlobal, -m_maxAppliedImpulse, m_maxAppliedImpulse - ); + ); + //@todo: support the case of btMultiBody versus btRigidBody, + //see btPoint2PointConstraint::getInfo2NonVirtual #else const btVector3 dummy(0, 0, 0); @@ -167,4 +177,4 @@ void btMultiBodyPoint2Point::createConstraintRows(btMultiBodyConstraintArray& co ); #endif } -} \ No newline at end of file +} From 46884e0f1f2df97c7dbdc3c4160f2d98aa830056 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Fri, 16 May 2014 16:11:59 -0700 Subject: [PATCH 054/116] update the binary premake4_osx binary, avoid the -Wl,-x flag so clang linker doesn't produce an error ld: internal error: atom not found in symbolIndex see http://industriousone.com/topic/how-remove-flags-ldflags --- build3/premake4_osx | Bin 481412 -> 410668 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/build3/premake4_osx b/build3/premake4_osx index 67e25d5b94b80be747a92c571bd37121c4a5faa2..1979a5db2a1dbcf409b7653b2152cc20a1101869 100755 GIT binary patch delta 115851 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

n(lBr>#* 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 literal 481412 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 From 1e2b907562cf4a5a22183745a71e627d162adfc8 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Fri, 16 May 2014 16:20:07 -0700 Subject: [PATCH 055/116] update version to 2.83 for an intermediate release (2014 will be a transition year to Bullet 3.x) --- CMakeLists.txt | 2 +- VERSION | 1 + src/LinearMath/btScalar.h | 2 +- src/LinearMath/btSerializer.h | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 VERSION diff --git a/CMakeLists.txt b/CMakeLists.txt index cb0f07560..e0f659182 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) SET(MSVC_INCREMENTAL_DEFAULT ON) PROJECT(BULLET_PHYSICS) -SET(BULLET_VERSION 2.82) +SET(BULLET_VERSION 2.83) IF(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..0a95fec88 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +2.83 diff --git a/src/LinearMath/btScalar.h b/src/LinearMath/btScalar.h index e02f99abc..bcf81ad58 100644 --- a/src/LinearMath/btScalar.h +++ b/src/LinearMath/btScalar.h @@ -28,7 +28,7 @@ subject to the following restrictions: #include /* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/ -#define BT_BULLET_VERSION 282 +#define BT_BULLET_VERSION 283 inline int btGetVersion() { diff --git a/src/LinearMath/btSerializer.h b/src/LinearMath/btSerializer.h index ff1dc574c..c719b65ca 100644 --- a/src/LinearMath/btSerializer.h +++ b/src/LinearMath/btSerializer.h @@ -438,7 +438,7 @@ public: buffer[9] = '2'; buffer[10] = '8'; - buffer[11] = '2'; + buffer[11] = '3'; } From 26019322496936df5fc76c1bb6ff1dd824d001d5 Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Sat, 17 May 2014 14:24:22 -0700 Subject: [PATCH 056/116] fix issue related to addConstraint/removeConstraint, introduced by filtering collision between two particular bodies https://github.com/bulletphysics/bullet3/issues/173 --- .../Dynamics/btDiscreteDynamicsWorld.cpp | 3 ++ src/BulletDynamics/Dynamics/btRigidBody.cpp | 30 ++++++++++--------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp index fb8a4068e..df57f893c 100644 --- a/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp +++ b/src/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp @@ -653,6 +653,9 @@ void btDiscreteDynamicsWorld::updateActivationState(btScalar timeStep) void btDiscreteDynamicsWorld::addConstraint(btTypedConstraint* constraint,bool disableCollisionsBetweenLinkedBodies) { m_constraints.push_back(constraint); + //Make sure the two bodies of a type constraint are different (possibly add this to the btTypedConstraint constructor?) + btAssert(&constraint->getRigidBodyA()!=&constraint->getRigidBodyB()); + if (disableCollisionsBetweenLinkedBodies) { constraint->getRigidBodyA().addConstraintRef(constraint); diff --git a/src/BulletDynamics/Dynamics/btRigidBody.cpp b/src/BulletDynamics/Dynamics/btRigidBody.cpp index aad5089ed..732d75963 100644 --- a/src/BulletDynamics/Dynamics/btRigidBody.cpp +++ b/src/BulletDynamics/Dynamics/btRigidBody.cpp @@ -326,7 +326,7 @@ void btRigidBody::addConstraintRef(btTypedConstraint* c) int index = m_constraintRefs.findLinearSearch(c); //don't add constraints that are already referenced - btAssert(index == m_constraintRefs.size()); + //btAssert(index == m_constraintRefs.size()); if (index == m_constraintRefs.size()) { m_constraintRefs.push_back(c); @@ -340,25 +340,27 @@ void btRigidBody::addConstraintRef(btTypedConstraint* c) { colObjB->setIgnoreCollisionCheck(colObjA, true); } - } + } } void btRigidBody::removeConstraintRef(btTypedConstraint* c) { int index = m_constraintRefs.findLinearSearch(c); //don't remove constraints that are not referenced - btAssert(index < m_constraintRefs.size()); - m_constraintRefs.remove(c); - btCollisionObject* colObjA = &c->getRigidBodyA(); - btCollisionObject* colObjB = &c->getRigidBodyB(); - if (colObjA == this) - { - colObjA->setIgnoreCollisionCheck(colObjB, false); - } - else - { - colObjB->setIgnoreCollisionCheck(colObjA, false); - } + if(index < m_constraintRefs.size()) + { + m_constraintRefs.remove(c); + btCollisionObject* colObjA = &c->getRigidBodyA(); + btCollisionObject* colObjB = &c->getRigidBodyB(); + if (colObjA == this) + { + colObjA->setIgnoreCollisionCheck(colObjB, false); + } + else + { + colObjB->setIgnoreCollisionCheck(colObjA, false); + } + } } int btRigidBody::calculateSerializeBufferSize() const From 3dd759c46385ec80af60109532540d26ca1063a8 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 19 May 2014 14:53:11 -0700 Subject: [PATCH 057/116] fix BT_USE_DOUBLE_PRECISION build, address Issue 177 https://github.com/bulletphysics/bullet3/issues/177 --- Demos3/bullet2/BasicDemo/BasicDemo.cpp | 6 ++-- Demos3/bullet2/BasicDemo/MyDebugDrawer.h | 5 ++- Demos3/bullet2/ChainDemo/ChainDemo.cpp | 6 ++-- .../BulletMultiBodyDemos.cpp | 22 ++++++------ btgui/OpenGLWindow/GLInstancingRenderer.cpp | 9 +++++ btgui/OpenGLWindow/GLInstancingRenderer.h | 36 +++++++++++++++++++ 6 files changed, 66 insertions(+), 18 deletions(-) diff --git a/Demos3/bullet2/BasicDemo/BasicDemo.cpp b/Demos3/bullet2/BasicDemo/BasicDemo.cpp index 92147c16d..59980667a 100644 --- a/Demos3/bullet2/BasicDemo/BasicDemo.cpp +++ b/Demos3/bullet2/BasicDemo/BasicDemo.cpp @@ -26,8 +26,8 @@ BasicDemo::~BasicDemo() void BasicDemo::createGround(int cubeShapeId) { { - float color[]={0.3,0.3,1,1}; - float halfExtents[]={50,50,50,1}; + btVector4 color(0.3,0.3,1,1); + btVector4 halfExtents(50,50,50,1); btTransform groundTransform; groundTransform.setIdentity(); groundTransform.setOrigin(btVector3(0,-50,0)); @@ -71,7 +71,7 @@ void BasicDemo::initPhysics() { - float halfExtents[]={scaling,scaling,scaling,1}; + btVector4 halfExtents(scaling,scaling,scaling,1); btVector4 colors[4] = { btVector4(1,0,0,1), diff --git a/Demos3/bullet2/BasicDemo/MyDebugDrawer.h b/Demos3/bullet2/BasicDemo/MyDebugDrawer.h index 411815452..81f9a536c 100644 --- a/Demos3/bullet2/BasicDemo/MyDebugDrawer.h +++ b/Demos3/bullet2/BasicDemo/MyDebugDrawer.h @@ -15,8 +15,11 @@ public: { } - virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color) + virtual void drawLine(const btVector3& from1,const btVector3& to1,const btVector3& color1) { + float from[4] = {from1[0],from1[1],from1[2],from1[3]}; + float to[4] = {to1[0],to1[1],to1[2],to1[3]}; + float color[4] = {color1[0],color1[1],color1[2],color1[3]}; m_glApp->m_instancingRenderer->drawLine(from,to,color); } diff --git a/Demos3/bullet2/ChainDemo/ChainDemo.cpp b/Demos3/bullet2/ChainDemo/ChainDemo.cpp index 4c353a01b..71032cb7c 100644 --- a/Demos3/bullet2/ChainDemo/ChainDemo.cpp +++ b/Demos3/bullet2/ChainDemo/ChainDemo.cpp @@ -26,8 +26,8 @@ ChainDemo::~ChainDemo() void ChainDemo::createGround(int cubeShapeId) { { - float color[]={0.3,0.3,1,1}; - float halfExtents[]={50,1,50,1}; + btVector4 color(0.3,0.3,1,1); + btVector4 halfExtents(50,1,50,1); btTransform groundTransform; groundTransform.setIdentity(); groundTransform.setOrigin(btVector3(0,-5,0)); @@ -85,7 +85,7 @@ void ChainDemo::initPhysics() int sphereShapeId = m_glApp->registerGraphicsSphereShape(radius,false); { - float halfExtents[]={scaling,scaling,scaling,1}; + btVector4 halfExtents(scaling,scaling,scaling,1); btVector4 colors[4] = { btVector4(1,0,0,1), diff --git a/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp b/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp index e03afcdd9..80dced6bb 100644 --- a/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp +++ b/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp @@ -38,12 +38,12 @@ struct GraphicsVertex float texcoord[2]; }; -static b3Vector4 colors[4] = +static btVector4 colors[4] = { - b3MakeVector4(1,0,0,1), - b3MakeVector4(0,1,0,1), - b3MakeVector4(0,1,1,1), - b3MakeVector4(1,1,0,1), + btVector4(1,0,0,1), + btVector4(0,1,0,1), + btVector4(0,1,1,1), + btVector4(1,1,0,1), }; @@ -435,8 +435,8 @@ btMultiBody* FeatherstoneDemo1::createFeatherstoneMultiBody(class btMultiBodyDyn world_to_local[0] = bod->getWorldToBaseRot(); local_origin[0] = bod->getBasePos(); //float halfExtents[3]={7.5,0.05,4.5}; - float halfExtents[3]={7.5,0.45,4.5}; - { + btVector4 halfExtents(7.5,0.45,4.5,1); + { float pos[4]={local_origin[0].x(),local_origin[0].y(),local_origin[0].z(),1}; float quat[4]={-world_to_local[0].x(),-world_to_local[0].y(),-world_to_local[0].z(),world_to_local[0].w()}; @@ -455,7 +455,7 @@ btMultiBody* FeatherstoneDemo1::createFeatherstoneMultiBody(class btMultiBodyDyn tr.setRotation(btQuaternion(quat[0],quat[1],quat[2],quat[3])); col->setWorldTransform(tr); - b3Vector4 color = colors[curColor++]; + btVector4 color = colors[curColor++]; curColor&=3; int index = m_glApp->m_instancingRenderer->registerGraphicsInstance(cubeShapeId,tr.getOrigin(),tr.getRotation(),color,halfExtents); @@ -500,7 +500,7 @@ btMultiBody* FeatherstoneDemo1::createFeatherstoneMultiBody(class btMultiBodyDyn col->setFriction(friction); - b3Vector4 color = colors[curColor++]; + btVector4 color = colors[curColor++]; curColor&=3; int index = m_glApp->m_instancingRenderer->registerGraphicsInstance(cubeShapeId,tr.getOrigin(),tr.getRotation(),color,halfExtents); @@ -536,8 +536,8 @@ void FeatherstoneDemo1::createGround() { - float color[]={0.3,0.3,1,1}; - float halfExtents[]={50,50,50,1}; + btVector4 color(0.3,0.3,1,1); + btVector4 halfExtents(50,50,50,1); btTransform groundTransform; groundTransform.setIdentity(); groundTransform.setOrigin(btVector3(0,-50,0)); diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index e214c3220..a81fa19e3 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -582,6 +582,15 @@ void GLInstancingRenderer::writeTransforms() } +int GLInstancingRenderer::registerGraphicsInstance(int shapeIndex, const double* pos1, const double* orn1, const double* color1, const double* scaling1) +{ + float pos[4] = {pos1[0],pos1[1],pos1[2],pos1[3]}; + float orn[4] = {orn1[0],orn1[1],orn1[2],orn1[3]}; + float color[4] = {color1[0],color1[1],color1[2],color1[3]}; + float scaling[4] = {scaling1[0],scaling1[1],scaling1[2],scaling1[3]}; + return registerGraphicsInstance(shapeIndex,pos,orn,color,scaling); +} + int GLInstancingRenderer::registerGraphicsInstance(int shapeIndex, const float* position, const float* quaternion, const float* color, const float* scaling) { diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.h b/btgui/OpenGLWindow/GLInstancingRenderer.h index fd64a57e7..2325006e7 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.h +++ b/btgui/OpenGLWindow/GLInstancingRenderer.h @@ -77,10 +77,26 @@ public: ///position x,y,z, quaternion x,y,z,w, color r,g,b,a, scaling x,y,z int registerGraphicsInstance(int shapeIndex, const float* position, const float* quaternion, const float* color, const float* scaling); + int registerGraphicsInstance(int shapeIndex, const double* position, const double* quaternion, const double* color, const double* scaling); void writeTransforms(); void writeSingleInstanceTransformToCPU(const float* position, const float* orientation, int srcIndex); + void writeSingleInstanceTransformToCPU(const double* position, const double* orientation, int srcIndex) + { + float pos[4]; + float orn[4]; + pos[0] = position[0]; + pos[1] = position[1]; + pos[2] = position[2]; + pos[3] = position[3]; + orn[0] =orientation[0]; + orn[1] =orientation[1]; + orn[2] =orientation[2]; + orn[3] =orientation[3]; + writeSingleInstanceTransformToCPU(pos,orn,srcIndex); + + } void writeSingleInstanceTransformToGPU(float* position, float* orientation, int srcIndex); @@ -97,12 +113,32 @@ public: void updateCamera(); void getCameraPosition(float cameraPos[4]); + void getCameraPosition(double cameraPos[4]) + { + float campos[4]; + getCameraPosition(campos); + cameraPos[0] = campos[0]; + cameraPos[1] = campos[1]; + cameraPos[2] = campos[2]; + cameraPos[3] = campos[3]; + } + void setCameraDistance(float dist); float getCameraDistance() const; //set the camera 'target' void setCameraTargetPosition(float cameraPos[4]); void getCameraTargetPosition(float cameraPos[4]) const; + void getCameraTargetPosition(double cameraPos[4]) const + { + float campos[4]; + getCameraTargetPosition(campos); + cameraPos[0] = campos[0]; + cameraPos[1] = campos[1]; + cameraPos[2] = campos[2]; + cameraPos[3] = campos[3]; + + } void setCameraYaw(float yaw); void setCameraPitch(float pitch); From f213b000220702d4debd878d27d5e7f0206b75d2 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 19 May 2014 20:50:10 -0700 Subject: [PATCH 058/116] fix BUILD_SHARED_LIBS and add it as an OPTION (cross fingers that CMake lets you expose existing vars as OPTION) this should fix issue 176, thanks to Stephen Peters! --- CMakeLists.txt | 6 +++++- btgui/OpenGLWindow/CMakeLists.txt | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0f659182..2d9b5a4e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") OPTION(USE_DOUBLE_PRECISION "Use double precision" OFF) OPTION(USE_GRAPHICAL_BENCHMARK "Use Graphical Benchmark" ON) - +OPTION(BUILD_SHARED_LIBS "Use shared libraries" OFF) OPTION(USE_MSVC_RUNTIME_LIBRARY_DLL "Use MSVC Runtime Library DLL (/MD or /MDd)" OFF) OPTION(USE_MSVC_INCREMENTAL_LINKING "Use MSVC Incremental Linking" OFF) @@ -226,6 +226,10 @@ ENDIF(USE_GLUT) ENDIF() ENDIF(BUILD_BULLET2_DEMOS) +IF (APPLE) + FIND_LIBRARY(COCOA_LIBRARY Cocoa) +ENDIF() + OPTION(BUILD_BULLET3 "Set when you want to build Bullet 3" ON) IF(BUILD_BULLET3) OPTION(BUILD_BULLET3_DEMOS "Set when you want to build the Bullet 3 demos" ON) diff --git a/btgui/OpenGLWindow/CMakeLists.txt b/btgui/OpenGLWindow/CMakeLists.txt index 81e9bcf3e..4af098ac0 100644 --- a/btgui/OpenGLWindow/CMakeLists.txt +++ b/btgui/OpenGLWindow/CMakeLists.txt @@ -40,6 +40,8 @@ ENDIF() ADD_LIBRARY(OpenGLWindow ${OpenGLWindow_SRCS} ${OpenGLWindow_HDRS}) if (UNIX AND NOT APPLE) target_link_libraries(OpenGLWindow X11) +elseif (APPLE) + target_link_libraries(OpenGLWindow ${COCOA_LIBRARY}) endif () if (BUILD_SHARED_LIBS) From 010d5cbc2b29a9e4f839f3a846783a06321c6dfd Mon Sep 17 00:00:00 2001 From: Steven Peters Date: Tue, 20 May 2014 10:54:43 -0700 Subject: [PATCH 059/116] Add .travis.yml for continuous integration --- .travis.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..2b7a4fd19 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,13 @@ +language: cpp +compiler: + - gcc + - clang +install: + - sudo apt-get update + - sudo apt-get install libglew-dev +script: + - echo "CXX="$CXX + - echo "CC="$CC + - cmake . -G "Unix Makefiles" #-DCMAKE_CXX_FLAGS=-Werror + - make -j8 + - sudo make install From 6d36803de70495e6e267811e9f4698d487955b73 Mon Sep 17 00:00:00 2001 From: Steven Peters Date: Tue, 20 May 2014 11:11:15 -0700 Subject: [PATCH 060/116] Test also with double precision --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2b7a4fd19..b198e747a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,3 +11,7 @@ script: - cmake . -G "Unix Makefiles" #-DCMAKE_CXX_FLAGS=-Werror - make -j8 - sudo make install + # Test again with double precision + - cmake . -G "Unix Makefiles" -DUSE_DOUBLE_PRECISION=ON #-DCMAKE_CXX_FLAGS=-Werror + - make -j8 + - sudo make install From eb74688c185ddb44ae7fc58bd963bf53d379f57b Mon Sep 17 00:00:00 2001 From: erwin coumans Date: Tue, 20 May 2014 12:02:01 -0700 Subject: [PATCH 061/116] Add setUserIndex/getUserIndex (int index) to btCollisionShape Share physics setup of BasicDemo between different graphics frameworks, see Demos\BasicDemo\BasicDemoPhysicsSetup.* Plan is to do this for all Bullet demos. Improve gwen performance and cursor navigation for tree control. tweak shadowmap size SimpleOpenGL3App::registerCubeShape accepts half extents --- Demos/BasicDemo/BasicDemo.cpp | 156 ++----------- Demos/BasicDemo/BasicDemo.h | 19 +- Demos/BasicDemo/BasicDemoPhysicsSetup.cpp | 171 +++++++++++++++ Demos/BasicDemo/BasicDemoPhysicsSetup.h | 94 ++++++++ Demos/BasicDemo/CMakeLists.txt | 6 + Demos3/AllBullet2Demos/CMakeLists.txt | 2 + Demos3/AllBullet2Demos/main.cpp | 2 +- Demos3/AllBullet2Demos/premake4.lua | 2 + Demos3/bullet2/BasicDemo/BasicDemo.cpp | 118 ++++------ Demos3/bullet2/BasicDemo/BasicDemo.h | 12 + btgui/Gwen/Controls/Base.cpp | 29 ++- btgui/Gwen/Controls/Base.h | 45 +++- btgui/Gwen/Controls/ScrollBar.h | 10 + btgui/Gwen/Controls/TreeControl.cpp | 206 ++++++++++++++---- btgui/Gwen/Controls/TreeControl.h | 1 + btgui/Gwen/Controls/TreeNode.cpp | 10 +- btgui/GwenOpenGLTest/OpenGLSample.cpp | 3 + btgui/GwenOpenGLTest/UnitTest.cpp | 6 +- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 6 +- btgui/OpenGLWindow/GLInstancingRenderer.h | 16 +- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 27 ++- btgui/OpenGLWindow/SimpleOpenGL3App.h | 2 +- .../CollisionShapes/btCollisionShape.h | 17 +- 23 files changed, 657 insertions(+), 303 deletions(-) create mode 100644 Demos/BasicDemo/BasicDemoPhysicsSetup.cpp create mode 100644 Demos/BasicDemo/BasicDemoPhysicsSetup.h diff --git a/Demos/BasicDemo/BasicDemo.cpp b/Demos/BasicDemo/BasicDemo.cpp index c8dcfcc5c..82229062c 100644 --- a/Demos/BasicDemo/BasicDemo.cpp +++ b/Demos/BasicDemo/BasicDemo.cpp @@ -40,7 +40,7 @@ subject to the following restrictions: static GLDebugDrawer gDebugDraw; ///The MyOverlapCallback is used to show how to collect object that overlap with a given bounding box defined by aabbMin and aabbMax. -///See m_dynamicsWorld->getBroadphase()->aabbTest. +///See m_physicsSetup.m_dynamicsWorld->getBroadphase()->aabbTest. struct MyOverlapCallback : public btBroadphaseAabbCallback { btVector3 m_queryAabbMin; @@ -68,23 +68,27 @@ void BasicDemo::clientMoveAndDisplay() //simple dynamics world doesn't handle fixed-time-stepping float ms = getDeltaTimeMicroseconds(); + m_physicsSetup.stepSimulation(ms/1000000.f); + m_physicsSetup.m_dynamicsWorld->debugDrawWorld(); + + /* ///step the simulation - if (m_dynamicsWorld) + if (m_physicsSetup.m_dynamicsWorld) { - m_dynamicsWorld->stepSimulation(ms / 1000000.f); + m_physicsSetup.m_dynamicsWorld->stepSimulation(ms / 1000000.f); //optional but useful: debug drawing - m_dynamicsWorld->debugDrawWorld(); + m_physicsSetup.m_dynamicsWorld->debugDrawWorld(); btVector3 aabbMin(1,1,1); btVector3 aabbMax(2,2,2); MyOverlapCallback aabbOverlap(aabbMin,aabbMax); - m_dynamicsWorld->getBroadphase()->aabbTest(aabbMin,aabbMax,aabbOverlap); + m_physicsSetup.m_dynamicsWorld->getBroadphase()->aabbTest(aabbMin,aabbMax,aabbOverlap); //if (aabbOverlap.m_numOverlap) // printf("#aabb overlap = %d\n", aabbOverlap.m_numOverlap); } - + */ renderme(); glFlush(); @@ -102,8 +106,8 @@ void BasicDemo::displayCallback(void) { renderme(); //optional but useful: debug drawing to detect problems - if (m_dynamicsWorld) - m_dynamicsWorld->debugDrawWorld(); + if (m_physicsSetup.m_dynamicsWorld) + m_physicsSetup.m_dynamicsWorld->debugDrawWorld(); glFlush(); swapBuffers(); @@ -120,105 +124,10 @@ void BasicDemo::initPhysics() setCameraDistance(btScalar(SCALING*50.)); - ///collision configuration contains default setup for memory, collision setup - m_collisionConfiguration = new btDefaultCollisionConfiguration(); - //m_collisionConfiguration->setConvexConvexMultipointIterations(); + m_physicsSetup.initPhysics(); - ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) - m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); - - m_broadphase = new btDbvtBroadphase(); - - ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) - btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; - m_solver = sol; - - m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + m_dynamicsWorld = m_physicsSetup.m_dynamicsWorld; m_dynamicsWorld->setDebugDrawer(&gDebugDraw); - - m_dynamicsWorld->setGravity(btVector3(0,-10,0)); - - ///create a few basic rigid bodies - btBoxShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.))); - //groundShape->initializePolyhedralFeatures(); -// btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50); - - m_collisionShapes.push_back(groundShape); - - btTransform groundTransform; - groundTransform.setIdentity(); - groundTransform.setOrigin(btVector3(0,-50,0)); - - //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here: - { - btScalar mass(0.); - - //rigidbody is dynamic if and only if mass is non zero, otherwise static - bool isDynamic = (mass != 0.f); - - btVector3 localInertia(0,0,0); - if (isDynamic) - groundShape->calculateLocalInertia(mass,localInertia); - - //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects - btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); - btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); - btRigidBody* body = new btRigidBody(rbInfo); - - //add the body to the dynamics world - m_dynamicsWorld->addRigidBody(body); - } - - - { - //create a few dynamic rigidbodies - // Re-using the same collision is better for memory usage and performance - - btBoxShape* colShape = new btBoxShape(btVector3(SCALING*1,SCALING*1,SCALING*1)); - //btCollisionShape* colShape = new btSphereShape(btScalar(1.)); - m_collisionShapes.push_back(colShape); - - /// Create Dynamic Objects - btTransform startTransform; - startTransform.setIdentity(); - - btScalar mass(1.f); - - //rigidbody is dynamic if and only if mass is non zero, otherwise static - bool isDynamic = (mass != 0.f); - - btVector3 localInertia(0,0,0); - if (isDynamic) - colShape->calculateLocalInertia(mass,localInertia); - - float start_x = START_POS_X - ARRAY_SIZE_X/2; - float start_y = START_POS_Y; - float start_z = START_POS_Z - ARRAY_SIZE_Z/2; - - for (int k=0;kaddRigidBody(body); - } - } - } - } - } void BasicDemo::clientResetScene() @@ -230,42 +139,7 @@ void BasicDemo::clientResetScene() void BasicDemo::exitPhysics() { - - //cleanup in the reverse order of creation/initialization - - //remove the rigidbodies from the dynamics world and delete them - int i; - for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) - { - btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; - btRigidBody* body = btRigidBody::upcast(obj); - if (body && body->getMotionState()) - { - delete body->getMotionState(); - } - m_dynamicsWorld->removeCollisionObject( obj ); - delete obj; - } - - //delete collision shapes - for (int j=0;j m_collisionShapes; - - btBroadphaseInterface* m_broadphase; - - btCollisionDispatcher* m_dispatcher; - - btConstraintSolver* m_solver; - - btDefaultCollisionConfiguration* m_collisionConfiguration; + BasicDemoPhysicsSetup m_physicsSetup; public: diff --git a/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp b/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp new file mode 100644 index 000000000..f33d68e3b --- /dev/null +++ b/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp @@ -0,0 +1,171 @@ + + +#include "BasicDemoPhysicsSetup.h" +#include "btBulletDynamicsCommon.h" +#define ARRAY_SIZE_Y 5 +#define ARRAY_SIZE_X 5 +#define ARRAY_SIZE_Z 5 + +void BasicDemoPhysicsSetup::initPhysics() +{ + ///collision configuration contains default setup for memory, collision setup + m_collisionConfiguration = new btDefaultCollisionConfiguration(); + //m_collisionConfiguration->setConvexConvexMultipointIterations(); + + ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) + m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); + + m_broadphase = new btDbvtBroadphase(); + + ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) + btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; + m_solver = sol; + + m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + + + m_dynamicsWorld->setGravity(btVector3(0,-10,0)); + + ///create a few basic rigid bodies + btBoxShape* groundShape = createBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.))); + //groundShape->initializePolyhedralFeatures(); +// btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50); + + m_collisionShapes.push_back(groundShape); + + btTransform groundTransform; + groundTransform.setIdentity(); + groundTransform.setOrigin(btVector3(0,-50,0)); + + { + btScalar mass(0.); + createRigidBody(mass,groundTransform,groundShape); + } + + + { + //create a few dynamic rigidbodies + // Re-using the same collision is better for memory usage and performance + + btBoxShape* colShape = createBoxShape(btVector3(1,1,1)); + //btCollisionShape* colShape = new btSphereShape(btScalar(1.)); + m_collisionShapes.push_back(colShape); + + /// Create Dynamic Objects + btTransform startTransform; + startTransform.setIdentity(); + + btScalar mass(1.f); + + //rigidbody is dynamic if and only if mass is non zero, otherwise static + bool isDynamic = (mass != 0.f); + + btVector3 localInertia(0,0,0); + if (isDynamic) + colShape->calculateLocalInertia(mass,localInertia); + + + for (int k=0;kstepSimulation(deltaTime); +} + +btBoxShape* BasicDemoPhysicsSetup::createBoxShape(const btVector3& halfExtents) +{ + btBoxShape* box = new btBoxShape(halfExtents); + return box; +} + +btRigidBody* BasicDemoPhysicsSetup::createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape) +{ + btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE)); + + //rigidbody is dynamic if and only if mass is non zero, otherwise static + bool isDynamic = (mass != 0.f); + + btVector3 localInertia(0,0,0); + if (isDynamic) + shape->calculateLocalInertia(mass,localInertia); + + //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects + +#define USE_MOTIONSTATE 1 +#ifdef USE_MOTIONSTATE + btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); + + btRigidBody::btRigidBodyConstructionInfo cInfo(mass,myMotionState,shape,localInertia); + + btRigidBody* body = new btRigidBody(cInfo); + //body->setContactProcessingThreshold(m_defaultContactProcessingThreshold); + +#else + btRigidBody* body = new btRigidBody(mass,0,shape,localInertia); + body->setWorldTransform(startTransform); +#endif// + + body->setUserIndex(-1); + m_dynamicsWorld->addRigidBody(body); + return body; +} + + +void BasicDemoPhysicsSetup::exitPhysics() +{ + //cleanup in the reverse order of creation/initialization + + //remove the rigidbodies from the dynamics world and delete them + int i; + for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body = btRigidBody::upcast(obj); + if (body && body->getMotionState()) + { + delete body->getMotionState(); + } + m_dynamicsWorld->removeCollisionObject( obj ); + delete obj; + } + + //delete collision shapes + for (int j=0;j m_collisionShapes; + btBroadphaseInterface* m_broadphase; + btCollisionDispatcher* m_dispatcher; + btConstraintSolver* m_solver; + btDefaultCollisionConfiguration* m_collisionConfiguration; + btDiscreteDynamicsWorld* m_dynamicsWorld; + + virtual void initPhysics(); + + virtual void exitPhysics(); + + virtual void stepSimulation(float deltaTime); + + virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape); + + virtual btBoxShape* createBoxShape(const btVector3& halfExtents); + +/* + + //bodies + virtual btRigidBody* createRigidBody(bool isDynamic, btScalar mass, const btTransform& startTransform, btCollisionShape* shape,const char* bodyName); + virtual btCollisionObject* createCollisionObject( const btTransform& startTransform, btCollisionShape* shape,const char* bodyName); + + ///shapes + + virtual btCollisionShape* createPlaneShape(const btVector3& planeNormal,btScalar planeConstant); + + virtual btCollisionShape* createSphereShape(btScalar radius); + virtual btCollisionShape* createCapsuleShapeX(btScalar radius, btScalar height); + virtual btCollisionShape* createCapsuleShapeY(btScalar radius, btScalar height); + virtual btCollisionShape* createCapsuleShapeZ(btScalar radius, btScalar height); + + virtual btCollisionShape* createCylinderShapeX(btScalar radius,btScalar height); + virtual btCollisionShape* createCylinderShapeY(btScalar radius,btScalar height); + virtual btCollisionShape* createCylinderShapeZ(btScalar radius,btScalar height); + virtual btCollisionShape* createConeShapeX(btScalar radius,btScalar height); + virtual btCollisionShape* createConeShapeY(btScalar radius,btScalar height); + virtual btCollisionShape* createConeShapeZ(btScalar radius,btScalar height); + virtual class btTriangleIndexVertexArray* createTriangleMeshContainer(); + virtual btBvhTriangleMeshShape* createBvhTriangleMeshShape(btStridingMeshInterface* trimesh, btOptimizedBvh* bvh); + virtual btCollisionShape* createConvexTriangleMeshShape(btStridingMeshInterface* trimesh); + virtual btGImpactMeshShape* createGimpactShape(btStridingMeshInterface* trimesh); + virtual btStridingMeshInterfaceData* createStridingMeshInterfaceData(btStridingMeshInterfaceData* interfaceData); + + virtual class btConvexHullShape* createConvexHullShape(); + virtual class btCompoundShape* createCompoundShape(); + virtual class btScaledBvhTriangleMeshShape* createScaledTrangleMeshShape(btBvhTriangleMeshShape* meshShape,const btVector3& localScalingbtBvhTriangleMeshShape); + + virtual class btMultiSphereShape* createMultiSphereShape(const btVector3* positions,const btScalar* radi,int numSpheres); + + virtual btTriangleIndexVertexArray* createMeshInterface(btStridingMeshInterfaceData& meshData); + + ///acceleration and connectivity structures + virtual btOptimizedBvh* createOptimizedBvh(); + virtual btTriangleInfoMap* createTriangleInfoMap(); + + ///constraints + virtual btPoint2PointConstraint* createPoint2PointConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB); + virtual btPoint2PointConstraint* createPoint2PointConstraint(btRigidBody& rbA,const btVector3& pivotInA); + virtual btHingeConstraint* createHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA=false); + virtual btHingeConstraint* createHingeConstraint(btRigidBody& rbA,const btTransform& rbAFrame, bool useReferenceFrameA=false); + virtual btConeTwistConstraint* createConeTwistConstraint(btRigidBody& rbA,btRigidBody& rbB,const btTransform& rbAFrame, const btTransform& rbBFrame); + virtual btConeTwistConstraint* createConeTwistConstraint(btRigidBody& rbA,const btTransform& rbAFrame); + virtual btGeneric6DofConstraint* createGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); + virtual btGeneric6DofConstraint* createGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB); + virtual btGeneric6DofSpringConstraint* createGeneric6DofSpringConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); + virtual btSliderConstraint* createSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); + virtual btSliderConstraint* createSliderConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameA); + virtual btGearConstraint* createGearConstraint(btRigidBody& rbA, btRigidBody& rbB, const btVector3& axisInA,const btVector3& axisInB, btScalar ratio); +*/ + +}; + +#endif //BASIC_DEMO_PHYSICS_SETUP_H diff --git a/Demos/BasicDemo/CMakeLists.txt b/Demos/BasicDemo/CMakeLists.txt index eaf265a83..16bb9e404 100644 --- a/Demos/BasicDemo/CMakeLists.txt +++ b/Demos/BasicDemo/CMakeLists.txt @@ -28,6 +28,8 @@ ADD_EXECUTABLE(AppBasicDemo main.cpp BasicDemo.cpp BasicDemo.h + BasicDemoPhysicsSetup.cpp + BasicDemoPhysicsSetup.h ${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc ) ELSE() @@ -35,6 +37,8 @@ ELSE() main.cpp BasicDemo.cpp BasicDemo.h + BasicDemoPhysicsSetup.cpp + BasicDemoPhysicsSetup.h ) ENDIF() ELSE (USE_GLUT) @@ -52,6 +56,8 @@ ELSE (USE_GLUT) Win32BasicDemo.cpp BasicDemo.cpp BasicDemo.h + BasicDemoPhysicsSetup.cpp + BasicDemoPhysicsSetup.h ${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc ) diff --git a/Demos3/AllBullet2Demos/CMakeLists.txt b/Demos3/AllBullet2Demos/CMakeLists.txt index 6023d44c6..06557e166 100644 --- a/Demos3/AllBullet2Demos/CMakeLists.txt +++ b/Demos3/AllBullet2Demos/CMakeLists.txt @@ -12,6 +12,8 @@ SET(App_AllBullet2Demos_SRCS BulletDemoEntries.h ../bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp ../bullet2/BasicDemo/Bullet2RigidBodyDemo.h + ../../Demos/BasicDemo/BasicDemoPhysicsSetup.cpp + ../../Demos/BasicDemo/BasicDemoPhysicsSetup.h ../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp ../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h ../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.cpp diff --git a/Demos3/AllBullet2Demos/main.cpp b/Demos3/AllBullet2Demos/main.cpp index 3bae9da6f..2efe840f7 100644 --- a/Demos3/AllBullet2Demos/main.cpp +++ b/Demos3/AllBullet2Demos/main.cpp @@ -217,7 +217,7 @@ int main(int argc, char* argv[]) app->swapBuffer(); } while (!app->m_window->requestedExit()); - selectDemo(0); +// selectDemo(0); delete gui; delete app; return 0; diff --git a/Demos3/AllBullet2Demos/premake4.lua b/Demos3/AllBullet2Demos/premake4.lua index c7002808d..948199b39 100644 --- a/Demos3/AllBullet2Demos/premake4.lua +++ b/Demos3/AllBullet2Demos/premake4.lua @@ -23,6 +23,8 @@ "**.h", "../bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp", "../bullet2/BasicDemo/Bullet2RigidBodyDemo.h", + "../../Demos/BasicDemo/BasicDemoPhysicsSetup.cpp", + "../../Demos/BasicDemo/BasicDemoPhysicsSetup.h", "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp", "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h", "../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.cpp", diff --git a/Demos3/bullet2/BasicDemo/BasicDemo.cpp b/Demos3/bullet2/BasicDemo/BasicDemo.cpp index 59980667a..f0386862b 100644 --- a/Demos3/bullet2/BasicDemo/BasicDemo.cpp +++ b/Demos3/bullet2/BasicDemo/BasicDemo.cpp @@ -32,6 +32,7 @@ void BasicDemo::createGround(int cubeShapeId) groundTransform.setIdentity(); groundTransform.setOrigin(btVector3(0,-50,0)); m_glApp->m_instancingRenderer->registerGraphicsInstance(cubeShapeId,groundTransform.getOrigin(),groundTransform.getRotation(),color,halfExtents); + btBoxShape* groundShape = new btBoxShape(btVector3(btScalar(halfExtents[0]),btScalar(halfExtents[1]),btScalar(halfExtents[2]))); //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here: { @@ -52,88 +53,60 @@ void BasicDemo::createGround(int cubeShapeId) } void BasicDemo::initPhysics() { -// Bullet2RigidBodyDemo::initPhysics(); - - m_config = new btDefaultCollisionConfiguration; - m_dispatcher = new btCollisionDispatcher(m_config); - m_bp = new btDbvtBroadphase(); - m_solver = new btNNCGConstraintSolver(); - m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_bp,m_solver,m_config); - - int curColor=0; - //create ground - int cubeShapeId = m_glApp->registerCubeShape(); - float pos[]={0,0,0}; - float orn[]={0,0,0,1}; - - - createGround(cubeShapeId); - - - { - btVector4 halfExtents(scaling,scaling,scaling,1); - btVector4 colors[4] = - { - btVector4(1,0,0,1), - btVector4(0,1,0,1), - btVector4(0,1,1,1), - btVector4(1,1,0,1), - }; - - - - btTransform startTransform; - startTransform.setIdentity(); - btScalar mass = 1.f; - btVector3 localInertia; - btBoxShape* colShape = new btBoxShape(btVector3(halfExtents[0],halfExtents[1],halfExtents[2])); - colShape ->calculateLocalInertia(mass,localInertia); - - for (int k=0;km_instancingRenderer->registerGraphicsInstance(cubeShapeId,startTransform.getOrigin(),startTransform.getRotation(),color,halfExtents); - - //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects - btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); - btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia); - btRigidBody* body = new btRigidBody(rbInfo); - - - m_dynamicsWorld->addRigidBody(body); - } - } - } - } + m_physicsSetup.m_glApp = m_glApp; + m_physicsSetup.initPhysics(); + m_dynamicsWorld = m_physicsSetup.m_dynamicsWorld; m_glApp->m_instancingRenderer->writeTransforms(); } void BasicDemo::exitPhysics() { - - Bullet2RigidBodyDemo::exitPhysics(); + m_physicsSetup.exitPhysics(); + m_dynamicsWorld = 0; + //Bullet2RigidBodyDemo::exitPhysics(); } + +//SimpleOpenGL3App* m_glApp; + +btRigidBody* MyBasicDemoPhysicsSetup::createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape) +{ + btRigidBody* body = BasicDemoPhysicsSetup::createRigidBody(mass,startTransform,shape); + int graphicsShapeId = shape->getUserIndex(); + btAssert(graphicsShapeId>=0); + btVector3 localScaling = shape->getLocalScaling(); + float color[]={0.3,0.3,1,1}; + int graphicsInstanceId = m_glApp->m_instancingRenderer->registerGraphicsInstance(graphicsShapeId,startTransform.getOrigin(),startTransform.getRotation(),color,localScaling); + body->setUserIndex(graphicsInstanceId); + + //todo: create graphics representation + return body; + +} + +btBoxShape* MyBasicDemoPhysicsSetup::createBoxShape(const btVector3& halfExtents) +{ + btBoxShape* box = BasicDemoPhysicsSetup::createBoxShape(halfExtents); + int cubeShapeId = m_glApp->registerCubeShape(halfExtents.x(),halfExtents.y(),halfExtents.z()); + box->setUserIndex(cubeShapeId); + //todo: create graphics representation + return box; +} + + void BasicDemo::renderScene() { //sync graphics -> physics world transforms { for (int i=0;igetNumCollisionObjects();i++) { - btVector3 pos = m_dynamicsWorld->getCollisionObjectArray()[i]->getWorldTransform().getOrigin(); - btQuaternion orn = m_dynamicsWorld->getCollisionObjectArray()[i]->getWorldTransform().getRotation(); - m_glApp->m_instancingRenderer->writeSingleInstanceTransformToCPU(pos,orn,i); + btCollisionObject* colObj = m_dynamicsWorld->getCollisionObjectArray()[i]; + btVector3 pos = colObj->getWorldTransform().getOrigin(); + btQuaternion orn = colObj->getWorldTransform().getRotation(); + int index = colObj ->getUserIndex(); + if (index>=0) + { + m_glApp->m_instancingRenderer->writeSingleInstanceTransformToCPU(pos,orn,index); + } } m_glApp->m_instancingRenderer->writeTransforms(); } @@ -144,7 +117,10 @@ void BasicDemo::renderScene() void BasicDemo::stepSimulation(float dt) { - m_dynamicsWorld->stepSimulation(dt); + m_physicsSetup.stepSimulation(dt); + m_physicsSetup.m_dynamicsWorld->debugDrawWorld(); + + /* //print applied force diff --git a/Demos3/bullet2/BasicDemo/BasicDemo.h b/Demos3/bullet2/BasicDemo/BasicDemo.h index 456dc4f27..d1da7ac62 100644 --- a/Demos3/bullet2/BasicDemo/BasicDemo.h +++ b/Demos3/bullet2/BasicDemo/BasicDemo.h @@ -4,10 +4,22 @@ #include "LinearMath/btVector3.h" #include "Bullet2RigidBodyDemo.h" +#include "../../../Demos/BasicDemo/BasicDemoPhysicsSetup.h" +struct MyBasicDemoPhysicsSetup : public BasicDemoPhysicsSetup +{ + SimpleOpenGL3App* m_glApp; + + virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape); + + virtual btBoxShape* createBoxShape(const btVector3& halfExtents); +}; + class BasicDemo : public Bullet2RigidBodyDemo { + + MyBasicDemoPhysicsSetup m_physicsSetup; public: diff --git a/btgui/Gwen/Controls/Base.cpp b/btgui/Gwen/Controls/Base.cpp index ba856fb91..427d3b8a0 100644 --- a/btgui/Gwen/Controls/Base.cpp +++ b/btgui/Gwen/Controls/Base.cpp @@ -105,6 +105,8 @@ void Base::Invalidate() { m_bNeedsLayout = true; m_bCacheTextureDirty = true; + extern int avoidUpdate; + avoidUpdate = -3; } void Base::DelayedDelete() @@ -403,12 +405,13 @@ void Base::OnBoundsChanged(Gwen::Rect oldBounds) //Anything that needs to update on size changes //Iterate my children and tell them I've changed // - if ( GetParent() ) - GetParent()->OnChildBoundsChanged( oldBounds, this ); + if ( m_Bounds.w != oldBounds.w || m_Bounds.h != oldBounds.h ) { + if ( GetParent() ) + GetParent()->OnChildBoundsChanged( oldBounds, this ); Invalidate(); } @@ -694,6 +697,8 @@ void Base::Layout( Skin::Base* skin ) skin->GetRender()->GetCTT()->CreateControlCacheTexture( this ); } +int avoidUpdate = -15; + void Base::RecurseLayout( Skin::Base* skin ) { if ( m_Skin ) skin = m_Skin; @@ -704,6 +709,10 @@ void Base::RecurseLayout( Skin::Base* skin ) m_bNeedsLayout = false; Layout( skin ); } + + + if (avoidUpdate>0) + return; Gwen::Rect rBounds = GetRenderBounds(); @@ -713,13 +722,21 @@ void Base::RecurseLayout( Skin::Base* skin ) rBounds.y += m_Padding.top; rBounds.h -= m_Padding.top + m_Padding.bottom; + int sz = Children.size(); + if (sz>100) + { +// printf("!\n"); + + } + int curChild = 0; for (Base::List::iterator iter = Children.begin(); iter != Children.end(); ++iter) { Base* pChild = *iter; - + curChild++; if ( pChild->Hidden() ) continue; + int iDock = pChild->GetDock(); if ( iDock & Pos::Fill ) @@ -768,10 +785,12 @@ void Base::RecurseLayout( Skin::Base* skin ) } pChild->RecurseLayout( skin ); + } m_InnerBounds = rBounds; + curChild = 0; // // Fill uses the left over space, so do that now. // @@ -779,10 +798,12 @@ void Base::RecurseLayout( Skin::Base* skin ) { Base* pChild = *iter; int iDock = pChild->GetDock(); - + curChild++; if ( !(iDock & Pos::Fill) ) continue; + + const Margin& margin = pChild->GetMargin(); pChild->SetBounds( rBounds.x + margin.left, rBounds.y + margin.top, rBounds.w - margin.left - margin.right, rBounds.h - margin.top - margin.bottom ); diff --git a/btgui/Gwen/Controls/Base.h b/btgui/Gwen/Controls/Base.h index 46a4104c8..011a9e7bf 100644 --- a/btgui/Gwen/Controls/Base.h +++ b/btgui/Gwen/Controls/Base.h @@ -164,19 +164,43 @@ namespace Gwen virtual void RestrictToParent( bool restrict ) { m_bRestrictToParent = restrict; } virtual bool ShouldRestrictToParent() { return m_bRestrictToParent; } - virtual int X() const { return m_Bounds.x; } - virtual int Y() const { return m_Bounds.y; } - virtual int Width() const { return m_Bounds.w; } - virtual int Height() const { return m_Bounds.h; } - virtual int Bottom() const { return m_Bounds.y + m_Bounds.h + m_Margin.bottom; } - virtual int Right() const { return m_Bounds.x + m_Bounds.w + m_Margin.right; } + virtual int X() const + { + return m_Bounds.x; + } + virtual int Y() const + { + return m_Bounds.y; + } + virtual int Width() const + { + return m_Bounds.w; + } + virtual int Height() const + { + return m_Bounds.h; + } + virtual int Bottom() const + { + return m_Bounds.y + m_Bounds.h + m_Margin.bottom; + } + virtual int Right() const + { + return m_Bounds.x + m_Bounds.w + m_Margin.right; + } virtual const Margin& GetMargin() const { return m_Margin; } virtual const Padding& GetPadding() const { return m_Padding; } virtual void SetPos( int x, int y ); - virtual void SetWidth( int w ) { SetSize( w, Height()); } - virtual void SetHeight( int h ) { SetSize( Width(), h); } + virtual void SetWidth( int w ) + { + SetSize( w, Height()); + } + virtual void SetHeight( int h ) + { +SetSize( Width(), h); + } virtual bool SetSize( int w, int h ); virtual bool SetBounds( int x, int y, int w, int h ); virtual bool SetBounds( const Gwen::Rect& bounds ); @@ -188,7 +212,10 @@ namespace Gwen virtual void MoveTo (int x, int y ); virtual void MoveBy (int x, int y ); - virtual const Gwen::Rect& GetBounds() const { return m_Bounds; } + virtual const Gwen::Rect& GetBounds() const + { + return m_Bounds; + } virtual Controls::Base* GetControlAt( int x, int y ); diff --git a/btgui/Gwen/Controls/ScrollBar.h b/btgui/Gwen/Controls/ScrollBar.h index d6175dabe..a0cd02c42 100644 --- a/btgui/Gwen/Controls/ScrollBar.h +++ b/btgui/Gwen/Controls/ScrollBar.h @@ -61,6 +61,16 @@ namespace Gwen Gwen::Event::Caller onBarMoved; + float getContentSize() + { + return m_fContentSize; + } + float getViewableContentSize() const + { + + return m_fViewableContentSize; + } + protected: ControlsInternal::ScrollBarButton* m_ScrollButton[2]; diff --git a/btgui/Gwen/Controls/TreeControl.cpp b/btgui/Gwen/Controls/TreeControl.cpp index 0a4fb123f..e75010bbd 100644 --- a/btgui/Gwen/Controls/TreeControl.cpp +++ b/btgui/Gwen/Controls/TreeControl.cpp @@ -42,9 +42,14 @@ void TreeControl::Render( Skin::Base* skin ) skin->DrawTreeControl( this ); } +void TreeControl::ForceUpdateScrollBars() +{ + m_ScrollControl->UpdateScrollBars(); +} + void TreeControl::OnChildBoundsChanged( Gwen::Rect /*oldChildBounds*/, Base* /*pChild*/ ) { - m_ScrollControl->UpdateScrollBars(); + //m_ScrollControl->UpdateScrollBars(); } void TreeControl::Clear() @@ -74,7 +79,7 @@ void TreeControl::OnNodeSelection( Controls::Base* /*control*/ ) } -void TreeControl::iterate(int action, int* curIndex, int* targetIndex) +void TreeControl::iterate(int action, int* maxItem, int* curItem) { Base::List& children = m_InnerPanel->GetChildren(); @@ -83,7 +88,7 @@ void TreeControl::iterate(int action, int* curIndex, int* targetIndex) TreeNode* pChild = (*iter)->DynamicCastTreeNode(); if ( !pChild ) continue; - pChild->iterate(action ,curIndex, targetIndex); + pChild->iterate(action ,maxItem, curItem); } } @@ -93,26 +98,52 @@ bool TreeControl::OnKeyUp( bool bDown ) { if (bDown) { + ForceUpdateScrollBars(); int maxIndex = 0; int newIndex = 0; - int curIndex=0; - int targetIndex=-1; - iterate(ITERATE_ACTION_FIND_SELECTED_INDEX,&curIndex,&targetIndex); - maxIndex = curIndex; - if (targetIndex>0) + int maxItem=0; + int curItem=-1; + iterate(ITERATE_ACTION_FIND_SELECTED_INDEX,&maxItem,&curItem); + maxIndex = maxItem; + int targetItem = curItem; + if (curItem>0) { - curIndex=0; - int deselectIndex = targetIndex; - targetIndex--; - newIndex = targetIndex; - iterate(ITERATE_ACTION_SELECT,&curIndex,&targetIndex); - if (targetIndex<0) + maxItem=0; + int deselectIndex = targetItem; + targetItem--; + newIndex = targetItem; + iterate(ITERATE_ACTION_SELECT,&maxItem,&targetItem); + if (targetItem<0) { - curIndex=0; - iterate(ITERATE_ACTION_DESELECT_INDEX,&curIndex,&deselectIndex); + maxItem=0; + iterate(ITERATE_ACTION_DESELECT_INDEX,&maxItem,&deselectIndex); } + curItem = newIndex; float amount = float(newIndex)/float(maxIndex); - m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(amount,true); + float viewSize = m_ScrollControl->m_VerticalScrollBar->getViewableContentSize(); + float contSize = m_ScrollControl->m_VerticalScrollBar->getContentSize(); + + float curAmount = m_ScrollControl->m_VerticalScrollBar->GetScrolledAmount(); + float minCoordViewableWindow = curAmount*contSize; + float maxCoordViewableWindow = minCoordViewableWindow+viewSize; + float minCoordSelectedItem = curItem*16.f; + float maxCoordSelectedItem = (curItem+1)*16.f; + { + float newAmount = float(minCoordSelectedItem)/(contSize-viewSize); + if (newAmountm_VerticalScrollBar->SetScrolledAmount(newAmount,true); + } + } + { + int numItems = (viewSize)/16-1; + float newAmount = float((curItem-numItems)*16)/(contSize-viewSize); + + if (newAmount>curAmount) + { + m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(newAmount,true); + } + } } } return true; @@ -123,26 +154,52 @@ bool TreeControl::OnKeyDown( bool bDown ) { if (bDown) { + ForceUpdateScrollBars(); int maxIndex = 0; int newIndex = 0; - int curIndex=0; - int targetIndex=-1; - iterate(ITERATE_ACTION_FIND_SELECTED_INDEX,&curIndex,&targetIndex); - maxIndex = curIndex; - if (targetIndex>=0) + int maxItem=0; + int curItem=-1; + iterate(ITERATE_ACTION_FIND_SELECTED_INDEX,&maxItem,&curItem); + maxIndex = maxItem; + int targetItem = curItem; + if (curItem>=0) { - curIndex=0; - int deselectIndex = targetIndex; - targetIndex++; - newIndex = targetIndex; - iterate(ITERATE_ACTION_SELECT,&curIndex,&targetIndex); - if (targetIndex<0) + maxItem=0; + int deselectIndex = targetItem; + targetItem++; + newIndex = targetItem; + iterate(ITERATE_ACTION_SELECT,&maxItem,&targetItem); + if (targetItem<0) { - curIndex=0; - iterate(ITERATE_ACTION_DESELECT_INDEX,&curIndex,&deselectIndex); + maxItem=0; + iterate(ITERATE_ACTION_DESELECT_INDEX,&maxItem,&deselectIndex); + } + curItem= newIndex; + float amount = (int)float(newIndex)/float(maxIndex); + float viewSize = m_ScrollControl->m_VerticalScrollBar->getViewableContentSize(); + float contSize = m_ScrollControl->m_VerticalScrollBar->getContentSize(); + + float curAmount = m_ScrollControl->m_VerticalScrollBar->GetScrolledAmount(); + float minCoordViewableWindow = curAmount*contSize; + float maxCoordViewableWindow = minCoordViewableWindow+viewSize; + float minCoordSelectedItem = curItem*16.f; + float maxCoordSelectedItem = (curItem+1)*16.f; + { + float newAmount = float(minCoordSelectedItem)/(contSize-viewSize); + if (newAmountm_VerticalScrollBar->SetScrolledAmount(newAmount,true); + } + } + { + int numItems = (viewSize)/16-1; + float newAmount = float((curItem-numItems)*16)/(contSize-viewSize); + + if (newAmount>curAmount) + { + m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(newAmount,true); + } } - float amount = float(newIndex)/float(maxIndex); - m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(amount,true); } } return true; @@ -153,12 +210,39 @@ bool TreeControl::OnKeyRight( bool bDown ) { if (bDown) { + extern int avoidUpdate; + avoidUpdate = -3; + ForceUpdateScrollBars(); iterate(ITERATE_ACTION_OPEN,0,0); - int curIndex=0; - int targetIndex=0; - iterate(ITERATE_ACTION_FIND_SELECTED_INDEX,&curIndex,&targetIndex); - float amount = float(targetIndex)/float(curIndex); - m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(amount,true); + int maxItem=0; + int curItem=0; + iterate(ITERATE_ACTION_FIND_SELECTED_INDEX,&maxItem,&curItem); + float amount = float(curItem)/float(maxItem); + float viewSize = m_ScrollControl->m_VerticalScrollBar->getViewableContentSize(); + float contSize = m_ScrollControl->m_VerticalScrollBar->getContentSize(); + + float curAmount = m_ScrollControl->m_VerticalScrollBar->GetScrolledAmount(); + float minCoordViewableWindow = curAmount*contSize; + float maxCoordViewableWindow = minCoordViewableWindow+viewSize; + float minCoordSelectedItem = curItem*16.f; + float maxCoordSelectedItem = (curItem+1)*16.f; + { + float newAmount = float(minCoordSelectedItem)/(contSize-viewSize); + if (newAmountm_VerticalScrollBar->SetScrolledAmount(newAmount,true); + } + } + { + int numItems = (viewSize)/16-1; + float newAmount = float((curItem-numItems)*16)/(contSize-viewSize); + + if (newAmount>curAmount) + { + m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(newAmount,true); + } + } + Invalidate(); } return true; } @@ -166,13 +250,51 @@ bool TreeControl::OnKeyLeft( bool bDown ) { if (bDown) { + extern int avoidUpdate; + avoidUpdate = -3; + + ForceUpdateScrollBars(); + iterate(ITERATE_ACTION_CLOSE,0,0); - int curIndex=0; - int targetIndex=0; - iterate(ITERATE_ACTION_FIND_SELECTED_INDEX,&curIndex,&targetIndex); - float amount = float(targetIndex)/float(curIndex); - m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(amount,true); + int maxItems=0; + int curItem=0; + iterate(ITERATE_ACTION_FIND_SELECTED_INDEX,&maxItems,&curItem); + float amount = float(curItem)/float(maxItems); + + // m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(amount,true); + float viewSize = m_ScrollControl->m_VerticalScrollBar->getViewableContentSize(); + float contSize = m_ScrollControl->m_VerticalScrollBar->getContentSize(); + + float curAmount = m_ScrollControl->m_VerticalScrollBar->GetScrolledAmount(); + float minCoordViewableWindow = curAmount*contSize; + float maxCoordViewableWindow = minCoordViewableWindow+viewSize; + float minCoordSelectedItem = curItem*16.f; + float maxCoordSelectedItem = (curItem+1)*16.f; + + { + float newAmount = float(minCoordSelectedItem)/(contSize-viewSize); + if (newAmountm_VerticalScrollBar->SetScrolledAmount(newAmount,true); + } + } + { + int numItems = (viewSize)/16-1; + float newAmount = float((curItem-numItems)*16)/(contSize-viewSize); + + if (newAmount>curAmount) + { + m_ScrollControl->m_VerticalScrollBar->SetScrolledAmount(newAmount,true); + } + Invalidate(); + } + //viewSize/contSize + + printf("!\n"); + + //this->Layout(0); + } return true; diff --git a/btgui/Gwen/Controls/TreeControl.h b/btgui/Gwen/Controls/TreeControl.h index 7ab963185..79de3e9ff 100644 --- a/btgui/Gwen/Controls/TreeControl.h +++ b/btgui/Gwen/Controls/TreeControl.h @@ -43,6 +43,7 @@ namespace Gwen virtual void iterate(int action,int* curIndex, int* resultIndex); + virtual void ForceUpdateScrollBars(); private: diff --git a/btgui/Gwen/Controls/TreeNode.cpp b/btgui/Gwen/Controls/TreeNode.cpp index 732ef037d..e32ac7e52 100644 --- a/btgui/Gwen/Controls/TreeNode.cpp +++ b/btgui/Gwen/Controls/TreeNode.cpp @@ -73,6 +73,7 @@ void TreeNode::Render( Skin::Base* skin ) TreeNode* TreeNode::AddNode( const UnicodeString& strLabel ) { + int sz = sizeof(TreeNode); TreeNode* node = new TreeNode( this ); node->SetText( strLabel ); node->Dock( Pos::Top ); @@ -112,9 +113,16 @@ void TreeNode::Layout( Skin::Base* skin ) BaseClass::Layout( skin ); } - +//too many calls to PostLayout... +//int numCalls = 0xfd; void TreeNode::PostLayout( Skin::Base* /*skin*/ ) { + + //int bla = numCalls&0xffff; + //if (bla==0) + // printf("TreeNode::PostLayout numCalls = %d\n", numCalls); + + //numCalls++; if ( SizeToChildren( false, true ) ) { InvalidateParent(); diff --git a/btgui/GwenOpenGLTest/OpenGLSample.cpp b/btgui/GwenOpenGLTest/OpenGLSample.cpp index 218a50d22..137716af8 100644 --- a/btgui/GwenOpenGLTest/OpenGLSample.cpp +++ b/btgui/GwenOpenGLTest/OpenGLSample.cpp @@ -456,6 +456,9 @@ int main() pCanvas->RenderCanvas(); + extern int avoidUpdate; + if (avoidUpdate<=0) + avoidUpdate++; // SwapBuffers( GetDC( g_pHWND ) ); } diff --git a/btgui/GwenOpenGLTest/UnitTest.cpp b/btgui/GwenOpenGLTest/UnitTest.cpp index f2f0b0741..677d32884 100644 --- a/btgui/GwenOpenGLTest/UnitTest.cpp +++ b/btgui/GwenOpenGLTest/UnitTest.cpp @@ -84,8 +84,10 @@ GWEN_CONTROL_CONSTRUCTOR( UnitTest ) ctrl->Focus(); ctrl->SetKeyboardInputEnabled(true); - ctrl->SetBounds( 30, 30, 200, 200 ); - ctrl->ExpandAll(); + ctrl->SetBounds( 30, 30, 200, 30+16*10 ); + //ctrl->ExpandAll(); + ctrl->ForceUpdateScrollBars(); + ctrl->OnKeyDown(true); } diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index a81fa19e3..9436c09cd 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -16,9 +16,9 @@ subject to the following restrictions: ///todo: make this configurable in the gui bool useShadowMap=true; -float shadowMapWidth=16384; -float shadowMapHeight=16384; -float shadowMapWorldSize=1000; +float shadowMapWidth=8192; +float shadowMapHeight=8192; +float shadowMapWorldSize=200; float WHEEL_MULTIPLIER=0.01f; float MOUSE_MOVE_MULTIPLIER = 0.4f; #define MAX_POINTS_IN_BATCH 1024 diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.h b/btgui/OpenGLWindow/GLInstancingRenderer.h index 2325006e7..f5faeea03 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.h +++ b/btgui/OpenGLWindow/GLInstancingRenderer.h @@ -86,14 +86,14 @@ public: { float pos[4]; float orn[4]; - pos[0] = position[0]; - pos[1] = position[1]; - pos[2] = position[2]; - pos[3] = position[3]; - orn[0] =orientation[0]; - orn[1] =orientation[1]; - orn[2] =orientation[2]; - orn[3] =orientation[3]; + pos[0] = (float)position[0]; + pos[1] = (float)position[1]; + pos[2] = (float)position[2]; + pos[3] = (float)position[3]; + orn[0] =(float)orientation[0]; + orn[1] =(float)orientation[1]; + orn[2] =(float)orientation[2]; + orn[3] =(float)orientation[3]; writeSingleInstanceTransformToCPU(pos,orn,srcIndex); } diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index 9b89c62ee..fe69cfbf6 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -210,12 +210,35 @@ void SimpleOpenGL3App::drawText( const char* txt, int posX, int posY) glDisable(GL_BLEND); } -int SimpleOpenGL3App::registerCubeShape() +int SimpleOpenGL3App::registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ) { + struct GfxVertex + { + float x,y,z,w; + float nx,ny,nz; + float u,v; + }; + int strideInBytes = 9*sizeof(float); int numVertices = sizeof(cube_vertices)/strideInBytes; int numIndices = sizeof(cube_indices)/sizeof(int); - int shapeId = m_instancingRenderer->registerShape(&cube_vertices[0],numVertices,cube_indices,numIndices); + + b3AlignedObjectArray verts; + verts.resize(numVertices); + for (int i=0;iregisterShape(&verts[0].x,numVertices,cube_indices,numIndices); return shapeId; } diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.h b/btgui/OpenGLWindow/SimpleOpenGL3App.h index be50ee095..7bad61d70 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.h +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.h @@ -16,7 +16,7 @@ struct SimpleOpenGL3App SimpleOpenGL3App(const char* title, int width,int height); virtual ~SimpleOpenGL3App(); - int registerCubeShape(); + int registerCubeShape(float halfExtentsX=1.f,float halfExtentsY=1.f, float halfExtentsZ = 1.f); int registerGraphicsSphereShape(float radius, bool usePointSprites=true, int largeSphereThreshold=100, int mediumSphereThreshold=10); void drawGrid(int gridSize=10, float yOffset=0.001); diff --git a/src/BulletCollision/CollisionShapes/btCollisionShape.h b/src/BulletCollision/CollisionShapes/btCollisionShape.h index ff017a206..1d8a4dc30 100644 --- a/src/BulletCollision/CollisionShapes/btCollisionShape.h +++ b/src/BulletCollision/CollisionShapes/btCollisionShape.h @@ -28,8 +28,13 @@ ATTRIBUTE_ALIGNED16(class) btCollisionShape { protected: int m_shapeType; - void* m_userPointer; + union + { + void* m_userPointer; + int m_userIndex; + }; + public: BT_DECLARE_ALIGNED_ALLOCATOR(); @@ -131,6 +136,16 @@ public: return m_userPointer; } + void setUserIndex(int index) + { + m_userIndex = index; + } + + int getUserIndex() const + { + return m_userIndex; + } + virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) From 4912bebfbff896ec8d7fbb5fea664e7e38a731e1 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 20 May 2014 14:07:57 -0700 Subject: [PATCH 062/116] fix linker error on Mac OSX --- btgui/Gwen/Controls/Base.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/btgui/Gwen/Controls/Base.cpp b/btgui/Gwen/Controls/Base.cpp index 427d3b8a0..4d649d8d1 100644 --- a/btgui/Gwen/Controls/Base.cpp +++ b/btgui/Gwen/Controls/Base.cpp @@ -101,11 +101,16 @@ Base::~Base() } } + extern int avoidUpdate; + void Base::Invalidate() { + + + m_bNeedsLayout = true; m_bCacheTextureDirty = true; - extern int avoidUpdate; + avoidUpdate = -3; } From 7f300a877ff26b5facbe170b98cdd7a9dd44c36d Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 20 May 2014 14:43:19 -0700 Subject: [PATCH 063/116] fix some btgui issues on Mac OSX --- btgui/Gwen/Controls/Base.cpp | 1 + btgui/Gwen/Controls/TreeControl.cpp | 6 +-- btgui/GwenOpenGLTest/OpenGLSample.cpp | 9 ++-- btgui/OpenGLWindow/MacOpenGLWindow.mm | 60 ++++++++++++++----------- btgui/OpenGLWindow/b3gWindowInterface.h | 1 + 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/btgui/Gwen/Controls/Base.cpp b/btgui/Gwen/Controls/Base.cpp index 4d649d8d1..5e90f1d49 100644 --- a/btgui/Gwen/Controls/Base.cpp +++ b/btgui/Gwen/Controls/Base.cpp @@ -103,6 +103,7 @@ Base::~Base() extern int avoidUpdate; + void Base::Invalidate() { diff --git a/btgui/Gwen/Controls/TreeControl.cpp b/btgui/Gwen/Controls/TreeControl.cpp index e75010bbd..128b0386d 100644 --- a/btgui/Gwen/Controls/TreeControl.cpp +++ b/btgui/Gwen/Controls/TreeControl.cpp @@ -204,13 +204,13 @@ bool TreeControl::OnKeyDown( bool bDown ) } return true; } - +extern int avoidUpdate; bool TreeControl::OnKeyRight( bool bDown ) { if (bDown) { - extern int avoidUpdate; + avoidUpdate = -3; ForceUpdateScrollBars(); iterate(ITERATE_ACTION_OPEN,0,0); @@ -250,7 +250,7 @@ bool TreeControl::OnKeyLeft( bool bDown ) { if (bDown) { - extern int avoidUpdate; + avoidUpdate = -3; ForceUpdateScrollBars(); diff --git a/btgui/GwenOpenGLTest/OpenGLSample.cpp b/btgui/GwenOpenGLTest/OpenGLSample.cpp index 137716af8..9ad7a009e 100644 --- a/btgui/GwenOpenGLTest/OpenGLSample.cpp +++ b/btgui/GwenOpenGLTest/OpenGLSample.cpp @@ -296,6 +296,8 @@ void keyCallback(int key, int value) } } +extern int avoidUpdate; + int main() { @@ -306,8 +308,9 @@ int main() b3gWindowConstructionInfo wci; wci.m_width = sWidth; wci.m_height = sHeight; - - window->createWindow(wci); + wci.m_resizeCallback = MyResizeCallback; + window->createWindow(wci); + window->setResizeCallback(MyResizeCallback); window->setWindowTitle("render test"); #ifndef __APPLE__ @@ -456,7 +459,7 @@ int main() pCanvas->RenderCanvas(); - extern int avoidUpdate; + if (avoidUpdate<=0) avoidUpdate++; diff --git a/btgui/OpenGLWindow/MacOpenGLWindow.mm b/btgui/OpenGLWindow/MacOpenGLWindow.mm index d765a4e78..340898aaf 100644 --- a/btgui/OpenGLWindow/MacOpenGLWindow.mm +++ b/btgui/OpenGLWindow/MacOpenGLWindow.mm @@ -91,6 +91,7 @@ float loop; // Get view dimensions in pixels // glViewport(0,0,10,10); + if (m_resizeCallback) { (*m_resizeCallback)(width,height); @@ -329,6 +330,7 @@ void MacOpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) m_internalData->m_myview = [TestView alloc]; [m_internalData->m_myview setResizeCallback:0]; + ///ci.m_resizeCallback]; [m_internalData->m_myview initWithFrame: frame]; @@ -366,6 +368,8 @@ void MacOpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) [m_internalData->m_window makeKeyAndOrderFront: nil]; [m_internalData->m_myview MakeCurrent]; + m_internalData->m_width = m_internalData->m_myview.GetWindowWidth; + m_internalData->m_height = m_internalData->m_myview.GetWindowHeight; glGenBuffers(n, vbo); checkError("glGenBuffers"); @@ -589,32 +593,32 @@ int getAsciiCodeFromVirtualKeycode(int virtualKeyCode) switch (virtualKeyCode) { - case kVK_ANSI_A : {keycode = 'A'; break;} - case kVK_ANSI_B : {keycode = 'B'; break;} - case kVK_ANSI_C : {keycode = 'C'; break;} - case kVK_ANSI_D : {keycode = 'D';break;} - case kVK_ANSI_E : {keycode = 'E'; break;} - case kVK_ANSI_F : {keycode = 'F'; break;} - case kVK_ANSI_G : {keycode = 'G'; break;} - case kVK_ANSI_H : {keycode = 'H'; break;} - case kVK_ANSI_I : {keycode = 'I'; break;} - case kVK_ANSI_J : {keycode = 'J'; break;} - case kVK_ANSI_K : {keycode = 'K'; break;} - case kVK_ANSI_L : {keycode = 'L'; break;} - case kVK_ANSI_M : {keycode = 'M'; break;} - case kVK_ANSI_N : {keycode = 'N'; break;} - case kVK_ANSI_O : {keycode = 'O'; break;} - case kVK_ANSI_P : {keycode = 'P'; break;} - case kVK_ANSI_Q : {keycode = 'Q'; break;} - case kVK_ANSI_R : {keycode = 'R'; break;} - case kVK_ANSI_S : {keycode = 'S';break;} - case kVK_ANSI_T : {keycode = 'T'; break;} - case kVK_ANSI_U : {keycode = 'U'; break;} - case kVK_ANSI_V : {keycode = 'V'; break;} - case kVK_ANSI_W : {keycode = 'W'; break;} - case kVK_ANSI_X : {keycode = 'X'; break;} - case kVK_ANSI_Y : {keycode = 'Y'; break;} - case kVK_ANSI_Z : {keycode = 'Z'; break;} + case kVK_ANSI_A : {keycode = 'a'; break;} + case kVK_ANSI_B : {keycode = 'b'; break;} + case kVK_ANSI_C : {keycode = 'c'; break;} + case kVK_ANSI_D : {keycode = 'd';break;} + case kVK_ANSI_E : {keycode = 'e'; break;} + case kVK_ANSI_F : {keycode = 'f'; break;} + case kVK_ANSI_G : {keycode = 'g'; break;} + case kVK_ANSI_H : {keycode = 'h'; break;} + case kVK_ANSI_I : {keycode = 'i'; break;} + case kVK_ANSI_J : {keycode = 'j'; break;} + case kVK_ANSI_K : {keycode = 'k'; break;} + case kVK_ANSI_L : {keycode = 'l'; break;} + case kVK_ANSI_M : {keycode = 'm'; break;} + case kVK_ANSI_N : {keycode = 'n'; break;} + case kVK_ANSI_O : {keycode = 'o'; break;} + case kVK_ANSI_P : {keycode = 'p'; break;} + case kVK_ANSI_Q : {keycode = 'q'; break;} + case kVK_ANSI_R : {keycode = 'r'; break;} + case kVK_ANSI_S : {keycode = 's';break;} + case kVK_ANSI_T : {keycode = 't'; break;} + case kVK_ANSI_U : {keycode = 'u'; break;} + case kVK_ANSI_V : {keycode = 'v'; break;} + case kVK_ANSI_W : {keycode = 'w'; break;} + case kVK_ANSI_X : {keycode = 'x'; break;} + case kVK_ANSI_Y : {keycode = 'y'; break;} + case kVK_ANSI_Z : {keycode = 'z'; break;} case kVK_ANSI_1 : {keycode = '1'; break;} case kVK_ANSI_2 : {keycode = '2'; break;} @@ -1012,6 +1016,10 @@ void MacOpenGLWindow::getMouseCoordinates(int& x, int& y) void MacOpenGLWindow::setResizeCallback(b3ResizeCallback resizeCallback) { [m_internalData->m_myview setResizeCallback:resizeCallback]; + if (resizeCallback) + { + (resizeCallback)(m_internalData->m_width,m_internalData->m_height); + } } diff --git a/btgui/OpenGLWindow/b3gWindowInterface.h b/btgui/OpenGLWindow/b3gWindowInterface.h index 2141fd65e..122d6a3c3 100644 --- a/btgui/OpenGLWindow/b3gWindowInterface.h +++ b/btgui/OpenGLWindow/b3gWindowInterface.h @@ -51,6 +51,7 @@ struct b3gWindowConstructionInfo void* m_windowHandle; const char* m_title; int m_openglVersion; + b3gWindowConstructionInfo(int width=1024, int height=768) :m_width(width), From 28f19f1bab4ef07f20e56583afae3f19e9f594cc Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Wed, 21 May 2014 09:59:24 -0700 Subject: [PATCH 064/116] improve BasicDemo, better mouse handling, add colors to drawing --- Demos/BasicDemo/BasicDemoPhysicsSetup.cpp | 4 ++-- Demos/BasicDemo/BasicDemoPhysicsSetup.h | 3 ++- Demos3/bullet2/BasicDemo/BasicDemo.cpp | 4 ++-- Demos3/bullet2/BasicDemo/BasicDemo.h | 2 +- Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp | 10 ++++++---- Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h | 13 ++++++++++++- 6 files changed, 25 insertions(+), 11 deletions(-) diff --git a/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp b/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp index f33d68e3b..c3c03ba77 100644 --- a/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp +++ b/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp @@ -39,7 +39,7 @@ void BasicDemoPhysicsSetup::initPhysics() { btScalar mass(0.); - createRigidBody(mass,groundTransform,groundShape); + createRigidBody(mass,groundTransform,groundShape, btVector4(0,0,1,1)); } @@ -99,7 +99,7 @@ btBoxShape* BasicDemoPhysicsSetup::createBoxShape(const btVector3& halfExtents) return box; } -btRigidBody* BasicDemoPhysicsSetup::createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape) +btRigidBody* BasicDemoPhysicsSetup::createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color) { btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE)); diff --git a/Demos/BasicDemo/BasicDemoPhysicsSetup.h b/Demos/BasicDemo/BasicDemoPhysicsSetup.h index e335a3861..b275a6a78 100644 --- a/Demos/BasicDemo/BasicDemoPhysicsSetup.h +++ b/Demos/BasicDemo/BasicDemoPhysicsSetup.h @@ -11,6 +11,7 @@ class btDiscreteDynamicsWorld; class btTransform; class btVector3; class btBoxShape; +#include "LinearMath/btVector3.h" #include "LinearMath/btAlignedObjectArray.h" @@ -31,7 +32,7 @@ struct BasicDemoPhysicsSetup virtual void stepSimulation(float deltaTime); - virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape); + virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color=btVector4(1,0,0,1)); virtual btBoxShape* createBoxShape(const btVector3& halfExtents); diff --git a/Demos3/bullet2/BasicDemo/BasicDemo.cpp b/Demos3/bullet2/BasicDemo/BasicDemo.cpp index f0386862b..b47fb12de 100644 --- a/Demos3/bullet2/BasicDemo/BasicDemo.cpp +++ b/Demos3/bullet2/BasicDemo/BasicDemo.cpp @@ -68,13 +68,13 @@ void BasicDemo::exitPhysics() //SimpleOpenGL3App* m_glApp; -btRigidBody* MyBasicDemoPhysicsSetup::createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape) +btRigidBody* MyBasicDemoPhysicsSetup::createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color) { btRigidBody* body = BasicDemoPhysicsSetup::createRigidBody(mass,startTransform,shape); int graphicsShapeId = shape->getUserIndex(); btAssert(graphicsShapeId>=0); btVector3 localScaling = shape->getLocalScaling(); - float color[]={0.3,0.3,1,1}; + int graphicsInstanceId = m_glApp->m_instancingRenderer->registerGraphicsInstance(graphicsShapeId,startTransform.getOrigin(),startTransform.getRotation(),color,localScaling); body->setUserIndex(graphicsInstanceId); diff --git a/Demos3/bullet2/BasicDemo/BasicDemo.h b/Demos3/bullet2/BasicDemo/BasicDemo.h index d1da7ac62..283004929 100644 --- a/Demos3/bullet2/BasicDemo/BasicDemo.h +++ b/Demos3/bullet2/BasicDemo/BasicDemo.h @@ -11,7 +11,7 @@ struct MyBasicDemoPhysicsSetup : public BasicDemoPhysicsSetup { SimpleOpenGL3App* m_glApp; - virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape); + virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color); virtual btBoxShape* createBoxShape(const btVector3& halfExtents); }; diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp index 517a9d08b..72069c2b6 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp @@ -5,7 +5,9 @@ Bullet2RigidBodyDemo::Bullet2RigidBodyDemo(SimpleOpenGL3App* app) :m_glApp(app), m_pickedBody(0), - m_pickedConstraint(0) + m_pickedConstraint(0), +m_controlPressed(false), +m_altPressed(false) { m_config = 0; m_dispatcher = 0; @@ -113,8 +115,8 @@ btVector3 Bullet2RigidBodyDemo::getRayTo(int x,int y) bool Bullet2RigidBodyDemo::mouseMoveCallback(float x,float y) { -// if (m_data->m_altPressed!=0 || m_data->m_controlPressed!=0) -// return false; + //if (m_data->m_altPressed!=0 || m_data->m_controlPressed!=0) + //return false; if (m_pickedBody && m_pickedConstraint) { @@ -143,7 +145,7 @@ bool Bullet2RigidBodyDemo::mouseButtonCallback(int button, int state, float x, f if (state==1) { - if(button==0)// && (m_data->m_altPressed==0 && m_data->m_controlPressed==0)) + if(button==0 && (!m_altPressed && !m_controlPressed)) { btVector3 camPos; m_glApp->m_instancingRenderer->getCameraPosition(camPos); diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h index 53ddbb17b..3cabd9e17 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h @@ -5,6 +5,8 @@ #include "../../AllBullet2Demos/BulletDemoInterface.h" +#include "OpenGLWindow/b3gWindowInterface.h" + class Bullet2RigidBodyDemo : public BulletDemoInterface { public: @@ -19,7 +21,8 @@ public: btVector3 m_oldPickingPos; btVector3 m_hitPos; btScalar m_oldPickingDist; - + bool m_controlPressed; + bool m_altPressed; public: @@ -35,6 +38,14 @@ public: virtual bool mouseButtonCallback(int button, int state, float x, float y); virtual bool keyboardCallback(int key, int state) { + if (key==B3G_CONTROL) + { + m_controlPressed = (state==1); + } + if (key==B3G_ALT) + { + m_altPressed = (state==1); + } return false; } From f2e54ea0a5a2ba25d01047edd784e9b0448aef6d Mon Sep 17 00:00:00 2001 From: Gregory Jaegy Date: Fri, 20 Jun 2014 09:58:31 +0200 Subject: [PATCH 065/116] fix crash on CPU not having AVX support --- src/LinearMath/btCpuFeatureUtility.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/LinearMath/btCpuFeatureUtility.h b/src/LinearMath/btCpuFeatureUtility.h index 47e5a4178..d2cab52d4 100644 --- a/src/LinearMath/btCpuFeatureUtility.h +++ b/src/LinearMath/btCpuFeatureUtility.h @@ -55,10 +55,16 @@ public: { int cpuInfo[4]; memset(cpuInfo, 0, sizeof(cpuInfo)); - unsigned long long sseExt; + unsigned long long sseExt = 0; __cpuid(cpuInfo, 1); - sseExt = _xgetbv(0); + + bool osUsesXSAVE_XRSTORE = cpuInfo[2] & (1 << 27) || false; + bool cpuAVXSuport = cpuInfo[2] & (1 << 28) || false; + if (osUsesXSAVE_XRSTORE && cpuAVXSuport) + { + sseExt = _xgetbv(0); + } const int OSXSAVEFlag = (1UL << 27); const int AVXFlag = ((1UL << 28) | OSXSAVEFlag); const int FMAFlag = ((1UL << 12) | AVXFlag | OSXSAVEFlag); From 68f798a2da883412235398c6bdc9c139bf325dd6 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 24 Jun 2014 10:14:06 -0700 Subject: [PATCH 066/116] Start re-organizing demos so the physics setup can be shared easier (explicit create graphics objects, init/exit physics etc) Add B3G_RETURN key code, only implemented in Windows so far (todo: Mac, Linux) Fix Windows key management (use WM_CHAR event instead of WM_KEYUP Add Return (OnKeyReturn) key support TreeNode, so we can select an item using the return key. --- Demos/BasicDemo/BasicDemo.cpp | 4 +- Demos/BasicDemo/BasicDemoPhysicsSetup.cpp | 106 ++--------- Demos/BasicDemo/BasicDemoPhysicsSetup.h | 75 +------- Demos/CcdPhysicsDemo/CMakeLists.txt | 5 + Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp | 159 +--------------- Demos/CcdPhysicsDemo/CcdPhysicsDemo.h | 12 +- Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp | 179 +++++++++++++++++ Demos/CcdPhysicsDemo/CcdPhysicsSetup.h | 23 +++ Demos/CommonPhysicsSetup.h | 53 ++++++ Demos3/AllBullet2Demos/BulletDemoEntries.h | 51 +++-- Demos3/AllBullet2Demos/CMakeLists.txt | 16 +- Demos3/AllBullet2Demos/main.cpp | 148 +++++++++++++- Demos3/AllBullet2Demos/premake4.lua | 18 +- Demos3/GpuDemos/gwenInternalData.h | 7 +- Demos3/GpuDemos/gwenUserInterface.cpp | 99 ++++++++-- Demos3/GpuDemos/gwenUserInterface.h | 6 +- Demos3/bullet2/BasicDemo/BasicDemo.cpp | 122 +----------- Demos3/bullet2/BasicDemo/BasicDemo.h | 18 +- .../BasicDemo/Bullet2RigidBodyDemo.cpp | 180 +++++++++--------- .../bullet2/BasicDemo/Bullet2RigidBodyDemo.h | 24 +-- Demos3/bullet2/RagdollDemo/RagdollDemo.cpp | 11 -- Demos3/bullet2/RagdollDemo/RagdollDemo.h | 15 +- btgui/Gwen/Controls/Button.h | 13 +- btgui/Gwen/Controls/TreeControl.cpp | 2 + btgui/Gwen/Controls/TreeNode.cpp | 7 + btgui/Gwen/Controls/TreeNode.h | 14 +- btgui/GwenOpenGLTest/OpenGLSample.cpp | 2 +- btgui/OpenGLWindow/Win32Window.cpp | 29 ++- btgui/OpenGLWindow/b3gWindowInterface.h | 3 +- 29 files changed, 746 insertions(+), 655 deletions(-) create mode 100644 Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp create mode 100644 Demos/CcdPhysicsDemo/CcdPhysicsSetup.h create mode 100644 Demos/CommonPhysicsSetup.h diff --git a/Demos/BasicDemo/BasicDemo.cpp b/Demos/BasicDemo/BasicDemo.cpp index 82229062c..5cdfb0f16 100644 --- a/Demos/BasicDemo/BasicDemo.cpp +++ b/Demos/BasicDemo/BasicDemo.cpp @@ -123,8 +123,8 @@ void BasicDemo::initPhysics() setShadows(true); setCameraDistance(btScalar(SCALING*50.)); - - m_physicsSetup.initPhysics(); + GraphicsPhysicsBridge gfxBridge; + m_physicsSetup.initPhysics(gfxBridge); m_dynamicsWorld = m_physicsSetup.m_dynamicsWorld; m_dynamicsWorld->setDebugDrawer(&gDebugDraw); diff --git a/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp b/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp index c3c03ba77..62fced239 100644 --- a/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp +++ b/Demos/BasicDemo/BasicDemoPhysicsSetup.cpp @@ -6,28 +6,15 @@ #define ARRAY_SIZE_X 5 #define ARRAY_SIZE_Z 5 -void BasicDemoPhysicsSetup::initPhysics() +void BasicDemoPhysicsSetup::initPhysics(GraphicsPhysicsBridge& gfxBridge) { - ///collision configuration contains default setup for memory, collision setup - m_collisionConfiguration = new btDefaultCollisionConfiguration(); - //m_collisionConfiguration->setConvexConvexMultipointIterations(); + createEmptyDynamicsWorld(); - ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) - m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); - - m_broadphase = new btDbvtBroadphase(); - - ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) - btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; - m_solver = sol; - - m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); - - - m_dynamicsWorld->setGravity(btVector3(0,-10,0)); ///create a few basic rigid bodies btBoxShape* groundShape = createBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.))); + gfxBridge.createCollisionShapeGraphicsObject(groundShape); + //groundShape->initializePolyhedralFeatures(); // btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50); @@ -39,7 +26,8 @@ void BasicDemoPhysicsSetup::initPhysics() { btScalar mass(0.); - createRigidBody(mass,groundTransform,groundShape, btVector4(0,0,1,1)); + btRigidBody* body = createRigidBody(mass,groundTransform,groundShape, btVector4(0,0,1,1)); + gfxBridge.createRigidBodyGraphicsObject(body, btVector3(0, 1, 0)); } @@ -48,6 +36,8 @@ void BasicDemoPhysicsSetup::initPhysics() // Re-using the same collision is better for memory usage and performance btBoxShape* colShape = createBoxShape(btVector3(1,1,1)); + gfxBridge.createCollisionShapeGraphicsObject(colShape); + //btCollisionShape* colShape = new btSphereShape(btScalar(1.)); m_collisionShapes.push_back(colShape); @@ -77,7 +67,9 @@ void BasicDemoPhysicsSetup::initPhysics() btScalar(2.0*j))); - createRigidBody(mass,startTransform,colShape); + btRigidBody* body = createRigidBody(mass,startTransform,colShape); + gfxBridge.createRigidBodyGraphicsObject(body, btVector3(1, 1, 0)); + } } } @@ -88,84 +80,10 @@ void BasicDemoPhysicsSetup::initPhysics() -void BasicDemoPhysicsSetup::stepSimulation(float deltaTime) -{ - m_dynamicsWorld->stepSimulation(deltaTime); -} - -btBoxShape* BasicDemoPhysicsSetup::createBoxShape(const btVector3& halfExtents) -{ - btBoxShape* box = new btBoxShape(halfExtents); - return box; -} - -btRigidBody* BasicDemoPhysicsSetup::createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color) -{ - btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE)); - - //rigidbody is dynamic if and only if mass is non zero, otherwise static - bool isDynamic = (mass != 0.f); - - btVector3 localInertia(0,0,0); - if (isDynamic) - shape->calculateLocalInertia(mass,localInertia); - - //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects - -#define USE_MOTIONSTATE 1 -#ifdef USE_MOTIONSTATE - btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); - - btRigidBody::btRigidBodyConstructionInfo cInfo(mass,myMotionState,shape,localInertia); - - btRigidBody* body = new btRigidBody(cInfo); - //body->setContactProcessingThreshold(m_defaultContactProcessingThreshold); - -#else - btRigidBody* body = new btRigidBody(mass,0,shape,localInertia); - body->setWorldTransform(startTransform); -#endif// - - body->setUserIndex(-1); - m_dynamicsWorld->addRigidBody(body); - return body; -} -void BasicDemoPhysicsSetup::exitPhysics() -{ - //cleanup in the reverse order of creation/initialization - - //remove the rigidbodies from the dynamics world and delete them - int i; - for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) - { - btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; - btRigidBody* body = btRigidBody::upcast(obj); - if (body && body->getMotionState()) - { - delete body->getMotionState(); - } - m_dynamicsWorld->removeCollisionObject( obj ); - delete obj; - } - //delete collision shapes - for (int j=0;j m_collisionShapes; - btBroadphaseInterface* m_broadphase; - btCollisionDispatcher* m_dispatcher; - btConstraintSolver* m_solver; - btDefaultCollisionConfiguration* m_collisionConfiguration; - btDiscreteDynamicsWorld* m_dynamicsWorld; - virtual void initPhysics(); - - virtual void exitPhysics(); - - virtual void stepSimulation(float deltaTime); - - virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color=btVector4(1,0,0,1)); - - virtual btBoxShape* createBoxShape(const btVector3& halfExtents); - -/* - - //bodies - virtual btRigidBody* createRigidBody(bool isDynamic, btScalar mass, const btTransform& startTransform, btCollisionShape* shape,const char* bodyName); - virtual btCollisionObject* createCollisionObject( const btTransform& startTransform, btCollisionShape* shape,const char* bodyName); - - ///shapes - - virtual btCollisionShape* createPlaneShape(const btVector3& planeNormal,btScalar planeConstant); - - virtual btCollisionShape* createSphereShape(btScalar radius); - virtual btCollisionShape* createCapsuleShapeX(btScalar radius, btScalar height); - virtual btCollisionShape* createCapsuleShapeY(btScalar radius, btScalar height); - virtual btCollisionShape* createCapsuleShapeZ(btScalar radius, btScalar height); - - virtual btCollisionShape* createCylinderShapeX(btScalar radius,btScalar height); - virtual btCollisionShape* createCylinderShapeY(btScalar radius,btScalar height); - virtual btCollisionShape* createCylinderShapeZ(btScalar radius,btScalar height); - virtual btCollisionShape* createConeShapeX(btScalar radius,btScalar height); - virtual btCollisionShape* createConeShapeY(btScalar radius,btScalar height); - virtual btCollisionShape* createConeShapeZ(btScalar radius,btScalar height); - virtual class btTriangleIndexVertexArray* createTriangleMeshContainer(); - virtual btBvhTriangleMeshShape* createBvhTriangleMeshShape(btStridingMeshInterface* trimesh, btOptimizedBvh* bvh); - virtual btCollisionShape* createConvexTriangleMeshShape(btStridingMeshInterface* trimesh); - virtual btGImpactMeshShape* createGimpactShape(btStridingMeshInterface* trimesh); - virtual btStridingMeshInterfaceData* createStridingMeshInterfaceData(btStridingMeshInterfaceData* interfaceData); - - virtual class btConvexHullShape* createConvexHullShape(); - virtual class btCompoundShape* createCompoundShape(); - virtual class btScaledBvhTriangleMeshShape* createScaledTrangleMeshShape(btBvhTriangleMeshShape* meshShape,const btVector3& localScalingbtBvhTriangleMeshShape); - - virtual class btMultiSphereShape* createMultiSphereShape(const btVector3* positions,const btScalar* radi,int numSpheres); - - virtual btTriangleIndexVertexArray* createMeshInterface(btStridingMeshInterfaceData& meshData); - - ///acceleration and connectivity structures - virtual btOptimizedBvh* createOptimizedBvh(); - virtual btTriangleInfoMap* createTriangleInfoMap(); - - ///constraints - virtual btPoint2PointConstraint* createPoint2PointConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB); - virtual btPoint2PointConstraint* createPoint2PointConstraint(btRigidBody& rbA,const btVector3& pivotInA); - virtual btHingeConstraint* createHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA=false); - virtual btHingeConstraint* createHingeConstraint(btRigidBody& rbA,const btTransform& rbAFrame, bool useReferenceFrameA=false); - virtual btConeTwistConstraint* createConeTwistConstraint(btRigidBody& rbA,btRigidBody& rbB,const btTransform& rbAFrame, const btTransform& rbBFrame); - virtual btConeTwistConstraint* createConeTwistConstraint(btRigidBody& rbA,const btTransform& rbAFrame); - virtual btGeneric6DofConstraint* createGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); - virtual btGeneric6DofConstraint* createGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB); - virtual btGeneric6DofSpringConstraint* createGeneric6DofSpringConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); - virtual btSliderConstraint* createSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); - virtual btSliderConstraint* createSliderConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameA); - virtual btGearConstraint* createGearConstraint(btRigidBody& rbA, btRigidBody& rbB, const btVector3& axisInA,const btVector3& axisInB, btScalar ratio); -*/ + virtual void initPhysics(GraphicsPhysicsBridge& gfxBridge); }; diff --git a/Demos/CcdPhysicsDemo/CMakeLists.txt b/Demos/CcdPhysicsDemo/CMakeLists.txt index f7ee06103..7ce0d25ef 100644 --- a/Demos/CcdPhysicsDemo/CMakeLists.txt +++ b/Demos/CcdPhysicsDemo/CMakeLists.txt @@ -25,12 +25,17 @@ IF (WIN32) ADD_EXECUTABLE(AppCcdPhysicsDemo main.cpp CcdPhysicsDemo.cpp + CcdPhysicsSetup.h + CcdPhysicsSetup.cpp ${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc ) ELSE() ADD_EXECUTABLE(AppCcdPhysicsDemo main.cpp CcdPhysicsDemo.cpp + CcdPhysicsSetup.h + CcdPhysicsSetup.cpp + ) ENDIF() diff --git a/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp b/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp index c0acf6551..afe53260e 100644 --- a/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp +++ b/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp @@ -167,26 +167,11 @@ void CcdPhysicsDemo::initPhysics() m_ShootBoxInitialSpeed = 4000.f; m_defaultContactProcessingThreshold = 0.f; - - ///collision configuration contains default setup for memory, collision setup - m_collisionConfiguration = new btDefaultCollisionConfiguration(); -// m_collisionConfiguration->setConvexConvexMultipointIterations(); - - ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) - m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); - //m_dispatcher->registerCollisionCreateFunc(BOX_SHAPE_PROXYTYPE,BOX_SHAPE_PROXYTYPE,m_collisionConfiguration->getCollisionAlgorithmCreateFunc(CONVEX_SHAPE_PROXYTYPE,CONVEX_SHAPE_PROXYTYPE)); - - m_broadphase = new btDbvtBroadphase(); - - ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) - btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; - m_solver = sol; - - m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + GraphicsPhysicsBridge bridge; + m_physicsSetup.initPhysics(bridge); + m_dynamicsWorld = m_physicsSetup.m_dynamicsWorld; m_dynamicsWorld->getSolverInfo().m_solverMode |=SOLVER_USE_2_FRICTION_DIRECTIONS|SOLVER_RANDMIZE_ORDER; - - - + m_dynamicsWorld ->setDebugDrawer(&sDebugDrawer); //m_dynamicsWorld->getSolverInfo().m_splitImpulse=false; @@ -203,108 +188,6 @@ void CcdPhysicsDemo::initPhysics() m_dynamicsWorld->setGravity(btVector3(0,-10,0)); - ///create a few basic rigid bodies - btBoxShape* box = new btBoxShape(btVector3(btScalar(110.),btScalar(1.),btScalar(110.))); -// box->initializePolyhedralFeatures(); - btCollisionShape* groundShape = box; - -// btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50); - - m_collisionShapes.push_back(groundShape); - //m_collisionShapes.push_back(new btCylinderShape (btVector3(CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS))); - m_collisionShapes.push_back(new btBoxShape (btVector3(CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS))); - - btTransform groundTransform; - groundTransform.setIdentity(); - //groundTransform.setOrigin(btVector3(5,5,5)); - - //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here: - { - btScalar mass(0.); - - //rigidbody is dynamic if and only if mass is non zero, otherwise static - bool isDynamic = (mass != 0.f); - - btVector3 localInertia(0,0,0); - if (isDynamic) - groundShape->calculateLocalInertia(mass,localInertia); - - //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects - btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); - btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); - btRigidBody* body = new btRigidBody(rbInfo); - body->setFriction(0.5); - //body->setRollingFriction(0.3); - //add the body to the dynamics world - m_dynamicsWorld->addRigidBody(body); - } - - - { - //create a few dynamic rigidbodies - // Re-using the same collision is better for memory usage and performance - - btCollisionShape* colShape = new btBoxShape(btVector3(1,1,1)); - - //btCollisionShape* colShape = new btSphereShape(btScalar(1.)); - m_collisionShapes.push_back(colShape); - - /// Create Dynamic Objects - btTransform startTransform; - startTransform.setIdentity(); - - btScalar mass(1.f); - - //rigidbody is dynamic if and only if mass is non zero, otherwise static - bool isDynamic = (mass != 0.f); - - btVector3 localInertia(0,0,0); - if (isDynamic) - colShape->calculateLocalInertia(mass,localInertia); - - int gNumObjects = 120;//120; - int i; - for (i=0;i3) - { - col=11; - row2 |=1; - } - - btVector3 pos(col*2*CUBE_HALF_EXTENTS + (row2%2)*CUBE_HALF_EXTENTS, - row*2*CUBE_HALF_EXTENTS+CUBE_HALF_EXTENTS+EXTRA_HEIGHT,0); - - trans.setOrigin(pos); - - float mass = 1.f; - - btRigidBody* body = localCreateRigidBody(mass,trans,shape); - body->setAnisotropicFriction(shape->getAnisotropicRollingFrictionDirection(),btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); - body->setFriction(0.5); - - //body->setRollingFriction(.3); - ///when using m_ccdMode - if (m_ccdMode==USE_CCD) - { - body->setCcdMotionThreshold(CUBE_HALF_EXTENTS); - body->setCcdSweptSphereRadius(0.9*CUBE_HALF_EXTENTS); - } - } - } - } void CcdPhysicsDemo::clientResetScene() @@ -381,40 +264,8 @@ void CcdPhysicsDemo::shootBox(const btVector3& destination) void CcdPhysicsDemo::exitPhysics() { + m_physicsSetup.exitPhysics(); - //cleanup in the reverse order of creation/initialization - - //remove the rigidbodies from the dynamics world and delete them - int i; - for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) - { - btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; - btRigidBody* body = btRigidBody::upcast(obj); - if (body && body->getMotionState()) - { - delete body->getMotionState(); - } - m_dynamicsWorld->removeCollisionObject( obj ); - delete obj; - } - - //delete collision shapes - for (int j=0;j m_collisionShapes; - - btBroadphaseInterface* m_broadphase; - - btCollisionDispatcher* m_dispatcher; - - btConstraintSolver* m_solver; + CcdPhysicsSetup m_physicsSetup; enum { @@ -54,7 +49,6 @@ class CcdPhysicsDemo : public PlatformDemoApplication }; int m_ccdMode; - btDefaultCollisionConfiguration* m_collisionConfiguration; public: diff --git a/Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp b/Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp new file mode 100644 index 000000000..bbbe0088c --- /dev/null +++ b/Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp @@ -0,0 +1,179 @@ + +#include "CcdPhysicsSetup.h" +#include "btBulletDynamicsCommon.h" +#define CUBE_HALF_EXTENTS 1.f +#define EXTRA_HEIGHT 1.f + + +void KinematicObjectSetup::initPhysics(GraphicsPhysicsBridge& gfxBridge) +{ + createEmptyDynamicsWorld(); + { + btBoxShape* box = new btBoxShape(btVector3(btScalar(10.), btScalar(1.), btScalar(10.))); + gfxBridge.createCollisionShapeGraphicsObject(box); + btTransform startTrans; + startTrans.setIdentity(); + startTrans.setOrigin(btVector3(0, -1, 0)); + btRigidBody* body = createRigidBody(0, startTrans, box); + body->setMotionState(0); + body->setFriction(1); + body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT); + body->setActivationState(DISABLE_DEACTIVATION); + + gfxBridge.createRigidBodyGraphicsObject(body, btVector3(0,1,0)); + } + { + btBoxShape* box = new btBoxShape(btVector3(btScalar(1.), btScalar(1.), btScalar(1.))); + gfxBridge.createCollisionShapeGraphicsObject(box); + btTransform startTrans; + startTrans.setIdentity(); + startTrans.setOrigin(btVector3(0, 1, 0)); + btRigidBody* body = createRigidBody(1, startTrans, box); + body->setFriction(1); + body->setActivationState(DISABLE_DEACTIVATION); + gfxBridge.createRigidBodyGraphicsObject(body, btVector3(1, 1, 0)); + } +} + +void KinematicObjectSetup::stepSimulation(float deltaTime) +{ + if (m_dynamicsWorld) + { + btCollisionObject* colObj = m_dynamicsWorld->getCollisionObjectArray()[0]; + btRigidBody* body = btRigidBody::upcast(colObj); + if (body) + { + btMotionState* ms = body->getMotionState(); + + btTransform startTrans; + startTrans.setIdentity(); + static float time = 0.f; + time += 0.01f; + static float xPos = 0.f; + xPos = sinf(time)*10.f; + startTrans.setOrigin(btVector3(xPos, -1, 0)); + if (ms) + { + + ms->setWorldTransform(startTrans); + } + else + { + body->setWorldTransform(startTrans); + } + } + m_dynamicsWorld->stepSimulation(deltaTime); + } +} + +void CcdPhysicsSetup::initPhysics(GraphicsPhysicsBridge& gfxBridge) +{ + createEmptyDynamicsWorld(); + + + ///create a few basic rigid bodies + btBoxShape* box = new btBoxShape(btVector3(btScalar(110.), btScalar(1.), btScalar(110.))); + gfxBridge.createCollisionShapeGraphicsObject(box); + // box->initializePolyhedralFeatures(); + btCollisionShape* groundShape = box; + + + m_collisionShapes.push_back(groundShape); + //m_collisionShapes.push_back(new btCylinderShape (btVector3(CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS))); + m_collisionShapes.push_back(new btBoxShape(btVector3(CUBE_HALF_EXTENTS, CUBE_HALF_EXTENTS, CUBE_HALF_EXTENTS))); + + btTransform groundTransform; + groundTransform.setIdentity(); + //groundTransform.setOrigin(btVector3(5,5,5)); + + //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here: + { + btScalar mass(0.); + + //rigidbody is dynamic if and only if mass is non zero, otherwise static + bool isDynamic = (mass != 0.f); + + btVector3 localInertia(0, 0, 0); + if (isDynamic) + groundShape->calculateLocalInertia(mass, localInertia); + + //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects + btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); + btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, groundShape, localInertia); + btRigidBody* body = new btRigidBody(rbInfo); + gfxBridge.createRigidBodyGraphicsObject(body, btVector3(0, 1, 0)); + body->setFriction(0.5); + //body->setRollingFriction(0.3); + //add the body to the dynamics world + m_dynamicsWorld->addRigidBody(body); + } + + + { + //create a few dynamic rigidbodies + // Re-using the same collision is better for memory usage and performance + + btCollisionShape* colShape = new btBoxShape(btVector3(1, 1, 1)); + gfxBridge.createCollisionShapeGraphicsObject(colShape); + //btCollisionShape* colShape = new btSphereShape(btScalar(1.)); + m_collisionShapes.push_back(colShape); + + /// Create Dynamic Objects + btTransform startTransform; + startTransform.setIdentity(); + + btScalar mass(1.f); + + //rigidbody is dynamic if and only if mass is non zero, otherwise static + bool isDynamic = (mass != 0.f); + + btVector3 localInertia(0, 0, 0); + if (isDynamic) + colShape->calculateLocalInertia(mass, localInertia); + + int gNumObjects = 120;//120; + int i; + for (i = 0; i3) + { + col = 11; + row2 |= 1; + } + + btVector3 pos(col * 2 * CUBE_HALF_EXTENTS + (row2 % 2)*CUBE_HALF_EXTENTS, + row * 2 * CUBE_HALF_EXTENTS + CUBE_HALF_EXTENTS + EXTRA_HEIGHT, 0); + + trans.setOrigin(pos); + + float mass = 1.f; + + btRigidBody* body = createRigidBody(mass, trans, shape); + gfxBridge.createRigidBodyGraphicsObject(body, btVector3(1, 1, 0)); + + body->setAnisotropicFriction(shape->getAnisotropicRollingFrictionDirection(), btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION); + body->setFriction(0.5); + + //body->setRollingFriction(.3); + ///when using m_ccdMode + //if (m_ccdMode == USE_CCD) + { + body->setCcdMotionThreshold(CUBE_HALF_EXTENTS); + body->setCcdSweptSphereRadius(0.9*CUBE_HALF_EXTENTS); + } + } + } + +} diff --git a/Demos/CcdPhysicsDemo/CcdPhysicsSetup.h b/Demos/CcdPhysicsDemo/CcdPhysicsSetup.h new file mode 100644 index 000000000..7355c3e3c --- /dev/null +++ b/Demos/CcdPhysicsDemo/CcdPhysicsSetup.h @@ -0,0 +1,23 @@ + +#ifndef CCD_PHYSICS_SETUP_H +#define CCD_PHYSICS_SETUP_H + + +#include "../CommonRigidBodySetup.h" + +struct CcdPhysicsSetup : public CommonRigidBodySetup +{ + virtual void initPhysics(GraphicsPhysicsBridge& gfxBridge); + +}; + +struct KinematicObjectSetup : public CommonRigidBodySetup +{ + virtual void initPhysics(GraphicsPhysicsBridge& gfxBridge); + + virtual void stepSimulation(float deltaTime); + +}; + + +#endif //CCD_PHYSICS_SETUP_H diff --git a/Demos/CommonPhysicsSetup.h b/Demos/CommonPhysicsSetup.h new file mode 100644 index 000000000..6be944e2c --- /dev/null +++ b/Demos/CommonPhysicsSetup.h @@ -0,0 +1,53 @@ + +#ifndef COMMON_PHYSICS_SETUP_H +#define COMMON_PHYSICS_SETUP_H + +class btRigidBody; +class btBoxShape; +class btTransform; +class btCollisionShape; +#include "LinearMath/btVector3.h" +class btDiscreteDynamicsWorld; + +///The GraphicsPhysicsBridge let's the graphics engine create graphics representation and synchronize +struct GraphicsPhysicsBridge +{ + virtual void createRigidBodyGraphicsObject(btRigidBody* body,const btVector3& color) + { + } + virtual void createCollisionShapeGraphicsObject(btCollisionShape* collisionShape) + { + } + virtual void syncPhysicsToGraphics(const btDiscreteDynamicsWorld* rbWorld) + { + } +}; + +struct CommonPhysicsSetup +{ +public: + + virtual ~CommonPhysicsSetup() {} + + virtual void initPhysics(GraphicsPhysicsBridge& gfxBridge) = 0; + + virtual void exitPhysics()=0; + + virtual void stepSimulation(float deltaTime)=0; + + virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) = 0; + virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld)=0; + virtual void removePickingConstraint() = 0; + + virtual void syncPhysicsToGraphics(GraphicsPhysicsBridge& gfxBridge) = 0; + + virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color=btVector4(1,0,0,1))=0; + + virtual btBoxShape* createBoxShape(const btVector3& halfExtents)=0; +}; + + + +#endif //COMMON_PHYSICS_SETUP_H + + diff --git a/Demos3/AllBullet2Demos/BulletDemoEntries.h b/Demos3/AllBullet2Demos/BulletDemoEntries.h index c603a2785..84334b0c3 100644 --- a/Demos3/AllBullet2Demos/BulletDemoEntries.h +++ b/Demos3/AllBullet2Demos/BulletDemoEntries.h @@ -11,9 +11,23 @@ #include "../bullet2/RagdollDemo/RagdollDemo.h" #include "../bullet2/LuaDemo/LuaDemo.h" #include "../bullet2/ChainDemo/ChainDemo.h" +#include "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h" + +static BulletDemoInterface* MyCcdPhysicsDemoCreateFunc(SimpleOpenGL3App* app) +{ + CommonPhysicsSetup* physicsSetup = new CcdPhysicsSetup(); + return new BasicDemo(app, physicsSetup); +} + +static BulletDemoInterface* MyKinematicObjectCreateFunc(SimpleOpenGL3App* app) +{ + CommonPhysicsSetup* physicsSetup = new KinematicObjectSetup(); + return new BasicDemo(app, physicsSetup); +} struct BulletDemoEntry { + int m_menuLevel; const char* m_name; BulletDemoInterface::CreateFunc* m_createFunc; }; @@ -23,23 +37,28 @@ static BulletDemoEntry allDemos[]= { //{"emptydemo",EmptyBulletDemo::MyCreateFunc}, - {"BasicDemo",BasicDemo::MyCreateFunc}, - - - {"ChainDemo",ChainDemo::MyCreateFunc}, - {"SIHingeDemo",HingeDemo::SICreateFunc}, - {"PGSHingeDemo",HingeDemo::PGSCreateFunc}, - {"DantzigHingeDemo",HingeDemo::DantzigCreateFunc}, - {"LemkeHingeDemo",HingeDemo::LemkeCreateFunc}, - {"InertiaHingeDemo",HingeDemo::InertiaCreateFunc}, - {"ABMHingeDemo",HingeDemo::FeatherstoneCreateFunc}, - - - {"Ragdoll",RagDollDemo::MyCreateFunc}, - {"MultiBody1",FeatherstoneDemo1::MyCreateFunc}, -// {"MultiBody2",FeatherstoneDemo2::MyCreateFunc}, + {0,"API Demos", 0}, - {"MultiDofDemo",MultiDofDemo::MyCreateFunc}, + {1,"BasicDemo",BasicDemo::MyCreateFunc}, + { 1, "CcdDemo", MyCcdPhysicsDemoCreateFunc }, + { 1, "Kinematic", MyKinematicObjectCreateFunc }, + +/* {1,"ChainDemo",ChainDemo::MyCreateFunc}, +// {0, "Stress tests", 0 }, + + {1,"SIHingeDemo",HingeDemo::SICreateFunc}, + {1,"PGSHingeDemo",HingeDemo::PGSCreateFunc}, + {1,"DantzigHingeDemo",HingeDemo::DantzigCreateFunc}, + {1,"LemkeHingeDemo",HingeDemo::LemkeCreateFunc}, + {1,"InertiaHingeDemo",HingeDemo::InertiaCreateFunc}, + {1,"ABMHingeDemo",HingeDemo::FeatherstoneCreateFunc}, + + {1,"Ragdoll",RagDollDemo::MyCreateFunc}, + */ + { 0, "Multibody" ,0}, + {1,"MultiBody1",FeatherstoneDemo1::MyCreateFunc}, +// {"MultiBody2",FeatherstoneDemo2::MyCreateFunc}, + {1,"MultiDofDemo",MultiDofDemo::MyCreateFunc}, // {"LuaDemo",LuaDemo::MyCreateFunc} }; diff --git a/Demos3/AllBullet2Demos/CMakeLists.txt b/Demos3/AllBullet2Demos/CMakeLists.txt index 06557e166..f4153f67d 100644 --- a/Demos3/AllBullet2Demos/CMakeLists.txt +++ b/Demos3/AllBullet2Demos/CMakeLists.txt @@ -14,18 +14,22 @@ SET(App_AllBullet2Demos_SRCS ../bullet2/BasicDemo/Bullet2RigidBodyDemo.h ../../Demos/BasicDemo/BasicDemoPhysicsSetup.cpp ../../Demos/BasicDemo/BasicDemoPhysicsSetup.h + ../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp + ../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h ../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp ../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h ../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.cpp ../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.h ../bullet2/BasicDemo/BasicDemo.cpp ../bullet2/BasicDemo/BasicDemo.h - ../bullet2/BasicDemo/HingeDemo.cpp - ../bullet2/BasicDemo/HingeDemo.h - ../bullet2/ChainDemo/ChainDemo.cpp - ../bullet2/ChainDemo/ChainDemo.h - ../bullet2/RagdollDemo/RagdollDemo.cpp - ../bullet2/RagdollDemo/RagdollDemo.h +# the next few demos are not converted to 'newer' structure yet +# target is to convert all Bullet 2 demos in new structure, but need to settle down on features +# ../bullet2/BasicDemo/HingeDemo.cpp +# ../bullet2/BasicDemo/HingeDemo.h +# ../bullet2/ChainDemo/ChainDemo.cpp +# ../bullet2/ChainDemo/ChainDemo.h +# ../bullet2/RagdollDemo/RagdollDemo.cpp +# ../bullet2/RagdollDemo/RagdollDemo.h # ../bullet2/LuaDemo/LuaDemo.cpp # ../bullet2/LuaDemo/LuaDemo.h ../GpuDemos/gwenUserInterface.cpp diff --git a/Demos3/AllBullet2Demos/main.cpp b/Demos3/AllBullet2Demos/main.cpp index 2efe840f7..4029b2bac 100644 --- a/Demos3/AllBullet2Demos/main.cpp +++ b/Demos3/AllBullet2Demos/main.cpp @@ -2,7 +2,7 @@ #include "Bullet3Common/b3Vector3.h" #include "assert.h" #include - +#include "../GpuDemos/gwenInternalData.h" #include "../GpuDemos/gwenUserInterface.h" #include "BulletDemoEntries.h" #include "../../btgui/Timing/b3Clock.h" @@ -11,6 +11,7 @@ const char* startFileName = "bulletDemo.txt"; static SimpleOpenGL3App* app=0; static GwenUserInterface* gui = 0; static int sCurrentDemoIndex = 0; +static int sCurrentHightlighted = 0; static BulletDemoInterface* sCurrentDemo = 0; static b3AlignedObjectArray allNames; @@ -22,11 +23,18 @@ static bool pauseSimulation=false; void MyKeyboardCallback(int key, int state) { + //printf("key=%d, state=%d\n", key, state); bool handled = false; - if (sCurrentDemo) + if (gui) + { + + handled = gui->keyboardCallback(key, state); + } + if (!handled && sCurrentDemo) { handled = sCurrentDemo->keyboardCallback(key,state); } + //checkout: is it desired to ignore keys, if the demo already handles them? //if (handled) // return; @@ -130,6 +138,88 @@ void MyComboBoxCallback(int comboId, const char* item) } + +struct MyMenuItemHander :public Gwen::Event::Handler +{ + int m_buttonId; + + MyMenuItemHander( int buttonId) + :m_buttonId(buttonId) + { + } + + void onButtonA(Gwen::Controls::Base* pControl) + { + const Gwen::String& name = pControl->GetName(); + Gwen::Controls::TreeNode* node = (Gwen::Controls::TreeNode*)pControl; + Gwen::Controls::Label* l = node->GetButton(); + + Gwen::UnicodeString la = node->GetButton()->GetText();// node->GetButton()->GetName();// GetText(); + Gwen::String laa = Gwen::Utility::UnicodeToString(la); + const char* ha = laa.c_str(); + + //printf("selected %s\n", ha); + //int dep = but->IsDepressed(); + //int tog = but->GetToggleState(); +// if (m_data->m_toggleButtonCallback) + // (*m_data->m_toggleButtonCallback)(m_buttonId, tog); + } + void onButtonB(Gwen::Controls::Base* pControl) + { + Gwen::Controls::Label* label = (Gwen::Controls::Label*) pControl; + Gwen::UnicodeString la = label->GetText();// node->GetButton()->GetName();// GetText(); + Gwen::String laa = Gwen::Utility::UnicodeToString(la); + const char* ha = laa.c_str(); + + + selectDemo(sCurrentHightlighted); + saveCurrentDemoEntry(sCurrentDemoIndex, startFileName); + } + void onButtonC(Gwen::Controls::Base* pControl) + { + Gwen::Controls::Label* label = (Gwen::Controls::Label*) pControl; + Gwen::UnicodeString la = label->GetText();// node->GetButton()->GetName();// GetText(); + Gwen::String laa = Gwen::Utility::UnicodeToString(la); + const char* ha = laa.c_str(); + + +// printf("onButtonC ! %s\n", ha); + } + void onButtonD(Gwen::Controls::Base* pControl) + { +/* Gwen::Controls::Label* label = (Gwen::Controls::Label*) pControl; + Gwen::UnicodeString la = label->GetText();// node->GetButton()->GetName();// GetText(); + Gwen::String laa = Gwen::Utility::UnicodeToString(la); + const char* ha = laa.c_str(); + */ + + // printf("onKeyReturn ! \n"); + selectDemo(sCurrentHightlighted); + saveCurrentDemoEntry(sCurrentDemoIndex, startFileName); + + } + + void onButtonE(Gwen::Controls::Base* pControl) + { + // printf("select %d\n",m_buttonId); + sCurrentHightlighted = m_buttonId; + } + + void onButtonF(Gwen::Controls::Base* pControl) + { + //printf("selection changed!\n"); + } + + void onButtonG(Gwen::Controls::Base* pControl) + { + //printf("onButtonG !\n"); + } + + + +}; + + int main(int argc, char* argv[]) { b3Clock clock; @@ -152,22 +242,66 @@ int main(int argc, char* argv[]) sth_stash* fontstash=app->getFontStash(); gui = new GwenUserInterface; gui->init(width,height,fontstash,app->m_window->getRetinaScale()); - +// gui->getInternalData()->m_explorerPage + Gwen::Controls::TreeControl* tree = gui->getInternalData()->m_explorerTreeCtrl; int numDemos = sizeof(allDemos)/sizeof(BulletDemoEntry); - for (int i=0;ionReturnKeyDown.Add(handler2, &MyMenuItemHander::onButtonD); + + for (int d = 0; dAddNode(nodeUText); + if (d == selectedDemo) + { + pNode->SetSelected(true); + tree->ExpandAll(); + selectDemo(d); + + + } + MyMenuItemHander* handler = new MyMenuItemHander(d); + pNode->onNamePress.Add(handler, &MyMenuItemHander::onButtonA); + pNode->GetButton()->onDoubleClick.Add(handler, &MyMenuItemHander::onButtonB); + pNode->GetButton()->onDown.Add(handler, &MyMenuItemHander::onButtonC); + pNode->onSelect.Add(handler, &MyMenuItemHander::onButtonE); + pNode->onReturnKeyDown.Add(handler, &MyMenuItemHander::onButtonG); + pNode->onSelectChange.Add(handler, &MyMenuItemHander::onButtonF); +// pNode->onKeyReturn.Add(handler, &MyMenuItemHander::onButtonD); +// pNode->GetButton()->onKeyboardReturn.Add(handler, &MyMenuItemHander::onButtonD); + // pNode->onNamePress.Add(handler, &MyMenuItemHander::onButtonD); +// pNode->onKeyboardPressed.Add(handler, &MyMenuItemHander::onButtonD); +// pNode->OnKeyPress + } + else + { + curNode = tree->AddNode(nodeUText); + } + } + +/* for (int i=0;iregisterComboBox(DEMO_SELECTION_COMBOBOX,allNames.size(),&allNames[0],sCurrentDemoIndex); //const char* names2[] = {"comboF", "comboG","comboH"}; //gui->registerComboBox(2,3,&names2[0],0); gui->setComboBoxCallback(MyComboBoxCallback); - + */ unsigned long int prevTimeInMicroseconds = clock.getTimeMicroseconds(); do diff --git a/Demos3/AllBullet2Demos/premake4.lua b/Demos3/AllBullet2Demos/premake4.lua index 948199b39..e9a3a3d59 100644 --- a/Demos3/AllBullet2Demos/premake4.lua +++ b/Demos3/AllBullet2Demos/premake4.lua @@ -25,21 +25,23 @@ "../bullet2/BasicDemo/Bullet2RigidBodyDemo.h", "../../Demos/BasicDemo/BasicDemoPhysicsSetup.cpp", "../../Demos/BasicDemo/BasicDemoPhysicsSetup.h", + "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp", + "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h", "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp", "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h", "../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.cpp", "../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.h", "../bullet2/BasicDemo/BasicDemo.cpp", "../bullet2/BasicDemo/BasicDemo.h", - "../bullet2/BasicDemo/HingeDemo.cpp", - "../bullet2/BasicDemo/HingeDemo.h", - "../bullet2/ChainDemo/ChainDemo.cpp", - "../bullet2/ChainDemo/ChainDemo.h", +-- "../bullet2/BasicDemo/HingeDemo.cpp", +-- "../bullet2/BasicDemo/HingeDemo.h", +-- "../bullet2/ChainDemo/ChainDemo.cpp", +-- "../bullet2/ChainDemo/ChainDemo.h", - "../bullet2/RagdollDemo/RagdollDemo.cpp", - "../bullet2/RagdollDemo/RagdollDemo.h", - "../bullet2/LuaDemo/LuaDemo.cpp", - "../bullet2/LuaDemo/LuaDemo.h", +-- "../bullet2/RagdollDemo/RagdollDemo.cpp", +-- "../bullet2/RagdollDemo/RagdollDemo.h", +-- "../bullet2/LuaDemo/LuaDemo.cpp", +-- "../bullet2/LuaDemo/LuaDemo.h", "../../src/Bullet3Common/**.cpp", diff --git a/Demos3/GpuDemos/gwenInternalData.h b/Demos3/GpuDemos/gwenInternalData.h index 5643f2316..11b6be228 100644 --- a/Demos3/GpuDemos/gwenInternalData.h +++ b/Demos3/GpuDemos/gwenInternalData.h @@ -26,6 +26,7 @@ #include "Gwen/Controls/ListBox.h" #include "Gwen/Skins/Simple.h" //#include "Gwen/Skins/TexturedBase.h" +#include "gwenUserInterface.h" struct GwenInternalData @@ -36,12 +37,14 @@ struct GwenInternalData Gwen::Controls::Canvas* pCanvas; GLPrimitiveRenderer* m_primRenderer; Gwen::Controls::TabButton* m_demoPage; + Gwen::Controls::TabButton* m_explorerPage; + Gwen::Controls::TreeControl* m_explorerTreeCtrl; + int m_curYposition; Gwen::Controls::Label* m_rightStatusBar; Gwen::Controls::Label* m_leftStatusBar; - - b3AlignedObjectArray m_handlers; + b3AlignedObjectArray m_handlers; b3ToggleButtonCallback m_toggleButtonCallback; b3ComboBoxCallback m_comboBoxCallback; diff --git a/Demos3/GpuDemos/gwenUserInterface.cpp b/Demos3/GpuDemos/gwenUserInterface.cpp index 2a9ed96b4..28204e09d 100644 --- a/Demos3/GpuDemos/gwenUserInterface.cpp +++ b/Demos3/GpuDemos/gwenUserInterface.cpp @@ -151,29 +151,22 @@ void GwenUserInterface::init(int width, int height,struct sth_stash* stash,float //m_data->m_leftStatusBar->SetText( L"Label Added to Left" ); m_data->m_leftStatusBar->SetWidth(width/2); bar->AddControl( m_data->m_leftStatusBar,false); - + //Gwen::KeyboardFocus /*Gwen::Controls::GroupBox* box = new Gwen::Controls::GroupBox(m_data->pCanvas); box->SetText("text"); box->SetName("name"); box->SetHeight(500); */ - Gwen::Controls::ScrollControl* windowLeft= new Gwen::Controls::ScrollControl(m_data->pCanvas); - windowLeft->Dock(Gwen::Pos::Right); - windowLeft->SetWidth(150); - windowLeft->SetHeight(250); - windowLeft->SetScroll(false,true); + Gwen::Controls::ScrollControl* windowRight= new Gwen::Controls::ScrollControl(m_data->pCanvas); + windowRight->Dock(Gwen::Pos::Right); + windowRight->SetWidth(150); + windowRight->SetHeight(250); + windowRight->SetScroll(false,true); + - /*Gwen::Controls::WindowControl* windowLeft = new Gwen::Controls::WindowControl(m_data->pCanvas); - windowLeft->Dock(Gwen::Pos::Left); - windowLeft->SetTitle("title"); - windowLeft->SetWidth(150); - windowLeft->SetClosable(false); - windowLeft->SetShouldDrawBackground(true); - windowLeft->SetTabable(true); - */ //windowLeft->SetSkin( - Gwen::Controls::TabControl* tab = new Gwen::Controls::TabControl(windowLeft); + Gwen::Controls::TabControl* tab = new Gwen::Controls::TabControl(windowRight); //tab->SetHeight(300); tab->SetWidth(140); @@ -217,6 +210,39 @@ void GwenUserInterface::init(int width, int height,struct sth_stash* stash,float */ + + Gwen::Controls::ScrollControl* windowLeft = new Gwen::Controls::ScrollControl(m_data->pCanvas); + windowLeft->Dock(Gwen::Pos::Left); + // windowLeft->SetTitle("title"); + windowLeft->SetScroll(false, false); + windowLeft->SetWidth(250); + windowLeft->SetPos(50, 50); + windowLeft->SetHeight(500); + //windowLeft->SetClosable(false); + // windowLeft->SetShouldDrawBackground(true); + windowLeft->SetTabable(true); + + Gwen::Controls::TabControl* explorerTab = new Gwen::Controls::TabControl(windowLeft); + + //tab->SetHeight(300); +// explorerTab->SetWidth(230); + explorerTab->SetHeight(250); + //tab->Dock(Gwen::Pos::Left); + explorerTab->Dock(Gwen::Pos::Fill); + + Gwen::UnicodeString explorerStr1(L"Explorer"); + m_data->m_explorerPage = explorerTab->AddPage(explorerStr1); + Gwen::UnicodeString shapesStr1(L"Shapes"); + explorerTab->AddPage(shapesStr1); + Gwen::UnicodeString testStr1(L"Test"); + explorerTab->AddPage(testStr1); + + Gwen::Controls::TreeControl* ctrl = new Gwen::Controls::TreeControl(m_data->m_explorerPage->GetPage()); + m_data->m_explorerTreeCtrl = ctrl; + ctrl->SetKeyboardInputEnabled(true); + ctrl->Focus(); + ctrl->SetBounds(2, 10, 236, 400); + } b3ToggleButtonCallback GwenUserInterface::getToggleButtonCallback() @@ -318,6 +344,47 @@ bool GwenUserInterface::mouseMoveCallback( float x, float y) return handled; } +#include "OpenGLWindow/b3gWindowInterface.h" + +bool GwenUserInterface::keyboardCallback(int bulletKey, int state) +{ + int key = -1; + if (m_data->pCanvas) + { + //convert 'Bullet' keys into 'Gwen' keys + switch (bulletKey) + { + case B3G_RETURN: + { + key = Gwen::Key::Return; + break; + } + case B3G_LEFT_ARROW: + key = Gwen::Key::Left; + break; + case B3G_RIGHT_ARROW: + key = Gwen::Key::Right; + break; + + case B3G_UP_ARROW: + key = Gwen::Key::Up; + break; + case B3G_DOWN_ARROW: + key = Gwen::Key::Down; + break; + default: + { + + } + }; + bool bDown = (state == 1); + + return m_data->pCanvas->InputKey(key, bDown); + } + return false; +} + + bool GwenUserInterface::mouseButtonCallback(int button, int state, float x, float y) { bool handled = false; @@ -327,7 +394,7 @@ bool GwenUserInterface::mouseButtonCallback(int button, int state, float x, floa if (button>=0) { - handled = m_data->pCanvas->InputMouseButton(button,state); + handled = m_data->pCanvas->InputMouseButton(button,(bool)state); if (handled) { //if (!state) diff --git a/Demos3/GpuDemos/gwenUserInterface.h b/Demos3/GpuDemos/gwenUserInterface.h index 4c32376bf..75f24cb5e 100644 --- a/Demos3/GpuDemos/gwenUserInterface.h +++ b/Demos3/GpuDemos/gwenUserInterface.h @@ -6,6 +6,8 @@ struct GwenInternalData; typedef void (*b3ComboBoxCallback) (int combobox, const char* item); typedef void (*b3ToggleButtonCallback)(int button, int state); + + class GwenUserInterface { GwenInternalData* m_data; @@ -24,6 +26,8 @@ class GwenUserInterface bool mouseMoveCallback( float x, float y); bool mouseButtonCallback(int button, int state, float x, float y); + bool keyboardCallback(int key, int state); + void setToggleButtonCallback(b3ToggleButtonCallback callback); b3ToggleButtonCallback getToggleButtonCallback(); @@ -33,7 +37,7 @@ class GwenUserInterface void setComboBoxCallback(b3ComboBoxCallback callback); b3ComboBoxCallback getComboBoxCallback(); void registerComboBox(int buttonId, int numItems, const char** items, int startItem = 0); - + void setStatusBarMessage(const char* message, bool isLeft=true); GwenInternalData* getInternalData() diff --git a/Demos3/bullet2/BasicDemo/BasicDemo.cpp b/Demos3/bullet2/BasicDemo/BasicDemo.cpp index b47fb12de..71fb75a11 100644 --- a/Demos3/bullet2/BasicDemo/BasicDemo.cpp +++ b/Demos3/bullet2/BasicDemo/BasicDemo.cpp @@ -14,8 +14,8 @@ static const float scaling=0.35f; -BasicDemo::BasicDemo(SimpleOpenGL3App* app) -:Bullet2RigidBodyDemo(app) +BasicDemo::BasicDemo(SimpleOpenGL3App* app, CommonPhysicsSetup* physicsSetup) +:Bullet2RigidBodyDemo(app,physicsSetup) { } @@ -25,124 +25,6 @@ BasicDemo::~BasicDemo() void BasicDemo::createGround(int cubeShapeId) { - { - btVector4 color(0.3,0.3,1,1); - btVector4 halfExtents(50,50,50,1); - btTransform groundTransform; - groundTransform.setIdentity(); - groundTransform.setOrigin(btVector3(0,-50,0)); - m_glApp->m_instancingRenderer->registerGraphicsInstance(cubeShapeId,groundTransform.getOrigin(),groundTransform.getRotation(),color,halfExtents); - - btBoxShape* groundShape = new btBoxShape(btVector3(btScalar(halfExtents[0]),btScalar(halfExtents[1]),btScalar(halfExtents[2]))); - //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here: - { - btScalar mass(0.); - //rigidbody is dynamic if and only if mass is non zero, otherwise static - bool isDynamic = (mass != 0.f); - btVector3 localInertia(0,0,0); - if (isDynamic) - groundShape->calculateLocalInertia(mass,localInertia); - //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects - btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); - btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); - btRigidBody* body = new btRigidBody(rbInfo); - //add the body to the dynamics world - m_dynamicsWorld->addRigidBody(body); - } - } -} -void BasicDemo::initPhysics() -{ - m_physicsSetup.m_glApp = m_glApp; - m_physicsSetup.initPhysics(); - m_dynamicsWorld = m_physicsSetup.m_dynamicsWorld; - - m_glApp->m_instancingRenderer->writeTransforms(); -} -void BasicDemo::exitPhysics() -{ - m_physicsSetup.exitPhysics(); - m_dynamicsWorld = 0; - //Bullet2RigidBodyDemo::exitPhysics(); -} - -//SimpleOpenGL3App* m_glApp; - -btRigidBody* MyBasicDemoPhysicsSetup::createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color) -{ - btRigidBody* body = BasicDemoPhysicsSetup::createRigidBody(mass,startTransform,shape); - int graphicsShapeId = shape->getUserIndex(); - btAssert(graphicsShapeId>=0); - btVector3 localScaling = shape->getLocalScaling(); - - int graphicsInstanceId = m_glApp->m_instancingRenderer->registerGraphicsInstance(graphicsShapeId,startTransform.getOrigin(),startTransform.getRotation(),color,localScaling); - body->setUserIndex(graphicsInstanceId); - - //todo: create graphics representation - return body; - -} - -btBoxShape* MyBasicDemoPhysicsSetup::createBoxShape(const btVector3& halfExtents) -{ - btBoxShape* box = BasicDemoPhysicsSetup::createBoxShape(halfExtents); - int cubeShapeId = m_glApp->registerCubeShape(halfExtents.x(),halfExtents.y(),halfExtents.z()); - box->setUserIndex(cubeShapeId); - //todo: create graphics representation - return box; -} - - -void BasicDemo::renderScene() -{ - //sync graphics -> physics world transforms - { - for (int i=0;igetNumCollisionObjects();i++) - { - btCollisionObject* colObj = m_dynamicsWorld->getCollisionObjectArray()[i]; - btVector3 pos = colObj->getWorldTransform().getOrigin(); - btQuaternion orn = colObj->getWorldTransform().getRotation(); - int index = colObj ->getUserIndex(); - if (index>=0) - { - m_glApp->m_instancingRenderer->writeSingleInstanceTransformToCPU(pos,orn,index); - } - } - m_glApp->m_instancingRenderer->writeTransforms(); - } - - m_glApp->m_instancingRenderer->renderScene(); -} - - -void BasicDemo::stepSimulation(float dt) -{ - m_physicsSetup.stepSimulation(dt); - m_physicsSetup.m_dynamicsWorld->debugDrawWorld(); - - - - /* - //print applied force - //contact points - for (int i=0;igetDispatcher()->getNumManifolds();i++) - { - btPersistentManifold* contact = m_dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i); - for (int c=0;cgetNumContacts();c++) - { - btManifoldPoint& pt = contact->getContactPoint(c); - btScalar dist = pt.getDistance(); - if (dist< contact->getContactProcessingThreshold()) - { - printf("normalImpulse[%d.%d] = %f\n",i,c,pt.m_appliedImpulse); - - } else - { - printf("?\n"); - } - } - } - */ } diff --git a/Demos3/bullet2/BasicDemo/BasicDemo.h b/Demos3/bullet2/BasicDemo/BasicDemo.h index 283004929..7bc77b306 100644 --- a/Demos3/bullet2/BasicDemo/BasicDemo.h +++ b/Demos3/bullet2/BasicDemo/BasicDemo.h @@ -7,36 +7,26 @@ #include "../../../Demos/BasicDemo/BasicDemoPhysicsSetup.h" -struct MyBasicDemoPhysicsSetup : public BasicDemoPhysicsSetup -{ - SimpleOpenGL3App* m_glApp; - virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color); - - virtual btBoxShape* createBoxShape(const btVector3& halfExtents); -}; class BasicDemo : public Bullet2RigidBodyDemo { - MyBasicDemoPhysicsSetup m_physicsSetup; + public: static BulletDemoInterface* MyCreateFunc(SimpleOpenGL3App* app) { - return new BasicDemo(app); + CommonPhysicsSetup* physicsSetup = new BasicDemoPhysicsSetup(); + return new BasicDemo(app, physicsSetup); } - BasicDemo(SimpleOpenGL3App* app); + BasicDemo(SimpleOpenGL3App* app, CommonPhysicsSetup* physicsSetup); virtual ~BasicDemo(); void createGround(int cubeShapeId); - virtual void initPhysics(); - virtual void exitPhysics(); - virtual void renderScene(); - virtual void stepSimulation(float dt); }; diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp index 72069c2b6..9d6077bd1 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp @@ -2,54 +2,102 @@ #include "btBulletDynamicsCommon.h" #include "OpenGLWindow/SimpleOpenGL3App.h" -Bullet2RigidBodyDemo::Bullet2RigidBodyDemo(SimpleOpenGL3App* app) - :m_glApp(app), - m_pickedBody(0), - m_pickedConstraint(0), -m_controlPressed(false), -m_altPressed(false) +struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge { - m_config = 0; - m_dispatcher = 0; - m_bp = 0; - m_solver = 0; - m_dynamicsWorld = 0; + SimpleOpenGL3App* m_glApp; + + MyGraphicsPhysicsBridge(SimpleOpenGL3App* glApp) + :m_glApp(glApp) + { + } + virtual void createRigidBodyGraphicsObject(btRigidBody* body, const btVector3& color) + { + btCollisionShape* shape = body->getCollisionShape(); + btTransform startTransform = body->getWorldTransform(); + int graphicsShapeId = shape->getUserIndex(); + btAssert(graphicsShapeId >= 0); + btVector3 localScaling = shape->getLocalScaling(); + int graphicsInstanceId = m_glApp->m_instancingRenderer->registerGraphicsInstance(graphicsShapeId, startTransform.getOrigin(), startTransform.getRotation(), color, localScaling); + body->setUserIndex(graphicsInstanceId); + } + virtual void createCollisionShapeGraphicsObject(btCollisionShape* collisionShape) + { + //todo: support all collision shape types + switch (collisionShape->getShapeType()) + { + case BOX_SHAPE_PROXYTYPE: + { + btBoxShape* box = (btBoxShape*)collisionShape; + btVector3 halfExtents = box->getHalfExtentsWithMargin(); + int cubeShapeId = m_glApp->registerCubeShape(halfExtents.x(), halfExtents.y(), halfExtents.z()); + box->setUserIndex(cubeShapeId); + break; + } + default: + { + btAssert(0); + } + }; + } + virtual void syncPhysicsToGraphics(const btDiscreteDynamicsWorld* rbWorld) + { + int numCollisionObjects = rbWorld->getNumCollisionObjects(); + for (int i = 0; igetCollisionObjectArray()[i]; + btVector3 pos = colObj->getWorldTransform().getOrigin(); + btQuaternion orn = colObj->getWorldTransform().getRotation(); + int index = colObj->getUserIndex(); + if (index >= 0) + { + m_glApp->m_instancingRenderer->writeSingleInstanceTransformToCPU(pos, orn, index); + } + } + m_glApp->m_instancingRenderer->writeTransforms(); + } +}; + +Bullet2RigidBodyDemo::Bullet2RigidBodyDemo(SimpleOpenGL3App* app, CommonPhysicsSetup* physicsSetup) + :m_glApp(app), + m_physicsSetup(physicsSetup), + m_controlPressed(false), + m_altPressed(false) +{ + } void Bullet2RigidBodyDemo::initPhysics() { - m_config = new btDefaultCollisionConfiguration; - m_dispatcher = new btCollisionDispatcher(m_config); - m_bp = new btDbvtBroadphase(); - m_solver = new btSequentialImpulseConstraintSolver(); - m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_bp,m_solver,m_config); + MyGraphicsPhysicsBridge glBridge(m_glApp); + m_physicsSetup->initPhysics(glBridge); + m_glApp->m_instancingRenderer->writeTransforms(); + } void Bullet2RigidBodyDemo::exitPhysics() { - delete m_dynamicsWorld; - m_dynamicsWorld=0; - delete m_solver; - m_solver=0; - delete m_bp; - m_bp=0; - delete m_dispatcher; - m_dispatcher=0; - delete m_config; - m_config=0; + + m_physicsSetup->exitPhysics(); + } void Bullet2RigidBodyDemo::stepSimulation(float deltaTime) { - m_dynamicsWorld->stepSimulation(deltaTime); + m_physicsSetup->stepSimulation(deltaTime); + } +void Bullet2RigidBodyDemo::renderScene() +{ + //sync graphics -> physics world transforms + + MyGraphicsPhysicsBridge glBridge(m_glApp); + m_physicsSetup->syncPhysicsToGraphics(glBridge); + + m_glApp->m_instancingRenderer->renderScene(); + +} Bullet2RigidBodyDemo::~Bullet2RigidBodyDemo() { - btAssert(m_config == 0); - btAssert(m_dispatcher == 0); - btAssert(m_bp == 0); - btAssert(m_solver == 0); - btAssert(m_dynamicsWorld == 0); } btVector3 Bullet2RigidBodyDemo::getRayTo(int x,int y) @@ -115,28 +163,10 @@ btVector3 Bullet2RigidBodyDemo::getRayTo(int x,int y) bool Bullet2RigidBodyDemo::mouseMoveCallback(float x,float y) { - //if (m_data->m_altPressed!=0 || m_data->m_controlPressed!=0) - //return false; - - if (m_pickedBody && m_pickedConstraint) - { - btPoint2PointConstraint* pickCon = static_cast(m_pickedConstraint); - if (pickCon) - { - //keep it at the same picking distance - btVector3 newRayTo = getRayTo(x,y); - btVector3 rayFrom; - btVector3 oldPivotInB = pickCon->getPivotInB(); - btVector3 newPivotB; - m_glApp->m_instancingRenderer->getCameraPosition(rayFrom); - btVector3 dir = newRayTo-rayFrom; - dir.normalize(); - dir *= m_oldPickingDist; - - newPivotB = rayFrom + dir; - pickCon->setPivotB(newPivotB); - } - } + btVector3 rayTo = getRayTo(x, y); + btVector3 rayFrom; + m_glApp->m_instancingRenderer->getCameraPosition(rayFrom); + m_physicsSetup->movePickedBody(rayFrom,rayTo); return false; } @@ -153,53 +183,15 @@ bool Bullet2RigidBodyDemo::mouseButtonCallback(int button, int state, float x, f btVector3 rayFrom = camPos; btVector3 rayTo = getRayTo(x,y); - btCollisionWorld::ClosestRayResultCallback rayCallback(rayFrom,rayTo); - m_dynamicsWorld->rayTest(rayFrom,rayTo,rayCallback); - if (rayCallback.hasHit()) - { + bool hasPicked = m_physicsSetup->pickBody(rayFrom, rayTo); - btVector3 pickPos = rayCallback.m_hitPointWorld; - btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject); - if (body) - { - //other exclusions? - if (!(body->isStaticObject() || body->isKinematicObject())) - { - m_pickedBody = body; - m_pickedBody->setActivationState(DISABLE_DEACTIVATION); - //printf("pickPos=%f,%f,%f\n",pickPos.getX(),pickPos.getY(),pickPos.getZ()); - btVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos; - btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body,localPivot); - m_dynamicsWorld->addConstraint(p2p,true); - m_pickedConstraint = p2p; - btScalar mousePickClamping = 30.f; - p2p->m_setting.m_impulseClamp = mousePickClamping; - //very weak constraint for picking - p2p->m_setting.m_tau = 0.001f; - } - } - - -// pickObject(pickPos, rayCallback.m_collisionObject); - m_oldPickingPos = rayTo; - m_hitPos = pickPos; - m_oldPickingDist = (pickPos-rayFrom).length(); -// printf("hit !\n"); - //add p2p - } } } else { if (button==0) { - if (m_pickedConstraint) - { - m_dynamicsWorld->removeConstraint(m_pickedConstraint); - delete m_pickedConstraint; - m_pickedConstraint=0; - m_pickedBody = 0; - } + m_physicsSetup->removePickingConstraint(); //remove p2p } } diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h index 3cabd9e17..07e3f41e8 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h @@ -6,31 +6,28 @@ #include "../../AllBullet2Demos/BulletDemoInterface.h" #include "OpenGLWindow/b3gWindowInterface.h" +#include "../../../Demos/CommonPhysicsSetup.h" + class Bullet2RigidBodyDemo : public BulletDemoInterface { -public: - class btDiscreteDynamicsWorld* m_dynamicsWorld; - class btCollisionDispatcher* m_dispatcher; - class btBroadphaseInterface* m_bp; - class btCollisionConfiguration* m_config; - class btConstraintSolver* m_solver; + CommonPhysicsSetup* m_physicsSetup; + +public: - class btRigidBody* m_pickedBody; - class btTypedConstraint* m_pickedConstraint; - btVector3 m_oldPickingPos; - btVector3 m_hitPos; - btScalar m_oldPickingDist; bool m_controlPressed; bool m_altPressed; public: - class SimpleOpenGL3App* m_glApp; + struct SimpleOpenGL3App* m_glApp; - Bullet2RigidBodyDemo(SimpleOpenGL3App* app); + Bullet2RigidBodyDemo(SimpleOpenGL3App* app, CommonPhysicsSetup* physicsSetup); virtual void initPhysics(); virtual void exitPhysics(); + virtual void renderScene(); + virtual void stepSimulation(float dt); + virtual ~Bullet2RigidBodyDemo(); btVector3 getRayTo(int x,int y); @@ -49,7 +46,6 @@ public: return false; } - virtual void stepSimulation(float deltaTime); }; diff --git a/Demos3/bullet2/RagdollDemo/RagdollDemo.cpp b/Demos3/bullet2/RagdollDemo/RagdollDemo.cpp index 2ca5976e6..155d84dd4 100644 --- a/Demos3/bullet2/RagdollDemo/RagdollDemo.cpp +++ b/Demos3/bullet2/RagdollDemo/RagdollDemo.cpp @@ -343,17 +343,6 @@ public: -RagDollDemo::RagDollDemo(SimpleOpenGL3App* app) -:BasicDemo(app) -{ - -} -RagDollDemo::~RagDollDemo() -{ - -} - - void RagDollDemo::initPhysics() diff --git a/Demos3/bullet2/RagdollDemo/RagdollDemo.h b/Demos3/bullet2/RagdollDemo/RagdollDemo.h index 1ed88b38f..e633d0574 100644 --- a/Demos3/bullet2/RagdollDemo/RagdollDemo.h +++ b/Demos3/bullet2/RagdollDemo/RagdollDemo.h @@ -2,21 +2,24 @@ #define RAGDOLL_DEMO_H +#include "../../Demos/CommonRigidBodySetup.h" #include "../BasicDemo/BasicDemo.h" -class RagDollDemo : public BasicDemo +struct BulletDemoInterface; +struct SimpleOpenGL3App; + +class RagDollSetup : public CommonRigidBodySetup { public: - RagDollDemo(SimpleOpenGL3App* app); - virtual ~RagDollDemo(); - static BulletDemoInterface* MyCreateFunc(SimpleOpenGL3App* app) { - return new RagDollDemo(app); + CommonPhysicsSetup* physicsSetup = new RagDollSetup(); + return new BasicDemo(app, physicsSetup); + } - void initPhysics(); + void initPhysics(GraphicsPhysicsBridge& gfxBridge); }; diff --git a/btgui/Gwen/Controls/Button.h b/btgui/Gwen/Controls/Button.h index c4e35a85c..4e9d3358e 100644 --- a/btgui/Gwen/Controls/Button.h +++ b/btgui/Gwen/Controls/Button.h @@ -49,17 +49,28 @@ namespace Gwen virtual void SetImage( const TextObject& strName, bool bCenter = false ); // You can use this to trigger OnPress directly from other controls using GWEN_CALL_EX - virtual void ReceiveEventPress( Base* /*pControl*/ ){ OnPress(); } + virtual void ReceiveEventPress( Base* /*pControl*/ ) + { + OnPress(); + } virtual void SizeToContents(); virtual void Layout( Skin::Base* pSkin ); + virtual bool OnKeyReturn(bool bDown) + { + onKeyboardReturn.Call(this); + return true; + } + public: Gwen::Event::Caller onPress; Gwen::Event::Caller onDown; Gwen::Event::Caller onUp; Gwen::Event::Caller onDoubleClick; + Gwen::Event::Caller onKeyboardReturn; + Gwen::Event::Caller onToggle; Gwen::Event::Caller onToggleOn; Gwen::Event::Caller onToggleOff; diff --git a/btgui/Gwen/Controls/TreeControl.cpp b/btgui/Gwen/Controls/TreeControl.cpp index 128b0386d..972ec8456 100644 --- a/btgui/Gwen/Controls/TreeControl.cpp +++ b/btgui/Gwen/Controls/TreeControl.cpp @@ -72,8 +72,10 @@ void TreeControl::OnNodeAdded( TreeNode* pNode ) pNode->onNamePress.Add( this, &TreeControl::OnNodeSelection ); } + void TreeControl::OnNodeSelection( Controls::Base* /*control*/ ) { + //printf("TreeControl::OnNodeSelection\n"); if ( !m_bAllowMultipleSelection || !Gwen::Input::IsKeyDown( Key::Control ) ) DeselectAll(); } diff --git a/btgui/Gwen/Controls/TreeNode.cpp b/btgui/Gwen/Controls/TreeNode.cpp index e32ac7e52..ba694567c 100644 --- a/btgui/Gwen/Controls/TreeNode.cpp +++ b/btgui/Gwen/Controls/TreeNode.cpp @@ -132,6 +132,13 @@ void TreeNode::PostLayout( Skin::Base* /*skin*/ ) void TreeNode::SetText( const UnicodeString& text ){ m_Title->SetText( text ); }; void TreeNode::SetText( const String& text ){ m_Title->SetText( text ); }; +UnicodeString TreeNode::GetText() const +{ + UnicodeString bla = m_Title->GetText(); + return bla; +} + + void TreeNode::Open() { m_InnerPanel->Show(); diff --git a/btgui/Gwen/Controls/TreeNode.h b/btgui/Gwen/Controls/TreeNode.h index 6355a8724..cfeb7b11b 100644 --- a/btgui/Gwen/Controls/TreeNode.h +++ b/btgui/Gwen/Controls/TreeNode.h @@ -38,6 +38,7 @@ namespace Gwen virtual void SetText( const UnicodeString& text ); virtual void SetText( const String& text ); + UnicodeString GetText() const; virtual void Open(); virtual void Close(); @@ -60,7 +61,18 @@ namespace Gwen virtual void DeselectAll(); virtual void iterate(int action, int* curIndex, int* resultIndex); - + virtual bool OnKeyReturn(bool bDown) + { + static bool prevDown = false; + if (!prevDown && bDown) + { + onReturnKeyDown.Call(this); + } + prevDown = bDown; + return Base::OnKeyReturn(bDown); + } + + Event::Caller onReturnKeyDown; Event::Caller onNamePress; Event::Caller onSelectChange; diff --git a/btgui/GwenOpenGLTest/OpenGLSample.cpp b/btgui/GwenOpenGLTest/OpenGLSample.cpp index 9ad7a009e..a0ed1445f 100644 --- a/btgui/GwenOpenGLTest/OpenGLSample.cpp +++ b/btgui/GwenOpenGLTest/OpenGLSample.cpp @@ -308,7 +308,7 @@ int main() b3gWindowConstructionInfo wci; wci.m_width = sWidth; wci.m_height = sHeight; - wci.m_resizeCallback = MyResizeCallback; +// wci.m_resizeCallback = MyResizeCallback; window->createWindow(wci); window->setResizeCallback(MyResizeCallback); diff --git a/btgui/OpenGLWindow/Win32Window.cpp b/btgui/OpenGLWindow/Win32Window.cpp index b4afe623c..1d94ae3c4 100644 --- a/btgui/OpenGLWindow/Win32Window.cpp +++ b/btgui/OpenGLWindow/Win32Window.cpp @@ -55,8 +55,21 @@ void Win32Window::pumpMessage() int getAsciiCodeFromVirtualKeycode(int virtualKeyCode) { int keycode = 0xffffffff; + if (virtualKeyCode >= '0' && virtualKeyCode <= '9') + { + return virtualKeyCode; + } + if (virtualKeyCode >= 'a' && virtualKeyCode <= 'z') + { + return virtualKeyCode; + } + if (virtualKeyCode >= 'A' && virtualKeyCode <= 'Z') + { + return virtualKeyCode; + } switch (virtualKeyCode) { + case VK_RETURN: {keycode = B3G_RETURN; break; }; case VK_F1: {keycode = B3G_F1; break;} case VK_F2: {keycode = B3G_F2; break;} case VK_F3: {keycode = B3G_F3; break;} @@ -126,7 +139,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_SYSKEYUP: case WM_KEYUP: - { + { int keycode = getAsciiCodeFromVirtualKeycode(wParam); @@ -140,12 +153,15 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } case WM_CHAR: { - int keycode = wParam; - - if (sData && sData->m_keyboardCallback && ((HIWORD(lParam) & KF_REPEAT) == 0)) + //skip 'enter' key, it is processed in WM_KEYUP/WM_KEYDOWN + int keycode = getAsciiCodeFromVirtualKeycode(wParam); + if (keycode < 0) { - int state = 1; - (*sData->m_keyboardCallback)(keycode,state); + if (sData && sData->m_keyboardCallback && ((HIWORD(lParam) & KF_REPEAT) == 0)) + { + int state = 1; + (*sData->m_keyboardCallback)(wParam, state); + } } return 0; } @@ -322,6 +338,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) break; default:{ + } }; diff --git a/btgui/OpenGLWindow/b3gWindowInterface.h b/btgui/OpenGLWindow/b3gWindowInterface.h index 122d6a3c3..e404e4629 100644 --- a/btgui/OpenGLWindow/b3gWindowInterface.h +++ b/btgui/OpenGLWindow/b3gWindowInterface.h @@ -39,7 +39,8 @@ enum { B3G_BACKSPACE, B3G_SHIFT, B3G_CONTROL, - B3G_ALT + B3G_ALT, + B3G_RETURN }; struct b3gWindowConstructionInfo From f82f01662195c6467c094ed4fc202590b662f4e7 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 24 Jun 2014 10:27:03 -0700 Subject: [PATCH 067/116] add missing file --- Demos/CommonRigidBodySetup.h | 233 +++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 Demos/CommonRigidBodySetup.h diff --git a/Demos/CommonRigidBodySetup.h b/Demos/CommonRigidBodySetup.h new file mode 100644 index 000000000..bf28d5f59 --- /dev/null +++ b/Demos/CommonRigidBodySetup.h @@ -0,0 +1,233 @@ + +#ifndef COMMON_RIGID_BODY_SETUP_H +#define COMMON_RIGID_BODY_SETUP_H + +//todo: replace this 'btBulletDynamicsCommon.h' header with specific used header files +#include "btBulletDynamicsCommon.h" +#include "CommonPhysicsSetup.h" + +struct CommonRigidBodySetup : public CommonPhysicsSetup +{ + //keep the collision shapes, for deletion/cleanup + btAlignedObjectArray m_collisionShapes; + btBroadphaseInterface* m_broadphase; + btCollisionDispatcher* m_dispatcher; + btConstraintSolver* m_solver; + btDefaultCollisionConfiguration* m_collisionConfiguration; + btDiscreteDynamicsWorld* m_dynamicsWorld; + + //data for picking objects + class btRigidBody* m_pickedBody; + class btTypedConstraint* m_pickedConstraint; + btVector3 m_oldPickingPos; + btVector3 m_hitPos; + btScalar m_oldPickingDist; + + CommonRigidBodySetup() + :m_broadphase(0), + m_dispatcher(0), + m_solver(0), + m_collisionConfiguration(0), + m_dynamicsWorld(0), + m_pickedBody(0), + m_pickedConstraint(0) + { + } + + virtual void createEmptyDynamicsWorld() + { + ///collision configuration contains default setup for memory, collision setup + m_collisionConfiguration = new btDefaultCollisionConfiguration(); + //m_collisionConfiguration->setConvexConvexMultipointIterations(); + + ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) + m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); + + m_broadphase = new btDbvtBroadphase(); + + ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) + btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; + m_solver = sol; + + m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration); + + m_dynamicsWorld->setGravity(btVector3(0, -10, 0)); + } + + + virtual void stepSimulation(float deltaTime) + { + if (m_dynamicsWorld) + { + m_dynamicsWorld->stepSimulation(deltaTime); + } + } + + + virtual void exitPhysics() + { + removePickingConstraint(); + //cleanup in the reverse order of creation/initialization + + //remove the rigidbodies from the dynamics world and delete them + int i; + if (m_dynamicsWorld) + { + + for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body = btRigidBody::upcast(obj); + if (body && body->getMotionState()) + { + delete body->getMotionState(); + } + m_dynamicsWorld->removeCollisionObject(obj); + delete obj; + } + } + //delete collision shapes + for (int j = 0; jrayTest(rayFromWorld, rayToWorld, rayCallback); + if (rayCallback.hasHit()) + { + + btVector3 pickPos = rayCallback.m_hitPointWorld; + btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject); + if (body) + { + //other exclusions? + if (!(body->isStaticObject() || body->isKinematicObject())) + { + m_pickedBody = body; + m_pickedBody->setActivationState(DISABLE_DEACTIVATION); + //printf("pickPos=%f,%f,%f\n",pickPos.getX(),pickPos.getY(),pickPos.getZ()); + btVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos; + btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body, localPivot); + m_dynamicsWorld->addConstraint(p2p, true); + m_pickedConstraint = p2p; + btScalar mousePickClamping = 30.f; + p2p->m_setting.m_impulseClamp = mousePickClamping; + //very weak constraint for picking + p2p->m_setting.m_tau = 0.001f; + } + } + + + // pickObject(pickPos, rayCallback.m_collisionObject); + m_oldPickingPos = rayToWorld; + m_hitPos = pickPos; + m_oldPickingDist = (pickPos - rayFromWorld).length(); + // printf("hit !\n"); + //add p2p + } + return false; + } + virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) + { + if (m_pickedBody && m_pickedConstraint) + { + btPoint2PointConstraint* pickCon = static_cast(m_pickedConstraint); + if (pickCon) + { + //keep it at the same picking distance + + btVector3 newPivotB; + + btVector3 dir = rayToWorld - rayFromWorld; + dir.normalize(); + dir *= m_oldPickingDist; + + newPivotB = rayFromWorld + dir; + pickCon->setPivotB(newPivotB); + return true; + } + } + return false; + } + virtual void removePickingConstraint() + { + if (m_pickedConstraint) + { + m_dynamicsWorld->removeConstraint(m_pickedConstraint); + delete m_pickedConstraint; + m_pickedConstraint = 0; + m_pickedBody = 0; + } + } + + + + btBoxShape* createBoxShape(const btVector3& halfExtents) + { + btBoxShape* box = new btBoxShape(halfExtents); + return box; + } + + btRigidBody* createRigidBody(float mass, const btTransform& startTransform, btCollisionShape* shape, const btVector4& color = btVector4(1, 0, 0, 1)) + { + btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE)); + + //rigidbody is dynamic if and only if mass is non zero, otherwise static + bool isDynamic = (mass != 0.f); + + btVector3 localInertia(0, 0, 0); + if (isDynamic) + shape->calculateLocalInertia(mass, localInertia); + + //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects + +#define USE_MOTIONSTATE 1 +#ifdef USE_MOTIONSTATE + btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); + + btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia); + + btRigidBody* body = new btRigidBody(cInfo); + //body->setContactProcessingThreshold(m_defaultContactProcessingThreshold); + +#else + btRigidBody* body = new btRigidBody(mass, 0, shape, localInertia); + body->setWorldTransform(startTransform); +#endif// + + body->setUserIndex(-1); + m_dynamicsWorld->addRigidBody(body); + return body; + } +}; + +#endif //COMMON_RIGID_BODY_SETUP_H + From 3480cb5eee50bfe503bcbc5a5376edff8184ea8d Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Tue, 24 Jun 2014 11:33:00 -0700 Subject: [PATCH 068/116] fix Linux build --- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 69 +++++++++++++------------ 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index fe69cfbf6..1dd995fdc 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -40,7 +40,7 @@ void SimpleResizeCallback( float width, float height) { gApp->m_instancingRenderer->resize(width,height); gApp->m_primRenderer->setScreenSize(width,height); - + } static GLuint BindFont(const CTexFont *_Font) @@ -76,7 +76,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) ci.m_width = width; ci.m_height = height; m_window->createWindow(ci); - + m_window->setWindowTitle(title); glClearColor(1,1,1,1); m_window->startRendering(); @@ -85,7 +85,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) #endif m_primRenderer = new GLPrimitiveRenderer(width,height); - + m_instancingRenderer = new GLInstancingRenderer(128*1024,4*1024*1024); m_instancingRenderer->init(); m_instancingRenderer->resize(width,height); @@ -103,7 +103,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) { GLint err; - + int datasize; float sx,sy,dx,dy,lh; @@ -141,25 +141,25 @@ struct sth_stash* SimpleOpenGL3App::getFontStash() void SimpleOpenGL3App::drawText( const char* txt, int posX, int posY) { - - - - + + + + // //printf("str = %s\n",unicodeText); float dx=0; - + int measureOnly=0; - + glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + if (1)//m_useTrueTypeFont) { bool measureOnly = false; - + float fontSize= 64;//512;//128; sth_draw_text(m_data->m_fontStash, m_data->m_droidRegular,fontSize,posX,posY, @@ -173,13 +173,13 @@ void SimpleOpenGL3App::drawText( const char* txt, int posX, int posY) float color[]={0.2f,0.2,0.2f,1.f}; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,m_data->m_fontTextureId); - + //float width = r.x; float extraSpacing = 0.; int startX = posX; int startY = posY; - + while (txt[pos]) { @@ -191,7 +191,7 @@ void SimpleOpenGL3App::drawText( const char* txt, int posX, int posY) //Gwen::Rect rect = r; //Translate( rect ); - + float currentColor[]={0.2f,0.2,0.2f,1.f}; m_primRenderer->drawTexturedRect(startX, startY, endX, endY, currentColor,g_DefaultNormalFont->m_CharU0[c],g_DefaultNormalFont->m_CharV0[c],g_DefaultNormalFont->m_CharU1[c],g_DefaultNormalFont->m_CharV1[c]); @@ -201,24 +201,27 @@ void SimpleOpenGL3App::drawText( const char* txt, int posX, int posY) startX = endX; //startY = endY; - + pos++; - + } glBindTexture(GL_TEXTURE_2D,0); } glDisable(GL_BLEND); } -int SimpleOpenGL3App::registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ) -{ - struct GfxVertex + +struct GfxVertex { float x,y,z,w; float nx,ny,nz; float u,v; }; - + +int SimpleOpenGL3App::registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ) +{ + + int strideInBytes = 9*sizeof(float); int numVertices = sizeof(cube_vertices)/strideInBytes; int numIndices = sizeof(cube_indices)/sizeof(int); @@ -237,7 +240,7 @@ int SimpleOpenGL3App::registerCubeShape(float halfExtentsX,float halfExtentsY, f verts[i].u = cube_vertices[i*9+7]; verts[i].v = cube_vertices[i*9+8]; } - + int shapeId = m_instancingRenderer->registerShape(&verts[0].x,numVertices,cube_indices,numIndices); return shapeId; } @@ -245,11 +248,11 @@ int SimpleOpenGL3App::registerCubeShape(float halfExtentsX,float halfExtentsY, f int SimpleOpenGL3App::registerGraphicsSphereShape(float radius, bool usePointSprites, int largeSphereThreshold, int mediumSphereThreshold) { - + int strideInBytes = 9*sizeof(float); - + int graphicsShapeIndex = -1; - + if (radius>=largeSphereThreshold) { int numVertices = sizeof(detailed_sphere_vertices)/strideInBytes; @@ -257,7 +260,7 @@ int SimpleOpenGL3App::registerGraphicsSphereShape(float radius, bool usePointSpr graphicsShapeIndex = m_instancingRenderer->registerShape(&detailed_sphere_vertices[0],numVertices,detailed_sphere_indices,numIndices); } else { - + if (usePointSprites) { int numVertices = sizeof(point_sphere_vertices)/strideInBytes; @@ -283,22 +286,22 @@ int SimpleOpenGL3App::registerGraphicsSphereShape(float radius, bool usePointSpr void SimpleOpenGL3App::drawGrid(int gridSize, float yOffset) { - + b3Vector3 gridColor = b3MakeVector3(0.5,0.5,0.5); for(int i=-gridSize;i<=gridSize;i++) { - + GLint err = glGetError(); b3Assert(err==GL_NO_ERROR); - + m_instancingRenderer->drawLine(b3MakeVector3(float(i),yOffset,float(-gridSize)),b3MakeVector3(float(i),yOffset,float(gridSize)),gridColor); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + m_instancingRenderer->drawLine(b3MakeVector3(float(-gridSize),yOffset,float(i)),b3MakeVector3(float(gridSize),yOffset,float(i)),gridColor); } - + m_instancingRenderer->drawLine(b3MakeVector3(0,0,0),b3MakeVector3(1,0,0),b3MakeVector3(1,0,0),3); m_instancingRenderer->drawLine(b3MakeVector3(0,0,0),b3MakeVector3(0,1,0),b3MakeVector3(0,1,0),3); m_instancingRenderer->drawLine(b3MakeVector3(0,0,0),b3MakeVector3(0,0,1),b3MakeVector3(0,0,1),3); @@ -327,4 +330,4 @@ void SimpleOpenGL3App::swapBuffer() { m_window->endRendering(); m_window->startRendering(); -} \ No newline at end of file +} From c1db34a046dadc527cfdf0f8df566b89c7c0ec43 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 24 Jun 2014 11:49:34 -0700 Subject: [PATCH 069/116] enable B3G_RETURN for Mac OSX --- btgui/OpenGLWindow/MacOpenGLWindow.mm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/btgui/OpenGLWindow/MacOpenGLWindow.mm b/btgui/OpenGLWindow/MacOpenGLWindow.mm index 340898aaf..10090ee9a 100644 --- a/btgui/OpenGLWindow/MacOpenGLWindow.mm +++ b/btgui/OpenGLWindow/MacOpenGLWindow.mm @@ -682,7 +682,7 @@ int getAsciiCodeFromVirtualKeycode(int virtualKeyCode) case kVK_ANSI_KeypadPlus : {keycode = '+'; break;} case kVK_ANSI_KeypadClear : {keycode = '?'; break;} case kVK_ANSI_KeypadDivide : {keycode = '/'; break;} - case kVK_ANSI_KeypadEnter : {keycode = 13; break;} + case kVK_ANSI_KeypadEnter : {keycode = B3G_RETURN; break;} case kVK_ANSI_KeypadMinus : {keycode = '-'; break;} case kVK_ANSI_KeypadEquals : {keycode = '='; break;} case kVK_ANSI_Keypad0 : {keycode = '0'; break;} @@ -695,7 +695,11 @@ int getAsciiCodeFromVirtualKeycode(int virtualKeyCode) case kVK_ANSI_Keypad7 : {keycode = '7'; break;} case kVK_ANSI_Keypad8 : {keycode = '8'; break;} case kVK_ANSI_Keypad9 : {keycode = '9'; break;} - + case kVK_Return: + { + keycode = B3G_RETURN; break; + } + default: { From 8f94ced88a2f9029100cd784fc7b7c3a8ab9bffe Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Tue, 24 Jun 2014 15:43:04 -0700 Subject: [PATCH 070/116] improve Linux OpenGL 3.x context creation handling, don't crash if the shadowmap shader fails add cursor-key support for Linux --- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 282 +++++++++-------- btgui/OpenGLWindow/LoadShader.cpp | 50 +-- .../Shaders/createShadowMapInstancingPS.h | 2 +- .../Shaders/createShadowMapInstancingVS.h | 3 - btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 30 +- btgui/OpenGLWindow/X11OpenGLWindow.cpp | 298 ++++++++++++++++-- 6 files changed, 482 insertions(+), 183 deletions(-) diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index 9436c09cd..f5f86e70f 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -1,10 +1,10 @@ /* -Copyright (c) 2012 Advanced Micro Devices, Inc. +Copyright (c) 2012 Advanced Micro Devices, Inc. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -15,7 +15,7 @@ subject to the following restrictions: ///todo: make this configurable in the gui -bool useShadowMap=true; +bool useShadowMap=true;//false;//true; float shadowMapWidth=8192; float shadowMapHeight=8192; float shadowMapWorldSize=200; @@ -79,7 +79,7 @@ struct b3GraphicsInstance int m_numVertices; int m_numGraphicsInstances; - + int m_instanceOffset; int m_vertexArrayOffset; int m_primitiveType; @@ -139,11 +139,11 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData int m_leftMouseButton; int m_middleMouseButton; int m_rightMouseButton; - + int m_altPressed; int m_controlPressed; - + GLuint m_defaultTexturehandle; b3AlignedObjectArray m_textureHandles; @@ -167,7 +167,7 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData m_altPressed(0), m_controlPressed(0) { - + } @@ -210,7 +210,7 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData { float xDelta = x-m_mouseXpos; float yDelta = y-m_mouseYpos; - + if (m_leftMouseButton) { // if (b3Fabs(xDelta)>b3Fabs(yDelta)) @@ -225,7 +225,7 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData { m_cameraTargetPosition += m_cameraUp * yDelta*0.01; - + b3Vector3 fwd = m_cameraTargetPosition-m_cameraPosition; b3Vector3 side = m_cameraUp.cross(fwd); side.normalize(); @@ -253,7 +253,7 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData void mouseButtonCallback(int button, int state, float x, float y) { - + if (button==0) m_leftMouseButton=state; if (button==1) @@ -261,7 +261,7 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData if (button==2) m_rightMouseButton=state; - + m_mouseXpos = x; m_mouseYpos = y; m_mouseInitialized = true; @@ -493,7 +493,7 @@ void GLInstancingRenderer::writeTransforms() GLint err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo); glFlush(); @@ -503,7 +503,7 @@ void GLInstancingRenderer::writeTransforms() char* orgBase = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE); if (orgBase) { - + int totalNumInstances= 0; @@ -520,7 +520,7 @@ void GLInstancingRenderer::writeTransforms() //int k=0; b3GraphicsInstance* gfxObj = m_graphicsInstances[k]; - + int POSITION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4); int ORIENTATION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4); @@ -561,7 +561,7 @@ void GLInstancingRenderer::writeTransforms() scaling[srcIndex*3]=m_data->m_instance_scale_ptr[srcIndex*3]; scaling[srcIndex*3+1]=m_data->m_instance_scale_ptr[srcIndex*3+1]; scaling[srcIndex*3+2]=m_data->m_instance_scale_ptr[srcIndex*3+2]; - + } } } else @@ -579,7 +579,7 @@ void GLInstancingRenderer::writeTransforms() err = glGetError(); b3Assert(err==GL_NO_ERROR); - + } int GLInstancingRenderer::registerGraphicsInstance(int shapeIndex, const double* pos1, const double* orn1, const double* color1, const double* scaling1) @@ -600,7 +600,7 @@ int GLInstancingRenderer::registerGraphicsInstance(int shapeIndex, const float* b3GraphicsInstance* gfxObj = m_graphicsInstances[shapeIndex]; int index = gfxObj->m_numGraphicsInstances + gfxObj->m_instanceOffset; - + int maxElements = m_data->m_instance_positions_ptr.size(); if (index*4m_textureHandles.push_back(textureHandle); return textureIndex; } @@ -679,14 +679,14 @@ void GLInstancingRenderer::updateShape(int shapeIndex, const float* vertices) int GLInstancingRenderer::registerShape(const float* vertices, int numvertices, const int* indices, int numIndices,int primitiveType, int textureId) { b3GraphicsInstance* gfxObj = new b3GraphicsInstance; - + if (textureId>=0) { gfxObj->m_texturehandle = m_data->m_textureHandles[textureId]; } - + gfxObj->m_primitiveType = primitiveType; - + if (m_graphicsInstances.size()) { b3GraphicsInstance* prevObj = m_graphicsInstances[m_graphicsInstances.size()-1]; @@ -700,15 +700,15 @@ int GLInstancingRenderer::registerShape(const float* vertices, int numvertices, m_graphicsInstances.push_back(gfxObj); gfxObj->m_numIndices = numIndices; gfxObj->m_numVertices = numvertices; - - + + glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo); char* dest= (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_WRITE_ONLY);//GL_WRITE_ONLY int vertexStrideInBytes = 9*sizeof(float); int sz = numvertices*vertexStrideInBytes; int totalUsed = vertexStrideInBytes*gfxObj->m_vertexArrayOffset+sz; b3Assert(totalUsedm_maxShapeCapacityInBytes); - + memcpy(dest+vertexStrideInBytes*gfxObj->m_vertexArrayOffset,vertices,sz); glUnmapBuffer( GL_ARRAY_BUFFER); @@ -720,7 +720,7 @@ int GLInstancingRenderer::registerShape(const float* vertices, int numvertices, glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBufferSizeInBytes, NULL, GL_STATIC_DRAW); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,0,indexBufferSizeInBytes,indices); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - + glGenVertexArrays(1, &gfxObj->m_cube_vao); glBindVertexArray(gfxObj->m_cube_vao); glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo); @@ -728,7 +728,7 @@ int GLInstancingRenderer::registerShape(const float* vertices, int numvertices, glBindBuffer(GL_ARRAY_BUFFER,0); glBindVertexArray(0); - + return m_graphicsInstances.size()-1; } @@ -737,7 +737,7 @@ int GLInstancingRenderer::registerShape(const float* vertices, int numvertices, void GLInstancingRenderer::InitShaders() { - + int POSITION_BUFFER_SIZE = (m_maxNumObjectCapacity*sizeof(float)*4); int ORIENTATION_BUFFER_SIZE = (m_maxNumObjectCapacity*sizeof(float)*4); int COLOR_BUFFER_SIZE = (m_maxNumObjectCapacity*sizeof(float)*4); @@ -757,12 +757,12 @@ void GLInstancingRenderer::InitShaders() glGenBuffers(1, &linesVertexBufferObject); glGenBuffers(1, &linesIndexVbo); - + int sz = MAX_LINES_IN_BATCH*sizeof(b3Vector3); glBindVertexArray(linesVertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, linesVertexBufferObject); glBufferData(GL_ARRAY_BUFFER, sz, 0, GL_DYNAMIC_DRAW); - + glBindVertexArray(0); } { @@ -771,23 +771,23 @@ void GLInstancingRenderer::InitShaders() glGenBuffers(1, &lineVertexBufferObject); glGenBuffers(1, &lineIndexVbo); - + int sz = MAX_POINTS_IN_BATCH*sizeof(b3Vector3); glBindVertexArray(lineVertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, lineVertexBufferObject); glBufferData(GL_ARRAY_BUFFER, sz, 0, GL_DYNAMIC_DRAW); - + glBindVertexArray(0); } - + //glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, range); glGetIntegerv(GL_SMOOTH_LINE_WIDTH_RANGE, lineWidthRange); - - + + useShadowMapInstancingShader = gltLoadShaderPair(useShadowMapInstancingVertexShader,useShadowMapInstancingFragmentShader); - + glLinkProgram(useShadowMapInstancingShader); glUseProgram(useShadowMapInstancingShader); useShadow_ModelViewMatrix = glGetUniformLocation(useShadowMapInstancingShader, "ModelViewMatrix"); @@ -802,10 +802,14 @@ void GLInstancingRenderer::InitShaders() glLinkProgram(createShadowMapInstancingShader); glUseProgram(createShadowMapInstancingShader); createShadow_depthMVP = glGetUniformLocation(createShadowMapInstancingShader, "depthMVP"); - + if (createShadow_depthMVP==0) + { + printf("Issue with createShadowMapInstancingFragmentShader (createShadow_depthMVP==0), disabling shadow maps\n"); + useShadowMap=false; + } glUseProgram(0); - + instancingShader = gltLoadShaderPair(instancingVertexShader,instancingFragmentShader); glLinkProgram(instancingShader); glUseProgram(instancingShader); @@ -813,13 +817,13 @@ void GLInstancingRenderer::InitShaders() ProjectionMatrix = glGetUniformLocation(instancingShader, "ProjectionMatrix"); uniform_texture_diffuse = glGetUniformLocation(instancingShader, "Diffuse"); glUseProgram(0); - + instancingShaderPointSprite = gltLoadShaderPair(pointSpriteVertexShader,pointSpriteFragmentShader); glUseProgram(instancingShaderPointSprite); ModelViewMatrixPointSprite = glGetUniformLocation(instancingShaderPointSprite, "ModelViewMatrix"); ProjectionMatrixPointSprite = glGetUniformLocation(instancingShaderPointSprite, "ProjectionMatrix"); screenWidthPointSprite = glGetUniformLocation(instancingShaderPointSprite, "screenWidth"); - + glUseProgram(0); //GLuint offset = 0; @@ -839,7 +843,7 @@ void GLInstancingRenderer::InitShaders() glBindVertexArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - + } @@ -850,25 +854,25 @@ void GLInstancingRenderer::init() { GLint err = glGetError(); b3Assert(err==GL_NO_ERROR); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); err = glGetError(); b3Assert(err==GL_NO_ERROR); - + // glClearColor(float(0.),float(0.),float(0.4),float(0)); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + { B3_PROFILE("texture"); if(m_textureenabled) @@ -898,7 +902,7 @@ void GLInstancingRenderer::init() /* const int s=x>>5; - const GLubyte b=180; + const GLubyte b=180; GLubyte c=b+((s+t&1)&1)*(255-b); pi[0]=c; pi[1]=c; @@ -918,44 +922,44 @@ void GLInstancingRenderer::init() glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); err = glGetError(); b3Assert(err==GL_NO_ERROR); - - + + #endif err = glGetError(); b3Assert(err==GL_NO_ERROR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256,256,0,GL_RGB,GL_UNSIGNED_BYTE,image); glGenerateMipmap(GL_TEXTURE_2D); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + delete[] image; m_textureinitialized=true; } - + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glBindTexture(GL_TEXTURE_2D,m_data->m_defaultTexturehandle); err = glGetError(); b3Assert(err==GL_NO_ERROR); - + } else { @@ -965,7 +969,7 @@ void GLInstancingRenderer::init() } } //glEnable(GL_COLOR_MATERIAL); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); @@ -983,27 +987,27 @@ void b3CreateFrustum( float farVal, float frustum[16]) { - + frustum[0*4+0] = (float(2) * nearVal) / (right - left); frustum[0*4+1] = float(0); frustum[0*4+2] = float(0); frustum[0*4+3] = float(0); - + frustum[1*4+0] = float(0); frustum[1*4+1] = (float(2) * nearVal) / (top - bottom); frustum[1*4+2] = float(0); frustum[1*4+3] = float(0); - + frustum[2*4+0] = (right + left) / (right - left); frustum[2*4+1] = (top + bottom) / (top - bottom); frustum[2*4+2] = -(farVal + nearVal) / (farVal - nearVal); frustum[2*4+3] = float(-1); - + frustum[3*4+0] = float(0); frustum[3*4+1] = float(0); frustum[3*4+2] = -(float(2) * farVal * nearVal) / (farVal - nearVal); frustum[3*4+3] = float(0); - + } @@ -1057,11 +1061,11 @@ void b3CreateLookAt(const b3Vector3& eye, const b3Vector3& center,const b3Vec b3Vector3 u = up.normalized(); b3Vector3 s = (f.cross(u)).normalized(); u = s.cross(f); - + result[0*4+0] = s.x; result[1*4+0] = s.y; result[2*4+0] = s.z; - + result[0*4+1] = u.x; result[1*4+1] = u.y; result[2*4+1] = u.z; @@ -1069,7 +1073,7 @@ void b3CreateLookAt(const b3Vector3& eye, const b3Vector3& center,const b3Vec result[0*4+2] =-f.x; result[1*4+2] =-f.y; result[2*4+2] =-f.z; - + result[0*4+3] = 0.f; result[1*4+3] = 0.f; result[2*4+3] = 0.f; @@ -1087,18 +1091,18 @@ void GLInstancingRenderer::resize(int width, int height) m_screenHeight = height; } -void GLInstancingRenderer::updateCamera() +void GLInstancingRenderer::updateCamera() { GLint err = glGetError(); b3Assert(err==GL_NO_ERROR); - + int m_forwardAxis(2); float m_frustumZNear=1; float m_frustumZFar=10000.f; - + // m_azi=m_azi+0.01; b3Scalar rele = m_data->m_ele * b3Scalar(0.01745329251994329547);// rads per deg @@ -1135,7 +1139,7 @@ void GLInstancingRenderer::updateCamera() aspect = m_screenWidth / (b3Scalar)m_screenHeight; extents.setValue(aspect * 1.0f, 1.0f,0); - + if (m_screenWidth > m_screenHeight) { b3CreateFrustum(-aspect * m_frustumZNear, aspect * m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar,projectionMatrix); @@ -1145,8 +1149,8 @@ void GLInstancingRenderer::updateCamera() } b3CreateLookAt(m_data->m_cameraPosition,m_data->m_cameraTargetPosition,m_data->m_cameraUp,modelviewMatrix); - - + + } @@ -1230,9 +1234,9 @@ void GLInstancingRenderer::getMouseDirection(float* dir, int x, int y) vertical *= 2.f * farPlane * tanfov; b3Scalar aspect; - + aspect = m_screenWidth / (b3Scalar)m_screenHeight; - + hor*=aspect; @@ -1262,7 +1266,7 @@ void writeTextureToPng(int textureWidth, int textureHeight, const char* fileName b3Assert(err==GL_NO_ERROR); glPixelStorei(GL_PACK_ALIGNMENT,4); - + glReadBuffer(GL_NONE); float* orgPixels = (float*)malloc(textureWidth*textureHeight*numComponents*4); char* pixels = (char*)malloc(textureWidth*textureHeight*numComponents*4); @@ -1284,7 +1288,7 @@ void writeTextureToPng(int textureWidth, int textureHeight, const char* fileName pixels[(j*textureWidth+i)*numComponents+2]=0;//255.f; pixels[(j*textureWidth+i)*numComponents+3]=255; - + //pixels[(j*textureWidth+i)*+1]=val; //pixels[(j*textureWidth+i)*numComponents+2]=val; //pixels[(j*textureWidth+i)*numComponents+3]=255; @@ -1301,7 +1305,7 @@ void writeTextureToPng(int textureWidth, int textureHeight, const char* fileName { //swap the pixels unsigned char tmp; - + for (int j=0;jm_vbo); GLint err = glGetError(); b3Assert(err==GL_NO_ERROR); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0); int curOffset = 0; @@ -1409,13 +1413,13 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 glUniformMatrix4fv(lines_ProjectionMatrix, 1, false, &projectionMatrix[0]); glUniformMatrix4fv(lines_ModelViewMatrix, 1, false, &modelviewMatrix[0]); glUniform4f(lines_colour,color[0],color[1],color[2],color[3]); - + // glPointSize(pointDrawSize); glBindVertexArray(linesVertexArrayObject); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glBindBuffer(GL_ARRAY_BUFFER, linesVertexBufferObject); { @@ -1463,23 +1467,23 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 err = glGetError(); b3Assert(err==GL_NO_ERROR); - + } void GLInstancingRenderer::drawLine(const float from[4], const float to[4], const float color[4], float lineWidth) { GLint err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0); err = glGetError(); b3Assert(err==GL_NO_ERROR); - + int curOffset = 0; - + glUseProgram(linesShader); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); @@ -1487,7 +1491,7 @@ void GLInstancingRenderer::drawLine(const float from[4], const float to[4], cons glUniformMatrix4fv(lines_ModelViewMatrix, 1, false, &modelviewMatrix[0]); glUniform4f(lines_colour,color[0],color[1],color[2],color[3]); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); @@ -1499,10 +1503,10 @@ void GLInstancingRenderer::drawLine(const float from[4], const float to[4], cons err = glGetError(); b3Assert(err==GL_NO_ERROR); - + b3Clamp(lineWidth,(float)lineWidthRange[0],(float)lineWidthRange[1]); glLineWidth(lineWidth); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); @@ -1515,12 +1519,12 @@ void GLInstancingRenderer::drawLine(const float from[4], const float to[4], cons err = glGetError(); b3Assert(err==GL_NO_ERROR); - + { glBufferSubData(GL_ARRAY_BUFFER, 0,sz, vertexPositions); } - - + + err = glGetError(); b3Assert(err==GL_NO_ERROR); @@ -1538,18 +1542,18 @@ void GLInstancingRenderer::drawLine(const float from[4], const float to[4], cons err = glGetError(); b3Assert(err==GL_NO_ERROR); - + glBindVertexArray(0); glLineWidth(1); - + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + } void GLInstancingRenderer::renderSceneInternal(int renderMode) { - + // glEnable(GL_DEPTH_TEST); GLint dims[4]; @@ -1557,7 +1561,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) //we need to get the viewport dims, because on Apple Retina the viewport dimension is different from screenWidth //printf("dims=%d,%d,%d,%d\n",dims[0],dims[1],dims[2],dims[3]); // Accept fragment if it closer to the camera than the former one - //glDepthFunc(GL_LESS); + //glDepthFunc(GL_LESS); // Cull triangles which normal is not towards the camera //glEnable(GL_CULL_FACE); @@ -1570,8 +1574,8 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) B3_PROFILE("init"); init(); } - - + + GLint err = glGetError(); b3Assert(err==GL_NO_ERROR); @@ -1585,7 +1589,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) { glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); - + if (!m_data->m_shadowMap) { glActiveTexture(GL_TEXTURE0); @@ -1595,7 +1599,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) //glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT16,m_screenWidth,m_screenHeight,0,GL_DEPTH_COMPONENT,GL_FLOAT,0); //glTexImage2D(GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT32,m_screenWidth,m_screenHeight,0,GL_DEPTH_COMPONENT,GL_FLOAT,0); glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, shadowMapWidth, shadowMapHeight, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0); - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -1628,7 +1632,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) { glDisable(GL_CULL_FACE); //glCullFace(GL_BACK); - + } static b3Vector3 lightPos = b3MakeVector3(-5.f,200,-40);//20,15,10);//-13,6,2);// = b3Vector3(0.5f,2,2); // lightPos.y+=0.1f; @@ -1643,12 +1647,12 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) b3CreateDiagonalMatrix(1.f,depthModelMatrix); b3Matrix4x4Mul(depthViewMatrix, depthModelMatrix, depthModelViewMatrix); - + GLfloat depthMVP[4][4]; b3Matrix4x4Mul(depthProjectionMatrix,depthModelViewMatrix,depthMVP); - + GLfloat biasMatrix[4][4]={ - 0.5, 0.0, 0.0, 0.0, + 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.5, 1.0 @@ -1657,14 +1661,14 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) GLfloat depthBiasMVP[4][4]; b3Matrix4x4Mul(biasMatrix,depthMVP,depthBiasMVP); - + //float m_frustumZNear=0.1; //float m_frustumZFar=100.f; - + //b3CreateFrustum(-m_frustumZNear, m_frustumZNear, -m_frustumZNear, m_frustumZNear, m_frustumZNear, m_frustumZFar,(float*)depthProjectionMatrix); - + //b3CreateLookAt(lightPos,m_data->m_cameraTargetPosition,b3Vector3(0,0,1),(float*)depthModelViewMatrix); @@ -1675,7 +1679,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) err = glGetError(); b3Assert(err==GL_NO_ERROR); - + // glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -1687,7 +1691,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) } err = glGetError(); b3Assert(err==GL_NO_ERROR); - + int totalNumInstances = 0; @@ -1702,7 +1706,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) for (int i=0;im_numGraphicsInstances) { @@ -1730,7 +1734,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) glBindVertexArray(gfxObj->m_cube_vao); - + int vertexStride = 9*sizeof(float); int vertexBase = gfxObj->m_vertexArrayOffset*vertexStride; @@ -1759,26 +1763,26 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) glVertexAttribDivisorARB(4, 0); glVertexAttribDivisorARB(5, 1); glVertexAttribDivisorARB(6, 1); - - - - - + + + + + int indexCount = gfxObj->m_numIndices; int indexOffset = 0; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gfxObj->m_index_vbo); { B3_PROFILE("glDrawElementsInstanced"); - + if (gfxObj->m_primitiveType==B3_GL_POINTS) { glUseProgram(instancingShaderPointSprite); glUniformMatrix4fv(ProjectionMatrixPointSprite, 1, false, &projectionMatrix[0]); glUniformMatrix4fv(ModelViewMatrixPointSprite, 1, false, &modelviewMatrix[0]); glUniform1f(screenWidthPointSprite,m_screenWidth); - + //glUniform1i(uniform_texture_diffusePointSprite, 0); err = glGetError(); b3Assert(err==GL_NO_ERROR); @@ -1807,6 +1811,12 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) } case B3_CREATE_SHADOWMAP_RENDERMODE: { + /*printf("createShadowMapInstancingShader=%d\n",createShadowMapInstancingShader); + printf("createShadow_depthMVP=%d\n",createShadow_depthMVP); + printf("indexOffset=%d\n",indexOffset); + printf("gfxObj->m_numGraphicsInstances=%d\n",gfxObj->m_numGraphicsInstances); + printf("indexCount=%d\n",indexCount); + */ glUseProgram(createShadowMapInstancingShader); glUniformMatrix4fv(createShadow_depthMVP, 1, false, &depthMVP[0][0]); glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); @@ -1835,7 +1845,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) }; } - + //glDrawElementsInstanced(GL_LINE_LOOP, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); } } @@ -1862,13 +1872,13 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) glBindBuffer(GL_ARRAY_BUFFER,0); glBindVertexArray(0); } - - + + err = glGetError(); b3Assert(err==GL_NO_ERROR); - + } diff --git a/btgui/OpenGLWindow/LoadShader.cpp b/btgui/OpenGLWindow/LoadShader.cpp index aa2971337..efef4550a 100644 --- a/btgui/OpenGLWindow/LoadShader.cpp +++ b/btgui/OpenGLWindow/LoadShader.cpp @@ -9,7 +9,7 @@ void gltLoadShaderSrc(const char *szShaderSrc, GLuint shader) { GLchar *fsStringPtr[1]; - + fsStringPtr[0] = (GLchar *)szShaderSrc; glShaderSource(shader, 1, (const GLchar **)fsStringPtr, NULL); } @@ -17,29 +17,27 @@ void gltLoadShaderSrc(const char *szShaderSrc, GLuint shader) GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg) { + + GLuint err = glGetError(); + assert(err==GL_NO_ERROR); + // Temporary Shader objects GLuint hVertexShader; GLuint hFragmentShader; GLuint hReturn = 0; GLint testVal; - + // Create shader objects hVertexShader = glCreateShader(GL_VERTEX_SHADER); hFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - + gltLoadShaderSrc(szVertexProg, hVertexShader); gltLoadShaderSrc(szFragmentProg, hFragmentShader); - + // Compile them glCompileShader(hVertexShader); - GLuint err = glGetError(); - assert(err==GL_NO_ERROR); - - glCompileShader(hFragmentShader); err = glGetError(); - assert(err==GL_NO_ERROR); - - // Check for errors + glGetShaderiv(hVertexShader, GL_COMPILE_STATUS, &testVal); if(testVal == GL_FALSE) { @@ -52,8 +50,13 @@ GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg) glDeleteShader(hFragmentShader); return (GLuint)NULL; } - - glGetShaderiv(hFragmentShader, GL_COMPILE_STATUS, &testVal); + + assert(err==GL_NO_ERROR); + + glCompileShader(hFragmentShader); + err = glGetError(); + + glGetShaderiv(hFragmentShader, GL_COMPILE_STATUS, &testVal); if(testVal == GL_FALSE) { char temp[256] = ""; @@ -65,18 +68,25 @@ GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg) glDeleteShader(hFragmentShader); return (GLuint)NULL; } - + + assert(err==GL_NO_ERROR); + + // Check for errors + + + + // Link them - assuming it works... hReturn = glCreateProgram(); glAttachShader(hReturn, hVertexShader); glAttachShader(hReturn, hFragmentShader); - + glLinkProgram(hReturn); - + // These are no longer needed glDeleteShader(hVertexShader); glDeleteShader(hFragmentShader); - + // Make sure link worked too glGetProgramiv(hReturn, GL_LINK_STATUS, &testVal); if(testVal == GL_FALSE) @@ -84,7 +94,7 @@ GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg) GLsizei maxLen = 4096; GLchar infoLog[4096]; GLsizei actualLen; - + glGetProgramInfoLog( hReturn, maxLen, &actualLen, @@ -95,8 +105,8 @@ GLuint gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg) glDeleteProgram(hReturn); return (GLuint)NULL; } - - return hReturn; + + return hReturn; } diff --git a/btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h b/btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h index 8b2dce8f1..f94672a14 100644 --- a/btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h +++ b/btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h @@ -5,6 +5,6 @@ static const char* createShadowMapInstancingFragmentShader= \ "layout(location = 0) out float fragmentdepth;\n" "void main(void)\n" "{\n" -" fragmentdepth = gl_FragCoord.z;\n" +" fragmentdepth = gl_FragCoord.z+0.0001*gl_FragCoord.x;\n" "}\n" ; diff --git a/btgui/OpenGLWindow/Shaders/createShadowMapInstancingVS.h b/btgui/OpenGLWindow/Shaders/createShadowMapInstancingVS.h index 2a8aef96b..58fc1da51 100644 --- a/btgui/OpenGLWindow/Shaders/createShadowMapInstancingVS.h +++ b/btgui/OpenGLWindow/Shaders/createShadowMapInstancingVS.h @@ -5,9 +5,6 @@ static const char* createShadowMapInstancingVertexShader= \ "layout (location = 0) in vec4 position;\n" "layout (location = 1) in vec4 instance_position;\n" "layout (location = 2) in vec4 instance_quaternion;\n" -"layout (location = 3) in vec2 uvcoords;\n" -"layout (location = 4) in vec3 vertexnormal;\n" -"layout (location = 5) in vec4 instance_color;\n" "layout (location = 6) in vec3 instance_scale;\n" "uniform mat4 depthMVP;\n" "vec4 quatMul ( in vec4 q1, in vec4 q2 )\n" diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index 1dd995fdc..2be04937b 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -1,6 +1,5 @@ #include "SimpleOpenGL3App.h" #include "ShapeData.h" - #ifdef __APPLE__ #include "OpenGLWindow/MacOpenGLWindow.h" #else @@ -78,17 +77,44 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) m_window->createWindow(ci); m_window->setWindowTitle(title); + + GLuint err = glGetError(); + assert(err==GL_NO_ERROR); + glClearColor(1,1,1,1); m_window->startRendering(); + err = glGetError(); + assert(err==GL_NO_ERROR); + #ifndef __APPLE__ - glewInit(); +#ifndef _WIN32 +//some Linux implementations need the 'glewExperimental' to be true + glewExperimental = GL_TRUE; #endif + err = glewInit(); + if (err != GLEW_OK) + exit(1); // or handle the error in a nicer way + if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API. + exit(1); // or handle the error in a nicer way + +#endif + err = glGetError(); + err = glGetError(); + assert(err==GL_NO_ERROR); + m_primRenderer = new GLPrimitiveRenderer(width,height); + err = glGetError(); + assert(err==GL_NO_ERROR); + m_instancingRenderer = new GLInstancingRenderer(128*1024,4*1024*1024); m_instancingRenderer->init(); m_instancingRenderer->resize(width,height); + + err = glGetError(); + assert(err==GL_NO_ERROR); + m_instancingRenderer->InitShaders(); m_window->setMouseMoveCallback(b3DefaultMouseMoveCallback); diff --git a/btgui/OpenGLWindow/X11OpenGLWindow.cpp b/btgui/OpenGLWindow/X11OpenGLWindow.cpp index 6b5bcb39d..2091c1d86 100644 --- a/btgui/OpenGLWindow/X11OpenGLWindow.cpp +++ b/btgui/OpenGLWindow/X11OpenGLWindow.cpp @@ -10,11 +10,14 @@ //#include #include +#include +#include +#include #include GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; - +static bool forceOpenGL3 = true; struct InternalData2 { @@ -27,6 +30,7 @@ struct InternalData2 GLXContext m_glc; XWindowAttributes m_gwa; XEvent m_xev; + GLXFBConfig m_bestFbc; b3WheelCallback m_wheelCallback; b3MouseMoveCallback m_mouseMoveCallback; @@ -47,6 +51,49 @@ struct InternalData2 } }; +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); + +// Helper to check for extension string presence. Adapted from: +// http://www.opengl.org/resources/features/OGLextensions/ +static bool isExtensionSupported(const char *extList, const char *extension) +{ + const char *start; + const char *where, *terminator; + + /* Extension names should not have spaces. */ + where = strchr(extension, ' '); + if (where || *extension == '\0') + return false; + + /* It takes a bit of care to be fool-proof about parsing the + OpenGL extensions string. Don't be fooled by sub-strings, + etc. */ + for (start=extList;;) { + where = strstr(start, extension); + + if (!where) + break; + + terminator = where + strlen(extension); + + if ( where == start || *(where - 1) == ' ' ) + if ( *terminator == ' ' || *terminator == '\0' ) + return true; + + start = terminator; + } + + return false; +} + +static bool ctxErrorOccurred = false; +static int ctxErrorHandler( Display *dpy, XErrorEvent *ev ) +{ + ctxErrorOccurred = true; + return 0; +} @@ -73,9 +120,117 @@ X11OpenGLWindow::~X11OpenGLWindow() void X11OpenGLWindow::enableOpenGL() { - m_data->m_glc = glXCreateContext(m_data->m_dpy, m_data->m_vi, NULL, GL_TRUE); - glXMakeCurrent(m_data->m_dpy, m_data->m_win, m_data->m_glc); + if (forceOpenGL3) + { + // Get the default screen's GLX extension list + const char *glxExts = glXQueryExtensionsString( m_data->m_dpy, + DefaultScreen( m_data->m_dpy ) ); + // NOTE: It is not necessary to create or make current to a context before + // calling glXGetProcAddressARB + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) + glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); + + GLXContext ctx = 0; + + // Install an X error handler so the application won't exit if GL 3.0 + // context allocation fails. + // + // Note this error handler is global. All display connections in all threads + // of a process use the same error handler, so be sure to guard against other + // threads issuing X commands while this code is running. + ctxErrorOccurred = false; + int (*oldHandler)(Display*, XErrorEvent*) = + XSetErrorHandler(&ctxErrorHandler); + + // Check for the GLX_ARB_create_context extension string and the function. + // If either is not present, use GLX 1.3 context creation method. + if ( !isExtensionSupported( glxExts, "GLX_ARB_create_context" ) || + !glXCreateContextAttribsARB ) + { + printf( "glXCreateContextAttribsARB() not found" + " ... using old-style GLX context\n" ); + ctx = glXCreateNewContext( m_data->m_dpy, m_data->m_bestFbc, GLX_RGBA_TYPE, 0, True ); + } + + // If it does, try to get a GL 3.0 context! + else + { + int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB ,3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,None + }; +/* + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, + + //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + None + }; +*/ + printf( "Creating context\n" ); + ctx = glXCreateContextAttribsARB( m_data->m_dpy, m_data->m_bestFbc, 0, + True, context_attribs ); + + // Sync to ensure any errors generated are processed. + XSync( m_data->m_dpy, False ); + if ( !ctxErrorOccurred && ctx ) + printf( "Created GL 3.0 context\n" ); + else + { + // Couldn't create GL 3.0 context. Fall back to old-style 2.x context. + // When a context version below 3.0 is requested, implementations will + // return the newest context version compatible with OpenGL versions less + // than version 3.0. + // GLX_CONTEXT_MAJOR_VERSION_ARB = 1 + context_attribs[1] = 1; + // GLX_CONTEXT_MINOR_VERSION_ARB = 0 + context_attribs[3] = 0; + + ctxErrorOccurred = false; + + printf( "Failed to create GL 3.0 context" + " ... using old-style GLX context\n" ); + ctx = glXCreateContextAttribsARB( m_data->m_dpy, m_data->m_bestFbc, 0, + True, context_attribs ); + } + } + + // Sync to ensure any errors generated are processed. + XSync( m_data->m_dpy, False ); + + // Restore the original error handler + XSetErrorHandler( oldHandler ); + + if ( ctxErrorOccurred || !ctx ) + { + printf( "Failed to create an OpenGL context\n" ); + exit(1); + } + + // Verifying that context is a direct context + if ( ! glXIsDirect ( m_data->m_dpy, ctx ) ) + { + printf( "Indirect GLX rendering context obtained\n" ); + } + else + { + printf( "Direct GLX rendering context obtained\n" ); + } + + printf( "Making context current\n" ); + glXMakeCurrent( m_data->m_dpy, m_data->m_win, ctx ); + + } else + { + m_data->m_glc = glXCreateContext(m_data->m_dpy, m_data->m_vi, NULL, GL_TRUE); + glXMakeCurrent(m_data->m_dpy, m_data->m_win, m_data->m_glc); + } const GLubyte* ven = glGetString(GL_VENDOR); printf("GL_VENDOR=%s\n", ven); const GLubyte* ren = glGetString(GL_RENDERER); @@ -104,6 +259,7 @@ void X11OpenGLWindow::disableOpenGL() void X11OpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) { +printf("createWindow\n"); m_data->m_dpy = XOpenDisplay(NULL); if(m_data->m_dpy == NULL) { @@ -111,29 +267,123 @@ void X11OpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) exit(0); } - m_data->m_root = DefaultRootWindow(m_data->m_dpy); + m_data->m_root = DefaultRootWindow(m_data->m_dpy); - m_data->m_vi = glXChooseVisual(m_data->m_dpy, 0, att); - if(m_data->m_vi == NULL) { - printf("\n\tno appropriate visual found\n\n"); + + if (forceOpenGL3) + { + int glxMinor, glxMajor; + if (!glXQueryVersion(m_data->m_dpy,&glxMajor,&glxMinor) || (((glxMajor==1)&&(glxMinor<3)) || (glxMajor<1))) + { + printf("Invalid GLX version: major %d, minor %d\n",glxMajor,glxMinor); exit(0); - } - else { - printf("\n\tvisual %p selected\n", (void *)m_data->m_vi->visualid); /* %p creates hexadecimal output like in glxinfo */ - } + } + + static int visual_attribs[] = + { + GLX_X_RENDERABLE , True, + GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, + GLX_RENDER_TYPE , GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, + GLX_RED_SIZE , 8, + GLX_GREEN_SIZE , 8, + GLX_BLUE_SIZE , 8, + GLX_ALPHA_SIZE , 8, + GLX_DEPTH_SIZE , 24, + GLX_STENCIL_SIZE , 8, + GLX_DOUBLEBUFFER , True, + None + }; + int fbcount; + GLXFBConfig* fbc = glXChooseFBConfig(m_data->m_dpy, DefaultScreen(m_data->m_dpy), visual_attribs, &fbcount); + if (!fbc) + { + printf( "Failed to retrieve a framebuffer config\n" ); + exit(1); + } + + int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; + + int i; + for (i=0; im_dpy, fbc[i] ); + if ( vi ) + { + int samp_buf, samples; + glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf ); + glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLES , &samples ); + + //printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," + // " SAMPLES = %d\n", + // i, vi -> visualid, samp_buf, samples ); + + if ( best_fbc < 0 || samp_buf && samples > best_num_samp ) + best_fbc = i, best_num_samp = samples; + if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) + worst_fbc = i, worst_num_samp = samples; + } + XFree( vi ); + } + + m_data->m_bestFbc = fbc[ best_fbc ]; + // Be sure to free the FBConfig list allocated by glXChooseFBConfig() + XFree( fbc ); + + m_data->m_vi = glXGetVisualFromFBConfig( m_data->m_dpy, m_data->m_bestFbc ); - m_data->m_cmap = XCreateColormap(m_data->m_dpy, m_data->m_root, m_data->m_vi->visual, AllocNone); + m_data->m_swa.colormap = m_data->m_cmap = XCreateColormap( m_data->m_dpy, + RootWindow( m_data->m_dpy, m_data->m_vi->screen ), + m_data->m_vi->visual, AllocNone ); + m_data->m_swa.background_pixmap = None ; + m_data->m_swa.border_pixel = 0; + m_data->m_swa.event_mask = ExposureMask | KeyReleaseMask | KeyPressMask |ButtonPressMask | ButtonReleaseMask |PointerMotionMask|StructureNotifyMask; +; + m_data->m_root = RootWindow( m_data->m_dpy, m_data->m_vi->screen ); - m_data->m_swa.colormap = m_data->m_cmap; - m_data->m_swa.event_mask = ExposureMask | KeyReleaseMask | KeyPressMask |ButtonPressMask | ButtonReleaseMask |PointerMotionMask|StructureNotifyMask; + m_data->m_win = XCreateWindow( m_data->m_dpy, m_data->m_root, + 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, + m_data->m_vi->visual, + CWBorderPixel|CWColormap|CWEventMask, &m_data->m_swa ); - m_data->m_win = XCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); + //m_data->m_win = XCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); - XMapWindow(m_data->m_dpy, m_data->m_win); - XStoreName(m_data->m_dpy, m_data->m_win, "VERY SIMPLE APPLICATION"); + if (!m_data->m_win) + { + printf("Cannot create window\n"); + exit(0); + } + + XMapWindow(m_data->m_dpy, m_data->m_win); + XStoreName(m_data->m_dpy, m_data->m_win, "OpenGL3 Window"); + + + } else + { + m_data->m_vi = glXChooseVisual(m_data->m_dpy, 0, att); + + if(m_data->m_vi == NULL) { + printf("\n\tno appropriate visual found\n\n"); + exit(0); + } + else { + printf("\n\tvisual %p selected\n", (void *)m_data->m_vi->visualid); /* %p creates hexadecimal output like in glxinfo */ + } + + + m_data->m_cmap = XCreateColormap(m_data->m_dpy, m_data->m_root, m_data->m_vi->visual, AllocNone); + + m_data->m_swa.colormap = m_data->m_cmap; + m_data->m_swa.event_mask = ExposureMask | KeyReleaseMask | KeyPressMask |ButtonPressMask | ButtonReleaseMask |PointerMotionMask|StructureNotifyMask; + + m_data->m_win = XCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); + + XMapWindow(m_data->m_dpy, m_data->m_win); + XStoreName(m_data->m_dpy, m_data->m_win, "OpenGL3 Window"); + } enableOpenGL(); } @@ -153,13 +403,19 @@ int X11OpenGLWindow::getAsciiCodeFromVirtualKeycode(int keycode) switch( key ) { case XK_Escape: return B3G_ESCAPE; - + case XK_Return: return B3G_RETURN; + case XK_Control_L: case XK_Control_R: { return B3G_CONTROL; - } - case XK_Alt_L: - case XK_Alt_R: + } + case XK_Left: return B3G_LEFT_ARROW; + case XK_Right: return B3G_RIGHT_ARROW; + case XK_Up: return B3G_UP_ARROW; + case XK_Down: return B3G_DOWN_ARROW; + + case XK_Alt_L: + case XK_Alt_R: { return B3G_ALT; } From 4189a9a67fb952f2884f453156484f9061fbd2ea Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Tue, 24 Jun 2014 20:12:05 -0700 Subject: [PATCH 071/116] fix issue with Intel OpenGL 3.x driver under Ubuntu, render to texture cannot handle glDrawBuffer(GL_NONE) --- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 5 ----- btgui/OpenGLWindow/GLRenderToTexture.cpp | 4 +++- btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index f5f86e70f..d8789ff08 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -802,11 +802,6 @@ void GLInstancingRenderer::InitShaders() glLinkProgram(createShadowMapInstancingShader); glUseProgram(createShadowMapInstancingShader); createShadow_depthMVP = glGetUniformLocation(createShadowMapInstancingShader, "depthMVP"); - if (createShadow_depthMVP==0) - { - printf("Issue with createShadowMapInstancingFragmentShader (createShadow_depthMVP==0), disabling shadow maps\n"); - useShadowMap=false; - } glUseProgram(0); diff --git a/btgui/OpenGLWindow/GLRenderToTexture.cpp b/btgui/OpenGLWindow/GLRenderToTexture.cpp index 332967e5e..aee7e7b40 100644 --- a/btgui/OpenGLWindow/GLRenderToTexture.cpp +++ b/btgui/OpenGLWindow/GLRenderToTexture.cpp @@ -66,7 +66,9 @@ bool GLRenderToTexture::enable() } case RENDERTEXTURE_DEPTH: { - glDrawBuffer(GL_NONE); + GLenum drawBuffers[2] = {GL_DEPTH_ATTACHMENT,0}; + glDrawBuffers(1, drawBuffers); + //glDrawBuffer(GL_NONE); break; } default: diff --git a/btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h b/btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h index f94672a14..8b2dce8f1 100644 --- a/btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h +++ b/btgui/OpenGLWindow/Shaders/createShadowMapInstancingPS.h @@ -5,6 +5,6 @@ static const char* createShadowMapInstancingFragmentShader= \ "layout(location = 0) out float fragmentdepth;\n" "void main(void)\n" "{\n" -" fragmentdepth = gl_FragCoord.z+0.0001*gl_FragCoord.x;\n" +" fragmentdepth = gl_FragCoord.z;\n" "}\n" ; From b063cfc5099484df118edbfd9d2e92d71530ae05 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 24 Jun 2014 20:24:31 -0700 Subject: [PATCH 072/116] more workaround for glDrawBuffers issue --- btgui/OpenGLWindow/GLRenderToTexture.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/btgui/OpenGLWindow/GLRenderToTexture.cpp b/btgui/OpenGLWindow/GLRenderToTexture.cpp index aee7e7b40..99929956c 100644 --- a/btgui/OpenGLWindow/GLRenderToTexture.cpp +++ b/btgui/OpenGLWindow/GLRenderToTexture.cpp @@ -66,9 +66,9 @@ bool GLRenderToTexture::enable() } case RENDERTEXTURE_DEPTH: { - GLenum drawBuffers[2] = {GL_DEPTH_ATTACHMENT,0}; - glDrawBuffers(1, drawBuffers); - //glDrawBuffer(GL_NONE); + GLenum drawBuffers[2] = { GL_NONE, 0 };// GL_DEPTH_ATTACHMENT, 0}; + glDrawBuffers(1, drawBuffers); +// glDrawBuffer(GL_NONE); break; } default: From a7f0567d046ab5ccdae405e1f80ebe8e4205978b Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 24 Jun 2014 20:44:01 -0700 Subject: [PATCH 073/116] more workaround for the Intel glDrawBuffers issue --- btgui/OpenGLWindow/GLRenderToTexture.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/btgui/OpenGLWindow/GLRenderToTexture.cpp b/btgui/OpenGLWindow/GLRenderToTexture.cpp index 99929956c..04a028ea8 100644 --- a/btgui/OpenGLWindow/GLRenderToTexture.cpp +++ b/btgui/OpenGLWindow/GLRenderToTexture.cpp @@ -66,7 +66,7 @@ bool GLRenderToTexture::enable() } case RENDERTEXTURE_DEPTH: { - GLenum drawBuffers[2] = { GL_NONE, 0 };// GL_DEPTH_ATTACHMENT, 0}; + GLenum drawBuffers[2] = { GL_COLOR_ATTACHMENT0, 0 };// GL_DEPTH_ATTACHMENT, 0}; glDrawBuffers(1, drawBuffers); // glDrawBuffer(GL_NONE); break; From 771a2e0bcbb98c624b418452cf586672ce6e60db Mon Sep 17 00:00:00 2001 From: erwin coumans Date: Thu, 26 Jun 2014 22:06:01 -0700 Subject: [PATCH 074/116] enable auto-conversion of btConvexHullShape to basic graphics representation for the GLInstancedPrimitiveRenderer --- .../BasicDemo/Bullet2RigidBodyDemo.cpp | 70 ++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp index 9d6077bd1..fad0a877a 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp @@ -1,6 +1,14 @@ #include "Bullet2RigidBodyDemo.h" #include "btBulletDynamicsCommon.h" #include "OpenGLWindow/SimpleOpenGL3App.h" +#include "BulletCollision/CollisionShapes/btShapeHull.h"//to create a tesselation of a generic btConvexShape +struct GraphicsVertex +{ + float pos[4]; + float normal[3]; + float texcoord[2]; +}; + struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge { @@ -33,9 +41,69 @@ struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge box->setUserIndex(cubeShapeId); break; } + default: { - btAssert(0); + if (collisionShape->isConvex()) + { + btConvexShape* convex = (btConvexShape*)collisionShape; + { + btShapeHull* hull = new btShapeHull(convex); + hull->buildHull(0.0); + + { + int strideInBytes = 9*sizeof(float); + int numVertices = hull->numVertices(); + int numIndices =hull->numIndices(); + + btAlignedObjectArray gvertices; + btAlignedObjectArray indices; + + for (int t=0;tnumTriangles();t++) + { + + btVector3 triNormal; + + int index0 = hull->getIndexPointer()[t*3+0]; + int index1 = hull->getIndexPointer()[t*3+1]; + int index2 = hull->getIndexPointer()[t*3+2]; + btVector3 pos0 =hull->getVertexPointer()[index0]; + btVector3 pos1 =hull->getVertexPointer()[index1]; + btVector3 pos2 =hull->getVertexPointer()[index2]; + triNormal = (pos1-pos0).cross(pos2-pos0); + triNormal.normalize(); + + for (int v=0;v<3;v++) + { + int index = hull->getIndexPointer()[t*3+v]; + GraphicsVertex vtx; + btVector3 pos =hull->getVertexPointer()[index]; + vtx.pos[0] = pos.x(); + vtx.pos[1] = pos.y(); + vtx.pos[2] = pos.z(); + vtx.pos[3] = 0.f; + + vtx.normal[0] =triNormal.x(); + vtx.normal[1] =triNormal.y(); + vtx.normal[2] =triNormal.z(); + vtx.normal[3] =0; + vtx.texcoord[0] = 0.5f; + vtx.texcoord[1] = 0.5f; + + indices.push_back(gvertices.size()); + gvertices.push_back(vtx); + } + } + + + int shapeId = m_glApp->m_instancingRenderer->registerShape(&gvertices[0].pos[0],gvertices.size(),&indices[0],indices.size()); + convex->setUserIndex(shapeId); + } + } + } else + { + btAssert(0); + } } }; } From 063a0344acdae57df0321d898f1375d68a152aaf Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Fri, 27 Jun 2014 17:18:25 -0700 Subject: [PATCH 075/116] better workaround for Intel GPU crash for glDrawBuffer on Linux fix a linux build issue --- Demos3/bullet2/RagdollDemo/RagdollDemo.h | 2 +- btgui/OpenGLWindow/GLRenderToTexture.cpp | 15 ++++++++++++--- btgui/OpenGLWindow/X11OpenGLWindow.cpp | 7 +++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Demos3/bullet2/RagdollDemo/RagdollDemo.h b/Demos3/bullet2/RagdollDemo/RagdollDemo.h index e633d0574..e42379565 100644 --- a/Demos3/bullet2/RagdollDemo/RagdollDemo.h +++ b/Demos3/bullet2/RagdollDemo/RagdollDemo.h @@ -2,7 +2,7 @@ #define RAGDOLL_DEMO_H -#include "../../Demos/CommonRigidBodySetup.h" +#include "../../../Demos/CommonRigidBodySetup.h" #include "../BasicDemo/BasicDemo.h" struct BulletDemoInterface; diff --git a/btgui/OpenGLWindow/GLRenderToTexture.cpp b/btgui/OpenGLWindow/GLRenderToTexture.cpp index 04a028ea8..ed9dec575 100644 --- a/btgui/OpenGLWindow/GLRenderToTexture.cpp +++ b/btgui/OpenGLWindow/GLRenderToTexture.cpp @@ -1,6 +1,8 @@ ///See http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/ +bool gIntelLinuxglDrawBufferWorkaround=false; + #include "GLRenderToTexture.h" #include "Bullet3Common/b3Scalar.h" // for b3Assert GLRenderToTexture::GLRenderToTexture() @@ -66,9 +68,16 @@ bool GLRenderToTexture::enable() } case RENDERTEXTURE_DEPTH: { - GLenum drawBuffers[2] = { GL_COLOR_ATTACHMENT0, 0 };// GL_DEPTH_ATTACHMENT, 0}; - glDrawBuffers(1, drawBuffers); -// glDrawBuffer(GL_NONE); + //Intel OpenGL driver crashes when using GL_NONE for glDrawBuffer on Linux, so use a workaround + if (gIntelLinuxglDrawBufferWorkaround) + { + GLenum drawBuffers[2] = { GL_DEPTH_ATTACHMENT,0}; + glDrawBuffers(1, drawBuffers); + + } else + { + glDrawBuffer(GL_NONE); + } break; } default: diff --git a/btgui/OpenGLWindow/X11OpenGLWindow.cpp b/btgui/OpenGLWindow/X11OpenGLWindow.cpp index 2091c1d86..a872767b0 100644 --- a/btgui/OpenGLWindow/X11OpenGLWindow.cpp +++ b/btgui/OpenGLWindow/X11OpenGLWindow.cpp @@ -15,6 +15,7 @@ #include #include +extern bool gIntelLinuxglDrawBufferWorkaround; GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; static bool forceOpenGL3 = true; @@ -233,6 +234,12 @@ void X11OpenGLWindow::enableOpenGL() } const GLubyte* ven = glGetString(GL_VENDOR); printf("GL_VENDOR=%s\n", ven); + + if (strncmp((const char*)ven,"Intel",5)==0) + { + printf("Workaround for some crash in the Intel OpenGL driver on Linux/Ubuntu\n"); + gIntelLinuxglDrawBufferWorkaround=true; + } const GLubyte* ren = glGetString(GL_RENDERER); printf("GL_RENDERER=%s\n",ren); const GLubyte* ver = glGetString(GL_VERSION); From 791b5149f6c65371b26ea0003a27ddf8d261dd09 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 30 Jun 2014 12:09:59 -0700 Subject: [PATCH 076/116] prepare to re-enable Gwen user interface (OpenGL_DebugFont) for OpenGL2.x prepare to add improved btGeneric6DofSpringConstraint --- Demos3/GpuDemos/gwenUserInterface.cpp | 2 +- btgui/Gwen/BaseRender.h | 1 + btgui/Gwen/Renderers/OpenGL_DebugFont.cpp | 405 ++++++++++++++++++ btgui/Gwen/Renderers/OpenGL_DebugFont.h | 2 + btgui/GwenOpenGLTest/OpenGLSample.cpp | 52 ++- btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h | 2 +- .../ConstraintSolver/btTypedConstraint.h | 1 + 7 files changed, 458 insertions(+), 7 deletions(-) create mode 100644 btgui/Gwen/Renderers/OpenGL_DebugFont.cpp diff --git a/Demos3/GpuDemos/gwenUserInterface.cpp b/Demos3/GpuDemos/gwenUserInterface.cpp index 28204e09d..a0aa18e2e 100644 --- a/Demos3/GpuDemos/gwenUserInterface.cpp +++ b/Demos3/GpuDemos/gwenUserInterface.cpp @@ -318,7 +318,7 @@ void GwenUserInterface::draw(int width, int height) { m_data->pCanvas->SetSize(width,height); m_data->m_primRenderer->setScreenSize(width,height); - m_data->pRenderer->resize(width,height); + m_data->pRenderer->Resize(width,height); m_data->pCanvas->RenderCanvas(); //restoreOpenGLState(); } diff --git a/btgui/Gwen/BaseRender.h b/btgui/Gwen/BaseRender.h index 1932461ca..80daaa375 100644 --- a/btgui/Gwen/BaseRender.h +++ b/btgui/Gwen/BaseRender.h @@ -74,6 +74,7 @@ namespace Gwen virtual Gwen::Point MeasureText( Gwen::Font* pFont, const Gwen::String& text ); virtual void RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::String& text ); + virtual void Resize(int width, int height)=0; public: // diff --git a/btgui/Gwen/Renderers/OpenGL_DebugFont.cpp b/btgui/Gwen/Renderers/OpenGL_DebugFont.cpp new file mode 100644 index 000000000..078598791 --- /dev/null +++ b/btgui/Gwen/Renderers/OpenGL_DebugFont.cpp @@ -0,0 +1,405 @@ + +#include "OpenGL_DebugFont.h" +#include "Gwen/Utility.h" +#include "Gwen/Font.h" +#include "Gwen/Texture.h" + +#include +#include "OpenGLWindow/GlewWindows/GL/glew.h" + +#include "FontData.h" + + //saved OpenGL settings + GLfloat m_PrevLineWidth; + GLint m_PrevTexEnv; + GLint m_PrevPolygonMode[2]; + GLint m_MaxClipPlanes; + GLint m_PrevTexture; + GLint m_PrevArrayBufferARB; + GLint m_PrevElementArrayBufferARB; + GLboolean m_PrevVertexProgramARB; + GLboolean m_PrevFragmentProgramARB; + GLuint m_PrevProgramObjectARB; + GLboolean m_PrevTexture3D; + GLboolean m_PrevActiveTexture1D[32]; + GLboolean m_PrevActiveTexture2D[32]; + GLboolean m_PrevActiveTexture3D[32]; + GLint m_PrevActiveTextureARB; + bool m_SupportTexRect; + GLboolean m_PrevTexRectARB; + GLint m_PrevBlendEquation; + GLint m_PrevBlendEquationRGB; + GLint m_PrevBlendEquationAlpha; + GLint m_PrevBlendSrcRGB; + GLint m_PrevBlendDstRGB; + GLint m_PrevBlendSrcAlpha; + GLint m_PrevBlendDstAlpha; + GLint m_ViewportInit[4]; + GLfloat m_ProjMatrixInit[16]; + GLboolean m_texGenS; + GLboolean m_texGenT; + GLboolean m_texGenR; + + + + void restoreOpenGLState() + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, m_PrevTexEnv); + glLineWidth(m_PrevLineWidth); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + glPopClientAttrib(); + glPopAttrib(); + if (m_texGenS) + glEnable(GL_TEXTURE_GEN_S); + else + glDisable(GL_TEXTURE_GEN_S); + + if (m_texGenT) + glEnable(GL_TEXTURE_GEN_T); + else + glDisable(GL_TEXTURE_GEN_T); + + if (m_texGenR) + glEnable(GL_TEXTURE_GEN_R); + else + glDisable(GL_TEXTURE_GEN_R); + + + + } + + void saveOpenGLState(int screenWidth, int screenHeight) + { + glPushAttrib(GL_ALL_ATTRIB_BITS); + glPushClientAttrib(GL_CLIENT_ALL_ATTRIB_BITS); + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + GLint Vp[4]; + glGetIntegerv(GL_VIEWPORT, Vp); + if (screenWidth>0 && screenHeight>0) + { + Vp[0] = 0; + Vp[1] = 0; + Vp[2] = screenWidth-1; + Vp[3] = screenHeight-1; + glViewport(Vp[0], Vp[1], Vp[2], Vp[3]); + } + glLoadIdentity(); + glOrtho(Vp[0], Vp[0]+Vp[2], Vp[1]+Vp[3], Vp[1], -1, 1); + glGetIntegerv(GL_VIEWPORT, m_ViewportInit); + glGetFloatv(GL_PROJECTION_MATRIX, m_ProjMatrixInit); + + glGetFloatv(GL_LINE_WIDTH, &m_PrevLineWidth); + // glDisable(GL_POLYGON_STIPPLE); + glLineWidth(1); + + glGetBooleanv(GL_TEXTURE_GEN_S,&m_texGenS); + glGetBooleanv(GL_TEXTURE_GEN_T,&m_texGenT); + glGetBooleanv(GL_TEXTURE_GEN_R,&m_texGenR); + + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + glDisable(GL_TEXTURE_GEN_R); + + glDisable(GL_LINE_SMOOTH); + // glDisable(GL_LINE_STIPPLE); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_LIGHTING); + glEnable(GL_BLEND); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &m_PrevTexEnv); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glDisable(GL_TEXTURE_2D); + + } + + +namespace Gwen +{ + namespace Renderer + { + OpenGL_DebugFont::OpenGL_DebugFont() + { + m_iVertNum = 0; + + for ( int i=0; idata = pglTexture; + m_pFontTexture->width = 256; + m_pFontTexture->height = 256; + + + // Create the opengl texture + glGenTextures( 1, pglTexture ); + glBindTexture( GL_TEXTURE_2D, *pglTexture ); + //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + GLenum format = GL_RGB; + unsigned char* texdata = new unsigned char[256*256*4]; + for (int i=0;i<256*256;i++) + { + texdata[i*4] = sGwenFontData[i]; + texdata[i*4+1] = sGwenFontData[i]; + texdata[i*4+2] = sGwenFontData[i]; + texdata[i*4+3] = sGwenFontData[i]; + } + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, m_pFontTexture->width, m_pFontTexture->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)texdata ); + delete[]texdata; + } + + OpenGL_DebugFont::~OpenGL_DebugFont() + { + FreeTexture( m_pFontTexture ); + delete m_pFontTexture; + } + + + + + + void OpenGL_DebugFont::Begin() + { + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glAlphaFunc( GL_GREATER, 1.0f ); + glEnable ( GL_BLEND ); + } + + void OpenGL_DebugFont::End() + { + if ( m_iVertNum == 0 ) return; + + glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), (void*) &m_Vertices[0].x ); + glEnableClientState( GL_VERTEX_ARRAY ); + + glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)&m_Vertices[0].r ); + glEnableClientState( GL_COLOR_ARRAY ); + + glTexCoordPointer( 2, GL_FLOAT, sizeof(Vertex), (void*) &m_Vertices[0].u ); + glEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + glDrawArrays( GL_TRIANGLES, 0, (GLsizei) m_iVertNum ); + + m_iVertNum = 0; + glFlush(); + } + + void OpenGL_DebugFont::Flush() + { + if ( m_iVertNum == 0 ) return; + + glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), (void*) &m_Vertices[0].x ); + glEnableClientState( GL_VERTEX_ARRAY ); + + glColorPointer( 4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void*)&m_Vertices[0].r ); + glEnableClientState( GL_COLOR_ARRAY ); + + glTexCoordPointer( 2, GL_FLOAT, sizeof(Vertex), (void*) &m_Vertices[0].u ); + glEnableClientState( GL_TEXTURE_COORD_ARRAY ); + + glDrawArrays( GL_TRIANGLES, 0, (GLsizei) m_iVertNum ); + + m_iVertNum = 0; + glFlush(); + } + + void OpenGL_DebugFont::AddVert( int x, int y, float u, float v ) + { + if ( m_iVertNum >= MaxVerts-1 ) + { + Flush(); + } + + m_Vertices[ m_iVertNum ].x = (float)x; + m_Vertices[ m_iVertNum ].y = (float)y; + m_Vertices[ m_iVertNum ].u = u; + m_Vertices[ m_iVertNum ].v = v; + + m_Vertices[ m_iVertNum ].r = m_Color.r; + m_Vertices[ m_iVertNum ].g = m_Color.g; + m_Vertices[ m_iVertNum ].b = m_Color.b; + m_Vertices[ m_iVertNum ].a = m_Color.a; + + m_iVertNum++; + } + + void OpenGL_DebugFont::DrawFilledRect( Gwen::Rect rect ) + { + GLboolean texturesOn; + + glGetBooleanv(GL_TEXTURE_2D, &texturesOn); + if ( texturesOn ) + { + Flush(); + glDisable(GL_TEXTURE_2D); + } + + Translate( rect ); + + AddVert( rect.x, rect.y ); + AddVert( rect.x+rect.w, rect.y ); + AddVert( rect.x, rect.y + rect.h ); + + AddVert( rect.x+rect.w, rect.y ); + AddVert( rect.x+rect.w, rect.y+rect.h ); + AddVert( rect.x, rect.y + rect.h ); + } + + void OpenGL_DebugFont::SetDrawColor(Gwen::Color color) + { + glColor4ubv( (GLubyte*)&color ); + m_Color = color; + } + + void OpenGL_DebugFont::StartClip() + { + Flush(); + Gwen::Rect rect = ClipRegion(); + + // OpenGL's coords are from the bottom left + // so we need to translate them here. + { + GLint view[4]; + glGetIntegerv( GL_VIEWPORT, &view[0] ); + rect.y = view[3] - (rect.y + rect.h); + } + + glScissor( rect.x * Scale(), rect.y * Scale(), rect.w * Scale(), rect.h * Scale() ); + glEnable( GL_SCISSOR_TEST ); + }; + + void OpenGL_DebugFont::EndClip() + { + + Flush(); + glDisable( GL_SCISSOR_TEST ); + + }; + + void OpenGL_DebugFont::RenderText( Gwen::Font* pFont, Gwen::Point pos, const Gwen::UnicodeString& text ) + { + + float fSize = pFont->size * Scale(); + + if ( !text.length() ) + return; + + Gwen::String converted_string = Gwen::Utility::UnicodeToString( text ); + + float yOffset=0.0f; + for ( int i=0; i= 0 ) + { + float cx= (ch%16)/16.0; + float cy= (ch/16)/16.0; + uv_texcoords[0] = cx; + uv_texcoords[1] = cy; + uv_texcoords[4] = float(cx+1.0f/16.0f); + uv_texcoords[5] = float(cy+1.0f/16.0f); + } + + DrawTexturedRect( m_pFontTexture, r, uv_texcoords[0], uv_texcoords[5], uv_texcoords[4], uv_texcoords[1] ); + yOffset+=curSpacing; + } + else + { + DrawFilledRect( r ); + yOffset+=curSpacing; + + } + } + + } + + void OpenGL_DebugFont::DrawTexturedRect( Gwen::Texture* pTexture, Gwen::Rect rect, float u1, float v1, float u2, float v2 ) + { + GLuint* tex = (GLuint*)pTexture->data; + + // Missing image, not loaded properly? + if ( !tex ) + { + return DrawMissingImage( rect ); + } + + Translate( rect ); + GLuint boundtex; + + GLboolean texturesOn; + glGetBooleanv(GL_TEXTURE_2D, &texturesOn); + glGetIntegerv(GL_TEXTURE_BINDING_2D, (GLint *)&boundtex); + if ( !texturesOn || *tex != boundtex ) + { + Flush(); + glBindTexture( GL_TEXTURE_2D, *tex ); + glEnable(GL_TEXTURE_2D); + } + + AddVert( rect.x, rect.y, u1, v1 ); + AddVert( rect.x+rect.w, rect.y, u2, v1 ); + AddVert( rect.x, rect.y + rect.h, u1, v2 ); + + AddVert( rect.x+rect.w, rect.y, u2, v1 ); + AddVert( rect.x+rect.w, rect.y+rect.h, u2, v2 ); + AddVert( rect.x, rect.y + rect.h, u1, v2 ); + } + + Gwen::Point OpenGL_DebugFont::MeasureText( Gwen::Font* pFont, const Gwen::UnicodeString& text ) + { + Gwen::Point p; + float fSize = pFont->size * Scale(); + + Gwen::String converted_string = Gwen::Utility::UnicodeToString( text ); + float spacing = 0.0f; + + for ( int i=0; isize * Scale() * m_fFontScale[1]; + return p; + } + + } +} \ No newline at end of file diff --git a/btgui/Gwen/Renderers/OpenGL_DebugFont.h b/btgui/Gwen/Renderers/OpenGL_DebugFont.h index 4fd995892..fa625a30a 100644 --- a/btgui/Gwen/Renderers/OpenGL_DebugFont.h +++ b/btgui/Gwen/Renderers/OpenGL_DebugFont.h @@ -53,6 +53,8 @@ namespace Gwen void Flush(); void AddVert( int x, int y, float u = 0.0f , float v = 0.0f ); + virtual void Resize(int width, int height) {} + protected: diff --git a/btgui/GwenOpenGLTest/OpenGLSample.cpp b/btgui/GwenOpenGLTest/OpenGLSample.cpp index a0ed1445f..39790559a 100644 --- a/btgui/GwenOpenGLTest/OpenGLSample.cpp +++ b/btgui/GwenOpenGLTest/OpenGLSample.cpp @@ -7,6 +7,7 @@ extern char OpenSansData[]; +#include "Gwen/Renderers/OpenGL_DebugFont.h" #ifdef __APPLE__ #include "OpenGLWindow/MacOpenGLWindow.h" #else @@ -27,6 +28,7 @@ extern char OpenSansData[]; #include Gwen::Controls::Canvas* pCanvas = NULL; +Gwen::Skin::Simple skin; void MyMouseMoveCallback( float x, float y) { @@ -69,7 +71,9 @@ void MyMouseButtonCallback(int button, int state, float x, float y) int sWidth = 1050; int sHeight = 768; GLPrimitiveRenderer* primRenderer=0; -GwenOpenGL3CoreRenderer* gwenRenderer=0; +//GwenOpenGL3CoreRenderer* gwenRenderer=0; +Gwen::Renderer::Base* gwenRenderer =0; + static void MyResizeCallback( float width, float height) { sWidth = width; @@ -81,7 +85,7 @@ static void MyResizeCallback( float width, float height) } if (gwenRenderer) { - gwenRenderer->resize(width,height); + gwenRenderer->Resize(width,height); } if (pCanvas) { @@ -301,6 +305,42 @@ extern int avoidUpdate; int main() { +//#define TEST_OPENGL2_GWEN +#ifdef TEST_OPENGL2_GWEN + b3gDefaultOpenGLWindow* window = new b3gDefaultOpenGLWindow(); + window->setKeyboardCallback(keyCallback); + b3gWindowConstructionInfo wci; + wci.m_width = sWidth; + wci.m_height = sHeight; + // wci.m_resizeCallback = MyResizeCallback; + window->createWindow(wci); + window->setResizeCallback(MyResizeCallback); + window->setWindowTitle("render test"); + +// Gwen::Renderer::OpenGL_DebugFont* pRenderer = new Gwen::Renderer::OpenGL_DebugFont(); +gwenRenderer = new Gwen::Renderer::OpenGL_DebugFont(); + + + skin.SetRender( gwenRenderer ); + +pCanvas = new Gwen::Controls::Canvas( &skin ); + pCanvas->SetSize( sWidth, sHeight); + pCanvas->SetDrawBackground( true ); + pCanvas->SetBackgroundColor( Gwen::Color( 150, 170, 170, 255 ) ); + +glClearColor(1,0,0,1); +/* while( !window->requestedExit() ) + { + window->startRendering(); + + // Main OpenGL Render Loop + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + window->endRendering(); + } +*/ +//exit(0); +#else + float retinaScale = 1.f; b3gDefaultOpenGLWindow* window = new b3gDefaultOpenGLWindow(); @@ -325,7 +365,7 @@ int main() gwenRenderer = new GwenOpenGL3CoreRenderer(primRenderer,font,sWidth,sHeight,retinaScale); - +#endif // @@ -343,7 +383,6 @@ int main() skin.SetRender( pRenderer ); skin.Init("DefaultSkin.png"); #else - Gwen::Skin::Simple skin; skin.SetRender( gwenRenderer ); #endif @@ -379,6 +418,9 @@ int main() // MSG msg; while( !window->requestedExit() ) { + + saveOpenGLState(sWidth,sHeight); + // Skip out if the window is closed //if ( !IsWindowVisible( g_pHWND ) ) //break; @@ -466,7 +508,7 @@ int main() // SwapBuffers( GetDC( g_pHWND ) ); } window->endRendering(); - + restoreOpenGLState(); } window->closeWindow(); diff --git a/btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h b/btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h index e938ad453..4dcb12d12 100644 --- a/btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h +++ b/btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h @@ -83,7 +83,7 @@ public: { TwDeleteDefaultFonts(); } - void resize(int width, int height) + virtual void Resize(int width, int height) { m_screenWidth = width; m_screenHeight = height; diff --git a/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h b/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h index b58f984d0..ea44ae4b4 100644 --- a/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h +++ b/src/BulletDynamics/ConstraintSolver/btTypedConstraint.h @@ -44,6 +44,7 @@ enum btTypedConstraintType D6_SPRING_CONSTRAINT_TYPE, GEAR_CONSTRAINT_TYPE, FIXED_CONSTRAINT_TYPE, + D6_SPRING_2_CONSTRAINT_TYPE, MAX_CONSTRAINT_TYPE }; From 8e2a4f81719a39fca048cdddd2e9d4fd0c160804 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Mon, 30 Jun 2014 14:42:11 -0700 Subject: [PATCH 077/116] dynamically switch between OpenGL 2 and OpenGL 3 (test gwen) --- btgui/GwenOpenGLTest/OpenGLSample.cpp | 98 +++++++++++++-------------- btgui/OpenGLWindow/MacOpenGLWindow.mm | 21 ++---- 2 files changed, 54 insertions(+), 65 deletions(-) diff --git a/btgui/GwenOpenGLTest/OpenGLSample.cpp b/btgui/GwenOpenGLTest/OpenGLSample.cpp index 39790559a..29f9354b9 100644 --- a/btgui/GwenOpenGLTest/OpenGLSample.cpp +++ b/btgui/GwenOpenGLTest/OpenGLSample.cpp @@ -305,68 +305,60 @@ extern int avoidUpdate; int main() { -//#define TEST_OPENGL2_GWEN -#ifdef TEST_OPENGL2_GWEN b3gDefaultOpenGLWindow* window = new b3gDefaultOpenGLWindow(); window->setKeyboardCallback(keyCallback); b3gWindowConstructionInfo wci; + wci.m_openglVersion = 2; wci.m_width = sWidth; wci.m_height = sHeight; // wci.m_resizeCallback = MyResizeCallback; + window->createWindow(wci); window->setResizeCallback(MyResizeCallback); window->setWindowTitle("render test"); -// Gwen::Renderer::OpenGL_DebugFont* pRenderer = new Gwen::Renderer::OpenGL_DebugFont(); -gwenRenderer = new Gwen::Renderer::OpenGL_DebugFont(); - - - skin.SetRender( gwenRenderer ); - -pCanvas = new Gwen::Controls::Canvas( &skin ); - pCanvas->SetSize( sWidth, sHeight); - pCanvas->SetDrawBackground( true ); - pCanvas->SetBackgroundColor( Gwen::Color( 150, 170, 170, 255 ) ); - -glClearColor(1,0,0,1); -/* while( !window->requestedExit() ) - { - window->startRendering(); - - // Main OpenGL Render Loop - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - window->endRendering(); - } -*/ -//exit(0); -#else - - float retinaScale = 1.f; - - b3gDefaultOpenGLWindow* window = new b3gDefaultOpenGLWindow(); - window->setKeyboardCallback(keyCallback); - b3gWindowConstructionInfo wci; - wci.m_width = sWidth; - wci.m_height = sHeight; -// wci.m_resizeCallback = MyResizeCallback; - window->createWindow(wci); + int majorGlVersion, minorGlVersion; - window->setResizeCallback(MyResizeCallback); - window->setWindowTitle("render test"); + if (!sscanf((const char*)glGetString(GL_VERSION), "%d.%d", &majorGlVersion, &minorGlVersion)==2) + { + printf("Exit: Error cannot extract OpenGL version from GL_VERSION string\n"); + exit(0); + } + if (majorGlVersion>=3) + { + float retinaScale = 1.f; + #ifndef __APPLE__ - glewInit(); + glewInit(); #endif + + retinaScale = window->getRetinaScale(); + + primRenderer = new GLPrimitiveRenderer(sWidth,sHeight); + + sth_stash* font = initFont(primRenderer ); + + + gwenRenderer = new GwenOpenGL3CoreRenderer(primRenderer,font,sWidth,sHeight,retinaScale); - retinaScale = window->getRetinaScale(); - - primRenderer = new GLPrimitiveRenderer(sWidth,sHeight); - - sth_stash* font = initFont(primRenderer ); - - - gwenRenderer = new GwenOpenGL3CoreRenderer(primRenderer,font,sWidth,sHeight,retinaScale); -#endif + } else + { + //OpenGL 2.x + gwenRenderer = new Gwen::Renderer::OpenGL_DebugFont(); + + + skin.SetRender( gwenRenderer ); + + pCanvas = new Gwen::Controls::Canvas( &skin ); + pCanvas->SetSize( sWidth, sHeight); + pCanvas->SetDrawBackground( true ); + pCanvas->SetBackgroundColor( Gwen::Color( 150, 170, 170, 255 ) ); + + glClearColor(1,0,0,1); + + } + // // Create a GWEN OpenGL Renderer @@ -418,8 +410,10 @@ glClearColor(1,0,0,1); // MSG msg; while( !window->requestedExit() ) { - - saveOpenGLState(sWidth,sHeight); + if (majorGlVersion<3) + { + saveOpenGLState(sWidth,sHeight); + } // Skip out if the window is closed //if ( !IsWindowVisible( g_pHWND ) ) @@ -508,7 +502,11 @@ glClearColor(1,0,0,1); // SwapBuffers( GetDC( g_pHWND ) ); } window->endRendering(); - restoreOpenGLState(); + + if (majorGlVersion<3) + { + restoreOpenGLState(); + } } window->closeWindow(); diff --git a/btgui/OpenGLWindow/MacOpenGLWindow.mm b/btgui/OpenGLWindow/MacOpenGLWindow.mm index 340898aaf..cd9abad55 100644 --- a/btgui/OpenGLWindow/MacOpenGLWindow.mm +++ b/btgui/OpenGLWindow/MacOpenGLWindow.mm @@ -339,8 +339,10 @@ void MacOpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) // https://developer.apple.com/library/mac/#documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/CapturingScreenContents/CapturingScreenContents.html#//apple_ref/doc/uid/TP40012302-CH10-SW1 //support HighResolutionOSX for Retina Macbook - [m_internalData->m_myview setWantsBestResolutionOpenGLSurface:YES]; - + if (ci.m_openglVersion>=3) + { + [m_internalData->m_myview setWantsBestResolutionOpenGLSurface:YES]; + } NSSize sz; sz.width = 1; sz.height = 1; @@ -354,29 +356,18 @@ void MacOpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) [m_internalData->m_window setContentView: m_internalData->m_myview]; - GLuint n = 1; - GLuint vbo[3]={-1,-1,-1}; - - glGenBuffers(n, vbo); - checkError("glGenBuffers"); - + [m_internalData->m_window setDelegate:(id) m_internalData->m_myview]; - glGenBuffers(n, vbo); - checkError("glGenBuffers"); - + [m_internalData->m_window makeKeyAndOrderFront: nil]; [m_internalData->m_myview MakeCurrent]; m_internalData->m_width = m_internalData->m_myview.GetWindowWidth; m_internalData->m_height = m_internalData->m_myview.GetWindowHeight; - glGenBuffers(n, vbo); - checkError("glGenBuffers"); [NSApp activateIgnoringOtherApps:YES]; - glGenBuffers(n, vbo); - checkError("glGenBuffers"); //[m_internalData->m_window setLevel:NSMainMenuWindowLevel]; From b7402df015c2903f734e21c9a5a505f71affd3b0 Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Mon, 30 Jun 2014 16:03:36 -0700 Subject: [PATCH 078/116] more X11/Linux debug-graphics fixes --- btgui/GwenOpenGLTest/OpenGLSample.cpp | 109 +++++++++++++---------- btgui/OpenGLWindow/GLRenderToTexture.cpp | 15 +++- btgui/OpenGLWindow/GLRenderToTexture.h | 1 - btgui/OpenGLWindow/X11OpenGLWindow.cpp | 11 +-- 4 files changed, 78 insertions(+), 58 deletions(-) diff --git a/btgui/GwenOpenGLTest/OpenGLSample.cpp b/btgui/GwenOpenGLTest/OpenGLSample.cpp index 29f9354b9..5a2ee8d4a 100644 --- a/btgui/GwenOpenGLTest/OpenGLSample.cpp +++ b/btgui/GwenOpenGLTest/OpenGLSample.cpp @@ -68,8 +68,8 @@ void MyMouseButtonCallback(int button, int state, float x, float y) } } -int sWidth = 1050; -int sHeight = 768; +int sWidth = 800;//1050; +int sHeight = 600;//768; GLPrimitiveRenderer* primRenderer=0; //GwenOpenGL3CoreRenderer* gwenRenderer=0; Gwen::Renderer::Base* gwenRenderer =0; @@ -107,7 +107,7 @@ sth_stash* initFont(GLPrimitiveRenderer* primRenderer) stash = sth_create(512,512,renderCallbacks);//256,256);//,1024);//512,512); err = glGetError(); assert(err==GL_NO_ERROR); - + if (!stash) { fprintf(stderr, "Could not create stash.\n"); @@ -121,7 +121,7 @@ sth_stash* initFont(GLPrimitiveRenderer* primRenderer) float sx,sy,dx,dy,lh; GLuint texture; - + const char* fontPaths[]={ "./", @@ -131,16 +131,16 @@ sth_stash* initFont(GLPrimitiveRenderer* primRenderer) }; int numPaths=sizeof(fontPaths)/sizeof(char*); - + // Load the first truetype font from memory (just because we can). - + FILE* fp = 0; const char* fontPath ="./"; char fullFontFileName[1024]; for (int i=0;iInputKey(key,value==1); - + int gwenKey = -1; @@ -278,8 +278,8 @@ void keyCallback(int key, int value) gwenKey = Gwen::Key::Control; break; } - - + + default: { @@ -308,57 +308,68 @@ int main() b3gDefaultOpenGLWindow* window = new b3gDefaultOpenGLWindow(); window->setKeyboardCallback(keyCallback); b3gWindowConstructionInfo wci; - wci.m_openglVersion = 2; + wci.m_openglVersion = 3; wci.m_width = sWidth; wci.m_height = sHeight; // wci.m_resizeCallback = MyResizeCallback; - + window->createWindow(wci); window->setResizeCallback(MyResizeCallback); window->setWindowTitle("render test"); - + int majorGlVersion, minorGlVersion; - + if (!sscanf((const char*)glGetString(GL_VERSION), "%d.%d", &majorGlVersion, &minorGlVersion)==2) { printf("Exit: Error cannot extract OpenGL version from GL_VERSION string\n"); exit(0); } - if (majorGlVersion>=3) + if (majorGlVersion>=3 && wci.m_openglVersion>=3) { float retinaScale = 1.f; - + #ifndef __APPLE__ +#ifndef _WIN32 + //we need glewExperimental on Linux + glewExperimental = GL_TRUE; +#endif // _WIN32 glewInit(); #endif - + + //we ned to call glGetError twice, because of some Ubuntu/Intel/OpenGL issue + + GLuint err = glGetError(); + err = glGetError(); + assert(err==GL_NO_ERROR); + + retinaScale = window->getRetinaScale(); - + primRenderer = new GLPrimitiveRenderer(sWidth,sHeight); - + sth_stash* font = initFont(primRenderer ); - - + + gwenRenderer = new GwenOpenGL3CoreRenderer(primRenderer,font,sWidth,sHeight,retinaScale); } else { //OpenGL 2.x gwenRenderer = new Gwen::Renderer::OpenGL_DebugFont(); - - + + skin.SetRender( gwenRenderer ); - + pCanvas = new Gwen::Controls::Canvas( &skin ); pCanvas->SetSize( sWidth, sHeight); pCanvas->SetDrawBackground( true ); pCanvas->SetBackgroundColor( Gwen::Color( 150, 170, 170, 255 ) ); - + glClearColor(1,0,0,1); - + } - + // // Create a GWEN OpenGL Renderer @@ -368,7 +379,7 @@ int main() // // Create a GWEN skin // - + #ifdef USE_TEXTURED_SKIN Gwen::Skin::TexturedBase skin; @@ -398,7 +409,7 @@ int main() pUnit->SetPos( 10, 10 ); // - // Create a Windows Control helper + // Create a Windows Control helper // (Processes Windows MSG's and fires input at GWEN) // //Gwen::Input::Windows GwenInput; @@ -410,7 +421,7 @@ int main() // MSG msg; while( !window->requestedExit() ) { - if (majorGlVersion<3) + if (majorGlVersion<3 || wci.m_openglVersion<3) { saveOpenGLState(sWidth,sHeight); } @@ -437,7 +448,7 @@ int main() } window->startRendering(); - + // Main OpenGL Render Loop { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); @@ -447,33 +458,33 @@ int main() assert(err==GL_NO_ERROR); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + err = glGetError(); assert(err==GL_NO_ERROR); err = glGetError(); assert(err==GL_NO_ERROR); - + glDisable(GL_DEPTH_TEST); err = glGetError(); assert(err==GL_NO_ERROR); - + //glColor4ub(255,0,0,255); - + err = glGetError(); assert(err==GL_NO_ERROR); - - + + err = glGetError(); assert(err==GL_NO_ERROR); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); // saveOpenGLState(width,height);//m_glutScreenWidth,m_glutScreenHeight); - + err = glGetError(); assert(err==GL_NO_ERROR); - + err = glGetError(); assert(err==GL_NO_ERROR); @@ -485,25 +496,25 @@ int main() err = glGetError(); assert(err==GL_NO_ERROR); - + glEnable(GL_BLEND); - + err = glGetError(); assert(err==GL_NO_ERROR); - - + + pCanvas->RenderCanvas(); - + if (avoidUpdate<=0) avoidUpdate++; // SwapBuffers( GetDC( g_pHWND ) ); } window->endRendering(); - - if (majorGlVersion<3) + + if (majorGlVersion<3 || wci.m_openglVersion<3) { restoreOpenGLState(); } @@ -511,6 +522,6 @@ int main() window->closeWindow(); delete window; - + } diff --git a/btgui/OpenGLWindow/GLRenderToTexture.cpp b/btgui/OpenGLWindow/GLRenderToTexture.cpp index ed9dec575..cbaf80e69 100644 --- a/btgui/OpenGLWindow/GLRenderToTexture.cpp +++ b/btgui/OpenGLWindow/GLRenderToTexture.cpp @@ -1,13 +1,26 @@ ///See http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/ -bool gIntelLinuxglDrawBufferWorkaround=false; #include "GLRenderToTexture.h" #include "Bullet3Common/b3Scalar.h" // for b3Assert +#include +#include + +bool gIntelLinuxglDrawBufferWorkaround=false; + GLRenderToTexture::GLRenderToTexture() :m_framebufferName(0) { + const GLubyte* ven = glGetString(GL_VENDOR); + printf("ven = %s\n",ven); + + if (strncmp((const char*)ven,"Intel",5)==0) + { + printf("Workaround for some crash in the Intel OpenGL driver on Linux/Ubuntu\n"); + gIntelLinuxglDrawBufferWorkaround=true; + } + } void GLRenderToTexture::init(int width, int height, GLuint textureId, int renderTextureType) diff --git a/btgui/OpenGLWindow/GLRenderToTexture.h b/btgui/OpenGLWindow/GLRenderToTexture.h index 513f3e157..d1c913e95 100644 --- a/btgui/OpenGLWindow/GLRenderToTexture.h +++ b/btgui/OpenGLWindow/GLRenderToTexture.h @@ -17,7 +17,6 @@ struct GLRenderToTexture bool m_initialized; int m_renderTextureType; public: - GLRenderToTexture(); void init(int width, int height, GLuint textureId, int renderTextureType=RENDERTEXTURE_COLOR); diff --git a/btgui/OpenGLWindow/X11OpenGLWindow.cpp b/btgui/OpenGLWindow/X11OpenGLWindow.cpp index a872767b0..7d9809f68 100644 --- a/btgui/OpenGLWindow/X11OpenGLWindow.cpp +++ b/btgui/OpenGLWindow/X11OpenGLWindow.cpp @@ -15,7 +15,6 @@ #include #include -extern bool gIntelLinuxglDrawBufferWorkaround; GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; static bool forceOpenGL3 = true; @@ -235,11 +234,6 @@ void X11OpenGLWindow::enableOpenGL() const GLubyte* ven = glGetString(GL_VENDOR); printf("GL_VENDOR=%s\n", ven); - if (strncmp((const char*)ven,"Intel",5)==0) - { - printf("Workaround for some crash in the Intel OpenGL driver on Linux/Ubuntu\n"); - gIntelLinuxglDrawBufferWorkaround=true; - } const GLubyte* ren = glGetString(GL_RENDERER); printf("GL_RENDERER=%s\n",ren); const GLubyte* ver = glGetString(GL_VERSION); @@ -276,7 +270,10 @@ printf("createWindow\n"); m_data->m_root = DefaultRootWindow(m_data->m_dpy); - + if (ci.m_openglVersion < 3) + { + forceOpenGL3 = false; + } if (forceOpenGL3) { From 6d62a318ae58380ad89fbd4ea74d6fc0ceb69bc7 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 1 Jul 2014 10:26:45 -0700 Subject: [PATCH 079/116] only apply the Intel glDrawBuffers fix on Linux (not Win/Mac) --- btgui/OpenGLWindow/GLRenderToTexture.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/btgui/OpenGLWindow/GLRenderToTexture.cpp b/btgui/OpenGLWindow/GLRenderToTexture.cpp index cbaf80e69..e8b3080d6 100644 --- a/btgui/OpenGLWindow/GLRenderToTexture.cpp +++ b/btgui/OpenGLWindow/GLRenderToTexture.cpp @@ -12,6 +12,7 @@ bool gIntelLinuxglDrawBufferWorkaround=false; GLRenderToTexture::GLRenderToTexture() :m_framebufferName(0) { +#if !defined(_WIN32) && !defined(__APPLE__) const GLubyte* ven = glGetString(GL_VENDOR); printf("ven = %s\n",ven); @@ -20,6 +21,7 @@ GLRenderToTexture::GLRenderToTexture() printf("Workaround for some crash in the Intel OpenGL driver on Linux/Ubuntu\n"); gIntelLinuxglDrawBufferWorkaround=true; } +#endif//!defined(_WIN32) && !defined(__APPLE__) } From 6598d1fdde06ba39e61e638f226db2534deeb5ec Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 1 Jul 2014 12:57:32 -0700 Subject: [PATCH 080/116] update Windows glew source --- btgui/OpenGLWindow/GlewWindows/GL/glew.h | 1362 ++++++++++++++++---- btgui/OpenGLWindow/GlewWindows/GL/glxew.h | 66 +- btgui/OpenGLWindow/GlewWindows/GL/glxext.h | 546 -------- btgui/OpenGLWindow/GlewWindows/GL/wglew.h | 24 + btgui/OpenGLWindow/GlewWindows/GL/wglext.h | 466 ------- btgui/OpenGLWindow/GlewWindows/glew.c | 1268 +++++++++++++++++- 6 files changed, 2427 insertions(+), 1305 deletions(-) delete mode 100644 btgui/OpenGLWindow/GlewWindows/GL/glxext.h delete mode 100644 btgui/OpenGLWindow/GlewWindows/GL/wglext.h diff --git a/btgui/OpenGLWindow/GlewWindows/GL/glew.h b/btgui/OpenGLWindow/GlewWindows/GL/glew.h index 9e1f25ec8..90ce65a73 100644 --- a/btgui/OpenGLWindow/GlewWindows/GL/glew.h +++ b/btgui/OpenGLWindow/GlewWindows/GL/glew.h @@ -29,6 +29,7 @@ ** THE POSSIBILITY OF SUCH DAMAGE. */ +#define GLEW_NO_GLU /* * Mesa 3-D graphics library * Version: 7.0 @@ -80,11 +81,15 @@ #define __glew_h__ #define __GLEW_H__ -#define GLEW_STATIC 1 - #if defined(__gl_h_) || defined(__GL_H__) || defined(__X_GL_H) #error gl.h included before glew.h #endif +#if defined(__gl2_h_) +#error gl2.h included before glew.h +#endif +#if defined(__gltypes_h_) +#error gltypes.h included before glew.h +#endif #if defined(__REGAL_H__) #error Regal.h included before glew.h #endif @@ -96,7 +101,9 @@ #endif #define __gl_h_ +#define __gl2_h_ #define __GL_H__ +#define __gltypes_h_ #define __REGAL_H__ #define __X_GL_H #define __glext_h_ @@ -1173,7 +1180,6 @@ GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei heigh #endif /* GL_VERSION_1_1 */ /* ---------------------------------- GLU ---------------------------------- */ -#define GLEW_NO_GLU #ifndef GLEW_NO_GLU /* this is where we can safely include GLU */ @@ -1227,7 +1233,6 @@ GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei heigh #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E @@ -2052,8 +2057,6 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMMATRIX4X3FVPROC) (GLint location, GLsizei #define GL_CONTEXT_FLAGS 0x821E #define GL_DEPTH_BUFFER 0x8223 #define GL_STENCIL_BUFFER 0x8224 -#define GL_COMPRESSED_RED 0x8225 -#define GL_COMPRESSED_RG 0x8226 #define GL_RGBA32F 0x8814 #define GL_RGB32F 0x8815 #define GL_RGBA16F 0x881A @@ -2360,11 +2363,6 @@ typedef void (GLAPIENTRY * PFNGLGETINTEGER64I_VPROC) (GLenum, GLuint, GLint64 *) #define GL_VERSION_3_3 1 #define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46 #define GL_RGB10_A2UI 0x906F typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor); @@ -2380,13 +2378,8 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint d #ifndef GL_VERSION_4_0 #define GL_VERSION_4_0 1 -#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F #define GL_SAMPLE_SHADING 0x8C36 #define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37 -#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A -#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B -#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C -#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D #define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E #define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F #define GL_MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS 0x8F9F @@ -2449,6 +2442,17 @@ typedef void (GLAPIENTRY * PFNGLMINSAMPLESHADINGPROC) (GLclampf value); #endif /* GL_VERSION_4_3 */ +/* ----------------------------- GL_VERSION_4_4 ---------------------------- */ + +#ifndef GL_VERSION_4_4 +#define GL_VERSION_4_4 1 + +#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5 + +#define GLEW_VERSION_4_4 GLEW_GET_VAR(__GLEW_VERSION_4_4) + +#endif /* GL_VERSION_4_4 */ + /* -------------------------- GL_3DFX_multisample -------------------------- */ #ifndef GL_3DFX_multisample @@ -2531,7 +2535,7 @@ typedef void (GLAPIENTRY * PFNGLTBUFFERMASK3DFXPROC) (GLuint mask); typedef void (APIENTRY *GLDEBUGPROCAMD)(GLuint id, GLenum category, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam); -typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, void* userParam); +typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKAMDPROC) (GLDEBUGPROCAMD callback, GLvoid *userParam); typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEENABLEAMDPROC) (GLenum category, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled); typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEINSERTAMDPROC) (GLenum category, GLenum severity, GLuint id, GLsizei length, const GLchar* buf); typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGAMDPROC) (GLuint count, GLsizei bufsize, GLenum* categories, GLuint* severities, GLuint* ids, GLsizei* lengths, GLchar* message); @@ -2576,13 +2580,36 @@ typedef void (GLAPIENTRY * PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC) (GLuint buf, GL #endif /* GL_AMD_draw_buffers_blend */ +/* ---------------------- GL_AMD_interleaved_elements ---------------------- */ + +#ifndef GL_AMD_interleaved_elements +#define GL_AMD_interleaved_elements 1 + +#define GL_RED 0x1903 +#define GL_GREEN 0x1904 +#define GL_BLUE 0x1905 +#define GL_ALPHA 0x1906 +#define GL_RG8UI 0x8238 +#define GL_RG16UI 0x823A +#define GL_RGBA8UI 0x8D7C +#define GL_VERTEX_ELEMENT_SWIZZLE_AMD 0x91A4 +#define GL_VERTEX_ID_SWIZZLE_AMD 0x91A5 + +typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPARAMETERIAMDPROC) (GLuint index, GLenum pname, GLint param); + +#define glVertexAttribParameteriAMD GLEW_GET_FUN(__glewVertexAttribParameteriAMD) + +#define GLEW_AMD_interleaved_elements GLEW_GET_VAR(__GLEW_AMD_interleaved_elements) + +#endif /* GL_AMD_interleaved_elements */ + /* ----------------------- GL_AMD_multi_draw_indirect ---------------------- */ #ifndef GL_AMD_multi_draw_indirect #define GL_AMD_multi_draw_indirect 1 -typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const void* indirect, GLsizei primcount, GLsizei stride); -typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const void* indirect, GLsizei primcount, GLsizei stride); +typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); +typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); #define glMultiDrawArraysIndirectAMD GLEW_GET_FUN(__glewMultiDrawArraysIndirectAMD) #define glMultiDrawElementsIndirectAMD GLEW_GET_FUN(__glewMultiDrawElementsIndirectAMD) @@ -2632,7 +2659,7 @@ typedef void (GLAPIENTRY * PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint* m typedef void (GLAPIENTRY * PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); typedef void (GLAPIENTRY * PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint* monitors); typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint* data, GLint *bytesWritten); -typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void* data); +typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data); typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei* length, GLchar *counterString); typedef void (GLAPIENTRY * PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint* numCounters, GLint *maxActiveCounters, GLsizei countersSize, GLuint *counters); typedef void (GLAPIENTRY * PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei* length, GLchar *groupString); @@ -2714,6 +2741,40 @@ typedef void (GLAPIENTRY * PFNGLSETMULTISAMPLEFVAMDPROC) (GLenum pname, GLuint i #endif /* GL_AMD_shader_stencil_export */ +/* ---------------------- GL_AMD_shader_trinary_minmax --------------------- */ + +#ifndef GL_AMD_shader_trinary_minmax +#define GL_AMD_shader_trinary_minmax 1 + +#define GLEW_AMD_shader_trinary_minmax GLEW_GET_VAR(__GLEW_AMD_shader_trinary_minmax) + +#endif /* GL_AMD_shader_trinary_minmax */ + +/* ------------------------- GL_AMD_sparse_texture ------------------------- */ + +#ifndef GL_AMD_sparse_texture +#define GL_AMD_sparse_texture 1 + +#define GL_TEXTURE_STORAGE_SPARSE_BIT_AMD 0x00000001 +#define GL_VIRTUAL_PAGE_SIZE_X_AMD 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_AMD 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_AMD 0x9197 +#define GL_MAX_SPARSE_TEXTURE_SIZE_AMD 0x9198 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_AMD 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS 0x919A +#define GL_MIN_SPARSE_LEVEL_AMD 0x919B +#define GL_MIN_LOD_WARNING_AMD 0x919C + +typedef void (GLAPIENTRY * PFNGLTEXSTORAGESPARSEAMDPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); +typedef void (GLAPIENTRY * PFNGLTEXTURESTORAGESPARSEAMDPROC) (GLuint texture, GLenum target, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei layers, GLbitfield flags); + +#define glTexStorageSparseAMD GLEW_GET_FUN(__glewTexStorageSparseAMD) +#define glTextureStorageSparseAMD GLEW_GET_FUN(__glewTextureStorageSparseAMD) + +#define GLEW_AMD_sparse_texture GLEW_GET_VAR(__GLEW_AMD_sparse_texture) + +#endif /* GL_AMD_sparse_texture */ + /* ------------------- GL_AMD_stencil_operation_extended ------------------- */ #ifndef GL_AMD_stencil_operation_extended @@ -2791,6 +2852,200 @@ typedef void (GLAPIENTRY * PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); #endif /* GL_AMD_vertex_shader_viewport_index */ +/* ------------------------- GL_ANGLE_depth_texture ------------------------ */ + +#ifndef GL_ANGLE_depth_texture +#define GL_ANGLE_depth_texture 1 + +#define GLEW_ANGLE_depth_texture GLEW_GET_VAR(__GLEW_ANGLE_depth_texture) + +#endif /* GL_ANGLE_depth_texture */ + +/* ----------------------- GL_ANGLE_framebuffer_blit ----------------------- */ + +#ifndef GL_ANGLE_framebuffer_blit +#define GL_ANGLE_framebuffer_blit 1 + +#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6 +#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8 +#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA + +typedef void (GLAPIENTRY * PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); + +#define glBlitFramebufferANGLE GLEW_GET_FUN(__glewBlitFramebufferANGLE) + +#define GLEW_ANGLE_framebuffer_blit GLEW_GET_VAR(__GLEW_ANGLE_framebuffer_blit) + +#endif /* GL_ANGLE_framebuffer_blit */ + +/* -------------------- GL_ANGLE_framebuffer_multisample ------------------- */ + +#ifndef GL_ANGLE_framebuffer_multisample +#define GL_ANGLE_framebuffer_multisample 1 + +#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56 +#define GL_MAX_SAMPLES_ANGLE 0x8D57 + +typedef void (GLAPIENTRY * PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); + +#define glRenderbufferStorageMultisampleANGLE GLEW_GET_FUN(__glewRenderbufferStorageMultisampleANGLE) + +#define GLEW_ANGLE_framebuffer_multisample GLEW_GET_VAR(__GLEW_ANGLE_framebuffer_multisample) + +#endif /* GL_ANGLE_framebuffer_multisample */ + +/* ----------------------- GL_ANGLE_instanced_arrays ----------------------- */ + +#ifndef GL_ANGLE_instanced_arrays +#define GL_ANGLE_instanced_arrays 1 + +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE + +typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount); +typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount); +typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor); + +#define glDrawArraysInstancedANGLE GLEW_GET_FUN(__glewDrawArraysInstancedANGLE) +#define glDrawElementsInstancedANGLE GLEW_GET_FUN(__glewDrawElementsInstancedANGLE) +#define glVertexAttribDivisorANGLE GLEW_GET_FUN(__glewVertexAttribDivisorANGLE) + +#define GLEW_ANGLE_instanced_arrays GLEW_GET_VAR(__GLEW_ANGLE_instanced_arrays) + +#endif /* GL_ANGLE_instanced_arrays */ + +/* -------------------- GL_ANGLE_pack_reverse_row_order -------------------- */ + +#ifndef GL_ANGLE_pack_reverse_row_order +#define GL_ANGLE_pack_reverse_row_order 1 + +#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4 + +#define GLEW_ANGLE_pack_reverse_row_order GLEW_GET_VAR(__GLEW_ANGLE_pack_reverse_row_order) + +#endif /* GL_ANGLE_pack_reverse_row_order */ + +/* ------------------------ GL_ANGLE_program_binary ------------------------ */ + +#ifndef GL_ANGLE_program_binary +#define GL_ANGLE_program_binary 1 + +#define GL_PROGRAM_BINARY_ANGLE 0x93A6 + +#define GLEW_ANGLE_program_binary GLEW_GET_VAR(__GLEW_ANGLE_program_binary) + +#endif /* GL_ANGLE_program_binary */ + +/* ------------------- GL_ANGLE_texture_compression_dxt1 ------------------- */ + +#ifndef GL_ANGLE_texture_compression_dxt1 +#define GL_ANGLE_texture_compression_dxt1 1 + +#define GL_COMPRESSED_RGB_S3TC_DXT1_ANGLE 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_ANGLE 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 + +#define GLEW_ANGLE_texture_compression_dxt1 GLEW_GET_VAR(__GLEW_ANGLE_texture_compression_dxt1) + +#endif /* GL_ANGLE_texture_compression_dxt1 */ + +/* ------------------- GL_ANGLE_texture_compression_dxt3 ------------------- */ + +#ifndef GL_ANGLE_texture_compression_dxt3 +#define GL_ANGLE_texture_compression_dxt3 1 + +#define GL_COMPRESSED_RGB_S3TC_DXT1_ANGLE 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_ANGLE 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 + +#define GLEW_ANGLE_texture_compression_dxt3 GLEW_GET_VAR(__GLEW_ANGLE_texture_compression_dxt3) + +#endif /* GL_ANGLE_texture_compression_dxt3 */ + +/* ------------------- GL_ANGLE_texture_compression_dxt5 ------------------- */ + +#ifndef GL_ANGLE_texture_compression_dxt5 +#define GL_ANGLE_texture_compression_dxt5 1 + +#define GL_COMPRESSED_RGB_S3TC_DXT1_ANGLE 0x83F0 +#define GL_COMPRESSED_RGBA_S3TC_DXT1_ANGLE 0x83F1 +#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2 +#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3 + +#define GLEW_ANGLE_texture_compression_dxt5 GLEW_GET_VAR(__GLEW_ANGLE_texture_compression_dxt5) + +#endif /* GL_ANGLE_texture_compression_dxt5 */ + +/* ------------------------- GL_ANGLE_texture_usage ------------------------ */ + +#ifndef GL_ANGLE_texture_usage +#define GL_ANGLE_texture_usage 1 + +#define GL_TEXTURE_USAGE_ANGLE 0x93A2 +#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3 + +#define GLEW_ANGLE_texture_usage GLEW_GET_VAR(__GLEW_ANGLE_texture_usage) + +#endif /* GL_ANGLE_texture_usage */ + +/* -------------------------- GL_ANGLE_timer_query ------------------------- */ + +#ifndef GL_ANGLE_timer_query +#define GL_ANGLE_timer_query 1 + +#define GL_QUERY_COUNTER_BITS_ANGLE 0x8864 +#define GL_CURRENT_QUERY_ANGLE 0x8865 +#define GL_QUERY_RESULT_ANGLE 0x8866 +#define GL_QUERY_RESULT_AVAILABLE_ANGLE 0x8867 +#define GL_TIME_ELAPSED_ANGLE 0x88BF +#define GL_TIMESTAMP_ANGLE 0x8E28 + +typedef void (GLAPIENTRY * PFNGLBEGINQUERYANGLEPROC) (GLenum target, GLuint id); +typedef void (GLAPIENTRY * PFNGLDELETEQUERIESANGLEPROC) (GLsizei n, const GLuint* ids); +typedef void (GLAPIENTRY * PFNGLENDQUERYANGLEPROC) (GLenum target); +typedef void (GLAPIENTRY * PFNGLGENQUERIESANGLEPROC) (GLsizei n, GLuint* ids); +typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTI64VANGLEPROC) (GLuint id, GLenum pname, GLint64* params); +typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTIVANGLEPROC) (GLuint id, GLenum pname, GLint* params); +typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTUI64VANGLEPROC) (GLuint id, GLenum pname, GLuint64* params); +typedef void (GLAPIENTRY * PFNGLGETQUERYOBJECTUIVANGLEPROC) (GLuint id, GLenum pname, GLuint* params); +typedef void (GLAPIENTRY * PFNGLGETQUERYIVANGLEPROC) (GLenum target, GLenum pname, GLint* params); +typedef GLboolean (GLAPIENTRY * PFNGLISQUERYANGLEPROC) (GLuint id); +typedef void (GLAPIENTRY * PFNGLQUERYCOUNTERANGLEPROC) (GLuint id, GLenum target); + +#define glBeginQueryANGLE GLEW_GET_FUN(__glewBeginQueryANGLE) +#define glDeleteQueriesANGLE GLEW_GET_FUN(__glewDeleteQueriesANGLE) +#define glEndQueryANGLE GLEW_GET_FUN(__glewEndQueryANGLE) +#define glGenQueriesANGLE GLEW_GET_FUN(__glewGenQueriesANGLE) +#define glGetQueryObjecti64vANGLE GLEW_GET_FUN(__glewGetQueryObjecti64vANGLE) +#define glGetQueryObjectivANGLE GLEW_GET_FUN(__glewGetQueryObjectivANGLE) +#define glGetQueryObjectui64vANGLE GLEW_GET_FUN(__glewGetQueryObjectui64vANGLE) +#define glGetQueryObjectuivANGLE GLEW_GET_FUN(__glewGetQueryObjectuivANGLE) +#define glGetQueryivANGLE GLEW_GET_FUN(__glewGetQueryivANGLE) +#define glIsQueryANGLE GLEW_GET_FUN(__glewIsQueryANGLE) +#define glQueryCounterANGLE GLEW_GET_FUN(__glewQueryCounterANGLE) + +#define GLEW_ANGLE_timer_query GLEW_GET_VAR(__GLEW_ANGLE_timer_query) + +#endif /* GL_ANGLE_timer_query */ + +/* ------------------- GL_ANGLE_translated_shader_source ------------------- */ + +#ifndef GL_ANGLE_translated_shader_source +#define GL_ANGLE_translated_shader_source 1 + +#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0 + +typedef void (GLAPIENTRY * PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source); + +#define glGetTranslatedShaderSourceANGLE GLEW_GET_FUN(__glewGetTranslatedShaderSourceANGLE) + +#define GLEW_ANGLE_translated_shader_source GLEW_GET_VAR(__GLEW_ANGLE_translated_shader_source) + +#endif /* GL_ANGLE_translated_shader_source */ + /* ----------------------- GL_APPLE_aux_depth_stencil ---------------------- */ #ifndef GL_APPLE_aux_depth_stencil @@ -2824,7 +3079,7 @@ typedef void (GLAPIENTRY * PFNGLTESSELLATIONMODEAMDPROC) (GLenum mode); typedef void (GLAPIENTRY * PFNGLDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, GLint first, GLsizei count); typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, GLint first, GLsizei count); -typedef void (GLAPIENTRY * PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const void* pointer); +typedef void (GLAPIENTRY * PFNGLELEMENTPOINTERAPPLEPROC) (GLenum type, const GLvoid *pointer); typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTARRAYAPPLEPROC) (GLenum mode, const GLint* first, const GLsizei *count, GLsizei primcount); typedef void (GLAPIENTRY * PFNGLMULTIDRAWRANGEELEMENTARRAYAPPLEPROC) (GLenum mode, GLuint start, GLuint end, const GLint* first, const GLsizei *count, GLsizei primcount); @@ -3049,9 +3304,9 @@ typedef GLboolean (GLAPIENTRY * PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array); #define GL_STORAGE_CACHED_APPLE 0x85BE #define GL_STORAGE_SHARED_APPLE 0x85BF -typedef void (GLAPIENTRY * PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void* pointer); +typedef void (GLAPIENTRY * PFNGLFLUSHVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); typedef void (GLAPIENTRY * PFNGLVERTEXARRAYPARAMETERIAPPLEPROC) (GLenum pname, GLint param); -typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, void* pointer); +typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGEAPPLEPROC) (GLsizei length, GLvoid *pointer); #define glFlushVertexArrayRangeAPPLE GLEW_GET_FUN(__glewFlushVertexArrayRangeAPPLE) #define glVertexArrayParameteriAPPLE GLEW_GET_FUN(__glewVertexArrayParameteriAPPLE) @@ -3130,6 +3385,8 @@ typedef void (GLAPIENTRY * PFNGLMAPVERTEXATTRIB2FAPPLEPROC) (GLuint index, GLuin #define GL_MAX_VARYING_VECTORS 0x8DFC #define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +typedef int GLfixed; + typedef void (GLAPIENTRY * PFNGLCLEARDEPTHFPROC) (GLclampf d); typedef void (GLAPIENTRY * PFNGLDEPTHRANGEFPROC) (GLclampf n, GLclampf f); typedef void (GLAPIENTRY * PFNGLGETSHADERPRECISIONFORMATPROC) (GLenum shadertype, GLenum precisiontype, GLint* range, GLint *precision); @@ -3151,6 +3408,7 @@ typedef void (GLAPIENTRY * PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint* #ifndef GL_ARB_ES3_compatibility #define GL_ARB_ES3_compatibility 1 +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A #define GL_MAX_ELEMENT_INDEX 0x8D6B @@ -3184,8 +3442,8 @@ typedef void (GLAPIENTRY * PFNGLSHADERBINARYPROC) (GLsizei count, const GLuint* #define GL_ARB_base_instance 1 typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance); -typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount, GLuint baseinstance); -typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount, GLint basevertex, GLuint baseinstance); +typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLuint baseinstance); +typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance); #define glDrawArraysInstancedBaseInstance GLEW_GET_FUN(__glewDrawArraysInstancedBaseInstance) #define glDrawElementsInstancedBaseInstance GLEW_GET_FUN(__glewDrawElementsInstancedBaseInstance) @@ -3195,6 +3453,51 @@ typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC) #endif /* GL_ARB_base_instance */ +/* ------------------------ GL_ARB_bindless_texture ------------------------ */ + +#ifndef GL_ARB_bindless_texture +#define GL_ARB_bindless_texture 1 + +#define GL_UNSIGNED_INT64_ARB 0x140F + +typedef GLuint64 (GLAPIENTRY * PFNGLGETIMAGEHANDLEARBPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format); +typedef GLuint64 (GLAPIENTRY * PFNGLGETTEXTUREHANDLEARBPROC) (GLuint texture); +typedef GLuint64 (GLAPIENTRY * PFNGLGETTEXTURESAMPLERHANDLEARBPROC) (GLuint texture, GLuint sampler); +typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBLUI64VARBPROC) (GLuint index, GLenum pname, GLuint64EXT* params); +typedef GLboolean (GLAPIENTRY * PFNGLISIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef GLboolean (GLAPIENTRY * PFNGLISTEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (GLAPIENTRY * PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef void (GLAPIENTRY * PFNGLMAKEIMAGEHANDLERESIDENTARBPROC) (GLuint64 handle, GLenum access); +typedef void (GLAPIENTRY * PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC) (GLuint64 handle); +typedef void (GLAPIENTRY * PFNGLMAKETEXTUREHANDLERESIDENTARBPROC) (GLuint64 handle); +typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC) (GLuint program, GLint location, GLuint64 value); +typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64* values); +typedef void (GLAPIENTRY * PFNGLUNIFORMHANDLEUI64ARBPROC) (GLint location, GLuint64 value); +typedef void (GLAPIENTRY * PFNGLUNIFORMHANDLEUI64VARBPROC) (GLint location, GLsizei count, const GLuint64* value); +typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL1UI64ARBPROC) (GLuint index, GLuint64EXT x); +typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL1UI64VARBPROC) (GLuint index, const GLuint64EXT* v); + +#define glGetImageHandleARB GLEW_GET_FUN(__glewGetImageHandleARB) +#define glGetTextureHandleARB GLEW_GET_FUN(__glewGetTextureHandleARB) +#define glGetTextureSamplerHandleARB GLEW_GET_FUN(__glewGetTextureSamplerHandleARB) +#define glGetVertexAttribLui64vARB GLEW_GET_FUN(__glewGetVertexAttribLui64vARB) +#define glIsImageHandleResidentARB GLEW_GET_FUN(__glewIsImageHandleResidentARB) +#define glIsTextureHandleResidentARB GLEW_GET_FUN(__glewIsTextureHandleResidentARB) +#define glMakeImageHandleNonResidentARB GLEW_GET_FUN(__glewMakeImageHandleNonResidentARB) +#define glMakeImageHandleResidentARB GLEW_GET_FUN(__glewMakeImageHandleResidentARB) +#define glMakeTextureHandleNonResidentARB GLEW_GET_FUN(__glewMakeTextureHandleNonResidentARB) +#define glMakeTextureHandleResidentARB GLEW_GET_FUN(__glewMakeTextureHandleResidentARB) +#define glProgramUniformHandleui64ARB GLEW_GET_FUN(__glewProgramUniformHandleui64ARB) +#define glProgramUniformHandleui64vARB GLEW_GET_FUN(__glewProgramUniformHandleui64vARB) +#define glUniformHandleui64ARB GLEW_GET_FUN(__glewUniformHandleui64ARB) +#define glUniformHandleui64vARB GLEW_GET_FUN(__glewUniformHandleui64vARB) +#define glVertexAttribL1ui64ARB GLEW_GET_FUN(__glewVertexAttribL1ui64ARB) +#define glVertexAttribL1ui64vARB GLEW_GET_FUN(__glewVertexAttribL1ui64vARB) + +#define GLEW_ARB_bindless_texture GLEW_GET_VAR(__GLEW_ARB_bindless_texture) + +#endif /* GL_ARB_bindless_texture */ + /* ----------------------- GL_ARB_blend_func_extended ---------------------- */ #ifndef GL_ARB_blend_func_extended @@ -3215,6 +3518,31 @@ typedef GLint (GLAPIENTRY * PFNGLGETFRAGDATAINDEXPROC) (GLuint program, const GL #endif /* GL_ARB_blend_func_extended */ +/* ------------------------- GL_ARB_buffer_storage ------------------------- */ + +#ifndef GL_ARB_buffer_storage +#define GL_ARB_buffer_storage 1 + +#define GL_MAP_READ_BIT 0x0001 +#define GL_MAP_WRITE_BIT 0x0002 +#define GL_MAP_PERSISTENT_BIT 0x00000040 +#define GL_MAP_COHERENT_BIT 0x00000080 +#define GL_DYNAMIC_STORAGE_BIT 0x0100 +#define GL_CLIENT_STORAGE_BIT 0x0200 +#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000 +#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F +#define GL_BUFFER_STORAGE_FLAGS 0x8220 + +typedef void (GLAPIENTRY * PFNGLBUFFERSTORAGEPROC) (GLenum target, GLsizeiptr size, const GLvoid* data, GLbitfield flags); +typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSTORAGEEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid* data, GLbitfield flags); + +#define glBufferStorage GLEW_GET_FUN(__glewBufferStorage) +#define glNamedBufferStorageEXT GLEW_GET_FUN(__glewNamedBufferStorageEXT) + +#define GLEW_ARB_buffer_storage GLEW_GET_VAR(__GLEW_ARB_buffer_storage) + +#endif /* GL_ARB_buffer_storage */ + /* ---------------------------- GL_ARB_cl_event ---------------------------- */ #ifndef GL_ARB_cl_event @@ -3253,6 +3581,23 @@ typedef void (GLAPIENTRY * PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, #endif /* GL_ARB_clear_buffer_object */ +/* -------------------------- GL_ARB_clear_texture ------------------------- */ + +#ifndef GL_ARB_clear_texture +#define GL_ARB_clear_texture 1 + +#define GL_CLEAR_TEXTURE 0x9365 + +typedef void (GLAPIENTRY * PFNGLCLEARTEXIMAGEPROC) (GLuint texture, GLint level, GLenum format, GLenum type, const GLvoid* data); +typedef void (GLAPIENTRY * PFNGLCLEARTEXSUBIMAGEPROC) (GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* data); + +#define glClearTexImage GLEW_GET_FUN(__glewClearTexImage) +#define glClearTexSubImage GLEW_GET_FUN(__glewClearTexSubImage) + +#define GLEW_ARB_clear_texture GLEW_GET_VAR(__GLEW_ARB_clear_texture) + +#endif /* GL_ARB_clear_texture */ + /* ----------------------- GL_ARB_color_buffer_float ----------------------- */ #ifndef GL_ARB_color_buffer_float @@ -3333,6 +3678,24 @@ typedef void (GLAPIENTRY * PFNGLDISPATCHCOMPUTEINDIRECTPROC) (GLintptr indirect) #endif /* GL_ARB_compute_shader */ +/* ------------------- GL_ARB_compute_variable_group_size ------------------ */ + +#ifndef GL_ARB_compute_variable_group_size +#define GL_ARB_compute_variable_group_size 1 + +#define GL_MAX_COMPUTE_FIXED_GROUP_INVOCATIONS_ARB 0x90EB +#define GL_MAX_COMPUTE_FIXED_GROUP_SIZE_ARB 0x91BF +#define GL_MAX_COMPUTE_VARIABLE_GROUP_INVOCATIONS_ARB 0x9344 +#define GL_MAX_COMPUTE_VARIABLE_GROUP_SIZE_ARB 0x9345 + +typedef void (GLAPIENTRY * PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z, GLuint group_size_x, GLuint group_size_y, GLuint group_size_z); + +#define glDispatchComputeGroupSizeARB GLEW_GET_FUN(__glewDispatchComputeGroupSizeARB) + +#define GLEW_ARB_compute_variable_group_size GLEW_GET_VAR(__GLEW_ARB_compute_variable_group_size) + +#endif /* GL_ARB_compute_variable_group_size */ + /* ----------------------- GL_ARB_conservative_depth ----------------------- */ #ifndef GL_ARB_conservative_depth @@ -3401,7 +3764,7 @@ typedef void (GLAPIENTRY * PFNGLCOPYIMAGESUBDATAPROC) (GLuint srcName, GLenum sr typedef void (APIENTRY *GLDEBUGPROCARB)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam); -typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, void* userParam); +typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKARBPROC) (GLDEBUGPROCARB callback, const GLvoid *userParam); typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECONTROLARBPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled); typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEINSERTARBPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf); typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGARBPROC) (GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog); @@ -3509,10 +3872,10 @@ typedef void (GLAPIENTRY * PFNGLBLENDFUNCIARBPROC) (GLuint buf, GLenum src, GLen #ifndef GL_ARB_draw_elements_base_vertex #define GL_ARB_draw_elements_base_vertex 1 -typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, void* indices, GLint basevertex); -typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const void* indices, GLsizei primcount, GLint basevertex); -typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, void* indices, GLint basevertex); -typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei* count, GLenum type, GLvoid**indices, GLsizei primcount, GLint *basevertex); +typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount, GLint basevertex); +typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices, GLint basevertex); +typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, const GLsizei* count, GLenum type, const GLvoid* const *indices, GLsizei primcount, const GLint *basevertex); #define glDrawElementsBaseVertex GLEW_GET_FUN(__glewDrawElementsBaseVertex) #define glDrawElementsInstancedBaseVertex GLEW_GET_FUN(__glewDrawElementsInstancedBaseVertex) @@ -3531,8 +3894,8 @@ typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC) (GLenum mode, G #define GL_DRAW_INDIRECT_BUFFER 0x8F3F #define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43 -typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const void* indirect); -typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void* indirect); +typedef void (GLAPIENTRY * PFNGLDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect); +typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect); #define glDrawArraysIndirect GLEW_GET_FUN(__glewDrawArraysIndirect) #define glDrawElementsIndirect GLEW_GET_FUN(__glewDrawElementsIndirect) @@ -3550,6 +3913,19 @@ typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum t #endif /* GL_ARB_draw_instanced */ +/* ------------------------ GL_ARB_enhanced_layouts ------------------------ */ + +#ifndef GL_ARB_enhanced_layouts +#define GL_ARB_enhanced_layouts 1 + +#define GL_LOCATION_COMPONENT 0x934A +#define GL_TRANSFORM_FEEDBACK_BUFFER_INDEX 0x934B +#define GL_TRANSFORM_FEEDBACK_BUFFER_STRIDE 0x934C + +#define GLEW_ARB_enhanced_layouts GLEW_GET_VAR(__GLEW_ARB_enhanced_layouts) + +#endif /* GL_ARB_enhanced_layouts */ + /* -------------------- GL_ARB_explicit_attrib_location -------------------- */ #ifndef GL_ARB_explicit_attrib_location @@ -3851,7 +4227,7 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMPARAMETERIARBPROC) (GLuint program, GLenu #define GL_PROGRAM_BINARY_FORMATS 0x87FF typedef void (GLAPIENTRY * PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufSize, GLsizei* length, GLenum *binaryFormat, GLvoid*binary); -typedef void (GLAPIENTRY * PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const void* binary, GLsizei length); +typedef void (GLAPIENTRY * PFNGLPROGRAMBINARYPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLsizei length); typedef void (GLAPIENTRY * PFNGLPROGRAMPARAMETERIPROC) (GLuint program, GLenum pname, GLint value); #define glGetProgramBinary GLEW_GET_FUN(__glewGetProgramBinary) @@ -4113,6 +4489,24 @@ typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DPROC) (GLenum target, GLenum in #endif /* GL_ARB_imaging */ +/* ----------------------- GL_ARB_indirect_parameters ---------------------- */ + +#ifndef GL_ARB_indirect_parameters +#define GL_ARB_indirect_parameters 1 + +#define GL_PARAMETER_BUFFER_ARB 0x80EE +#define GL_PARAMETER_BUFFER_BINDING_ARB 0x80EF + +typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC) (GLenum mode, const GLvoid *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); +typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLintptr drawcount, GLsizei maxdrawcount, GLsizei stride); + +#define glMultiDrawArraysIndirectCountARB GLEW_GET_FUN(__glewMultiDrawArraysIndirectCountARB) +#define glMultiDrawElementsIndirectCountARB GLEW_GET_FUN(__glewMultiDrawElementsIndirectCountARB) + +#define GLEW_ARB_indirect_parameters GLEW_GET_VAR(__GLEW_ARB_indirect_parameters) + +#endif /* GL_ARB_indirect_parameters */ + /* ------------------------ GL_ARB_instanced_arrays ------------------------ */ #ifndef GL_ARB_instanced_arrays @@ -4152,10 +4546,6 @@ typedef void (GLAPIENTRY * PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum #ifndef GL_ARB_internalformat_query2 #define GL_ARB_internalformat_query2 1 -#define GL_TEXTURE_1D 0x0DE0 -#define GL_TEXTURE_2D 0x0DE1 -#define GL_TEXTURE_3D 0x806F -#define GL_SAMPLES 0x80A9 #define GL_INTERNALFORMAT_SUPPORTED 0x826F #define GL_INTERNALFORMAT_PREFERRED 0x8270 #define GL_INTERNALFORMAT_RED_SIZE 0x8271 @@ -4255,15 +4645,6 @@ typedef void (GLAPIENTRY * PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum #define GL_VIEW_CLASS_RGTC2_RG 0x82D1 #define GL_VIEW_CLASS_BPTC_UNORM 0x82D2 #define GL_VIEW_CLASS_BPTC_FLOAT 0x82D3 -#define GL_TEXTURE_RECTANGLE 0x84F5 -#define GL_TEXTURE_1D_ARRAY 0x8C18 -#define GL_TEXTURE_2D_ARRAY 0x8C1A -#define GL_TEXTURE_BUFFER 0x8C2A -#define GL_RENDERBUFFER 0x8D41 -#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009 -#define GL_TEXTURE_2D_MULTISAMPLE 0x9100 -#define GL_TEXTURE_2D_MULTISAMPLE_ARRAY 0x9102 -#define GL_NUM_SAMPLE_COUNTS 0x9380 typedef void (GLAPIENTRY * PFNGLGETINTERNALFORMATI64VPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint64* params); @@ -4361,13 +4742,36 @@ typedef void (GLAPIENTRY * PFNGLMATRIXINDEXUSVARBPROC) (GLint size, GLushort *in #endif /* GL_ARB_matrix_palette */ +/* --------------------------- GL_ARB_multi_bind --------------------------- */ + +#ifndef GL_ARB_multi_bind +#define GL_ARB_multi_bind 1 + +typedef void (GLAPIENTRY * PFNGLBINDBUFFERSBASEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint* buffers); +typedef void (GLAPIENTRY * PFNGLBINDBUFFERSRANGEPROC) (GLenum target, GLuint first, GLsizei count, const GLuint* buffers, const GLintptr *offsets, const GLsizeiptr *sizes); +typedef void (GLAPIENTRY * PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint* textures); +typedef void (GLAPIENTRY * PFNGLBINDSAMPLERSPROC) (GLuint first, GLsizei count, const GLuint* samplers); +typedef void (GLAPIENTRY * PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint* textures); +typedef void (GLAPIENTRY * PFNGLBINDVERTEXBUFFERSPROC) (GLuint first, GLsizei count, const GLuint* buffers, const GLintptr *offsets, const GLsizei *strides); + +#define glBindBuffersBase GLEW_GET_FUN(__glewBindBuffersBase) +#define glBindBuffersRange GLEW_GET_FUN(__glewBindBuffersRange) +#define glBindImageTextures GLEW_GET_FUN(__glewBindImageTextures) +#define glBindSamplers GLEW_GET_FUN(__glewBindSamplers) +#define glBindTextures GLEW_GET_FUN(__glewBindTextures) +#define glBindVertexBuffers GLEW_GET_FUN(__glewBindVertexBuffers) + +#define GLEW_ARB_multi_bind GLEW_GET_VAR(__GLEW_ARB_multi_bind) + +#endif /* GL_ARB_multi_bind */ + /* ----------------------- GL_ARB_multi_draw_indirect ---------------------- */ #ifndef GL_ARB_multi_draw_indirect #define GL_ARB_multi_draw_indirect 1 -typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const void* indirect, GLsizei primcount, GLsizei stride); -typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const void* indirect, GLsizei primcount, GLsizei stride); +typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTPROC) (GLenum mode, const GLvoid *indirect, GLsizei primcount, GLsizei stride); +typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei primcount, GLsizei stride); #define glMultiDrawArraysIndirect GLEW_GET_FUN(__glewMultiDrawArraysIndirect) #define glMultiDrawElementsIndirect GLEW_GET_FUN(__glewMultiDrawElementsIndirect) @@ -4693,6 +5097,20 @@ typedef void (GLAPIENTRY * PFNGLPROVOKINGVERTEXPROC) (GLenum mode); #endif /* GL_ARB_provoking_vertex */ +/* ----------------------- GL_ARB_query_buffer_object ---------------------- */ + +#ifndef GL_ARB_query_buffer_object +#define GL_ARB_query_buffer_object 1 + +#define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000 +#define GL_QUERY_BUFFER 0x9192 +#define GL_QUERY_BUFFER_BINDING 0x9193 +#define GL_QUERY_RESULT_NO_WAIT 0x9194 + +#define GLEW_ARB_query_buffer_object GLEW_GET_VAR(__GLEW_ARB_query_buffer_object) + +#endif /* GL_ARB_query_buffer_object */ + /* ------------------ GL_ARB_robust_buffer_access_behavior ----------------- */ #ifndef GL_ARB_robust_buffer_access_behavior @@ -4847,6 +5265,17 @@ typedef void (GLAPIENTRY * PFNGLSAMPLERPARAMETERIVPROC) (GLuint sampler, GLenum #endif /* GL_ARB_seamless_cube_map */ +/* ------------------ GL_ARB_seamless_cubemap_per_texture ------------------ */ + +#ifndef GL_ARB_seamless_cubemap_per_texture +#define GL_ARB_seamless_cubemap_per_texture 1 + +#define GL_TEXTURE_CUBE_MAP_SEAMLESS 0x884F + +#define GLEW_ARB_seamless_cubemap_per_texture GLEW_GET_VAR(__GLEW_ARB_seamless_cubemap_per_texture) + +#endif /* GL_ARB_seamless_cubemap_per_texture */ + /* --------------------- GL_ARB_separate_shader_objects -------------------- */ #ifndef GL_ARB_separate_shader_objects @@ -5040,6 +5469,24 @@ typedef void (GLAPIENTRY * PFNGLGETACTIVEATOMICCOUNTERBUFFERIVPROC) (GLuint prog #endif /* GL_ARB_shader_bit_encoding */ +/* --------------------- GL_ARB_shader_draw_parameters --------------------- */ + +#ifndef GL_ARB_shader_draw_parameters +#define GL_ARB_shader_draw_parameters 1 + +#define GLEW_ARB_shader_draw_parameters GLEW_GET_VAR(__GLEW_ARB_shader_draw_parameters) + +#endif /* GL_ARB_shader_draw_parameters */ + +/* ------------------------ GL_ARB_shader_group_vote ----------------------- */ + +#ifndef GL_ARB_shader_group_vote +#define GL_ARB_shader_group_vote 1 + +#define GLEW_ARB_shader_group_vote GLEW_GET_VAR(__GLEW_ARB_shader_group_vote) + +#endif /* GL_ARB_shader_group_vote */ + /* --------------------- GL_ARB_shader_image_load_store -------------------- */ #ifndef GL_ARB_shader_image_load_store @@ -5379,7 +5826,7 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMSUBROUTINESUIVPROC) (GLenum shadertype, G #define GL_NAMED_STRING_LENGTH_ARB 0x8DE9 #define GL_NAMED_STRING_TYPE_ARB 0x8DEA -typedef void (GLAPIENTRY * PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar ** path, const GLint *length); +typedef void (GLAPIENTRY * PFNGLCOMPILESHADERINCLUDEARBPROC) (GLuint shader, GLsizei count, const GLchar* const *path, const GLint *length); typedef void (GLAPIENTRY * PFNGLDELETENAMEDSTRINGARBPROC) (GLint namelen, const GLchar* name); typedef void (GLAPIENTRY * PFNGLGETNAMEDSTRINGARBPROC) (GLint namelen, const GLchar* name, GLsizei bufSize, GLint *stringlen, GLchar *string); typedef void (GLAPIENTRY * PFNGLGETNAMEDSTRINGIVARBPROC) (GLint namelen, const GLchar* name, GLenum pname, GLint *params); @@ -5430,6 +5877,33 @@ typedef void (GLAPIENTRY * PFNGLNAMEDSTRINGARBPROC) (GLenum type, GLint namelen, #endif /* GL_ARB_shadow_ambient */ +/* ------------------------- GL_ARB_sparse_texture ------------------------- */ + +#ifndef GL_ARB_sparse_texture +#define GL_ARB_sparse_texture 1 + +#define GL_VIRTUAL_PAGE_SIZE_X_ARB 0x9195 +#define GL_VIRTUAL_PAGE_SIZE_Y_ARB 0x9196 +#define GL_VIRTUAL_PAGE_SIZE_Z_ARB 0x9197 +#define GL_MAX_SPARSE_TEXTURE_SIZE_ARB 0x9198 +#define GL_MAX_SPARSE_3D_TEXTURE_SIZE_ARB 0x9199 +#define GL_MAX_SPARSE_ARRAY_TEXTURE_LAYERS_ARB 0x919A +#define GL_TEXTURE_SPARSE_ARB 0x91A6 +#define GL_VIRTUAL_PAGE_SIZE_INDEX_ARB 0x91A7 +#define GL_NUM_VIRTUAL_PAGE_SIZES_ARB 0x91A8 +#define GL_SPARSE_TEXTURE_FULL_ARRAY_CUBE_MIPMAPS_ARB 0x91A9 +#define GL_NUM_SPARSE_LEVELS_ARB 0x91AA + +typedef void (GLAPIENTRY * PFNGLTEXPAGECOMMITMENTARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); +typedef void (GLAPIENTRY * PFNGLTEXTUREPAGECOMMITMENTEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); + +#define glTexPageCommitmentARB GLEW_GET_FUN(__glewTexPageCommitmentARB) +#define glTexturePageCommitmentEXT GLEW_GET_FUN(__glewTexturePageCommitmentEXT) + +#define GLEW_ARB_sparse_texture GLEW_GET_VAR(__GLEW_ARB_sparse_texture) + +#endif /* GL_ARB_sparse_texture */ + /* ------------------------ GL_ARB_stencil_texturing ----------------------- */ #ifndef GL_ARB_stencil_texturing @@ -5605,13 +6079,13 @@ typedef void (GLAPIENTRY * PFNGLTEXTUREBUFFERRANGEEXTPROC) (GLuint texture, GLen #define GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A2 #define GL_COMPRESSED_TEXTURE_FORMATS_ARB 0x86A3 -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, void* img); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE1DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE2DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXIMAGE3DARBPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GLint lod, GLvoid *img); #define glCompressedTexImage1DARB GLEW_GET_FUN(__glewCompressedTexImage1DARB) #define glCompressedTexImage2DARB GLEW_GET_FUN(__glewCompressedTexImage2DARB) @@ -5797,6 +6271,17 @@ typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXIMAGEARBPROC) (GLenum target, GL #endif /* GL_ARB_texture_gather */ +/* ------------------ GL_ARB_texture_mirror_clamp_to_edge ------------------ */ + +#ifndef GL_ARB_texture_mirror_clamp_to_edge +#define GL_ARB_texture_mirror_clamp_to_edge 1 + +#define GL_MIRROR_CLAMP_TO_EDGE 0x8743 + +#define GLEW_ARB_texture_mirror_clamp_to_edge GLEW_GET_VAR(__GLEW_ARB_texture_mirror_clamp_to_edge) + +#endif /* GL_ARB_texture_mirror_clamp_to_edge */ + /* --------------------- GL_ARB_texture_mirrored_repeat -------------------- */ #ifndef GL_ARB_texture_mirrored_repeat @@ -5937,6 +6422,18 @@ typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DMULTISAMPLEPROC) (GLenum target, GLsiz #endif /* GL_ARB_texture_rgb10_a2ui */ +/* ------------------------ GL_ARB_texture_stencil8 ------------------------ */ + +#ifndef GL_ARB_texture_stencil8 +#define GL_ARB_texture_stencil8 1 + +#define GL_STENCIL_INDEX 0x1901 +#define GL_STENCIL_INDEX8 0x8D48 + +#define GLEW_ARB_texture_stencil8 GLEW_GET_VAR(__GLEW_ARB_texture_stencil8) + +#endif /* GL_ARB_texture_stencil8 */ + /* ------------------------- GL_ARB_texture_storage ------------------------ */ #ifndef GL_ARB_texture_storage @@ -6228,13 +6725,6 @@ typedef GLboolean (GLAPIENTRY * PFNGLISVERTEXARRAYPROC) (GLuint array); #ifndef GL_ARB_vertex_attrib_64bit #define GL_ARB_vertex_attrib_64bit 1 -#define GL_DOUBLE_MAT2 0x8F46 -#define GL_DOUBLE_MAT3 0x8F47 -#define GL_DOUBLE_MAT4 0x8F48 -#define GL_DOUBLE_VEC2 0x8FFC -#define GL_DOUBLE_VEC3 0x8FFD -#define GL_DOUBLE_VEC4 0x8FFE - typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBLDVPROC) (GLuint index, GLenum pname, GLdouble* params); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL1DPROC) (GLuint index, GLdouble x); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL1DVPROC) (GLuint index, const GLdouble* v); @@ -6407,13 +6897,13 @@ typedef ptrdiff_t GLintptrARB; typedef ptrdiff_t GLsizeiptrARB; typedef void (GLAPIENTRY * PFNGLBINDBUFFERARBPROC) (GLenum target, GLuint buffer); -typedef void (GLAPIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid* data, GLenum usage); -typedef void (GLAPIENTRY * PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid* data); +typedef void (GLAPIENTRY * PFNGLBUFFERDATAARBPROC) (GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage); +typedef void (GLAPIENTRY * PFNGLBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data); typedef void (GLAPIENTRY * PFNGLDELETEBUFFERSARBPROC) (GLsizei n, const GLuint* buffers); typedef void (GLAPIENTRY * PFNGLGENBUFFERSARBPROC) (GLsizei n, GLuint* buffers); typedef void (GLAPIENTRY * PFNGLGETBUFFERPARAMETERIVARBPROC) (GLenum target, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETBUFFERPOINTERVARBPROC) (GLenum target, GLenum pname, GLvoid** params); -typedef void (GLAPIENTRY * PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid* data); +typedef void (GLAPIENTRY * PFNGLGETBUFFERSUBDATAARBPROC) (GLenum target, GLintptrARB offset, GLsizeiptrARB size, GLvoid *data); typedef GLboolean (GLAPIENTRY * PFNGLISBUFFERARBPROC) (GLuint buffer); typedef GLvoid * (GLAPIENTRY * PFNGLMAPBUFFERARBPROC) (GLenum target, GLenum access); typedef GLboolean (GLAPIENTRY * PFNGLUNMAPBUFFERARBPROC) (GLenum target); @@ -6528,7 +7018,7 @@ typedef void (GLAPIENTRY * PFNGLGETPROGRAMENVPARAMETERDVARBPROC) (GLenum target, typedef void (GLAPIENTRY * PFNGLGETPROGRAMENVPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) (GLenum target, GLuint index, GLdouble* params); typedef void (GLAPIENTRY * PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) (GLenum target, GLuint index, GLfloat* params); -typedef void (GLAPIENTRY * PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, void* string); +typedef void (GLAPIENTRY * PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pname, GLvoid *string); typedef void (GLAPIENTRY * PFNGLGETPROGRAMIVARBPROC) (GLenum target, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBPOINTERVARBPROC) (GLuint index, GLenum pname, GLvoid** pointer); typedef void (GLAPIENTRY * PFNGLGETVERTEXATTRIBDVARBPROC) (GLuint index, GLenum pname, GLdouble* params); @@ -6543,7 +7033,7 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETER4DARBPROC) (GLenum target, typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) (GLenum target, GLuint index, const GLdouble* params); typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETER4FARBPROC) (GLenum target, GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) (GLenum target, GLuint index, const GLfloat* params); -typedef void (GLAPIENTRY * PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const void* string); +typedef void (GLAPIENTRY * PFNGLPROGRAMSTRINGARBPROC) (GLenum target, GLenum format, GLsizei len, const GLvoid *string); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB1DARBPROC) (GLuint index, GLdouble x); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB1DVARBPROC) (GLuint index, const GLdouble* v); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB1FARBPROC) (GLuint index, GLfloat x); @@ -6580,7 +7070,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4SVARBPROC) (GLuint index, const GLs typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UBVARBPROC) (GLuint index, const GLubyte* v); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UIVARBPROC) (GLuint index, const GLuint* v); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4USVARBPROC) (GLuint index, const GLushort* v); -typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer); +typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERARBPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer); #define glBindProgramARB GLEW_GET_FUN(__glewBindProgramARB) #define glDeleteProgramsARB GLEW_GET_FUN(__glewDeleteProgramsARB) @@ -6674,6 +7164,17 @@ typedef GLint (GLAPIENTRY * PFNGLGETATTRIBLOCATIONARBPROC) (GLhandleARB programO #endif /* GL_ARB_vertex_shader */ +/* ------------------- GL_ARB_vertex_type_10f_11f_11f_rev ------------------ */ + +#ifndef GL_ARB_vertex_type_10f_11f_11f_rev +#define GL_ARB_vertex_type_10f_11f_11f_rev 1 + +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B + +#define GLEW_ARB_vertex_type_10f_11f_11f_rev GLEW_GET_VAR(__GLEW_ARB_vertex_type_10f_11f_11f_rev) + +#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ + /* ------------------- GL_ARB_vertex_type_2_10_10_10_rev ------------------- */ #ifndef GL_ARB_vertex_type_2_10_10_10_rev @@ -6947,7 +7448,7 @@ typedef void (GLAPIENTRY * PFNGLDRAWBUFFERSATIPROC) (GLsizei n, const GLenum* bu typedef void (GLAPIENTRY * PFNGLDRAWELEMENTARRAYATIPROC) (GLenum mode, GLsizei count); typedef void (GLAPIENTRY * PFNGLDRAWRANGEELEMENTARRAYATIPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count); -typedef void (GLAPIENTRY * PFNGLELEMENTPOINTERATIPROC) (GLenum type, const void* pointer); +typedef void (GLAPIENTRY * PFNGLELEMENTPOINTERATIPROC) (GLenum type, const GLvoid *pointer); #define glDrawElementArrayATI GLEW_GET_FUN(__glewDrawElementArrayATI) #define glDrawRangeElementArrayATI GLEW_GET_FUN(__glewDrawRangeElementArrayATI) @@ -7253,8 +7754,8 @@ typedef void (GLAPIENTRY * PFNGLGETOBJECTBUFFERIVATIPROC) (GLuint buffer, GLenum typedef void (GLAPIENTRY * PFNGLGETVARIANTARRAYOBJECTFVATIPROC) (GLuint id, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETVARIANTARRAYOBJECTIVATIPROC) (GLuint id, GLenum pname, GLint* params); typedef GLboolean (GLAPIENTRY * PFNGLISOBJECTBUFFERATIPROC) (GLuint buffer); -typedef GLuint (GLAPIENTRY * PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const void* pointer, GLenum usage); -typedef void (GLAPIENTRY * PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const void* pointer, GLenum preserve); +typedef GLuint (GLAPIENTRY * PFNGLNEWOBJECTBUFFERATIPROC) (GLsizei size, const GLvoid *pointer, GLenum usage); +typedef void (GLAPIENTRY * PFNGLUPDATEOBJECTBUFFERATIPROC) (GLuint buffer, GLuint offset, GLsizei size, const GLvoid *pointer, GLenum preserve); typedef void (GLAPIENTRY * PFNGLVARIANTARRAYOBJECTATIPROC) (GLuint id, GLenum type, GLsizei stride, GLuint buffer, GLuint offset); #define glArrayObjectATI GLEW_GET_FUN(__glewArrayObjectATI) @@ -7598,7 +8099,7 @@ typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONEXTPROC) (GLenum mode); #ifndef GL_EXT_color_subtable #define GL_EXT_color_subtable 1 -typedef void (GLAPIENTRY * PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const void* data); +typedef void (GLAPIENTRY * PFNGLCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, const GLvoid *data); typedef void (GLAPIENTRY * PFNGLCOPYCOLORSUBTABLEEXTPROC) (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width); #define glColorSubTableEXT GLEW_GET_FUN(__glewColorSubTableEXT) @@ -7652,19 +8153,19 @@ typedef void (GLAPIENTRY * PFNGLUNLOCKARRAYSEXTPROC) (void); #define GL_POST_CONVOLUTION_BLUE_BIAS_EXT 0x8022 #define GL_POST_CONVOLUTION_ALPHA_BIAS_EXT 0x8023 -typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void* image); -typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* image); +typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *image); +typedef void (GLAPIENTRY * PFNGLCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *image); typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFEXTPROC) (GLenum target, GLenum pname, GLfloat param); typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, const GLfloat* params); typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIEXTPROC) (GLenum target, GLenum pname, GLint param); typedef void (GLAPIENTRY * PFNGLCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, const GLint* params); typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER1DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (GLAPIENTRY * PFNGLCOPYCONVOLUTIONFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void* image); +typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *image); typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETCONVOLUTIONPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params); -typedef void (GLAPIENTRY * PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, void* row, void* column, void* span); -typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* row, const void* column); +typedef void (GLAPIENTRY * PFNGLGETSEPARABLEFILTEREXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span); +typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *row, const GLvoid *column); #define glConvolutionFilter1DEXT GLEW_GET_FUN(__glewConvolutionFilter1DEXT) #define glConvolutionFilter2DEXT GLEW_GET_FUN(__glewConvolutionFilter2DEXT) @@ -7704,8 +8205,8 @@ typedef void (GLAPIENTRY * PFNGLSEPARABLEFILTER2DEXTPROC) (GLenum target, GLenum #define GL_MAP1_BINORMAL_EXT 0x8446 #define GL_MAP2_BINORMAL_EXT 0x8447 -typedef void (GLAPIENTRY * PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, void* pointer); -typedef void (GLAPIENTRY * PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, void* pointer); +typedef void (GLAPIENTRY * PFNGLBINORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLTANGENTPOINTEREXTPROC) (GLenum type, GLsizei stride, GLvoid *pointer); #define glBinormalPointerEXT GLEW_GET_FUN(__glewBinormalPointerEXT) #define glTangentPointerEXT GLEW_GET_FUN(__glewTangentPointerEXT) @@ -7799,18 +8300,18 @@ typedef void (GLAPIENTRY * PFNGLDEPTHBOUNDSEXTPROC) (GLclampd zmin, GLclampd zma typedef void (GLAPIENTRY * PFNGLBINDMULTITEXTUREEXTPROC) (GLenum texunit, GLenum target, GLuint texture); typedef GLenum (GLAPIENTRY * PFNGLCHECKNAMEDFRAMEBUFFERSTATUSEXTPROC) (GLuint framebuffer, GLenum target); typedef void (GLAPIENTRY * PFNGLCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); -typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLCOMPRESSEDTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); typedef void (GLAPIENTRY * PFNGLCOPYMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (GLAPIENTRY * PFNGLCOPYMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (GLAPIENTRY * PFNGLCOPYMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); @@ -7835,8 +8336,8 @@ typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERDRAWBUFFERSEXTPROC) (GLuint framebuff typedef void (GLAPIENTRY * PFNGLFRAMEBUFFERREADBUFFEREXTPROC) (GLuint framebuffer, GLenum mode); typedef void (GLAPIENTRY * PFNGLGENERATEMULTITEXMIPMAPEXTPROC) (GLenum texunit, GLenum target); typedef void (GLAPIENTRY * PFNGLGENERATETEXTUREMIPMAPEXTPROC) (GLuint texture, GLenum target); -typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, void* img); -typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, void* img); +typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLvoid *img); +typedef void (GLAPIENTRY * PFNGLGETCOMPRESSEDTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLvoid *img); typedef void (GLAPIENTRY * PFNGLGETDOUBLEINDEXEDVEXTPROC) (GLenum target, GLuint index, GLdouble* params); typedef void (GLAPIENTRY * PFNGLGETDOUBLEI_VEXTPROC) (GLenum pname, GLuint index, GLdouble* params); typedef void (GLAPIENTRY * PFNGLGETFLOATINDEXEDVEXTPROC) (GLenum target, GLuint index, GLfloat* params); @@ -7847,7 +8348,7 @@ typedef void (GLAPIENTRY * PFNGLGETMULTITEXENVIVEXTPROC) (GLenum texunit, GLenum typedef void (GLAPIENTRY * PFNGLGETMULTITEXGENDVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLdouble* params); typedef void (GLAPIENTRY * PFNGLGETMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint* params); -typedef void (GLAPIENTRY * PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +typedef void (GLAPIENTRY * PFNGLGETMULTITEXIMAGEEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); typedef void (GLAPIENTRY * PFNGLGETMULTITEXLEVELPARAMETERFVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETMULTITEXLEVELPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLint level, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint* params); @@ -7856,18 +8357,18 @@ typedef void (GLAPIENTRY * PFNGLGETMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, typedef void (GLAPIENTRY * PFNGLGETMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERPARAMETERIVEXTPROC) (GLuint buffer, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERPOINTERVEXTPROC) (GLuint buffer, GLenum pname, void** params); -typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, void* data); +typedef void (GLAPIENTRY * PFNGLGETNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, GLvoid *data); typedef void (GLAPIENTRY * PFNGLGETNAMEDFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMLOCALPARAMETERIIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLint* params); typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMLOCALPARAMETERIUIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLuint* params); typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMLOCALPARAMETERDVEXTPROC) (GLuint program, GLenum target, GLuint index, GLdouble* params); typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMLOCALPARAMETERFVEXTPROC) (GLuint program, GLenum target, GLuint index, GLfloat* params); -typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, void* string); +typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum pname, GLvoid *string); typedef void (GLAPIENTRY * PFNGLGETNAMEDPROGRAMIVEXTPROC) (GLuint program, GLenum target, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETNAMEDRENDERBUFFERPARAMETERIVEXTPROC) (GLuint renderbuffer, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETPOINTERINDEXEDVEXTPROC) (GLenum target, GLuint index, GLvoid** params); typedef void (GLAPIENTRY * PFNGLGETPOINTERI_VEXTPROC) (GLenum pname, GLuint index, GLvoid** params); -typedef void (GLAPIENTRY * PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, void* pixels); +typedef void (GLAPIENTRY * PFNGLGETTEXTUREIMAGEEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); typedef void (GLAPIENTRY * PFNGLGETTEXTURELEVELPARAMETERFVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETTEXTURELEVELPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLint level, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLGETTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint* params); @@ -7900,7 +8401,7 @@ typedef void (GLAPIENTRY * PFNGLMATRIXSCALEFEXTPROC) (GLenum matrixMode, GLfloat typedef void (GLAPIENTRY * PFNGLMATRIXTRANSLATEDEXTPROC) (GLenum matrixMode, GLdouble x, GLdouble y, GLdouble z); typedef void (GLAPIENTRY * PFNGLMATRIXTRANSLATEFEXTPROC) (GLenum matrixMode, GLfloat x, GLfloat y, GLfloat z); typedef void (GLAPIENTRY * PFNGLMULTITEXBUFFEREXTPROC) (GLenum texunit, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (GLAPIENTRY * PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const void* pointer); +typedef void (GLAPIENTRY * PFNGLMULTITEXCOORDPOINTEREXTPROC) (GLenum texunit, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (GLAPIENTRY * PFNGLMULTITEXENVFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); typedef void (GLAPIENTRY * PFNGLMULTITEXENVFVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLfloat* params); typedef void (GLAPIENTRY * PFNGLMULTITEXENVIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); @@ -7911,9 +8412,9 @@ typedef void (GLAPIENTRY * PFNGLMULTITEXGENFEXTPROC) (GLenum texunit, GLenum coo typedef void (GLAPIENTRY * PFNGLMULTITEXGENFVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLfloat* params); typedef void (GLAPIENTRY * PFNGLMULTITEXGENIEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, GLint param); typedef void (GLAPIENTRY * PFNGLMULTITEXGENIVEXTPROC) (GLenum texunit, GLenum coord, GLenum pname, const GLint* params); -typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLMULTITEXIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERIIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint* params); typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERIUIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLuint* params); typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERFEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLfloat param); @@ -7921,11 +8422,11 @@ typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERFVEXTPROC) (GLenum texunit, GLe typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERIEXTPROC) (GLenum texunit, GLenum target, GLenum pname, GLint param); typedef void (GLAPIENTRY * PFNGLMULTITEXPARAMETERIVEXTPROC) (GLenum texunit, GLenum target, GLenum pname, const GLint* param); typedef void (GLAPIENTRY * PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenum target, GLuint renderbuffer); -typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const void* data, GLenum usage); -typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const void* data); +typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE1DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE2DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLMULTITEXSUBIMAGE3DEXTPROC) (GLenum texunit, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERDATAEXTPROC) (GLuint buffer, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef void (GLAPIENTRY * PFNGLNAMEDBUFFERSUBDATAEXTPROC) (GLuint buffer, GLintptr offset, GLsizeiptr size, const GLvoid *data); typedef void (GLAPIENTRY * PFNGLNAMEDCOPYBUFFERSUBDATAEXTPROC) (GLuint readBuffer, GLuint writeBuffer, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size); typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERRENDERBUFFEREXTPROC) (GLuint framebuffer, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (GLAPIENTRY * PFNGLNAMEDFRAMEBUFFERTEXTURE1DEXTPROC) (GLuint framebuffer, GLenum attachment, GLenum textarget, GLuint texture, GLint level); @@ -7945,65 +8446,48 @@ typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMLOCALPARAMETERI4UIVEXTPROC) (GLuint typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMLOCALPARAMETERS4FVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLfloat* params); typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMLOCALPARAMETERSI4IVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLint* params); typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMLOCALPARAMETERSI4UIVEXTPROC) (GLuint program, GLenum target, GLuint index, GLsizei count, const GLuint* params); -typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const void* string); +typedef void (GLAPIENTRY * PFNGLNAMEDPROGRAMSTRINGEXTPROC) (GLuint program, GLenum target, GLenum format, GLsizei len, const GLvoid *string); typedef void (GLAPIENTRY * PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC) (GLuint renderbuffer, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAPIENTRY * PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC) (GLuint renderbuffer, GLsizei coverageSamples, GLsizei colorSamples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAPIENTRY * PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLuint renderbuffer, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1DEXTPROC) (GLuint program, GLint location, GLdouble x); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat v0); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat* value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint v0); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint* value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1UIEXTPROC) (GLuint program, GLint location, GLuint v0); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM1UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat* value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint* value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM2UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat* value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint* value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM3UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4DEXTPROC) (GLuint program, GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4DVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat* value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint* value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4UIEXTPROC) (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORM4UIVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLuint* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); -typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value); typedef void (GLAPIENTRY * PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); typedef void (GLAPIENTRY * PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC) (GLbitfield mask); typedef void (GLAPIENTRY * PFNGLTEXTUREBUFFEREXTPROC) (GLuint texture, GLenum target, GLenum internalformat, GLuint buffer); -typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXTUREIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint* params); typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIUIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLuint* params); typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERFEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLfloat param); @@ -8011,9 +8495,9 @@ typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERFVEXTPROC) (GLuint texture, GLen typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIEXTPROC) (GLuint texture, GLenum target, GLenum pname, GLint param); typedef void (GLAPIENTRY * PFNGLTEXTUREPARAMETERIVEXTPROC) (GLuint texture, GLenum target, GLenum pname, const GLint* param); typedef void (GLAPIENTRY * PFNGLTEXTURERENDERBUFFEREXTPROC) (GLuint texture, GLenum target, GLuint renderbuffer); -typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE1DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE2DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXTURESUBIMAGE3DEXTPROC) (GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); typedef GLboolean (GLAPIENTRY * PFNGLUNMAPNAMEDBUFFEREXTPROC) (GLuint buffer); typedef void (GLAPIENTRY * PFNGLVERTEXARRAYCOLOROFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLint size, GLenum type, GLsizei stride, GLintptr offset); typedef void (GLAPIENTRY * PFNGLVERTEXARRAYEDGEFLAGOFFSETEXTPROC) (GLuint vaobj, GLuint buffer, GLsizei stride, GLintptr offset); @@ -8180,55 +8664,38 @@ typedef void (GLAPIENTRY * PFNGLVERTEXARRAYVERTEXOFFSETEXTPROC) (GLuint vaobj, G #define glNamedRenderbufferStorageEXT GLEW_GET_FUN(__glewNamedRenderbufferStorageEXT) #define glNamedRenderbufferStorageMultisampleCoverageEXT GLEW_GET_FUN(__glewNamedRenderbufferStorageMultisampleCoverageEXT) #define glNamedRenderbufferStorageMultisampleEXT GLEW_GET_FUN(__glewNamedRenderbufferStorageMultisampleEXT) -#define glProgramUniform1dEXT GLEW_GET_FUN(__glewProgramUniform1dEXT) -#define glProgramUniform1dvEXT GLEW_GET_FUN(__glewProgramUniform1dvEXT) #define glProgramUniform1fEXT GLEW_GET_FUN(__glewProgramUniform1fEXT) #define glProgramUniform1fvEXT GLEW_GET_FUN(__glewProgramUniform1fvEXT) #define glProgramUniform1iEXT GLEW_GET_FUN(__glewProgramUniform1iEXT) #define glProgramUniform1ivEXT GLEW_GET_FUN(__glewProgramUniform1ivEXT) #define glProgramUniform1uiEXT GLEW_GET_FUN(__glewProgramUniform1uiEXT) #define glProgramUniform1uivEXT GLEW_GET_FUN(__glewProgramUniform1uivEXT) -#define glProgramUniform2dEXT GLEW_GET_FUN(__glewProgramUniform2dEXT) -#define glProgramUniform2dvEXT GLEW_GET_FUN(__glewProgramUniform2dvEXT) #define glProgramUniform2fEXT GLEW_GET_FUN(__glewProgramUniform2fEXT) #define glProgramUniform2fvEXT GLEW_GET_FUN(__glewProgramUniform2fvEXT) #define glProgramUniform2iEXT GLEW_GET_FUN(__glewProgramUniform2iEXT) #define glProgramUniform2ivEXT GLEW_GET_FUN(__glewProgramUniform2ivEXT) #define glProgramUniform2uiEXT GLEW_GET_FUN(__glewProgramUniform2uiEXT) #define glProgramUniform2uivEXT GLEW_GET_FUN(__glewProgramUniform2uivEXT) -#define glProgramUniform3dEXT GLEW_GET_FUN(__glewProgramUniform3dEXT) -#define glProgramUniform3dvEXT GLEW_GET_FUN(__glewProgramUniform3dvEXT) #define glProgramUniform3fEXT GLEW_GET_FUN(__glewProgramUniform3fEXT) #define glProgramUniform3fvEXT GLEW_GET_FUN(__glewProgramUniform3fvEXT) #define glProgramUniform3iEXT GLEW_GET_FUN(__glewProgramUniform3iEXT) #define glProgramUniform3ivEXT GLEW_GET_FUN(__glewProgramUniform3ivEXT) #define glProgramUniform3uiEXT GLEW_GET_FUN(__glewProgramUniform3uiEXT) #define glProgramUniform3uivEXT GLEW_GET_FUN(__glewProgramUniform3uivEXT) -#define glProgramUniform4dEXT GLEW_GET_FUN(__glewProgramUniform4dEXT) -#define glProgramUniform4dvEXT GLEW_GET_FUN(__glewProgramUniform4dvEXT) #define glProgramUniform4fEXT GLEW_GET_FUN(__glewProgramUniform4fEXT) #define glProgramUniform4fvEXT GLEW_GET_FUN(__glewProgramUniform4fvEXT) #define glProgramUniform4iEXT GLEW_GET_FUN(__glewProgramUniform4iEXT) #define glProgramUniform4ivEXT GLEW_GET_FUN(__glewProgramUniform4ivEXT) #define glProgramUniform4uiEXT GLEW_GET_FUN(__glewProgramUniform4uiEXT) #define glProgramUniform4uivEXT GLEW_GET_FUN(__glewProgramUniform4uivEXT) -#define glProgramUniformMatrix2dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix2dvEXT) #define glProgramUniformMatrix2fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix2fvEXT) -#define glProgramUniformMatrix2x3dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix2x3dvEXT) #define glProgramUniformMatrix2x3fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix2x3fvEXT) -#define glProgramUniformMatrix2x4dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix2x4dvEXT) #define glProgramUniformMatrix2x4fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix2x4fvEXT) -#define glProgramUniformMatrix3dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix3dvEXT) #define glProgramUniformMatrix3fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix3fvEXT) -#define glProgramUniformMatrix3x2dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix3x2dvEXT) #define glProgramUniformMatrix3x2fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix3x2fvEXT) -#define glProgramUniformMatrix3x4dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix3x4dvEXT) #define glProgramUniformMatrix3x4fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix3x4fvEXT) -#define glProgramUniformMatrix4dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix4dvEXT) #define glProgramUniformMatrix4fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix4fvEXT) -#define glProgramUniformMatrix4x2dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix4x2dvEXT) #define glProgramUniformMatrix4x2fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix4x2fvEXT) -#define glProgramUniformMatrix4x3dvEXT GLEW_GET_FUN(__glewProgramUniformMatrix4x3dvEXT) #define glProgramUniformMatrix4x3fvEXT GLEW_GET_FUN(__glewProgramUniformMatrix4x3fvEXT) #define glPushClientAttribDefaultEXT GLEW_GET_FUN(__glewPushClientAttribDefaultEXT) #define glTextureBufferEXT GLEW_GET_FUN(__glewTextureBufferEXT) @@ -8742,10 +9209,10 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBIPOINTEREXTPROC) (GLuint index, GLin #define GL_MINMAX_FORMAT_EXT 0x802F #define GL_MINMAX_SINK_EXT 0x8030 -typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void* values); +typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETHISTOGRAMPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params); -typedef void (GLAPIENTRY * PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, void* values); +typedef void (GLAPIENTRY * PFNGLGETMINMAXEXTPROC) (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values); typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETMINMAXPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params); typedef void (GLAPIENTRY * PFNGLHISTOGRAMEXTPROC) (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink); @@ -8854,7 +9321,7 @@ typedef void (GLAPIENTRY * PFNGLTEXTUREMATERIALEXTPROC) (GLenum face, GLenum mod #define GL_EXT_multi_draw_arrays 1 typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, const GLint* first, const GLsizei *count, GLsizei primcount); -typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, GLsizei* count, GLenum type, const GLvoid **indices, GLsizei primcount); +typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, GLsizei* count, GLenum type, const GLvoid * const *indices, GLsizei primcount); #define glMultiDrawArraysEXT GLEW_GET_FUN(__glewMultiDrawArraysEXT) #define glMultiDrawElementsEXT GLEW_GET_FUN(__glewMultiDrawElementsEXT) @@ -8965,8 +9432,8 @@ typedef void (GLAPIENTRY * PFNGLSAMPLEPATTERNEXTPROC) (GLenum pattern); #define GL_TEXTURE_CUBE_MAP_ARB 0x8513 #define GL_PROXY_TEXTURE_CUBE_MAP_ARB 0x851B -typedef void (GLAPIENTRY * PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const void* data); -typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, void* data); +typedef void (GLAPIENTRY * PFNGLCOLORTABLEEXTPROC) (GLenum target, GLenum internalFormat, GLsizei width, GLenum format, GLenum type, const GLvoid *data); +typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEEXTPROC) (GLenum target, GLenum format, GLenum type, GLvoid *data); typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERFVEXTPROC) (GLenum target, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERIVEXTPROC) (GLenum target, GLenum pname, GLint* params); @@ -9337,9 +9804,9 @@ typedef void (GLAPIENTRY * PFNGLACTIVESTENCILFACEEXTPROC) (GLenum face); #ifndef GL_EXT_subtexture #define GL_EXT_subtexture 1 -typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE1DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE2DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); #define glTexSubImage1DEXT GLEW_GET_FUN(__glewTexSubImage1DEXT) #define glTexSubImage2DEXT GLEW_GET_FUN(__glewTexSubImage2DEXT) @@ -9416,7 +9883,7 @@ typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE3DEXTPROC) (GLenum target, GLint leve #define GL_TEXTURE_WRAP_R_EXT 0x8072 #define GL_MAX_3D_TEXTURE_SIZE_EXT 0x8073 -typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +typedef void (GLAPIENTRY * PFNGLTEXIMAGE3DEXTPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); #define glTexImage3DEXT GLEW_GET_FUN(__glewTexImage3DEXT) @@ -9554,18 +10021,6 @@ typedef void (GLAPIENTRY * PFNGLTEXBUFFEREXTPROC) (GLenum target, GLenum interna #ifndef GL_EXT_texture_env #define GL_EXT_texture_env 1 -#define GL_TEXTURE_ENV0_EXT 0 -#define GL_ENV_BLEND_EXT 0 -#define GL_TEXTURE_ENV_SHIFT_EXT 0 -#define GL_ENV_REPLACE_EXT 0 -#define GL_ENV_ADD_EXT 0 -#define GL_ENV_SUBTRACT_EXT 0 -#define GL_TEXTURE_ENV_MODE_ALPHA_EXT 0 -#define GL_ENV_REVERSE_SUBTRACT_EXT 0 -#define GL_ENV_REVERSE_BLEND_EXT 0 -#define GL_ENV_COPY_EXT 0 -#define GL_ENV_MODULATE_EXT 0 - #define GLEW_EXT_texture_env GLEW_GET_VAR(__GLEW_EXT_texture_env) #endif /* GL_EXT_texture_env */ @@ -9936,7 +10391,7 @@ typedef void (GLAPIENTRY * PFNGLBINDBUFFEROFFSETEXTPROC) (GLenum target, GLuint typedef void (GLAPIENTRY * PFNGLBINDBUFFERRANGEEXTPROC) (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (GLAPIENTRY * PFNGLENDTRANSFORMFEEDBACKEXTPROC) (void); typedef void (GLAPIENTRY * PFNGLGETTRANSFORMFEEDBACKVARYINGEXTPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei *size, GLenum *type, GLchar *name); -typedef void (GLAPIENTRY * PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar ** varyings, GLenum bufferMode); +typedef void (GLAPIENTRY * PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint program, GLsizei count, const GLchar * const* varyings, GLenum bufferMode); #define glBeginTransformFeedbackEXT GLEW_GET_FUN(__glewBeginTransformFeedbackEXT) #define glBindBufferBaseEXT GLEW_GET_FUN(__glewBindBufferBaseEXT) @@ -9990,13 +10445,13 @@ typedef void (GLAPIENTRY * PFNGLTRANSFORMFEEDBACKVARYINGSEXTPROC) (GLuint progra #define GL_EDGE_FLAG_ARRAY_POINTER_EXT 0x8093 typedef void (GLAPIENTRY * PFNGLARRAYELEMENTEXTPROC) (GLint i); -typedef void (GLAPIENTRY * PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer); +typedef void (GLAPIENTRY * PFNGLCOLORPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); typedef void (GLAPIENTRY * PFNGLDRAWARRAYSEXTPROC) (GLenum mode, GLint first, GLsizei count); typedef void (GLAPIENTRY * PFNGLEDGEFLAGPOINTEREXTPROC) (GLsizei stride, GLsizei count, const GLboolean* pointer); -typedef void (GLAPIENTRY * PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void* pointer); -typedef void (GLAPIENTRY * PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const void* pointer); -typedef void (GLAPIENTRY * PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer); -typedef void (GLAPIENTRY * PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const void* pointer); +typedef void (GLAPIENTRY * PFNGLINDEXPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLNORMALPOINTEREXTPROC) (GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLTEXCOORDPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLVERTEXPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *pointer); #define glArrayElementEXT GLEW_GET_FUN(__glewArrayElementEXT) #define glColorPointerEXT GLEW_GET_FUN(__glewColorPointerEXT) @@ -10050,7 +10505,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL3DEXTPROC) (GLuint index, GLdouble typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL3DVEXTPROC) (GLuint index, const GLdouble* v); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL4DEXTPROC) (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBL4DVEXTPROC) (GLuint index, const GLdouble* v); -typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); +typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBLPOINTEREXTPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); #define glGetVertexAttribLdvEXT GLEW_GET_FUN(__glewGetVertexAttribLdvEXT) #define glVertexArrayVertexAttribLOffsetEXT GLEW_GET_FUN(__glewVertexArrayVertexAttribLOffsetEXT) @@ -10293,7 +10748,7 @@ typedef void (GLAPIENTRY * PFNGLWRITEMASKEXTPROC) (GLuint res, GLuint in, GLenum #define GL_VERTEX_WEIGHT_ARRAY_STRIDE_EXT 0x850F #define GL_VERTEX_WEIGHT_ARRAY_POINTER_EXT 0x8510 -typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, void* pointer); +typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTPOINTEREXTPROC) (GLint size, GLenum type, GLsizei stride, GLvoid *pointer); typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTFEXTPROC) (GLfloat weight); typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTFVEXTPROC) (GLfloat* weight); @@ -10338,7 +10793,7 @@ typedef void (GLAPIENTRY * PFNGLFRAMETERMINATORGREMEDYPROC) (void); #ifndef GL_GREMEDY_string_marker #define GL_GREMEDY_string_marker 1 -typedef void (GLAPIENTRY * PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const void* string); +typedef void (GLAPIENTRY * PFNGLSTRINGMARKERGREMEDYPROC) (GLsizei len, const GLvoid *string); #define glStringMarkerGREMEDY GLEW_GET_FUN(__glewStringMarkerGREMEDY) @@ -10383,9 +10838,6 @@ typedef void (GLAPIENTRY * PFNGLIMAGETRANSFORMPARAMETERIVHPPROC) (GLenum target, #ifndef GL_HP_occlusion_test #define GL_HP_occlusion_test 1 -#define GL_OCCLUSION_TEST_HP 0x8165 -#define GL_OCCLUSION_TEST_RESULT_HP 0x8166 - #define GLEW_HP_occlusion_test GLEW_GET_VAR(__GLEW_HP_occlusion_test) #endif /* GL_HP_occlusion_test */ @@ -10532,6 +10984,28 @@ typedef void (GLAPIENTRY * PFNGLVERTEXPOINTERLISTIBMPROC) (GLint size, GLenum ty #endif /* GL_INGR_interlace_read */ +/* -------------------------- GL_INTEL_map_texture ------------------------- */ + +#ifndef GL_INTEL_map_texture +#define GL_INTEL_map_texture 1 + +#define GL_LAYOUT_DEFAULT_INTEL 0 +#define GL_LAYOUT_LINEAR_INTEL 1 +#define GL_LAYOUT_LINEAR_CPU_CACHED_INTEL 2 +#define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF + +typedef GLvoid * (GLAPIENTRY * PFNGLMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level, GLbitfield access, GLint* stride, GLenum *layout); +typedef void (GLAPIENTRY * PFNGLSYNCTEXTUREINTELPROC) (GLuint texture); +typedef void (GLAPIENTRY * PFNGLUNMAPTEXTURE2DINTELPROC) (GLuint texture, GLint level); + +#define glMapTexture2DINTEL GLEW_GET_FUN(__glewMapTexture2DINTEL) +#define glSyncTextureINTEL GLEW_GET_FUN(__glewSyncTextureINTEL) +#define glUnmapTexture2DINTEL GLEW_GET_FUN(__glewUnmapTexture2DINTEL) + +#define GLEW_INTEL_map_texture GLEW_GET_VAR(__GLEW_INTEL_map_texture) + +#endif /* GL_INTEL_map_texture */ + /* ------------------------ GL_INTEL_parallel_arrays ----------------------- */ #ifndef GL_INTEL_parallel_arrays @@ -10620,15 +11094,15 @@ typedef void (GLAPIENTRY * PFNGLTEXSCISSORINTELPROC) (GLenum target, GLclampf tl typedef void (APIENTRY *GLDEBUGPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, GLvoid* userParam); -typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, void* userParam); +typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const GLvoid *userParam); typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint* ids, GLboolean enabled); typedef void (GLAPIENTRY * PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* buf); typedef GLuint (GLAPIENTRY * PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum* sources, GLenum* types, GLuint* ids, GLenum* severities, GLsizei* lengths, GLchar* messageLog); typedef void (GLAPIENTRY * PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei* length, GLchar *label); typedef void (GLAPIENTRY * PFNGLGETOBJECTPTRLABELPROC) (void* ptr, GLsizei bufSize, GLsizei* length, GLchar *label); -typedef void (GLAPIENTRY * PFNGLGETPOINTERVPROC) (GLenum pname, void** params); typedef void (GLAPIENTRY * PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar* label); typedef void (GLAPIENTRY * PFNGLOBJECTPTRLABELPROC) (void* ptr, GLsizei length, const GLchar* label); +typedef void (GLAPIENTRY * PFNGLPOPDEBUGGROUPPROC) (void); typedef void (GLAPIENTRY * PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar * message); #define glDebugMessageCallback GLEW_GET_FUN(__glewDebugMessageCallback) @@ -10637,9 +11111,9 @@ typedef void (GLAPIENTRY * PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, G #define glGetDebugMessageLog GLEW_GET_FUN(__glewGetDebugMessageLog) #define glGetObjectLabel GLEW_GET_FUN(__glewGetObjectLabel) #define glGetObjectPtrLabel GLEW_GET_FUN(__glewGetObjectPtrLabel) -#define glGetPointerv GLEW_GET_FUN(__glewGetPointerv) #define glObjectLabel GLEW_GET_FUN(__glewObjectLabel) #define glObjectPtrLabel GLEW_GET_FUN(__glewObjectPtrLabel) +#define glPopDebugGroup GLEW_GET_FUN(__glewPopDebugGroup) #define glPushDebugGroup GLEW_GET_FUN(__glewPushDebugGroup) #define GLEW_KHR_debug GLEW_GET_VAR(__GLEW_KHR_debug) @@ -10822,6 +11296,21 @@ typedef void (GLAPIENTRY * PFNGLWINDOWPOS4SVMESAPROC) (const GLshort* p); #endif /* GL_MESA_ycbcr_texture */ +/* ----------------------- GL_NVX_conditional_render ----------------------- */ + +#ifndef GL_NVX_conditional_render +#define GL_NVX_conditional_render 1 + +typedef void (GLAPIENTRY * PFNGLBEGINCONDITIONALRENDERNVXPROC) (GLuint id); +typedef void (GLAPIENTRY * PFNGLENDCONDITIONALRENDERNVXPROC) (void); + +#define glBeginConditionalRenderNVX GLEW_GET_FUN(__glewBeginConditionalRenderNVX) +#define glEndConditionalRenderNVX GLEW_GET_FUN(__glewEndConditionalRenderNVX) + +#define GLEW_NVX_conditional_render GLEW_GET_VAR(__GLEW_NVX_conditional_render) + +#endif /* GL_NVX_conditional_render */ + /* ------------------------- GL_NVX_gpu_memory_info ------------------------ */ #ifndef GL_NVX_gpu_memory_info @@ -10837,6 +11326,21 @@ typedef void (GLAPIENTRY * PFNGLWINDOWPOS4SVMESAPROC) (const GLshort* p); #endif /* GL_NVX_gpu_memory_info */ +/* ------------------- GL_NV_bindless_multi_draw_indirect ------------------ */ + +#ifndef GL_NV_bindless_multi_draw_indirect +#define GL_NV_bindless_multi_draw_indirect 1 + +typedef void (GLAPIENTRY * PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC) (GLenum mode, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); +typedef void (GLAPIENTRY * PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC) (GLenum mode, GLenum type, const GLvoid *indirect, GLsizei drawCount, GLsizei stride, GLint vertexBufferCount); + +#define glMultiDrawArraysIndirectBindlessNV GLEW_GET_FUN(__glewMultiDrawArraysIndirectBindlessNV) +#define glMultiDrawElementsIndirectBindlessNV GLEW_GET_FUN(__glewMultiDrawElementsIndirectBindlessNV) + +#define GLEW_NV_bindless_multi_draw_indirect GLEW_GET_VAR(__GLEW_NV_bindless_multi_draw_indirect) + +#endif /* GL_NV_bindless_multi_draw_indirect */ + /* ------------------------- GL_NV_bindless_texture ------------------------ */ #ifndef GL_NV_bindless_texture @@ -10874,6 +11378,77 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsiz #endif /* GL_NV_bindless_texture */ +/* --------------------- GL_NV_blend_equation_advanced --------------------- */ + +#ifndef GL_NV_blend_equation_advanced +#define GL_NV_blend_equation_advanced 1 + +#define GL_BLEND_PREMULTIPLIED_SRC_NV 0x9280 +#define GL_BLEND_OVERLAP_NV 0x9281 +#define GL_UNCORRELATED_NV 0x9282 +#define GL_DISJOINT_NV 0x9283 +#define GL_CONJOINT_NV 0x9284 +#define GL_BLEND_ADVANCED_COHERENT_NV 0x9285 +#define GL_SRC_NV 0x9286 +#define GL_DST_NV 0x9287 +#define GL_SRC_OVER_NV 0x9288 +#define GL_DST_OVER_NV 0x9289 +#define GL_SRC_IN_NV 0x928A +#define GL_DST_IN_NV 0x928B +#define GL_SRC_OUT_NV 0x928C +#define GL_DST_OUT_NV 0x928D +#define GL_SRC_ATOP_NV 0x928E +#define GL_DST_ATOP_NV 0x928F +#define GL_PLUS_NV 0x9291 +#define GL_PLUS_DARKER_NV 0x9292 +#define GL_MULTIPLY_NV 0x9294 +#define GL_SCREEN_NV 0x9295 +#define GL_OVERLAY_NV 0x9296 +#define GL_DARKEN_NV 0x9297 +#define GL_LIGHTEN_NV 0x9298 +#define GL_COLORDODGE_NV 0x9299 +#define GL_COLORBURN_NV 0x929A +#define GL_HARDLIGHT_NV 0x929B +#define GL_SOFTLIGHT_NV 0x929C +#define GL_DIFFERENCE_NV 0x929E +#define GL_MINUS_NV 0x929F +#define GL_EXCLUSION_NV 0x92A0 +#define GL_CONTRAST_NV 0x92A1 +#define GL_INVERT_RGB_NV 0x92A3 +#define GL_LINEARDODGE_NV 0x92A4 +#define GL_LINEARBURN_NV 0x92A5 +#define GL_VIVIDLIGHT_NV 0x92A6 +#define GL_LINEARLIGHT_NV 0x92A7 +#define GL_PINLIGHT_NV 0x92A8 +#define GL_HARDMIX_NV 0x92A9 +#define GL_HSL_HUE_NV 0x92AD +#define GL_HSL_SATURATION_NV 0x92AE +#define GL_HSL_COLOR_NV 0x92AF +#define GL_HSL_LUMINOSITY_NV 0x92B0 +#define GL_PLUS_CLAMPED_NV 0x92B1 +#define GL_PLUS_CLAMPED_ALPHA_NV 0x92B2 +#define GL_MINUS_CLAMPED_NV 0x92B3 +#define GL_INVERT_OVG_NV 0x92B4 + +typedef void (GLAPIENTRY * PFNGLBLENDBARRIERNVPROC) (void); +typedef void (GLAPIENTRY * PFNGLBLENDPARAMETERINVPROC) (GLenum pname, GLint value); + +#define glBlendBarrierNV GLEW_GET_FUN(__glewBlendBarrierNV) +#define glBlendParameteriNV GLEW_GET_FUN(__glewBlendParameteriNV) + +#define GLEW_NV_blend_equation_advanced GLEW_GET_VAR(__GLEW_NV_blend_equation_advanced) + +#endif /* GL_NV_blend_equation_advanced */ + +/* ----------------- GL_NV_blend_equation_advanced_coherent ---------------- */ + +#ifndef GL_NV_blend_equation_advanced_coherent +#define GL_NV_blend_equation_advanced_coherent 1 + +#define GLEW_NV_blend_equation_advanced_coherent GLEW_GET_VAR(__GLEW_NV_blend_equation_advanced_coherent) + +#endif /* GL_NV_blend_equation_advanced_coherent */ + /* --------------------------- GL_NV_blend_square -------------------------- */ #ifndef GL_NV_blend_square @@ -10883,6 +11458,18 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMHANDLEUI64VNVPROC) (GLint location, GLsiz #endif /* GL_NV_blend_square */ +/* ------------------------- GL_NV_compute_program5 ------------------------ */ + +#ifndef GL_NV_compute_program5 +#define GL_NV_compute_program5 1 + +#define GL_COMPUTE_PROGRAM_NV 0x90FB +#define GL_COMPUTE_PROGRAM_PARAMETER_BUFFER_NV 0x90FC + +#define GLEW_NV_compute_program5 GLEW_GET_VAR(__GLEW_NV_compute_program5) + +#endif /* GL_NV_compute_program5 */ + /* ------------------------ GL_NV_conditional_render ----------------------- */ #ifndef GL_NV_conditional_render @@ -10928,6 +11515,18 @@ typedef void (GLAPIENTRY * PFNGLCOPYIMAGESUBDATANVPROC) (GLuint srcName, GLenum #endif /* GL_NV_copy_image */ +/* -------------------------- GL_NV_deep_texture3D ------------------------- */ + +#ifndef GL_NV_deep_texture3D +#define GL_NV_deep_texture3D 1 + +#define GL_MAX_DEEP_3D_TEXTURE_WIDTH_HEIGHT_NV 0x90D0 +#define GL_MAX_DEEP_3D_TEXTURE_DEPTH_NV 0x90D1 + +#define GLEW_NV_deep_texture3D GLEW_GET_VAR(__GLEW_NV_deep_texture3D) + +#endif /* GL_NV_deep_texture3D */ + /* ------------------------ GL_NV_depth_buffer_float ----------------------- */ #ifndef GL_NV_depth_buffer_float @@ -10976,6 +11575,19 @@ typedef void (GLAPIENTRY * PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFa #endif /* GL_NV_depth_range_unclamped */ +/* --------------------------- GL_NV_draw_texture -------------------------- */ + +#ifndef GL_NV_draw_texture +#define GL_NV_draw_texture 1 + +typedef void (GLAPIENTRY * PFNGLDRAWTEXTURENVPROC) (GLuint texture, GLuint sampler, GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1, GLfloat z, GLfloat s0, GLfloat t0, GLfloat s1, GLfloat t1); + +#define glDrawTextureNV GLEW_GET_FUN(__glewDrawTextureNV) + +#define GLEW_NV_draw_texture GLEW_GET_VAR(__GLEW_NV_draw_texture) + +#endif /* GL_NV_draw_texture */ + /* ---------------------------- GL_NV_evaluators --------------------------- */ #ifndef GL_NV_evaluators @@ -11009,10 +11621,10 @@ typedef void (GLAPIENTRY * PFNGLDEPTHRANGEDNVPROC) (GLdouble zNear, GLdouble zFa typedef void (GLAPIENTRY * PFNGLEVALMAPSNVPROC) (GLenum target, GLenum mode); typedef void (GLAPIENTRY * PFNGLGETMAPATTRIBPARAMETERFVNVPROC) (GLenum target, GLuint index, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETMAPATTRIBPARAMETERIVNVPROC) (GLenum target, GLuint index, GLenum pname, GLint* params); -typedef void (GLAPIENTRY * PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, void* points); +typedef void (GLAPIENTRY * PFNGLGETMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLboolean packed, GLvoid *points); typedef void (GLAPIENTRY * PFNGLGETMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, GLint* params); -typedef void (GLAPIENTRY * PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const void* points); +typedef void (GLAPIENTRY * PFNGLMAPCONTROLPOINTSNVPROC) (GLenum target, GLuint index, GLenum type, GLsizei ustride, GLsizei vstride, GLint uorder, GLint vorder, GLboolean packed, const GLvoid *points); typedef void (GLAPIENTRY * PFNGLMAPPARAMETERFVNVPROC) (GLenum target, GLenum pname, const GLfloat* params); typedef void (GLAPIENTRY * PFNGLMAPPARAMETERIVNVPROC) (GLenum target, GLenum pname, const GLint* params); @@ -11292,6 +11904,15 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMLOCALPARAMETERSI4UIVNVPROC) (GLenum targe #endif /* GL_NV_gpu_program5 */ +/* -------------------- GL_NV_gpu_program5_mem_extended -------------------- */ + +#ifndef GL_NV_gpu_program5_mem_extended +#define GL_NV_gpu_program5_mem_extended 1 + +#define GLEW_NV_gpu_program5_mem_extended GLEW_GET_VAR(__GLEW_NV_gpu_program5_mem_extended) + +#endif /* GL_NV_gpu_program5_mem_extended */ + /* ------------------------- GL_NV_gpu_program_fp64 ------------------------ */ #ifndef GL_NV_gpu_program_fp64 @@ -11533,7 +12154,6 @@ typedef void (GLAPIENTRY * PFNGLVERTEXWEIGHTHVNVPROC) (const GLhalf* weight); #ifndef GL_NV_multisample_coverage #define GL_NV_multisample_coverage 1 -#define GL_COVERAGE_SAMPLES_NV 0x80A9 #define GL_COLOR_SAMPLES_NV 0x8E20 #define GLEW_NV_multisample_coverage GLEW_GET_VAR(__GLEW_NV_multisample_coverage) @@ -11675,8 +12295,6 @@ typedef void (GLAPIENTRY * PFNGLPROGRAMBUFFERPARAMETERSFVNVPROC) (GLenum target, #define GL_ARC_TO_NV 0xFE #define GL_RELATIVE_ARC_TO_NV 0xFF #define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 -#define GL_PRIMARY_COLOR_NV 0x852C -#define GL_SECONDARY_COLOR_NV 0x852D #define GL_PRIMARY_COLOR 0x8577 #define GL_PATH_FORMAT_SVG_NV 0x9070 #define GL_PATH_FORMAT_PS_NV 0x9071 @@ -11878,7 +12496,7 @@ typedef void (GLAPIENTRY * PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei n #define GL_READ_PIXEL_DATA_RANGE_POINTER_NV 0x887D typedef void (GLAPIENTRY * PFNGLFLUSHPIXELDATARANGENVPROC) (GLenum target); -typedef void (GLAPIENTRY * PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, void* pointer); +typedef void (GLAPIENTRY * PFNGLPIXELDATARANGENVPROC) (GLenum target, GLsizei length, GLvoid *pointer); #define glFlushPixelDataRangeNV GLEW_GET_FUN(__glewFlushPixelDataRangeNV) #define glPixelDataRangeNV GLEW_GET_FUN(__glewPixelDataRangeNV) @@ -12060,6 +12678,15 @@ typedef void (GLAPIENTRY * PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC) (GLenum stage #endif /* GL_NV_register_combiners2 */ +/* ---------------------- GL_NV_shader_atomic_counters --------------------- */ + +#ifndef GL_NV_shader_atomic_counters +#define GL_NV_shader_atomic_counters 1 + +#define GLEW_NV_shader_atomic_counters GLEW_GET_VAR(__GLEW_NV_shader_atomic_counters) + +#endif /* GL_NV_shader_atomic_counters */ + /* ----------------------- GL_NV_shader_atomic_float ----------------------- */ #ifndef GL_NV_shader_atomic_float @@ -12110,6 +12737,15 @@ typedef void (GLAPIENTRY * PFNGLUNIFORMUI64VNVPROC) (GLint location, GLsizei cou #endif /* GL_NV_shader_buffer_load */ +/* ------------------- GL_NV_shader_storage_buffer_object ------------------ */ + +#ifndef GL_NV_shader_storage_buffer_object +#define GL_NV_shader_storage_buffer_object 1 + +#define GLEW_NV_shader_storage_buffer_object GLEW_GET_VAR(__GLEW_NV_shader_storage_buffer_object) + +#endif /* GL_NV_shader_storage_buffer_object */ + /* ---------------------- GL_NV_tessellation_program5 ---------------------- */ #ifndef GL_NV_tessellation_program5 @@ -12525,7 +13161,7 @@ typedef void (GLAPIENTRY * PFNGLVDPAUUNREGISTERSURFACENVPROC) (GLvdpauSurfaceNV #define GL_VERTEX_ARRAY_RANGE_POINTER_NV 0x8521 typedef void (GLAPIENTRY * PFNGLFLUSHVERTEXARRAYRANGENVPROC) (void); -typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, void* pointer); +typedef void (GLAPIENTRY * PFNGLVERTEXARRAYRANGENVPROC) (GLsizei length, GLvoid *pointer); #define glFlushVertexArrayRangeNV GLEW_GET_FUN(__glewFlushVertexArrayRangeNV) #define glVertexArrayRangeNV GLEW_GET_FUN(__glewVertexArrayRangeNV) @@ -12797,7 +13433,7 @@ typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4SNVPROC) (GLuint index, GLshort x, typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4SVNVPROC) (GLuint index, const GLshort* v); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UBNVPROC) (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIB4UBVNVPROC) (GLuint index, const GLubyte* v); -typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const void* pointer); +typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBPOINTERNVPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBS1DVNVPROC) (GLuint index, GLsizei n, const GLdouble* v); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBS1FVNVPROC) (GLuint index, GLsizei n, const GLfloat* v); typedef void (GLAPIENTRY * PFNGLVERTEXATTRIBS1SVNVPROC) (GLuint index, GLsizei n, const GLshort* v); @@ -13003,8 +13639,6 @@ typedef void (GLAPIENTRY * PFNGLVIDEOCAPTURESTREAMPARAMETERIVNVPROC) (GLuint vid #ifndef GL_OES_byte_coordinates #define GL_OES_byte_coordinates 1 -#define GL_BYTE 0x1400 - #define GLEW_OES_byte_coordinates GLEW_GET_VAR(__GLEW_OES_byte_coordinates) #endif /* GL_OES_byte_coordinates */ @@ -13166,6 +13800,138 @@ typedef void (GLAPIENTRY * PFNGLORTHOFOESPROC) (GLfloat l, GLfloat r, GLfloat b, #endif /* GL_PGI_vertex_hints */ +/* ---------------------- GL_REGAL_ES1_0_compatibility --------------------- */ + +#ifndef GL_REGAL_ES1_0_compatibility +#define GL_REGAL_ES1_0_compatibility 1 + +typedef int GLclampx; + +typedef void (GLAPIENTRY * PFNGLALPHAFUNCXPROC) (GLenum func, GLclampx ref); +typedef void (GLAPIENTRY * PFNGLCLEARCOLORXPROC) (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha); +typedef void (GLAPIENTRY * PFNGLCLEARDEPTHXPROC) (GLclampx depth); +typedef void (GLAPIENTRY * PFNGLCOLOR4XPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha); +typedef void (GLAPIENTRY * PFNGLDEPTHRANGEXPROC) (GLclampx zNear, GLclampx zFar); +typedef void (GLAPIENTRY * PFNGLFOGXPROC) (GLenum pname, GLfixed param); +typedef void (GLAPIENTRY * PFNGLFOGXVPROC) (GLenum pname, const GLfixed* params); +typedef void (GLAPIENTRY * PFNGLFRUSTUMFPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); +typedef void (GLAPIENTRY * PFNGLFRUSTUMXPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); +typedef void (GLAPIENTRY * PFNGLLIGHTMODELXPROC) (GLenum pname, GLfixed param); +typedef void (GLAPIENTRY * PFNGLLIGHTMODELXVPROC) (GLenum pname, const GLfixed* params); +typedef void (GLAPIENTRY * PFNGLLIGHTXPROC) (GLenum light, GLenum pname, GLfixed param); +typedef void (GLAPIENTRY * PFNGLLIGHTXVPROC) (GLenum light, GLenum pname, const GLfixed* params); +typedef void (GLAPIENTRY * PFNGLLINEWIDTHXPROC) (GLfixed width); +typedef void (GLAPIENTRY * PFNGLLOADMATRIXXPROC) (const GLfixed* m); +typedef void (GLAPIENTRY * PFNGLMATERIALXPROC) (GLenum face, GLenum pname, GLfixed param); +typedef void (GLAPIENTRY * PFNGLMATERIALXVPROC) (GLenum face, GLenum pname, const GLfixed* params); +typedef void (GLAPIENTRY * PFNGLMULTMATRIXXPROC) (const GLfixed* m); +typedef void (GLAPIENTRY * PFNGLMULTITEXCOORD4XPROC) (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q); +typedef void (GLAPIENTRY * PFNGLNORMAL3XPROC) (GLfixed nx, GLfixed ny, GLfixed nz); +typedef void (GLAPIENTRY * PFNGLORTHOFPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar); +typedef void (GLAPIENTRY * PFNGLORTHOXPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar); +typedef void (GLAPIENTRY * PFNGLPOINTSIZEXPROC) (GLfixed size); +typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETXPROC) (GLfixed factor, GLfixed units); +typedef void (GLAPIENTRY * PFNGLROTATEXPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z); +typedef void (GLAPIENTRY * PFNGLSAMPLECOVERAGEXPROC) (GLclampx value, GLboolean invert); +typedef void (GLAPIENTRY * PFNGLSCALEXPROC) (GLfixed x, GLfixed y, GLfixed z); +typedef void (GLAPIENTRY * PFNGLTEXENVXPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (GLAPIENTRY * PFNGLTEXENVXVPROC) (GLenum target, GLenum pname, const GLfixed* params); +typedef void (GLAPIENTRY * PFNGLTEXPARAMETERXPROC) (GLenum target, GLenum pname, GLfixed param); +typedef void (GLAPIENTRY * PFNGLTRANSLATEXPROC) (GLfixed x, GLfixed y, GLfixed z); + +#define glAlphaFuncx GLEW_GET_FUN(__glewAlphaFuncx) +#define glClearColorx GLEW_GET_FUN(__glewClearColorx) +#define glClearDepthx GLEW_GET_FUN(__glewClearDepthx) +#define glColor4x GLEW_GET_FUN(__glewColor4x) +#define glDepthRangex GLEW_GET_FUN(__glewDepthRangex) +#define glFogx GLEW_GET_FUN(__glewFogx) +#define glFogxv GLEW_GET_FUN(__glewFogxv) +#define glFrustumf GLEW_GET_FUN(__glewFrustumf) +#define glFrustumx GLEW_GET_FUN(__glewFrustumx) +#define glLightModelx GLEW_GET_FUN(__glewLightModelx) +#define glLightModelxv GLEW_GET_FUN(__glewLightModelxv) +#define glLightx GLEW_GET_FUN(__glewLightx) +#define glLightxv GLEW_GET_FUN(__glewLightxv) +#define glLineWidthx GLEW_GET_FUN(__glewLineWidthx) +#define glLoadMatrixx GLEW_GET_FUN(__glewLoadMatrixx) +#define glMaterialx GLEW_GET_FUN(__glewMaterialx) +#define glMaterialxv GLEW_GET_FUN(__glewMaterialxv) +#define glMultMatrixx GLEW_GET_FUN(__glewMultMatrixx) +#define glMultiTexCoord4x GLEW_GET_FUN(__glewMultiTexCoord4x) +#define glNormal3x GLEW_GET_FUN(__glewNormal3x) +#define glOrthof GLEW_GET_FUN(__glewOrthof) +#define glOrthox GLEW_GET_FUN(__glewOrthox) +#define glPointSizex GLEW_GET_FUN(__glewPointSizex) +#define glPolygonOffsetx GLEW_GET_FUN(__glewPolygonOffsetx) +#define glRotatex GLEW_GET_FUN(__glewRotatex) +#define glSampleCoveragex GLEW_GET_FUN(__glewSampleCoveragex) +#define glScalex GLEW_GET_FUN(__glewScalex) +#define glTexEnvx GLEW_GET_FUN(__glewTexEnvx) +#define glTexEnvxv GLEW_GET_FUN(__glewTexEnvxv) +#define glTexParameterx GLEW_GET_FUN(__glewTexParameterx) +#define glTranslatex GLEW_GET_FUN(__glewTranslatex) + +#define GLEW_REGAL_ES1_0_compatibility GLEW_GET_VAR(__GLEW_REGAL_ES1_0_compatibility) + +#endif /* GL_REGAL_ES1_0_compatibility */ + +/* ---------------------- GL_REGAL_ES1_1_compatibility --------------------- */ + +#ifndef GL_REGAL_ES1_1_compatibility +#define GL_REGAL_ES1_1_compatibility 1 + +typedef void (GLAPIENTRY * PFNGLCLIPPLANEFPROC) (GLenum plane, const GLfloat* equation); +typedef void (GLAPIENTRY * PFNGLCLIPPLANEXPROC) (GLenum plane, const GLfixed* equation); +typedef void (GLAPIENTRY * PFNGLGETCLIPPLANEFPROC) (GLenum pname, GLfloat eqn[4]); +typedef void (GLAPIENTRY * PFNGLGETCLIPPLANEXPROC) (GLenum pname, GLfixed eqn[4]); +typedef void (GLAPIENTRY * PFNGLGETFIXEDVPROC) (GLenum pname, GLfixed* params); +typedef void (GLAPIENTRY * PFNGLGETLIGHTXVPROC) (GLenum light, GLenum pname, GLfixed* params); +typedef void (GLAPIENTRY * PFNGLGETMATERIALXVPROC) (GLenum face, GLenum pname, GLfixed* params); +typedef void (GLAPIENTRY * PFNGLGETTEXENVXVPROC) (GLenum env, GLenum pname, GLfixed* params); +typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERXVPROC) (GLenum target, GLenum pname, GLfixed* params); +typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERXPROC) (GLenum pname, GLfixed param); +typedef void (GLAPIENTRY * PFNGLPOINTPARAMETERXVPROC) (GLenum pname, const GLfixed* params); +typedef void (GLAPIENTRY * PFNGLPOINTSIZEPOINTEROESPROC) (GLenum type, GLsizei stride, const GLvoid* pointer); +typedef void (GLAPIENTRY * PFNGLTEXPARAMETERXVPROC) (GLenum target, GLenum pname, const GLfixed* params); + +#define glClipPlanef GLEW_GET_FUN(__glewClipPlanef) +#define glClipPlanex GLEW_GET_FUN(__glewClipPlanex) +#define glGetClipPlanef GLEW_GET_FUN(__glewGetClipPlanef) +#define glGetClipPlanex GLEW_GET_FUN(__glewGetClipPlanex) +#define glGetFixedv GLEW_GET_FUN(__glewGetFixedv) +#define glGetLightxv GLEW_GET_FUN(__glewGetLightxv) +#define glGetMaterialxv GLEW_GET_FUN(__glewGetMaterialxv) +#define glGetTexEnvxv GLEW_GET_FUN(__glewGetTexEnvxv) +#define glGetTexParameterxv GLEW_GET_FUN(__glewGetTexParameterxv) +#define glPointParameterx GLEW_GET_FUN(__glewPointParameterx) +#define glPointParameterxv GLEW_GET_FUN(__glewPointParameterxv) +#define glPointSizePointerOES GLEW_GET_FUN(__glewPointSizePointerOES) +#define glTexParameterxv GLEW_GET_FUN(__glewTexParameterxv) + +#define GLEW_REGAL_ES1_1_compatibility GLEW_GET_VAR(__GLEW_REGAL_ES1_1_compatibility) + +#endif /* GL_REGAL_ES1_1_compatibility */ + +/* ---------------------------- GL_REGAL_enable ---------------------------- */ + +#ifndef GL_REGAL_enable +#define GL_REGAL_enable 1 + +#define GL_ERROR_REGAL 0x9322 +#define GL_DEBUG_REGAL 0x9323 +#define GL_LOG_REGAL 0x9324 +#define GL_EMULATION_REGAL 0x9325 +#define GL_DRIVER_REGAL 0x9326 +#define GL_MISSING_REGAL 0x9360 +#define GL_TRACE_REGAL 0x9361 +#define GL_CACHE_REGAL 0x9362 +#define GL_CODE_REGAL 0x9363 +#define GL_STATISTICS_REGAL 0x9364 + +#define GLEW_REGAL_enable GLEW_GET_VAR(__GLEW_REGAL_enable) + +#endif /* GL_REGAL_enable */ + /* ------------------------- GL_REGAL_error_string ------------------------- */ #ifndef GL_REGAL_error_string @@ -13209,6 +13975,12 @@ typedef GLboolean (GLAPIENTRY * PFNGLISSUPPORTEDREGALPROC) (const GLchar* ext); #define GL_LOG_STATUS_REGAL 0x9320 #define GL_LOG_HTTP_REGAL 0x9321 +typedef void (APIENTRY *GLLOGPROCREGAL)(GLenum stream, GLsizei length, const GLchar *message, GLvoid *context); + +typedef void (GLAPIENTRY * PFNGLLOGMESSAGECALLBACKREGALPROC) (GLLOGPROCREGAL callback); + +#define glLogMessageCallbackREGAL GLEW_GET_FUN(__glewLogMessageCallbackREGAL) + #define GLEW_REGAL_log GLEW_GET_VAR(__GLEW_REGAL_log) #endif /* GL_REGAL_log */ @@ -13381,8 +14153,8 @@ typedef void (GLAPIENTRY * PFNGLSHARPENTEXFUNCSGISPROC) (GLenum target, GLsizei #ifndef GL_SGIS_texture4D #define GL_SGIS_texture4D 1 -typedef void (GLAPIENTRY * PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLint border, GLenum format, GLenum type, const void* pixels); -typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLenum format, GLenum type, const void* pixels); +typedef void (GLAPIENTRY * PFNGLTEXIMAGE4DSGISPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE4DSGISPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint woffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei extent, GLenum format, GLenum type, const GLvoid *pixels); #define glTexImage4DSGIS GLEW_GET_FUN(__glewTexImage4DSGIS) #define glTexSubImage4DSGIS GLEW_GET_FUN(__glewTexSubImage4DSGIS) @@ -13957,11 +14729,11 @@ typedef void (GLAPIENTRY * PFNGLTAGSAMPLEBUFFERSGIXPROC) (void); typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, const GLfloat* params); typedef void (GLAPIENTRY * PFNGLCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, const GLint* params); -typedef void (GLAPIENTRY * PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const void* table); +typedef void (GLAPIENTRY * PFNGLCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, const GLvoid *table); typedef void (GLAPIENTRY * PFNGLCOPYCOLORTABLESGIPROC) (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width); typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERFVSGIPROC) (GLenum target, GLenum pname, GLfloat* params); typedef void (GLAPIENTRY * PFNGLGETCOLORTABLEPARAMETERIVSGIPROC) (GLenum target, GLenum pname, GLint* params); -typedef void (GLAPIENTRY * PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, void* table); +typedef void (GLAPIENTRY * PFNGLGETCOLORTABLESGIPROC) (GLenum target, GLenum format, GLenum type, GLvoid *table); #define glColorTableParameterfvSGI GLEW_GET_FUN(__glewColorTableParameterfvSGI) #define glColorTableParameterivSGI GLEW_GET_FUN(__glewColorTableParameterivSGI) @@ -14103,7 +14875,7 @@ typedef void (GLAPIENTRY * PFNGLREADVIDEOPIXELSSUNPROC) (GLint x, GLint y, GLsiz #define GL_R1UI_T2F_N3F_V3F_SUN 0x85CA #define GL_R1UI_T2F_C4F_N3F_V3F_SUN 0x85CB -typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const void* pointer); +typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEPOINTERSUNPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEUBSUNPROC) (GLubyte code); typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEUBVSUNPROC) (const GLubyte* code); typedef void (GLAPIENTRY * PFNGLREPLACEMENTCODEUISUNPROC) (GLuint code); @@ -14575,6 +15347,8 @@ GLEW_FUN_EXPORT PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC __glewBlendEquationSepa GLEW_FUN_EXPORT PFNGLBLENDFUNCINDEXEDAMDPROC __glewBlendFuncIndexedAMD; GLEW_FUN_EXPORT PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC __glewBlendFuncSeparateIndexedAMD; +GLEW_FUN_EXPORT PFNGLVERTEXATTRIBPARAMETERIAMDPROC __glewVertexAttribParameteriAMD; + GLEW_FUN_EXPORT PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC __glewMultiDrawArraysIndirectAMD; GLEW_FUN_EXPORT PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC __glewMultiDrawElementsIndirectAMD; @@ -14596,11 +15370,36 @@ GLEW_FUN_EXPORT PFNGLSELECTPERFMONITORCOUNTERSAMDPROC __glewSelectPerfMonitorCou GLEW_FUN_EXPORT PFNGLSETMULTISAMPLEFVAMDPROC __glewSetMultisamplefvAMD; +GLEW_FUN_EXPORT PFNGLTEXSTORAGESPARSEAMDPROC __glewTexStorageSparseAMD; +GLEW_FUN_EXPORT PFNGLTEXTURESTORAGESPARSEAMDPROC __glewTextureStorageSparseAMD; + GLEW_FUN_EXPORT PFNGLSTENCILOPVALUEAMDPROC __glewStencilOpValueAMD; GLEW_FUN_EXPORT PFNGLTESSELLATIONFACTORAMDPROC __glewTessellationFactorAMD; GLEW_FUN_EXPORT PFNGLTESSELLATIONMODEAMDPROC __glewTessellationModeAMD; +GLEW_FUN_EXPORT PFNGLBLITFRAMEBUFFERANGLEPROC __glewBlitFramebufferANGLE; + +GLEW_FUN_EXPORT PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC __glewRenderbufferStorageMultisampleANGLE; + +GLEW_FUN_EXPORT PFNGLDRAWARRAYSINSTANCEDANGLEPROC __glewDrawArraysInstancedANGLE; +GLEW_FUN_EXPORT PFNGLDRAWELEMENTSINSTANCEDANGLEPROC __glewDrawElementsInstancedANGLE; +GLEW_FUN_EXPORT PFNGLVERTEXATTRIBDIVISORANGLEPROC __glewVertexAttribDivisorANGLE; + +GLEW_FUN_EXPORT PFNGLBEGINQUERYANGLEPROC __glewBeginQueryANGLE; +GLEW_FUN_EXPORT PFNGLDELETEQUERIESANGLEPROC __glewDeleteQueriesANGLE; +GLEW_FUN_EXPORT PFNGLENDQUERYANGLEPROC __glewEndQueryANGLE; +GLEW_FUN_EXPORT PFNGLGENQUERIESANGLEPROC __glewGenQueriesANGLE; +GLEW_FUN_EXPORT PFNGLGETQUERYOBJECTI64VANGLEPROC __glewGetQueryObjecti64vANGLE; +GLEW_FUN_EXPORT PFNGLGETQUERYOBJECTIVANGLEPROC __glewGetQueryObjectivANGLE; +GLEW_FUN_EXPORT PFNGLGETQUERYOBJECTUI64VANGLEPROC __glewGetQueryObjectui64vANGLE; +GLEW_FUN_EXPORT PFNGLGETQUERYOBJECTUIVANGLEPROC __glewGetQueryObjectuivANGLE; +GLEW_FUN_EXPORT PFNGLGETQUERYIVANGLEPROC __glewGetQueryivANGLE; +GLEW_FUN_EXPORT PFNGLISQUERYANGLEPROC __glewIsQueryANGLE; +GLEW_FUN_EXPORT PFNGLQUERYCOUNTERANGLEPROC __glewQueryCounterANGLE; + +GLEW_FUN_EXPORT PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC __glewGetTranslatedShaderSourceANGLE; + GLEW_FUN_EXPORT PFNGLDRAWELEMENTARRAYAPPLEPROC __glewDrawElementArrayAPPLE; GLEW_FUN_EXPORT PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC __glewDrawRangeElementArrayAPPLE; GLEW_FUN_EXPORT PFNGLELEMENTPOINTERAPPLEPROC __glewElementPointerAPPLE; @@ -14653,9 +15452,29 @@ GLEW_FUN_EXPORT PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __glewDrawArraysInstanc GLEW_FUN_EXPORT PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __glewDrawElementsInstancedBaseInstance; GLEW_FUN_EXPORT PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __glewDrawElementsInstancedBaseVertexBaseInstance; +GLEW_FUN_EXPORT PFNGLGETIMAGEHANDLEARBPROC __glewGetImageHandleARB; +GLEW_FUN_EXPORT PFNGLGETTEXTUREHANDLEARBPROC __glewGetTextureHandleARB; +GLEW_FUN_EXPORT PFNGLGETTEXTURESAMPLERHANDLEARBPROC __glewGetTextureSamplerHandleARB; +GLEW_FUN_EXPORT PFNGLGETVERTEXATTRIBLUI64VARBPROC __glewGetVertexAttribLui64vARB; +GLEW_FUN_EXPORT PFNGLISIMAGEHANDLERESIDENTARBPROC __glewIsImageHandleResidentARB; +GLEW_FUN_EXPORT PFNGLISTEXTUREHANDLERESIDENTARBPROC __glewIsTextureHandleResidentARB; +GLEW_FUN_EXPORT PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC __glewMakeImageHandleNonResidentARB; +GLEW_FUN_EXPORT PFNGLMAKEIMAGEHANDLERESIDENTARBPROC __glewMakeImageHandleResidentARB; +GLEW_FUN_EXPORT PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC __glewMakeTextureHandleNonResidentARB; +GLEW_FUN_EXPORT PFNGLMAKETEXTUREHANDLERESIDENTARBPROC __glewMakeTextureHandleResidentARB; +GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC __glewProgramUniformHandleui64ARB; +GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC __glewProgramUniformHandleui64vARB; +GLEW_FUN_EXPORT PFNGLUNIFORMHANDLEUI64ARBPROC __glewUniformHandleui64ARB; +GLEW_FUN_EXPORT PFNGLUNIFORMHANDLEUI64VARBPROC __glewUniformHandleui64vARB; +GLEW_FUN_EXPORT PFNGLVERTEXATTRIBL1UI64ARBPROC __glewVertexAttribL1ui64ARB; +GLEW_FUN_EXPORT PFNGLVERTEXATTRIBL1UI64VARBPROC __glewVertexAttribL1ui64vARB; + GLEW_FUN_EXPORT PFNGLBINDFRAGDATALOCATIONINDEXEDPROC __glewBindFragDataLocationIndexed; GLEW_FUN_EXPORT PFNGLGETFRAGDATAINDEXPROC __glewGetFragDataIndex; +GLEW_FUN_EXPORT PFNGLBUFFERSTORAGEPROC __glewBufferStorage; +GLEW_FUN_EXPORT PFNGLNAMEDBUFFERSTORAGEEXTPROC __glewNamedBufferStorageEXT; + GLEW_FUN_EXPORT PFNGLCREATESYNCFROMCLEVENTARBPROC __glewCreateSyncFromCLeventARB; GLEW_FUN_EXPORT PFNGLCLEARBUFFERDATAPROC __glewClearBufferData; @@ -14663,11 +15482,16 @@ GLEW_FUN_EXPORT PFNGLCLEARBUFFERSUBDATAPROC __glewClearBufferSubData; GLEW_FUN_EXPORT PFNGLCLEARNAMEDBUFFERDATAEXTPROC __glewClearNamedBufferDataEXT; GLEW_FUN_EXPORT PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC __glewClearNamedBufferSubDataEXT; +GLEW_FUN_EXPORT PFNGLCLEARTEXIMAGEPROC __glewClearTexImage; +GLEW_FUN_EXPORT PFNGLCLEARTEXSUBIMAGEPROC __glewClearTexSubImage; + GLEW_FUN_EXPORT PFNGLCLAMPCOLORARBPROC __glewClampColorARB; GLEW_FUN_EXPORT PFNGLDISPATCHCOMPUTEPROC __glewDispatchCompute; GLEW_FUN_EXPORT PFNGLDISPATCHCOMPUTEINDIRECTPROC __glewDispatchComputeIndirect; +GLEW_FUN_EXPORT PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC __glewDispatchComputeGroupSizeARB; + GLEW_FUN_EXPORT PFNGLCOPYBUFFERSUBDATAPROC __glewCopyBufferSubData; GLEW_FUN_EXPORT PFNGLCOPYIMAGESUBDATAPROC __glewCopyImageSubData; @@ -14779,6 +15603,9 @@ GLEW_FUN_EXPORT PFNGLRESETHISTOGRAMPROC __glewResetHistogram; GLEW_FUN_EXPORT PFNGLRESETMINMAXPROC __glewResetMinmax; GLEW_FUN_EXPORT PFNGLSEPARABLEFILTER2DPROC __glewSeparableFilter2D; +GLEW_FUN_EXPORT PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __glewMultiDrawArraysIndirectCountARB; +GLEW_FUN_EXPORT PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __glewMultiDrawElementsIndirectCountARB; + GLEW_FUN_EXPORT PFNGLDRAWARRAYSINSTANCEDARBPROC __glewDrawArraysInstancedARB; GLEW_FUN_EXPORT PFNGLDRAWELEMENTSINSTANCEDARBPROC __glewDrawElementsInstancedARB; GLEW_FUN_EXPORT PFNGLVERTEXATTRIBDIVISORARBPROC __glewVertexAttribDivisorARB; @@ -14803,6 +15630,13 @@ GLEW_FUN_EXPORT PFNGLMATRIXINDEXUBVARBPROC __glewMatrixIndexubvARB; GLEW_FUN_EXPORT PFNGLMATRIXINDEXUIVARBPROC __glewMatrixIndexuivARB; GLEW_FUN_EXPORT PFNGLMATRIXINDEXUSVARBPROC __glewMatrixIndexusvARB; +GLEW_FUN_EXPORT PFNGLBINDBUFFERSBASEPROC __glewBindBuffersBase; +GLEW_FUN_EXPORT PFNGLBINDBUFFERSRANGEPROC __glewBindBuffersRange; +GLEW_FUN_EXPORT PFNGLBINDIMAGETEXTURESPROC __glewBindImageTextures; +GLEW_FUN_EXPORT PFNGLBINDSAMPLERSPROC __glewBindSamplers; +GLEW_FUN_EXPORT PFNGLBINDTEXTURESPROC __glewBindTextures; +GLEW_FUN_EXPORT PFNGLBINDVERTEXBUFFERSPROC __glewBindVertexBuffers; + GLEW_FUN_EXPORT PFNGLMULTIDRAWARRAYSINDIRECTPROC __glewMultiDrawArraysIndirect; GLEW_FUN_EXPORT PFNGLMULTIDRAWELEMENTSINDIRECTPROC __glewMultiDrawElementsIndirect; @@ -15026,6 +15860,9 @@ GLEW_FUN_EXPORT PFNGLGETNAMEDSTRINGIVARBPROC __glewGetNamedStringivARB; GLEW_FUN_EXPORT PFNGLISNAMEDSTRINGARBPROC __glewIsNamedStringARB; GLEW_FUN_EXPORT PFNGLNAMEDSTRINGARBPROC __glewNamedStringARB; +GLEW_FUN_EXPORT PFNGLTEXPAGECOMMITMENTARBPROC __glewTexPageCommitmentARB; +GLEW_FUN_EXPORT PFNGLTEXTUREPAGECOMMITMENTEXTPROC __glewTexturePageCommitmentEXT; + GLEW_FUN_EXPORT PFNGLCLIENTWAITSYNCPROC __glewClientWaitSync; GLEW_FUN_EXPORT PFNGLDELETESYNCPROC __glewDeleteSync; GLEW_FUN_EXPORT PFNGLFENCESYNCPROC __glewFenceSync; @@ -15586,55 +16423,38 @@ GLEW_FUN_EXPORT PFNGLNAMEDPROGRAMSTRINGEXTPROC __glewNamedProgramStringEXT; GLEW_FUN_EXPORT PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC __glewNamedRenderbufferStorageEXT; GLEW_FUN_EXPORT PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC __glewNamedRenderbufferStorageMultisampleCoverageEXT; GLEW_FUN_EXPORT PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __glewNamedRenderbufferStorageMultisampleEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1DEXTPROC __glewProgramUniform1dEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1DVEXTPROC __glewProgramUniform1dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1FEXTPROC __glewProgramUniform1fEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1FVEXTPROC __glewProgramUniform1fvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1IEXTPROC __glewProgramUniform1iEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1IVEXTPROC __glewProgramUniform1ivEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1UIEXTPROC __glewProgramUniform1uiEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM1UIVEXTPROC __glewProgramUniform1uivEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2DEXTPROC __glewProgramUniform2dEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2DVEXTPROC __glewProgramUniform2dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2FEXTPROC __glewProgramUniform2fEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2FVEXTPROC __glewProgramUniform2fvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2IEXTPROC __glewProgramUniform2iEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2IVEXTPROC __glewProgramUniform2ivEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2UIEXTPROC __glewProgramUniform2uiEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM2UIVEXTPROC __glewProgramUniform2uivEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3DEXTPROC __glewProgramUniform3dEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3DVEXTPROC __glewProgramUniform3dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3FEXTPROC __glewProgramUniform3fEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3FVEXTPROC __glewProgramUniform3fvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3IEXTPROC __glewProgramUniform3iEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3IVEXTPROC __glewProgramUniform3ivEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3UIEXTPROC __glewProgramUniform3uiEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM3UIVEXTPROC __glewProgramUniform3uivEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4DEXTPROC __glewProgramUniform4dEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4DVEXTPROC __glewProgramUniform4dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4FEXTPROC __glewProgramUniform4fEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4FVEXTPROC __glewProgramUniform4fvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4IEXTPROC __glewProgramUniform4iEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4IVEXTPROC __glewProgramUniform4ivEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4UIEXTPROC __glewProgramUniform4uiEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORM4UIVEXTPROC __glewProgramUniform4uivEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC __glewProgramUniformMatrix2dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC __glewProgramUniformMatrix2fvEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC __glewProgramUniformMatrix2x3dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __glewProgramUniformMatrix2x3fvEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC __glewProgramUniformMatrix2x4dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __glewProgramUniformMatrix2x4fvEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC __glewProgramUniformMatrix3dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC __glewProgramUniformMatrix3fvEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC __glewProgramUniformMatrix3x2dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __glewProgramUniformMatrix3x2fvEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC __glewProgramUniformMatrix3x4dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __glewProgramUniformMatrix3x4fvEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC __glewProgramUniformMatrix4dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC __glewProgramUniformMatrix4fvEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC __glewProgramUniformMatrix4x2dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __glewProgramUniformMatrix4x2fvEXT; -GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC __glewProgramUniformMatrix4x3dvEXT; GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __glewProgramUniformMatrix4x3fvEXT; GLEW_FUN_EXPORT PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC __glewPushClientAttribDefaultEXT; GLEW_FUN_EXPORT PFNGLTEXTUREBUFFEREXTPROC __glewTextureBufferEXT; @@ -15969,6 +16789,10 @@ GLEW_FUN_EXPORT PFNGLSECONDARYCOLORPOINTERLISTIBMPROC __glewSecondaryColorPointe GLEW_FUN_EXPORT PFNGLTEXCOORDPOINTERLISTIBMPROC __glewTexCoordPointerListIBM; GLEW_FUN_EXPORT PFNGLVERTEXPOINTERLISTIBMPROC __glewVertexPointerListIBM; +GLEW_FUN_EXPORT PFNGLMAPTEXTURE2DINTELPROC __glewMapTexture2DINTEL; +GLEW_FUN_EXPORT PFNGLSYNCTEXTUREINTELPROC __glewSyncTextureINTEL; +GLEW_FUN_EXPORT PFNGLUNMAPTEXTURE2DINTELPROC __glewUnmapTexture2DINTEL; + GLEW_FUN_EXPORT PFNGLCOLORPOINTERVINTELPROC __glewColorPointervINTEL; GLEW_FUN_EXPORT PFNGLNORMALPOINTERVINTELPROC __glewNormalPointervINTEL; GLEW_FUN_EXPORT PFNGLTEXCOORDPOINTERVINTELPROC __glewTexCoordPointervINTEL; @@ -15983,9 +16807,9 @@ GLEW_FUN_EXPORT PFNGLDEBUGMESSAGEINSERTPROC __glewDebugMessageInsert; GLEW_FUN_EXPORT PFNGLGETDEBUGMESSAGELOGPROC __glewGetDebugMessageLog; GLEW_FUN_EXPORT PFNGLGETOBJECTLABELPROC __glewGetObjectLabel; GLEW_FUN_EXPORT PFNGLGETOBJECTPTRLABELPROC __glewGetObjectPtrLabel; -GLEW_FUN_EXPORT PFNGLGETPOINTERVPROC __glewGetPointerv; GLEW_FUN_EXPORT PFNGLOBJECTLABELPROC __glewObjectLabel; GLEW_FUN_EXPORT PFNGLOBJECTPTRLABELPROC __glewObjectPtrLabel; +GLEW_FUN_EXPORT PFNGLPOPDEBUGGROUPPROC __glewPopDebugGroup; GLEW_FUN_EXPORT PFNGLPUSHDEBUGGROUPPROC __glewPushDebugGroup; GLEW_FUN_EXPORT PFNGLBUFFERREGIONENABLEDPROC __glewBufferRegionEnabled; @@ -16021,6 +16845,12 @@ GLEW_FUN_EXPORT PFNGLWINDOWPOS4IVMESAPROC __glewWindowPos4ivMESA; GLEW_FUN_EXPORT PFNGLWINDOWPOS4SMESAPROC __glewWindowPos4sMESA; GLEW_FUN_EXPORT PFNGLWINDOWPOS4SVMESAPROC __glewWindowPos4svMESA; +GLEW_FUN_EXPORT PFNGLBEGINCONDITIONALRENDERNVXPROC __glewBeginConditionalRenderNVX; +GLEW_FUN_EXPORT PFNGLENDCONDITIONALRENDERNVXPROC __glewEndConditionalRenderNVX; + +GLEW_FUN_EXPORT PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC __glewMultiDrawArraysIndirectBindlessNV; +GLEW_FUN_EXPORT PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC __glewMultiDrawElementsIndirectBindlessNV; + GLEW_FUN_EXPORT PFNGLGETIMAGEHANDLENVPROC __glewGetImageHandleNV; GLEW_FUN_EXPORT PFNGLGETTEXTUREHANDLENVPROC __glewGetTextureHandleNV; GLEW_FUN_EXPORT PFNGLGETTEXTURESAMPLERHANDLENVPROC __glewGetTextureSamplerHandleNV; @@ -16035,6 +16865,9 @@ GLEW_FUN_EXPORT PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC __glewProgramUniformHandleu GLEW_FUN_EXPORT PFNGLUNIFORMHANDLEUI64NVPROC __glewUniformHandleui64NV; GLEW_FUN_EXPORT PFNGLUNIFORMHANDLEUI64VNVPROC __glewUniformHandleui64vNV; +GLEW_FUN_EXPORT PFNGLBLENDBARRIERNVPROC __glewBlendBarrierNV; +GLEW_FUN_EXPORT PFNGLBLENDPARAMETERINVPROC __glewBlendParameteriNV; + GLEW_FUN_EXPORT PFNGLBEGINCONDITIONALRENDERNVPROC __glewBeginConditionalRenderNV; GLEW_FUN_EXPORT PFNGLENDCONDITIONALRENDERNVPROC __glewEndConditionalRenderNV; @@ -16044,6 +16877,8 @@ GLEW_FUN_EXPORT PFNGLCLEARDEPTHDNVPROC __glewClearDepthdNV; GLEW_FUN_EXPORT PFNGLDEPTHBOUNDSDNVPROC __glewDepthBoundsdNV; GLEW_FUN_EXPORT PFNGLDEPTHRANGEDNVPROC __glewDepthRangedNV; +GLEW_FUN_EXPORT PFNGLDRAWTEXTURENVPROC __glewDrawTextureNV; + GLEW_FUN_EXPORT PFNGLEVALMAPSNVPROC __glewEvalMapsNV; GLEW_FUN_EXPORT PFNGLGETMAPATTRIBPARAMETERFVNVPROC __glewGetMapAttribParameterfvNV; GLEW_FUN_EXPORT PFNGLGETMAPATTRIBPARAMETERIVNVPROC __glewGetMapAttribParameterivNV; @@ -16442,11 +17277,59 @@ GLEW_FUN_EXPORT PFNGLFRUSTUMFOESPROC __glewFrustumfOES; GLEW_FUN_EXPORT PFNGLGETCLIPPLANEFOESPROC __glewGetClipPlanefOES; GLEW_FUN_EXPORT PFNGLORTHOFOESPROC __glewOrthofOES; +GLEW_FUN_EXPORT PFNGLALPHAFUNCXPROC __glewAlphaFuncx; +GLEW_FUN_EXPORT PFNGLCLEARCOLORXPROC __glewClearColorx; +GLEW_FUN_EXPORT PFNGLCLEARDEPTHXPROC __glewClearDepthx; +GLEW_FUN_EXPORT PFNGLCOLOR4XPROC __glewColor4x; +GLEW_FUN_EXPORT PFNGLDEPTHRANGEXPROC __glewDepthRangex; +GLEW_FUN_EXPORT PFNGLFOGXPROC __glewFogx; +GLEW_FUN_EXPORT PFNGLFOGXVPROC __glewFogxv; +GLEW_FUN_EXPORT PFNGLFRUSTUMFPROC __glewFrustumf; +GLEW_FUN_EXPORT PFNGLFRUSTUMXPROC __glewFrustumx; +GLEW_FUN_EXPORT PFNGLLIGHTMODELXPROC __glewLightModelx; +GLEW_FUN_EXPORT PFNGLLIGHTMODELXVPROC __glewLightModelxv; +GLEW_FUN_EXPORT PFNGLLIGHTXPROC __glewLightx; +GLEW_FUN_EXPORT PFNGLLIGHTXVPROC __glewLightxv; +GLEW_FUN_EXPORT PFNGLLINEWIDTHXPROC __glewLineWidthx; +GLEW_FUN_EXPORT PFNGLLOADMATRIXXPROC __glewLoadMatrixx; +GLEW_FUN_EXPORT PFNGLMATERIALXPROC __glewMaterialx; +GLEW_FUN_EXPORT PFNGLMATERIALXVPROC __glewMaterialxv; +GLEW_FUN_EXPORT PFNGLMULTMATRIXXPROC __glewMultMatrixx; +GLEW_FUN_EXPORT PFNGLMULTITEXCOORD4XPROC __glewMultiTexCoord4x; +GLEW_FUN_EXPORT PFNGLNORMAL3XPROC __glewNormal3x; +GLEW_FUN_EXPORT PFNGLORTHOFPROC __glewOrthof; +GLEW_FUN_EXPORT PFNGLORTHOXPROC __glewOrthox; +GLEW_FUN_EXPORT PFNGLPOINTSIZEXPROC __glewPointSizex; +GLEW_FUN_EXPORT PFNGLPOLYGONOFFSETXPROC __glewPolygonOffsetx; +GLEW_FUN_EXPORT PFNGLROTATEXPROC __glewRotatex; +GLEW_FUN_EXPORT PFNGLSAMPLECOVERAGEXPROC __glewSampleCoveragex; +GLEW_FUN_EXPORT PFNGLSCALEXPROC __glewScalex; +GLEW_FUN_EXPORT PFNGLTEXENVXPROC __glewTexEnvx; +GLEW_FUN_EXPORT PFNGLTEXENVXVPROC __glewTexEnvxv; +GLEW_FUN_EXPORT PFNGLTEXPARAMETERXPROC __glewTexParameterx; +GLEW_FUN_EXPORT PFNGLTRANSLATEXPROC __glewTranslatex; + +GLEW_FUN_EXPORT PFNGLCLIPPLANEFPROC __glewClipPlanef; +GLEW_FUN_EXPORT PFNGLCLIPPLANEXPROC __glewClipPlanex; +GLEW_FUN_EXPORT PFNGLGETCLIPPLANEFPROC __glewGetClipPlanef; +GLEW_FUN_EXPORT PFNGLGETCLIPPLANEXPROC __glewGetClipPlanex; +GLEW_FUN_EXPORT PFNGLGETFIXEDVPROC __glewGetFixedv; +GLEW_FUN_EXPORT PFNGLGETLIGHTXVPROC __glewGetLightxv; +GLEW_FUN_EXPORT PFNGLGETMATERIALXVPROC __glewGetMaterialxv; +GLEW_FUN_EXPORT PFNGLGETTEXENVXVPROC __glewGetTexEnvxv; +GLEW_FUN_EXPORT PFNGLGETTEXPARAMETERXVPROC __glewGetTexParameterxv; +GLEW_FUN_EXPORT PFNGLPOINTPARAMETERXPROC __glewPointParameterx; +GLEW_FUN_EXPORT PFNGLPOINTPARAMETERXVPROC __glewPointParameterxv; +GLEW_FUN_EXPORT PFNGLPOINTSIZEPOINTEROESPROC __glewPointSizePointerOES; +GLEW_FUN_EXPORT PFNGLTEXPARAMETERXVPROC __glewTexParameterxv; + GLEW_FUN_EXPORT PFNGLERRORSTRINGREGALPROC __glewErrorStringREGAL; GLEW_FUN_EXPORT PFNGLGETEXTENSIONREGALPROC __glewGetExtensionREGAL; GLEW_FUN_EXPORT PFNGLISSUPPORTEDREGALPROC __glewIsSupportedREGAL; +GLEW_FUN_EXPORT PFNGLLOGMESSAGECALLBACKREGALPROC __glewLogMessageCallbackREGAL; + GLEW_FUN_EXPORT PFNGLDETAILTEXFUNCSGISPROC __glewDetailTexFuncSGIS; GLEW_FUN_EXPORT PFNGLGETDETAILTEXFUNCSGISPROC __glewGetDetailTexFuncSGIS; @@ -16600,6 +17483,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_0; GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_1; GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_2; GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_3; +GLEW_VAR_EXPORT GLboolean __GLEW_VERSION_4_4; GLEW_VAR_EXPORT GLboolean __GLEW_3DFX_multisample; GLEW_VAR_EXPORT GLboolean __GLEW_3DFX_tbuffer; GLEW_VAR_EXPORT GLboolean __GLEW_3DFX_texture_compression_FXT1; @@ -16608,6 +17492,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_AMD_conservative_depth; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_debug_output; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_depth_clamp_separate; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_draw_buffers_blend; +GLEW_VAR_EXPORT GLboolean __GLEW_AMD_interleaved_elements; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_multi_draw_indirect; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_name_gen_delete; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_performance_monitor; @@ -16616,12 +17501,26 @@ GLEW_VAR_EXPORT GLboolean __GLEW_AMD_query_buffer_object; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_sample_positions; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_seamless_cubemap_per_texture; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_shader_stencil_export; +GLEW_VAR_EXPORT GLboolean __GLEW_AMD_shader_trinary_minmax; +GLEW_VAR_EXPORT GLboolean __GLEW_AMD_sparse_texture; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_stencil_operation_extended; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_texture_texture4; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_transform_feedback3_lines_triangles; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_vertex_shader_layer; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_vertex_shader_tessellator; GLEW_VAR_EXPORT GLboolean __GLEW_AMD_vertex_shader_viewport_index; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_depth_texture; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_framebuffer_blit; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_framebuffer_multisample; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_instanced_arrays; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_pack_reverse_row_order; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_program_binary; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_texture_compression_dxt1; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_texture_compression_dxt3; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_texture_compression_dxt5; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_texture_usage; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_timer_query; +GLEW_VAR_EXPORT GLboolean __GLEW_ANGLE_translated_shader_source; GLEW_VAR_EXPORT GLboolean __GLEW_APPLE_aux_depth_stencil; GLEW_VAR_EXPORT GLboolean __GLEW_APPLE_client_storage; GLEW_VAR_EXPORT GLboolean __GLEW_APPLE_element_array; @@ -16643,13 +17542,17 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_ES2_compatibility; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_ES3_compatibility; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_arrays_of_arrays; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_base_instance; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_bindless_texture; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_blend_func_extended; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_buffer_storage; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_cl_event; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_clear_buffer_object; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_clear_texture; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_color_buffer_float; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_compatibility; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_compressed_texture_pixel_storage; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_compute_shader; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_compute_variable_group_size; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_conservative_depth; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_copy_buffer; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_copy_image; @@ -16662,6 +17565,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_draw_buffers_blend; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_draw_elements_base_vertex; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_draw_indirect; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_draw_instanced; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_enhanced_layouts; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_explicit_attrib_location; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_explicit_uniform_location; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_fragment_coord_conventions; @@ -16679,6 +17583,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_gpu_shader_fp64; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_half_float_pixel; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_half_float_vertex; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_imaging; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_indirect_parameters; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_instanced_arrays; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_internalformat_query; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_internalformat_query2; @@ -16686,6 +17591,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_invalidate_subdata; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_map_buffer_alignment; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_map_buffer_range; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_matrix_palette; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_multi_bind; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_multi_draw_indirect; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_multisample; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_multitexture; @@ -16696,6 +17602,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_point_parameters; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_point_sprite; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_program_interface_query; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_provoking_vertex; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_query_buffer_object; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_robust_buffer_access_behavior; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_robustness; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_robustness_application_isolation; @@ -16703,9 +17610,12 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_robustness_share_group_isolation; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sample_shading; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sampler_objects; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_seamless_cube_map; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_seamless_cubemap_per_texture; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_separate_shader_objects; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_atomic_counters; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_bit_encoding; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_draw_parameters; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_group_vote; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_image_load_store; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_image_size; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shader_objects; @@ -16720,6 +17630,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shading_language_include; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shading_language_packing; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shadow; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_shadow_ambient; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sparse_texture; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_stencil_texturing; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_sync; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_tessellation_shader; @@ -16738,6 +17649,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_env_crossbar; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_env_dot3; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_float; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_gather; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_mirror_clamp_to_edge; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_mirrored_repeat; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_multisample; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_non_power_of_two; @@ -16746,6 +17658,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_query_lod; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_rectangle; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_rg; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_rgb10_a2ui; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_stencil8; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_storage; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_storage_multisample; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_texture_swizzle; @@ -16764,6 +17677,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_ARB_vertex_blend; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_vertex_buffer_object; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_vertex_program; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_vertex_shader; +GLEW_VAR_EXPORT GLboolean __GLEW_ARB_vertex_type_10f_11f_11f_rev; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_vertex_type_2_10_10_10_rev; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_viewport_array; GLEW_VAR_EXPORT GLboolean __GLEW_ARB_window_pos; @@ -16902,6 +17816,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_IBM_texture_mirrored_repeat; GLEW_VAR_EXPORT GLboolean __GLEW_IBM_vertex_array_lists; GLEW_VAR_EXPORT GLboolean __GLEW_INGR_color_clamp; GLEW_VAR_EXPORT GLboolean __GLEW_INGR_interlace_read; +GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_map_texture; GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_parallel_arrays; GLEW_VAR_EXPORT GLboolean __GLEW_INTEL_texture_scissor; GLEW_VAR_EXPORT GLboolean __GLEW_KHR_debug; @@ -16912,15 +17827,22 @@ GLEW_VAR_EXPORT GLboolean __GLEW_MESA_pack_invert; GLEW_VAR_EXPORT GLboolean __GLEW_MESA_resize_buffers; GLEW_VAR_EXPORT GLboolean __GLEW_MESA_window_pos; GLEW_VAR_EXPORT GLboolean __GLEW_MESA_ycbcr_texture; +GLEW_VAR_EXPORT GLboolean __GLEW_NVX_conditional_render; GLEW_VAR_EXPORT GLboolean __GLEW_NVX_gpu_memory_info; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_bindless_multi_draw_indirect; GLEW_VAR_EXPORT GLboolean __GLEW_NV_bindless_texture; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_blend_equation_advanced; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_blend_equation_advanced_coherent; GLEW_VAR_EXPORT GLboolean __GLEW_NV_blend_square; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_compute_program5; GLEW_VAR_EXPORT GLboolean __GLEW_NV_conditional_render; GLEW_VAR_EXPORT GLboolean __GLEW_NV_copy_depth_to_color; GLEW_VAR_EXPORT GLboolean __GLEW_NV_copy_image; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_deep_texture3D; GLEW_VAR_EXPORT GLboolean __GLEW_NV_depth_buffer_float; GLEW_VAR_EXPORT GLboolean __GLEW_NV_depth_clamp; GLEW_VAR_EXPORT GLboolean __GLEW_NV_depth_range_unclamped; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_draw_texture; GLEW_VAR_EXPORT GLboolean __GLEW_NV_evaluators; GLEW_VAR_EXPORT GLboolean __GLEW_NV_explicit_multisample; GLEW_VAR_EXPORT GLboolean __GLEW_NV_fence; @@ -16935,6 +17857,7 @@ GLEW_VAR_EXPORT GLboolean __GLEW_NV_geometry_program4; GLEW_VAR_EXPORT GLboolean __GLEW_NV_geometry_shader4; GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_program4; GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_program5; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_program5_mem_extended; GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_program_fp64; GLEW_VAR_EXPORT GLboolean __GLEW_NV_gpu_shader5; GLEW_VAR_EXPORT GLboolean __GLEW_NV_half_float; @@ -16952,8 +17875,10 @@ GLEW_VAR_EXPORT GLboolean __GLEW_NV_present_video; GLEW_VAR_EXPORT GLboolean __GLEW_NV_primitive_restart; GLEW_VAR_EXPORT GLboolean __GLEW_NV_register_combiners; GLEW_VAR_EXPORT GLboolean __GLEW_NV_register_combiners2; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_atomic_counters; GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_atomic_float; GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_buffer_load; +GLEW_VAR_EXPORT GLboolean __GLEW_NV_shader_storage_buffer_object; GLEW_VAR_EXPORT GLboolean __GLEW_NV_tessellation_program5; GLEW_VAR_EXPORT GLboolean __GLEW_NV_texgen_emboss; GLEW_VAR_EXPORT GLboolean __GLEW_NV_texgen_reflection; @@ -16989,6 +17914,9 @@ GLEW_VAR_EXPORT GLboolean __GLEW_OML_resample; GLEW_VAR_EXPORT GLboolean __GLEW_OML_subsample; GLEW_VAR_EXPORT GLboolean __GLEW_PGI_misc_hints; GLEW_VAR_EXPORT GLboolean __GLEW_PGI_vertex_hints; +GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_ES1_0_compatibility; +GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_ES1_1_compatibility; +GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_enable; GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_error_string; GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_extension_query; GLEW_VAR_EXPORT GLboolean __GLEW_REGAL_log; diff --git a/btgui/OpenGLWindow/GlewWindows/GL/glxew.h b/btgui/OpenGLWindow/GlewWindows/GL/glxew.h index 9335b27bc..76a5f0d82 100644 --- a/btgui/OpenGLWindow/GlewWindows/GL/glxew.h +++ b/btgui/OpenGLWindow/GlewWindows/GL/glxew.h @@ -362,6 +362,26 @@ extern void ( * glXGetProcAddress (const GLubyte *procName)) (void); #define GLX_GPU_NUM_RB_AMD 0x21A7 #define GLX_GPU_NUM_SPI_AMD 0x21A8 +typedef void ( * PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC) (GLXContext dstCtx, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +typedef GLXContext ( * PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC) (unsigned int id, GLXContext share_list); +typedef GLXContext ( * PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC) (unsigned int id, GLXContext share_context, const int* attribList); +typedef Bool ( * PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC) (GLXContext ctx); +typedef unsigned int ( * PFNGLXGETCONTEXTGPUIDAMDPROC) (GLXContext ctx); +typedef GLXContext ( * PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC) (void); +typedef unsigned int ( * PFNGLXGETGPUIDSAMDPROC) (unsigned int maxCount, unsigned int* ids); +typedef int ( * PFNGLXGETGPUINFOAMDPROC) (unsigned int id, int property, GLenum dataType, unsigned int size, void* data); +typedef Bool ( * PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC) (GLXContext ctx); + +#define glXBlitContextFramebufferAMD GLXEW_GET_FUN(__glewXBlitContextFramebufferAMD) +#define glXCreateAssociatedContextAMD GLXEW_GET_FUN(__glewXCreateAssociatedContextAMD) +#define glXCreateAssociatedContextAttribsAMD GLXEW_GET_FUN(__glewXCreateAssociatedContextAttribsAMD) +#define glXDeleteAssociatedContextAMD GLXEW_GET_FUN(__glewXDeleteAssociatedContextAMD) +#define glXGetContextGPUIDAMD GLXEW_GET_FUN(__glewXGetContextGPUIDAMD) +#define glXGetCurrentAssociatedContextAMD GLXEW_GET_FUN(__glewXGetCurrentAssociatedContextAMD) +#define glXGetGPUIDsAMD GLXEW_GET_FUN(__glewXGetGPUIDsAMD) +#define glXGetGPUInfoAMD GLXEW_GET_FUN(__glewXGetGPUInfoAMD) +#define glXMakeAssociatedContextCurrentAMD GLXEW_GET_FUN(__glewXMakeAssociatedContextCurrentAMD) + #define GLXEW_AMD_gpu_association GLXEW_GET_VAR(__GLXEW_AMD_gpu_association) #endif /* GLX_AMD_gpu_association */ @@ -555,6 +575,17 @@ typedef void ( * PFNGLXRELEASETEXIMAGEATIPROC) (Display *dpy, GLXPbuffer pbuf, i #endif /* GLX_ATI_render_texture */ +/* --------------------------- GLX_EXT_buffer_age -------------------------- */ + +#ifndef GLX_EXT_buffer_age +#define GLX_EXT_buffer_age 1 + +#define GLX_BACK_BUFFER_AGE_EXT 0x20F4 + +#define GLXEW_EXT_buffer_age GLXEW_GET_VAR(__GLXEW_EXT_buffer_age) + +#endif /* GLX_EXT_buffer_age */ + /* ------------------- GLX_EXT_create_context_es2_profile ------------------ */ #ifndef GLX_EXT_create_context_es2_profile @@ -962,10 +993,10 @@ typedef void ( * PFNGLXRELEASEVIDEOCAPTUREDEVICENVPROC) (Display* dpy, GLXVideoC #endif /* GLX_NV_video_capture */ -/* ---------------------------- GLX_NV_video_out --------------------------- */ +/* -------------------------- GLX_NV_video_output -------------------------- */ -#ifndef GLX_NV_video_out -#define GLX_NV_video_out 1 +#ifndef GLX_NV_video_output +#define GLX_NV_video_output 1 #define GLX_VIDEO_OUT_COLOR_NV 0x20C3 #define GLX_VIDEO_OUT_ALPHA_NV 0x20C4 @@ -992,9 +1023,9 @@ typedef int ( * PFNGLXSENDPBUFFERTOVIDEONVPROC) (Display* dpy, GLXPbuffer pbuf, #define glXReleaseVideoImageNV GLXEW_GET_FUN(__glewXReleaseVideoImageNV) #define glXSendPbufferToVideoNV GLXEW_GET_FUN(__glewXSendPbufferToVideoNV) -#define GLXEW_NV_video_out GLXEW_GET_VAR(__GLXEW_NV_video_out) +#define GLXEW_NV_video_output GLXEW_GET_VAR(__GLXEW_NV_video_output) -#endif /* GLX_NV_video_out */ +#endif /* GLX_NV_video_output */ /* -------------------------- GLX_OML_swap_method -------------------------- */ @@ -1047,16 +1078,6 @@ typedef Bool ( * PFNGLXWAITFORSBCOMLPROC) (Display* dpy, GLXDrawable drawable, i #ifndef GLX_SGIS_color_range #define GLX_SGIS_color_range 1 -#define GLX_MIN_RED_SGIS 0 -#define GLX_MAX_GREEN_SGIS 0 -#define GLX_MIN_BLUE_SGIS 0 -#define GLX_MAX_ALPHA_SGIS 0 -#define GLX_MIN_GREEN_SGIS 0 -#define GLX_MIN_ALPHA_SGIS 0 -#define GLX_MAX_RED_SGIS 0 -#define GLX_EXTENDED_RANGE_SGIS 0 -#define GLX_MAX_BLUE_SGIS 0 - #define GLXEW_SGIS_color_range GLXEW_GET_VAR(__GLXEW_SGIS_color_range) #endif /* GLX_SGIS_color_range */ @@ -1393,7 +1414,7 @@ typedef int ( * PFNGLXVIDEORESIZESUNPROC) (Display* display, GLXDrawable window, /* ------------------------------------------------------------------------- */ #ifdef GLEW_MX -#define GLXEW_FUN_EXPORT +#define GLXEW_FUN_EXPORT GLEW_FUN_EXPORT #define GLXEW_VAR_EXPORT #else #define GLXEW_FUN_EXPORT GLEW_FUN_EXPORT @@ -1420,6 +1441,16 @@ GLXEW_FUN_EXPORT PFNGLXQUERYCONTEXTPROC __glewXQueryContext; GLXEW_FUN_EXPORT PFNGLXQUERYDRAWABLEPROC __glewXQueryDrawable; GLXEW_FUN_EXPORT PFNGLXSELECTEVENTPROC __glewXSelectEvent; +GLXEW_FUN_EXPORT PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC __glewXBlitContextFramebufferAMD; +GLXEW_FUN_EXPORT PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC __glewXCreateAssociatedContextAMD; +GLXEW_FUN_EXPORT PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC __glewXCreateAssociatedContextAttribsAMD; +GLXEW_FUN_EXPORT PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC __glewXDeleteAssociatedContextAMD; +GLXEW_FUN_EXPORT PFNGLXGETCONTEXTGPUIDAMDPROC __glewXGetContextGPUIDAMD; +GLXEW_FUN_EXPORT PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC __glewXGetCurrentAssociatedContextAMD; +GLXEW_FUN_EXPORT PFNGLXGETGPUIDSAMDPROC __glewXGetGPUIDsAMD; +GLXEW_FUN_EXPORT PFNGLXGETGPUINFOAMDPROC __glewXGetGPUInfoAMD; +GLXEW_FUN_EXPORT PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC __glewXMakeAssociatedContextCurrentAMD; + GLXEW_FUN_EXPORT PFNGLXCREATECONTEXTATTRIBSARBPROC __glewXCreateContextAttribsARB; GLXEW_FUN_EXPORT PFNGLXBINDTEXIMAGEATIPROC __glewXBindTexImageATI; @@ -1555,6 +1586,7 @@ GLXEW_VAR_EXPORT GLboolean __GLXEW_ARB_robustness_share_group_isolation; GLXEW_VAR_EXPORT GLboolean __GLXEW_ARB_vertex_buffer_object; GLXEW_VAR_EXPORT GLboolean __GLXEW_ATI_pixel_format_float; GLXEW_VAR_EXPORT GLboolean __GLXEW_ATI_render_texture; +GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_buffer_age; GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_create_context_es2_profile; GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_create_context_es_profile; GLXEW_VAR_EXPORT GLboolean __GLXEW_EXT_fbconfig_packed_float; @@ -1580,7 +1612,7 @@ GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_present_video; GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_swap_group; GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_vertex_array_range; GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_video_capture; -GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_video_out; +GLXEW_VAR_EXPORT GLboolean __GLXEW_NV_video_output; GLXEW_VAR_EXPORT GLboolean __GLXEW_OML_swap_method; GLXEW_VAR_EXPORT GLboolean __GLXEW_OML_sync_control; GLXEW_VAR_EXPORT GLboolean __GLXEW_SGIS_blended_overlay; diff --git a/btgui/OpenGLWindow/GlewWindows/GL/glxext.h b/btgui/OpenGLWindow/GlewWindows/GL/glxext.h deleted file mode 100644 index b3de958da..000000000 --- a/btgui/OpenGLWindow/GlewWindows/GL/glxext.h +++ /dev/null @@ -1,546 +0,0 @@ -#ifndef __glxext_h_ -#define __glxext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** License Applicability. Except to the extent portions of this file are -** made subject to an alternative license as permitted in the SGI Free -** Software License B, Version 1.1 (the "License"), the contents of this -** file are subject only to the provisions of the License. You may not use -** this file except in compliance with the License. You may obtain a copy -** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 -** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: -** -** http://oss.sgi.com/projects/FreeB -** -** Note that, as provided in the License, the Software is distributed on an -** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS -** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND -** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A -** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. -** -** Original Code. The Original Code is: OpenGL Sample Implementation, -** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, -** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. -** Copyright in any portions created by third parties is as indicated -** elsewhere herein. All Rights Reserved. -** -** Additional Notice Provisions: This software was created using the -** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has -** not been independently verified as being compliant with the OpenGL(R) -** version 1.2.1 Specification. -*/ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) -#define WIN32_LEAN_AND_MEAN 1 -#include -#else -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif - - -/*************************************************************/ - -/* Header file version number, required by OpenGL ABI for Linux */ -#define GLX_GLXEXT_VERSION 2 - -#ifndef GLX_VERSION_1_3 -#define GLX_WINDOW_BIT 0x00000001 -#define GLX_PIXMAP_BIT 0x00000002 -#define GLX_PBUFFER_BIT 0x00000004 -#define GLX_RGBA_BIT 0x00000001 -#define GLX_COLOR_INDEX_BIT 0x00000002 -#define GLX_PBUFFER_CLOBBER_MASK 0x08000000 -#define GLX_FRONT_LEFT_BUFFER_BIT 0x00000001 -#define GLX_FRONT_RIGHT_BUFFER_BIT 0x00000002 -#define GLX_BACK_LEFT_BUFFER_BIT 0x00000004 -#define GLX_BACK_RIGHT_BUFFER_BIT 0x00000008 -#define GLX_AUX_BUFFERS_BIT 0x00000010 -#define GLX_DEPTH_BUFFER_BIT 0x00000020 -#define GLX_STENCIL_BUFFER_BIT 0x00000040 -#define GLX_ACCUM_BUFFER_BIT 0x00000080 -#define GLX_CONFIG_CAVEAT 0x20 -#define GLX_X_VISUAL_TYPE 0x22 -#define GLX_TRANSPARENT_TYPE 0x23 -#define GLX_TRANSPARENT_INDEX_VALUE 0x24 -#define GLX_TRANSPARENT_RED_VALUE 0x25 -#define GLX_TRANSPARENT_GREEN_VALUE 0x26 -#define GLX_TRANSPARENT_BLUE_VALUE 0x27 -#define GLX_TRANSPARENT_ALPHA_VALUE 0x28 -#define GLX_DONT_CARE 0xFFFFFFFF -#define GLX_NONE 0x8000 -#define GLX_SLOW_CONFIG 0x8001 -#define GLX_TRUE_COLOR 0x8002 -#define GLX_DIRECT_COLOR 0x8003 -#define GLX_PSEUDO_COLOR 0x8004 -#define GLX_STATIC_COLOR 0x8005 -#define GLX_GRAY_SCALE 0x8006 -#define GLX_STATIC_GRAY 0x8007 -#define GLX_TRANSPARENT_RGB 0x8008 -#define GLX_TRANSPARENT_INDEX 0x8009 -#define GLX_VISUAL_ID 0x800B -#define GLX_SCREEN 0x800C -#define GLX_NON_CONFORMANT_CONFIG 0x800D -#define GLX_DRAWABLE_TYPE 0x8010 -#define GLX_RENDER_TYPE 0x8011 -#define GLX_X_RENDERABLE 0x8012 -#define GLX_FBCONFIG_ID 0x8013 -#define GLX_RGBA_TYPE 0x8014 -#define GLX_COLOR_INDEX_TYPE 0x8015 -#define GLX_MAX_PBUFFER_WIDTH 0x8016 -#define GLX_MAX_PBUFFER_HEIGHT 0x8017 -#define GLX_MAX_PBUFFER_PIXELS 0x8018 -#define GLX_PRESERVED_CONTENTS 0x801B -#define GLX_LARGEST_PBUFFER 0x801C -#define GLX_WIDTH 0x801D -#define GLX_HEIGHT 0x801E -#define GLX_EVENT_MASK 0x801F -#define GLX_DAMAGED 0x8020 -#define GLX_SAVED 0x8021 -#define GLX_WINDOW 0x8022 -#define GLX_PBUFFER 0x8023 -#define GLX_PBUFFER_HEIGHT 0x8040 -#define GLX_PBUFFER_WIDTH 0x8041 -#endif - -#ifndef GLX_EXT_visual_info -#define GLX_X_VISUAL_TYPE_EXT 0x22 -#define GLX_TRANSPARENT_TYPE_EXT 0x23 -#define GLX_TRANSPARENT_INDEX_VALUE_EXT 0x24 -#define GLX_TRANSPARENT_RED_VALUE_EXT 0x25 -#define GLX_TRANSPARENT_GREEN_VALUE_EXT 0x26 -#define GLX_TRANSPARENT_BLUE_VALUE_EXT 0x27 -#define GLX_TRANSPARENT_ALPHA_VALUE_EXT 0x28 -#define GLX_NONE_EXT 0x8000 -#define GLX_TRUE_COLOR_EXT 0x8002 -#define GLX_DIRECT_COLOR_EXT 0x8003 -#define GLX_PSEUDO_COLOR_EXT 0x8004 -#define GLX_STATIC_COLOR_EXT 0x8005 -#define GLX_GRAY_SCALE_EXT 0x8006 -#define GLX_STATIC_GRAY_EXT 0x8007 -#define GLX_TRANSPARENT_RGB_EXT 0x8008 -#define GLX_TRANSPARENT_INDEX_EXT 0x8009 -#endif - -#ifndef GLX_SGI_swap_control -#endif - -#ifndef GLX_SGI_video_sync -#endif - -#ifndef GLX_SGI_make_current_read -#endif - -#ifndef GLX_SGIX_video_source -#endif - -#ifndef GLX_EXT_visual_rating -#define GLX_VISUAL_CAVEAT_EXT 0x20 -#define GLX_SLOW_VISUAL_EXT 0x8001 -#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D -/* reuse GLX_NONE_EXT */ -#endif - -#ifndef GLX_EXT_import_context -#define GLX_SHARE_CONTEXT_EXT 0x800A -#define GLX_VISUAL_ID_EXT 0x800B -#define GLX_SCREEN_EXT 0x800C -#endif - -#ifndef GLX_SGIX_fbconfig -#define GLX_WINDOW_BIT_SGIX 0x00000001 -#define GLX_PIXMAP_BIT_SGIX 0x00000002 -#define GLX_RGBA_BIT_SGIX 0x00000001 -#define GLX_COLOR_INDEX_BIT_SGIX 0x00000002 -#define GLX_DRAWABLE_TYPE_SGIX 0x8010 -#define GLX_RENDER_TYPE_SGIX 0x8011 -#define GLX_X_RENDERABLE_SGIX 0x8012 -#define GLX_FBCONFIG_ID_SGIX 0x8013 -#define GLX_RGBA_TYPE_SGIX 0x8014 -#define GLX_COLOR_INDEX_TYPE_SGIX 0x8015 -/* reuse GLX_SCREEN_EXT */ -#endif - -#ifndef GLX_SGIX_pbuffer -#define GLX_PBUFFER_BIT_SGIX 0x00000004 -#define GLX_BUFFER_CLOBBER_MASK_SGIX 0x08000000 -#define GLX_FRONT_LEFT_BUFFER_BIT_SGIX 0x00000001 -#define GLX_FRONT_RIGHT_BUFFER_BIT_SGIX 0x00000002 -#define GLX_BACK_LEFT_BUFFER_BIT_SGIX 0x00000004 -#define GLX_BACK_RIGHT_BUFFER_BIT_SGIX 0x00000008 -#define GLX_AUX_BUFFERS_BIT_SGIX 0x00000010 -#define GLX_DEPTH_BUFFER_BIT_SGIX 0x00000020 -#define GLX_STENCIL_BUFFER_BIT_SGIX 0x00000040 -#define GLX_ACCUM_BUFFER_BIT_SGIX 0x00000080 -#define GLX_SAMPLE_BUFFERS_BIT_SGIX 0x00000100 -#define GLX_MAX_PBUFFER_WIDTH_SGIX 0x8016 -#define GLX_MAX_PBUFFER_HEIGHT_SGIX 0x8017 -#define GLX_MAX_PBUFFER_PIXELS_SGIX 0x8018 -#define GLX_OPTIMAL_PBUFFER_WIDTH_SGIX 0x8019 -#define GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX 0x801A -#define GLX_PRESERVED_CONTENTS_SGIX 0x801B -#define GLX_LARGEST_PBUFFER_SGIX 0x801C -#define GLX_WIDTH_SGIX 0x801D -#define GLX_HEIGHT_SGIX 0x801E -#define GLX_EVENT_MASK_SGIX 0x801F -#define GLX_DAMAGED_SGIX 0x8020 -#define GLX_SAVED_SGIX 0x8021 -#define GLX_WINDOW_SGIX 0x8022 -#define GLX_PBUFFER_SGIX 0x8023 -#endif - -#ifndef GLX_SGI_cushion -#endif - -#ifndef GLX_SGIX_video_resize -#define GLX_SYNC_FRAME_SGIX 0x00000000 -#define GLX_SYNC_SWAP_SGIX 0x00000001 -#endif - -#ifndef GLX_SGIX_dmbuffer -#define GLX_DIGITAL_MEDIA_PBUFFER_SGIX 0x8024 -#endif - -#ifndef GLX_SGIX_swap_group -#endif - -#ifndef GLX_SGIX_swap_barrier -#endif - -#ifndef GLX_SGIS_blended_overlay -#define GLX_BLENDED_RGBA_SGIS 0x8025 -#endif - -#ifndef GLX_SGIS_shared_multisample -#define GLX_MULTISAMPLE_SUB_RECT_WIDTH_SGIS 0x8026 -#define GLX_MULTISAMPLE_SUB_RECT_HEIGHT_SGIS 0x8027 -#endif - -#ifndef GLX_SUN_get_transparent_index -#endif - -#ifndef GLX_3DFX_multisample -#define GLX_SAMPLE_BUFFERS_3DFX 0x8050 -#define GLX_SAMPLES_3DFX 0x8051 -#endif - -#ifndef GLX_MESA_copy_sub_buffer -#endif - -#ifndef GLX_MESA_pixmap_colormap -#endif - -#ifndef GLX_MESA_release_buffers -#endif - -#ifndef GLX_MESA_set_3dfx_mode -#define GLX_3DFX_WINDOW_MODE_MESA 0x1 -#define GLX_3DFX_FULLSCREEN_MODE_MESA 0x2 -#endif - - -/*************************************************************/ - -#ifndef GLX_ARB_get_proc_address -typedef void (*__GLXextFuncPtr)(); -#endif - -#ifndef GLX_SGIX_video_source -typedef XID GLXVideoSourceSGIX; -#endif - -#ifndef GLX_SGIX_fbconfig -typedef XID GLXFBConfigIDSGIX; -typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; -#endif - -#ifndef GLX_SGIX_pbuffer -typedef XID GLXPbufferSGIX; -typedef struct { - int type; - unsigned long serial; /* # of last request processed by server */ - Bool send_event; /* true if this came for SendEvent request */ - Display *display; /* display the event was read from */ - GLXDrawable drawable; /* i.d. of Drawable */ - int event_type; /* GLX_DAMAGED_SGIX or GLX_SAVED_SGIX */ - int draw_type; /* GLX_WINDOW_SGIX or GLX_PBUFFER_SGIX */ - unsigned int mask; /* mask indicating which buffers are affected*/ - int x, y; - int width, height; - int count; /* if nonzero, at least this many more */ -} GLXBufferClobberEventSGIX; -#endif - -#ifdef GL_NV_vertex_array_range -#ifndef PFNGLXALLOCATEMEMORYNVPROC -#ifdef GLX_GLXEXT_PROTOTYPES -extern void *glXAllocateMemoryNV (GLsizei, GLfloat, GLfloat, GLfloat); -#endif -typedef void * ( * PFNGLXALLOCATEMEMORYNVPROC) (GLsizei, GLfloat, GLfloat, GLfloat); -#endif -#ifndef PFNGLXFREEMEMORYNVPROC -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXFreeMemoryNV (void *); -#endif -typedef void ( * PFNGLXFREEMEMORYNVPROC) (void *); -#endif -#endif - -#ifndef GLX_VERSION_1_3 -#define GLX_VERSION_1_3 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXFBConfig * glXGetFBConfigs (Display *, int, int *); -extern GLXFBConfig * glXChooseFBConfig (Display *, int, const int *, int *); -extern int glXGetFBConfigAttrib (Display *, GLXFBConfig, int, int *); -extern XVisualInfo * glXGetVisualFromFBConfig (Display *, GLXFBConfig); -extern GLXWindow glXCreateWindow (Display *, GLXFBConfig, Window, const int *); -extern void glXDestroyWindow (Display *, GLXWindow); -extern GLXPixmap glXCreatePixmap (Display *, GLXFBConfig, Pixmap, const int *); -extern void glXDestroyPixmap (Display *, GLXPixmap); -extern GLXPbuffer glXCreatePbuffer (Display *, GLXFBConfig, const int *); -extern void glXDestroyPbuffer (Display *, GLXPbuffer); -extern void glXQueryDrawable (Display *, GLXDrawable, int, unsigned int *); -extern GLXContext glXCreateNewContext (Display *, GLXFBConfig, int, GLXContext, Bool); -extern Bool glXMakeContextCurrent (Display *, GLXDrawable, GLXDrawable, GLXContext); -extern GLXDrawable glXGetCurrentReadDrawable (void); -extern Display * glXGetCurrentDisplay (void); -extern int glXQueryContext (Display *, GLXContext, int, int *); -extern void glXSelectEvent (Display *, GLXDrawable, unsigned long); -extern void glXGetSelectedEvent (Display *, GLXDrawable, unsigned long *); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXFBConfig * ( * PFNGLXGETFBCONFIGSPROC) (Display *dpy, int screen, int *nelements); -typedef GLXFBConfig * ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements); -typedef int ( * PFNGLXGETFBCONFIGATTRIBPROC) (Display *dpy, GLXFBConfig config, int attribute, int *value); -typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGPROC) (Display *dpy, GLXFBConfig config); -typedef GLXWindow ( * PFNGLXCREATEWINDOWPROC) (Display *dpy, GLXFBConfig config, Window win, const int *attrib_list); -typedef void ( * PFNGLXDESTROYWINDOWPROC) (Display *dpy, GLXWindow win); -typedef GLXPixmap ( * PFNGLXCREATEPIXMAPPROC) (Display *dpy, GLXFBConfig config, Pixmap pixmap, const int *attrib_list); -typedef void ( * PFNGLXDESTROYPIXMAPPROC) (Display *dpy, GLXPixmap pixmap); -typedef GLXPbuffer ( * PFNGLXCREATEPBUFFERPROC) (Display *dpy, GLXFBConfig config, const int *attrib_list); -typedef void ( * PFNGLXDESTROYPBUFFERPROC) (Display *dpy, GLXPbuffer pbuf); -typedef void ( * PFNGLXQUERYDRAWABLEPROC) (Display *dpy, GLXDrawable draw, int attribute, unsigned int *value); -typedef GLXContext ( * PFNGLXCREATENEWCONTEXTPROC) (Display *dpy, GLXFBConfig config, int render_type, GLXContext share_list, Bool direct); -typedef Bool ( * PFNGLXMAKECONTEXTCURRENTPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLEPROC) (void); -typedef Display * ( * PFNGLXGETCURRENTDISPLAYPROC) (void); -typedef int ( * PFNGLXQUERYCONTEXTPROC) (Display *dpy, GLXContext ctx, int attribute, int *value); -typedef void ( * PFNGLXSELECTEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long event_mask); -typedef void ( * PFNGLXGETSELECTEDEVENTPROC) (Display *dpy, GLXDrawable draw, unsigned long *event_mask); -#endif - -#ifndef GLX_ARB_get_proc_address -#define GLX_ARB_get_proc_address 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern __GLXextFuncPtr glXGetProcAddressARB (const GLubyte *); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef __GLXextFuncPtr ( * PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName); -#endif - -#ifndef GLX_SGIS_multisample -#define GLX_SGIS_multisample 1 -#endif - -#ifndef GLX_EXT_visual_info -#define GLX_EXT_visual_info 1 -#endif - -#ifndef GLX_SGI_swap_control -#define GLX_SGI_swap_control 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXSwapIntervalSGI (int); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval); -#endif - -#ifndef GLX_SGI_video_sync -#define GLX_SGI_video_sync 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXGetVideoSyncSGI (unsigned int *); -extern int glXWaitVideoSyncSGI (int, int, unsigned int *); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXGETVIDEOSYNCSGIPROC) (unsigned int *count); -typedef int ( * PFNGLXWAITVIDEOSYNCSGIPROC) (int divisor, int remainder, unsigned int *count); -#endif - -#ifndef GLX_SGI_make_current_read -#define GLX_SGI_make_current_read 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXMakeCurrentReadSGI (Display *, GLXDrawable, GLXDrawable, GLXContext); -extern GLXDrawable glXGetCurrentReadDrawableSGI (void); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXMAKECURRENTREADSGIPROC) (Display *dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx); -typedef GLXDrawable ( * PFNGLXGETCURRENTREADDRAWABLESGIPROC) (void); -#endif - -#ifdef _VL_H -#ifndef GLX_SGIX_video_source -#define GLX_SGIX_video_source 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXVideoSourceSGIX glXCreateGLXVideoSourceSGIX (Display *, int, VLServer, VLPath, int, VLNode); -extern void glXDestroyGLXVideoSourceSGIX (Display *, GLXVideoSourceSGIX); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXVideoSourceSGIX ( * PFNGLXCREATEGLXVIDEOSOURCESGIXPROC) (Display *display, int screen, VLServer server, VLPath path, int nodeClass, VLNode drainNode); -typedef void ( * PFNGLXDESTROYGLXVIDEOSOURCESGIXPROC) (Display *dpy, GLXVideoSourceSGIX glxvideosource); -#endif - -#endif /* _VL_H */ -#ifndef GLX_EXT_visual_rating -#define GLX_EXT_visual_rating 1 -#endif - -#ifndef GLX_EXT_import_context -#define GLX_EXT_import_context 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Display * glXGetCurrentDisplayEXT (void); -extern int glXQueryContextInfoEXT (Display *, GLXContext, int, int *); -extern GLXContextID glXGetContextIDEXT (GLXContext); -extern GLXContext glXImportContextEXT (Display *, GLXContextID); -extern void glXFreeContextEXT (Display *, GLXContext); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Display * ( * PFNGLXGETCURRENTDISPLAYEXTPROC) (void); -typedef int ( * PFNGLXQUERYCONTEXTINFOEXTPROC) (Display *dpy, GLXContext context, int attribute, int *value); -typedef GLXContextID ( * PFNGLXGETCONTEXTIDEXTPROC) (GLXContext context); -typedef GLXContext ( * PFNGLXIMPORTCONTEXTEXTPROC) (Display *dpy, GLXContextID contextID); -typedef void ( * PFNGLXFREECONTEXTEXTPROC) (Display *dpy, GLXContext context); -#endif - -#ifndef GLX_SGIX_fbconfig -#define GLX_SGIX_fbconfig 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXGetFBConfigAttribSGIX (Display *, GLXFBConfigSGIX, int, int *); -extern GLXFBConfigSGIX * glXChooseFBConfigSGIX (Display *, int, int *, int *); -extern GLXPixmap glXCreateGLXPixmapWithConfigSGIX (Display *, GLXFBConfigSGIX, Pixmap); -extern GLXContext glXCreateContextWithConfigSGIX (Display *, GLXFBConfigSGIX, int, GLXContext, Bool); -extern XVisualInfo * glXGetVisualFromFBConfigSGIX (Display *, GLXFBConfigSGIX); -extern GLXFBConfigSGIX glXGetFBConfigFromVisualSGIX (Display *, XVisualInfo *); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXGETFBCONFIGATTRIBSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int attribute, int *value); -typedef GLXFBConfigSGIX * ( * PFNGLXCHOOSEFBCONFIGSGIXPROC) (Display *dpy, int screen, int *attrib_list, int *nelements); -typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, Pixmap pixmap); -typedef GLXContext ( * PFNGLXCREATECONTEXTWITHCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, int render_type, GLXContext share_list, Bool direct); -typedef XVisualInfo * ( * PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLXFBConfigSGIX config); -typedef GLXFBConfigSGIX ( * PFNGLXGETFBCONFIGFROMVISUALSGIXPROC) (Display *dpy, XVisualInfo *vis); -#endif - -#ifndef GLX_SGIX_pbuffer -#define GLX_SGIX_pbuffer 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXPbufferSGIX glXCreateGLXPbufferSGIX (Display *, GLXFBConfigSGIX, unsigned int, unsigned int, int *); -extern void glXDestroyGLXPbufferSGIX (Display *, GLXPbufferSGIX); -extern int glXQueryGLXPbufferSGIX (Display *, GLXPbufferSGIX, int, unsigned int *); -extern void glXSelectEventSGIX (Display *, GLXDrawable, unsigned long); -extern void glXGetSelectedEventSGIX (Display *, GLXDrawable, unsigned long *); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXPbufferSGIX ( * PFNGLXCREATEGLXPBUFFERSGIXPROC) (Display *dpy, GLXFBConfigSGIX config, unsigned int width, unsigned int height, int *attrib_list); -typedef void ( * PFNGLXDESTROYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf); -typedef int ( * PFNGLXQUERYGLXPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuf, int attribute, unsigned int *value); -typedef void ( * PFNGLXSELECTEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long mask); -typedef void ( * PFNGLXGETSELECTEDEVENTSGIXPROC) (Display *dpy, GLXDrawable drawable, unsigned long *mask); -#endif - -#ifndef GLX_SGI_cushion -#define GLX_SGI_cushion 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXCushionSGI (Display *, Window, float); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXCUSHIONSGIPROC) (Display *dpy, Window window, float cushion); -#endif - -#ifndef GLX_SGIX_video_resize -#define GLX_SGIX_video_resize 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern int glXBindChannelToWindowSGIX (Display *, int, int, Window); -extern int glXChannelRectSGIX (Display *, int, int, int, int, int, int); -extern int glXQueryChannelRectSGIX (Display *, int, int, int *, int *, int *, int *); -extern int glXQueryChannelDeltasSGIX (Display *, int, int, int *, int *, int *, int *); -extern int glXChannelRectSyncSGIX (Display *, int, int, GLenum); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef int ( * PFNGLXBINDCHANNELTOWINDOWSGIXPROC) (Display *display, int screen, int channel, Window window); -typedef int ( * PFNGLXCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int x, int y, int w, int h); -typedef int ( * PFNGLXQUERYCHANNELRECTSGIXPROC) (Display *display, int screen, int channel, int *dx, int *dy, int *dw, int *dh); -typedef int ( * PFNGLXQUERYCHANNELDELTASSGIXPROC) (Display *display, int screen, int channel, int *x, int *y, int *w, int *h); -typedef int ( * PFNGLXCHANNELRECTSYNCSGIXPROC) (Display *display, int screen, int channel, GLenum synctype); -#endif - -#ifdef _DM_BUFFER_H_ -#ifndef GLX_SGIX_dmbuffer -#define GLX_SGIX_dmbuffer 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXAssociateDMPbufferSGIX (Display *, GLXPbufferSGIX, DMparams *, DMbuffer); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXASSOCIATEDMPBUFFERSGIXPROC) (Display *dpy, GLXPbufferSGIX pbuffer, DMparams *params, DMbuffer dmbuffer); -#endif - -#endif /* _DM_BUFFER_H_ */ -#ifndef GLX_SGIX_swap_group -#define GLX_SGIX_swap_group 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXJoinSwapGroupSGIX (Display *, GLXDrawable, GLXDrawable); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXJOINSWAPGROUPSGIXPROC) (Display *dpy, GLXDrawable drawable, GLXDrawable member); -#endif - -#ifndef GLX_SGIX_swap_barrier -#define GLX_SGIX_swap_barrier 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXBindSwapBarrierSGIX (Display *, GLXDrawable, int); -extern Bool glXQueryMaxSwapBarriersSGIX (Display *, int, int *); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXBINDSWAPBARRIERSGIXPROC) (Display *dpy, GLXDrawable drawable, int barrier); -typedef Bool ( * PFNGLXQUERYMAXSWAPBARRIERSSGIXPROC) (Display *dpy, int screen, int *max); -#endif - -#ifndef GLX_SUN_get_transparent_index -#define GLX_SUN_get_transparent_index 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Status glXGetTransparentIndexSUN (Display *, Window, Window, long *); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Status ( * PFNGLXGETTRANSPARENTINDEXSUNPROC) (Display *dpy, Window overlay, Window underlay, long *pTransparentIndex); -#endif - -#ifndef GLX_MESA_copy_sub_buffer -#define GLX_MESA_copy_sub_buffer 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern void glXCopySubBufferMESA (Display *, GLXDrawable, int, int, int, int); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef void ( * PFNGLXCOPYSUBBUFFERMESAPROC) (Display *dpy, GLXDrawable drawable, int x, int y, int width, int height); -#endif - -#ifndef GLX_MESA_pixmap_colormap -#define GLX_MESA_pixmap_colormap 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern GLXPixmap glXCreateGLXPixmapMESA (Display *, XVisualInfo *, Pixmap, Colormap); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef GLXPixmap ( * PFNGLXCREATEGLXPIXMAPMESAPROC) (Display *dpy, XVisualInfo *visual, Pixmap pixmap, Colormap cmap); -#endif - -#ifndef GLX_MESA_release_buffers -#define GLX_MESA_release_buffers 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXReleaseBuffersMESA (Display *, GLXDrawable); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXRELEASEBUFFERSMESAPROC) (Display *dpy, GLXDrawable drawable); -#endif - -#ifndef GLX_MESA_set_3dfx_mode -#define GLX_MESA_set_3dfx_mode 1 -#ifdef GLX_GLXEXT_PROTOTYPES -extern Bool glXSet3DfxModeMESA (int); -#endif /* GLX_GLXEXT_PROTOTYPES */ -typedef Bool ( * PFNGLXSET3DFXMODEMESAPROC) (int mode); -#endif - - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/btgui/OpenGLWindow/GlewWindows/GL/wglew.h b/btgui/OpenGLWindow/GlewWindows/GL/wglew.h index c0f59f56d..8659841d3 100644 --- a/btgui/OpenGLWindow/GlewWindows/GL/wglew.h +++ b/btgui/OpenGLWindow/GlewWindows/GL/wglew.h @@ -446,6 +446,28 @@ typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, con #endif /* WGL_ARB_render_texture */ +/* ---------------- WGL_ARB_robustness_application_isolation --------------- */ + +#ifndef WGL_ARB_robustness_application_isolation +#define WGL_ARB_robustness_application_isolation 1 + +#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 + +#define WGLEW_ARB_robustness_application_isolation WGLEW_GET_VAR(__WGLEW_ARB_robustness_application_isolation) + +#endif /* WGL_ARB_robustness_application_isolation */ + +/* ---------------- WGL_ARB_robustness_share_group_isolation --------------- */ + +#ifndef WGL_ARB_robustness_share_group_isolation +#define WGL_ARB_robustness_share_group_isolation 1 + +#define WGL_CONTEXT_RESET_ISOLATION_BIT_ARB 0x00000008 + +#define WGLEW_ARB_robustness_share_group_isolation WGLEW_GET_VAR(__WGLEW_ARB_robustness_share_group_isolation) + +#endif /* WGL_ARB_robustness_share_group_isolation */ + /* ----------------------- WGL_ATI_pixel_format_float ---------------------- */ #ifndef WGL_ATI_pixel_format_float @@ -1323,6 +1345,8 @@ WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_pbuffer; WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_pixel_format; WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_pixel_format_float; WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_render_texture; +WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_robustness_application_isolation; +WGLEW_VAR_EXPORT GLboolean __WGLEW_ARB_robustness_share_group_isolation; WGLEW_VAR_EXPORT GLboolean __WGLEW_ATI_pixel_format_float; WGLEW_VAR_EXPORT GLboolean __WGLEW_ATI_render_texture_rectangle; WGLEW_VAR_EXPORT GLboolean __WGLEW_EXT_create_context_es2_profile; diff --git a/btgui/OpenGLWindow/GlewWindows/GL/wglext.h b/btgui/OpenGLWindow/GlewWindows/GL/wglext.h deleted file mode 100644 index 8c6192c27..000000000 --- a/btgui/OpenGLWindow/GlewWindows/GL/wglext.h +++ /dev/null @@ -1,466 +0,0 @@ -#ifndef __wglext_h_ -#define __wglext_h_ - -#ifdef __cplusplus -extern "C" { -#endif - -/* -** License Applicability. Except to the extent portions of this file are -** made subject to an alternative license as permitted in the SGI Free -** Software License B, Version 1.1 (the "License"), the contents of this -** file are subject only to the provisions of the License. You may not use -** this file except in compliance with the License. You may obtain a copy -** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 -** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: -** -** http://oss.sgi.com/projects/FreeB -** -** Note that, as provided in the License, the Software is distributed on an -** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS -** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND -** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A -** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. -** -** Original Code. The Original Code is: OpenGL Sample Implementation, -** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, -** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. -** Copyright in any portions created by third parties is as indicated -** elsewhere herein. All Rights Reserved. -** -** Additional Notice Provisions: This software was created using the -** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has -** not been independently verified as being compliant with the OpenGL(R) -** version 1.2.1 Specification. -*/ - -#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) -#define WIN32_LEAN_AND_MEAN 1 -#include -#endif - -#ifndef APIENTRY -#define APIENTRY -#endif - -/*************************************************************/ - -/* Header file version number */ -#define WGL_WGLEXT_VERSION 1 - -#ifndef WGL_ARB_buffer_region -#define WGL_FRONT_COLOR_BUFFER_BIT_ARB 0x00000001 -#define WGL_BACK_COLOR_BUFFER_BIT_ARB 0x00000002 -#define WGL_DEPTH_BUFFER_BIT_ARB 0x00000004 -#define WGL_STENCIL_BUFFER_BIT_ARB 0x00000008 -#endif - -#ifndef WGL_ARB_extensions_string -#endif - -#ifndef WGL_ARB_pixel_format -#define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000 -#define WGL_DRAW_TO_WINDOW_ARB 0x2001 -#define WGL_DRAW_TO_BITMAP_ARB 0x2002 -#define WGL_ACCELERATION_ARB 0x2003 -#define WGL_NEED_PALETTE_ARB 0x2004 -#define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005 -#define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006 -#define WGL_SWAP_METHOD_ARB 0x2007 -#define WGL_NUMBER_OVERLAYS_ARB 0x2008 -#define WGL_NUMBER_UNDERLAYS_ARB 0x2009 -#define WGL_TRANSPARENT_ARB 0x200A -#define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037 -#define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038 -#define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039 -#define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A -#define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B -#define WGL_SHARE_DEPTH_ARB 0x200C -#define WGL_SHARE_STENCIL_ARB 0x200D -#define WGL_SHARE_ACCUM_ARB 0x200E -#define WGL_SUPPORT_GDI_ARB 0x200F -#define WGL_SUPPORT_OPENGL_ARB 0x2010 -#define WGL_DOUBLE_BUFFER_ARB 0x2011 -#define WGL_STEREO_ARB 0x2012 -#define WGL_PIXEL_TYPE_ARB 0x2013 -#define WGL_COLOR_BITS_ARB 0x2014 -#define WGL_RED_BITS_ARB 0x2015 -#define WGL_RED_SHIFT_ARB 0x2016 -#define WGL_GREEN_BITS_ARB 0x2017 -#define WGL_GREEN_SHIFT_ARB 0x2018 -#define WGL_BLUE_BITS_ARB 0x2019 -#define WGL_BLUE_SHIFT_ARB 0x201A -#define WGL_ALPHA_BITS_ARB 0x201B -#define WGL_ALPHA_SHIFT_ARB 0x201C -#define WGL_ACCUM_BITS_ARB 0x201D -#define WGL_ACCUM_RED_BITS_ARB 0x201E -#define WGL_ACCUM_GREEN_BITS_ARB 0x201F -#define WGL_ACCUM_BLUE_BITS_ARB 0x2020 -#define WGL_ACCUM_ALPHA_BITS_ARB 0x2021 -#define WGL_DEPTH_BITS_ARB 0x2022 -#define WGL_STENCIL_BITS_ARB 0x2023 -#define WGL_AUX_BUFFERS_ARB 0x2024 -#define WGL_NO_ACCELERATION_ARB 0x2025 -#define WGL_GENERIC_ACCELERATION_ARB 0x2026 -#define WGL_FULL_ACCELERATION_ARB 0x2027 -#define WGL_SWAP_EXCHANGE_ARB 0x2028 -#define WGL_SWAP_COPY_ARB 0x2029 -#define WGL_SWAP_UNDEFINED_ARB 0x202A -#define WGL_TYPE_RGBA_ARB 0x202B -#define WGL_TYPE_COLORINDEX_ARB 0x202C -#endif - -#ifndef WGL_ARB_make_current_read -#define ERROR_INVALID_PIXEL_TYPE_ARB 0x2043 -#define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054 -#endif - -#ifndef WGL_ARB_pbuffer -#define WGL_DRAW_TO_PBUFFER_ARB 0x202D -#define WGL_MAX_PBUFFER_PIXELS_ARB 0x202E -#define WGL_MAX_PBUFFER_WIDTH_ARB 0x202F -#define WGL_MAX_PBUFFER_HEIGHT_ARB 0x2030 -#define WGL_PBUFFER_LARGEST_ARB 0x2033 -#define WGL_PBUFFER_WIDTH_ARB 0x2034 -#define WGL_PBUFFER_HEIGHT_ARB 0x2035 -#define WGL_PBUFFER_LOST_ARB 0x2036 -#endif - -#ifndef WGL_ARB_render_texture -#define WGL_BIND_TO_TEXTURE_RGB_ARB 0x2070 -#define WGL_BIND_TO_TEXTURE_RGBA_ARB 0x2071 -#define WGL_TEXTURE_FORMAT_ARB 0x2072 -#define WGL_TEXTURE_TARGET_ARB 0x2073 -#define WGL_MIPMAP_TEXTURE_ARB 0x2074 -#define WGL_TEXTURE_RGB_ARB 0x2075 -#define WGL_TEXTURE_RGBA_ARB 0x2076 -#define WGL_NO_TEXTURE_ARB 0x2077 -#define WGL_TEXTURE_CUBE_MAP_ARB 0x2078 -#define WGL_TEXTURE_1D_ARB 0x2079 -#define WGL_TEXTURE_2D_ARB 0x207A -#define WGL_MIPMAP_LEVEL_ARB 0x207B -#define WGL_CUBE_MAP_FACE_ARB 0x207C -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB 0x207D -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB 0x207E -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB 0x207F -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB 0x2080 -#define WGL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB 0x2081 -#define WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB 0x2082 -#define WGL_FRONT_LEFT_ARB 0x2083 -#define WGL_FRONT_RIGHT_ARB 0x2084 -#define WGL_BACK_LEFT_ARB 0x2085 -#define WGL_BACK_RIGHT_ARB 0x2086 -#define WGL_AUX0_ARB 0x2087 -#define WGL_AUX1_ARB 0x2088 -#define WGL_AUX2_ARB 0x2089 -#define WGL_AUX3_ARB 0x208A -#define WGL_AUX4_ARB 0x208B -#define WGL_AUX5_ARB 0x208C -#define WGL_AUX6_ARB 0x208D -#define WGL_AUX7_ARB 0x208E -#define WGL_AUX8_ARB 0x208F -#define WGL_AUX9_ARB 0x2090 -#endif - -#ifndef WGL_EXT_make_current_read -#define ERROR_INVALID_PIXEL_TYPE_EXT 0x2043 -#endif - -#ifndef WGL_EXT_pixel_format -#define WGL_NUMBER_PIXEL_FORMATS_EXT 0x2000 -#define WGL_DRAW_TO_WINDOW_EXT 0x2001 -#define WGL_DRAW_TO_BITMAP_EXT 0x2002 -#define WGL_ACCELERATION_EXT 0x2003 -#define WGL_NEED_PALETTE_EXT 0x2004 -#define WGL_NEED_SYSTEM_PALETTE_EXT 0x2005 -#define WGL_SWAP_LAYER_BUFFERS_EXT 0x2006 -#define WGL_SWAP_METHOD_EXT 0x2007 -#define WGL_NUMBER_OVERLAYS_EXT 0x2008 -#define WGL_NUMBER_UNDERLAYS_EXT 0x2009 -#define WGL_TRANSPARENT_EXT 0x200A -#define WGL_TRANSPARENT_VALUE_EXT 0x200B -#define WGL_SHARE_DEPTH_EXT 0x200C -#define WGL_SHARE_STENCIL_EXT 0x200D -#define WGL_SHARE_ACCUM_EXT 0x200E -#define WGL_SUPPORT_GDI_EXT 0x200F -#define WGL_SUPPORT_OPENGL_EXT 0x2010 -#define WGL_DOUBLE_BUFFER_EXT 0x2011 -#define WGL_STEREO_EXT 0x2012 -#define WGL_PIXEL_TYPE_EXT 0x2013 -#define WGL_COLOR_BITS_EXT 0x2014 -#define WGL_RED_BITS_EXT 0x2015 -#define WGL_RED_SHIFT_EXT 0x2016 -#define WGL_GREEN_BITS_EXT 0x2017 -#define WGL_GREEN_SHIFT_EXT 0x2018 -#define WGL_BLUE_BITS_EXT 0x2019 -#define WGL_BLUE_SHIFT_EXT 0x201A -#define WGL_ALPHA_BITS_EXT 0x201B -#define WGL_ALPHA_SHIFT_EXT 0x201C -#define WGL_ACCUM_BITS_EXT 0x201D -#define WGL_ACCUM_RED_BITS_EXT 0x201E -#define WGL_ACCUM_GREEN_BITS_EXT 0x201F -#define WGL_ACCUM_BLUE_BITS_EXT 0x2020 -#define WGL_ACCUM_ALPHA_BITS_EXT 0x2021 -#define WGL_DEPTH_BITS_EXT 0x2022 -#define WGL_STENCIL_BITS_EXT 0x2023 -#define WGL_AUX_BUFFERS_EXT 0x2024 -#define WGL_NO_ACCELERATION_EXT 0x2025 -#define WGL_GENERIC_ACCELERATION_EXT 0x2026 -#define WGL_FULL_ACCELERATION_EXT 0x2027 -#define WGL_SWAP_EXCHANGE_EXT 0x2028 -#define WGL_SWAP_COPY_EXT 0x2029 -#define WGL_SWAP_UNDEFINED_EXT 0x202A -#define WGL_TYPE_RGBA_EXT 0x202B -#define WGL_TYPE_COLORINDEX_EXT 0x202C -#endif - -#ifndef WGL_EXT_pbuffer -#define WGL_DRAW_TO_PBUFFER_EXT 0x202D -#define WGL_MAX_PBUFFER_PIXELS_EXT 0x202E -#define WGL_MAX_PBUFFER_WIDTH_EXT 0x202F -#define WGL_MAX_PBUFFER_HEIGHT_EXT 0x2030 -#define WGL_OPTIMAL_PBUFFER_WIDTH_EXT 0x2031 -#define WGL_OPTIMAL_PBUFFER_HEIGHT_EXT 0x2032 -#define WGL_PBUFFER_LARGEST_EXT 0x2033 -#define WGL_PBUFFER_WIDTH_EXT 0x2034 -#define WGL_PBUFFER_HEIGHT_EXT 0x2035 -#endif - -#ifndef WGL_EXT_depth_float -#define WGL_DEPTH_FLOAT_EXT 0x2040 -#endif - -#ifndef WGL_NV_render_texture_rectangle -#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGB_NV 0x20A0 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_RGBA_NV 0x20A1 -#define WGL_TEXTURE_RECTANGLE_NV 0x20A2 -#endif - -#ifndef WGL_NV_render_depth_texture -#define WGL_TEXTURE_DEPTH_COMPONENT_NV 0x20A6 -#define WGL_DEPTH_TEXTURE_FORMAT_NV 0x20A5 -#define WGL_BIND_TO_TEXTURE_DEPTH_NV 0x20A3 -#define WGL_BIND_TO_TEXTURE_RECTANGLE_DEPTH_NV 0x20A4 -#define WGL_DEPTH_COMPONENT_NV 0x20A7 -#endif - -#ifndef WGL_3DFX_multisample -#define WGL_SAMPLE_BUFFERS_3DFX 0x2060 -#define WGL_SAMPLES_3DFX 0x2061 -#endif - -#ifndef WGL_EXT_multisample -#define WGL_SAMPLE_BUFFERS_EXT 0x2041 -#define WGL_SAMPLES_EXT 0x2042 -#endif - -#ifndef WGL_I3D_unknown_genlock_extension_name -#define WGL_GENLOCK_SOURCE_MULTIVIEW_I3D 0x2044 -#define WGL_GENLOCK_SOURCE_EXTENAL_SYNC_I3D 0x2045 -#define WGL_GENLOCK_SOURCE_EXTENAL_FIELD_I3D 0x2046 -#define WGL_GENLOCK_SOURCE_EXTENAL_TTL_I3D 0x2047 -#define WGL_GENLOCK_SOURCE_DIGITAL_SYNC_I3D 0x2048 -#define WGL_GENLOCK_SOURCE_DIGITAL_FIELD_I3D 0x2049 -#define WGL_GENLOCK_SOURCE_EDGE_FALLING_I3D 0x204A -#define WGL_GENLOCK_SOURCE_EDGE_RISING_I3D 0x204B -#define WGL_GENLOCK_SOURCE_EDGE_BOTH_I3D 0x204C -#endif - -#ifndef WGL_I3D_unknown_gamma_extension_name -#define WGL_GAMMA_TABLE_SIZE_I3D 0x204E -#define WGL_GAMMA_EXCLUDE_DESKTOP_I3D 0x204F -#endif - -#ifndef WGL_I3D_unknown_digital_video_cursor_extension_name -#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_FRAMEBUFFER_I3D 0x2050 -#define WGL_DIGITAL_VIDEO_CURSOR_ALPHA_VALUE_I3D 0x2051 -#define WGL_DIGITAL_VIDEO_CURSOR_INCLUDED_I3D 0x2052 -#define WGL_DIGITAL_VIDEO_GAMMA_CORRECTED_I3D 0x2053 -#endif - - -/*************************************************************/ - -#ifndef WGL_ARB_pbuffer -DECLARE_HANDLE(HPBUFFERARB); -#endif -#ifndef WGL_EXT_pbuffer -DECLARE_HANDLE(HPBUFFEREXT); -#endif - -#ifndef WGL_ARB_buffer_region -#define WGL_ARB_buffer_region 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HANDLE WINAPI wglCreateBufferRegionARB (HDC, int, UINT); -extern VOID WINAPI wglDeleteBufferRegionARB (HANDLE); -extern BOOL WINAPI wglSaveBufferRegionARB (HANDLE, int, int, int, int); -extern BOOL WINAPI wglRestoreBufferRegionARB (HANDLE, int, int, int, int, int, int); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HANDLE (WINAPI * PFNWGLCREATEBUFFERREGIONARBPROC) (HDC hDC, int iLayerPlane, UINT uType); -typedef VOID (WINAPI * PFNWGLDELETEBUFFERREGIONARBPROC) (HANDLE hRegion); -typedef BOOL (WINAPI * PFNWGLSAVEBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height); -typedef BOOL (WINAPI * PFNWGLRESTOREBUFFERREGIONARBPROC) (HANDLE hRegion, int x, int y, int width, int height, int xSrc, int ySrc); -#endif - -#ifndef WGL_ARB_extensions_string -#define WGL_ARB_extensions_string 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern const char * WINAPI wglGetExtensionsStringARB (HDC); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC) (HDC hdc); -#endif - -#ifndef WGL_ARB_pixel_format -#define WGL_ARB_pixel_format 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetPixelFormatAttribivARB (HDC, int, int, UINT, const int *, int *); -extern BOOL WINAPI wglGetPixelFormatAttribfvARB (HDC, int, int, UINT, const int *, FLOAT *); -extern BOOL WINAPI wglChoosePixelFormatARB (HDC, const int *, const FLOAT *, UINT, int *, UINT *); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues); -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVARBPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues); -typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif - -#ifndef WGL_ARB_make_current_read -#define WGL_ARB_make_current_read 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglMakeContextCurrentARB (HDC, HDC, HGLRC); -extern HDC WINAPI wglGetCurrentReadDCARB (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTARBPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCARBPROC) (void); -#endif - -#ifndef WGL_ARB_pbuffer -#define WGL_ARB_pbuffer 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HPBUFFERARB WINAPI wglCreatePbufferARB (HDC, int, int, int, const int *); -extern HDC WINAPI wglGetPbufferDCARB (HPBUFFERARB); -extern int WINAPI wglReleasePbufferDCARB (HPBUFFERARB, HDC); -extern BOOL WINAPI wglDestroyPbufferARB (HPBUFFERARB); -extern BOOL WINAPI wglQueryPbufferARB (HPBUFFERARB, int, int *); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HPBUFFERARB (WINAPI * PFNWGLCREATEPBUFFERARBPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -typedef HDC (WINAPI * PFNWGLGETPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer); -typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCARBPROC) (HPBUFFERARB hPbuffer, HDC hDC); -typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFERARBPROC) (HPBUFFERARB hPbuffer); -typedef BOOL (WINAPI * PFNWGLQUERYPBUFFERARBPROC) (HPBUFFERARB hPbuffer, int iAttribute, int *piValue); -#endif - -#ifndef WGL_EXT_display_color_table -#define WGL_EXT_display_color_table 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern GLboolean WINAPI wglCreateDisplayColorTableEXT (GLushort); -extern GLboolean WINAPI wglLoadDisplayColorTableEXT (const GLushort *, GLuint); -extern GLboolean WINAPI wglBindDisplayColorTableEXT (GLushort); -extern VOID WINAPI wglDestroyDisplayColorTableEXT (GLushort); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef GLboolean (WINAPI * PFNWGLCREATEDISPLAYCOLORTABLEEXTPROC) (GLushort id); -typedef GLboolean (WINAPI * PFNWGLLOADDISPLAYCOLORTABLEEXTPROC) (const GLushort *table, GLuint length); -typedef GLboolean (WINAPI * PFNWGLBINDDISPLAYCOLORTABLEEXTPROC) (GLushort id); -typedef VOID (WINAPI * PFNWGLDESTROYDISPLAYCOLORTABLEEXTPROC) (GLushort id); -#endif - -#ifndef WGL_EXT_extensions_string -#define WGL_EXT_extensions_string 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern const char * WINAPI wglGetExtensionsStringEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef const char * (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC) (void); -#endif - -#ifndef WGL_EXT_make_current_read -#define WGL_EXT_make_current_read 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglMakeContextCurrentEXT (HDC, HDC, HGLRC); -extern HDC WINAPI wglGetCurrentReadDCEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLMAKECONTEXTCURRENTEXTPROC) (HDC hDrawDC, HDC hReadDC, HGLRC hglrc); -typedef HDC (WINAPI * PFNWGLGETCURRENTREADDCEXTPROC) (void); -#endif - -#ifndef WGL_EXT_pbuffer -#define WGL_EXT_pbuffer 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern HPBUFFEREXT WINAPI wglCreatePbufferEXT (HDC, int, int, int, const int *); -extern HDC WINAPI wglGetPbufferDCEXT (HPBUFFEREXT); -extern int WINAPI wglReleasePbufferDCEXT (HPBUFFEREXT, HDC); -extern BOOL WINAPI wglDestroyPbufferEXT (HPBUFFEREXT); -extern BOOL WINAPI wglQueryPbufferEXT (HPBUFFEREXT, int, int *); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef HPBUFFEREXT (WINAPI * PFNWGLCREATEPBUFFEREXTPROC) (HDC hDC, int iPixelFormat, int iWidth, int iHeight, const int *piAttribList); -typedef HDC (WINAPI * PFNWGLGETPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer); -typedef int (WINAPI * PFNWGLRELEASEPBUFFERDCEXTPROC) (HPBUFFEREXT hPbuffer, HDC hDC); -typedef BOOL (WINAPI * PFNWGLDESTROYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer); -typedef BOOL (WINAPI * PFNWGLQUERYPBUFFEREXTPROC) (HPBUFFEREXT hPbuffer, int iAttribute, int *piValue); -#endif - -#ifndef WGL_EXT_pixel_format -#define WGL_EXT_pixel_format 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglGetPixelFormatAttribivEXT (HDC, int, int, UINT, int *, int *); -extern BOOL WINAPI wglGetPixelFormatAttribfvEXT (HDC, int, int, UINT, int *, FLOAT *); -extern BOOL WINAPI wglChoosePixelFormatEXT (HDC, const int *, const FLOAT *, UINT, int *, UINT *); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, int *piValues); -typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBFVEXTPROC) (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, int *piAttributes, FLOAT *pfValues); -typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATEXTPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats); -#endif - -#ifndef WGL_EXT_swap_control -#define WGL_EXT_swap_control 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern BOOL WINAPI wglSwapIntervalEXT (int); -extern int WINAPI wglGetSwapIntervalEXT (void); -#endif /* WGL_WGLEXT_PROTOTYPES */ -typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); -typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC) (void); -#endif - -#ifndef WGL_WGL_EXT_depth_float -#define WGL_WGL_EXT_depth_float 1 -#endif - -#ifndef WGL_WGL_3DFX_multisample -#define WGL_WGL_3DFX_multisample 1 -#endif - -#ifndef WGL_WGL_EXT_multisample -#define WGL_WGL_EXT_multisample 1 -#endif - -/* added by Cass -- but this should already be in here! */ -#ifndef WGL_NV_allocate_memory -#define WGL_NV_allocate_memory 1 -#ifdef WGL_WGLEXT_PROTOTYPES -extern void * wglAllocateMemoryNV(int size, float readfreq, float writefreq, float priority); -extern void wglFreeMemoryNV(void * pointer); -#endif -typedef void * (APIENTRY * PFNWGLALLOCATEMEMORYNVPROC) (int size, float readfreq, float writefreq, float priority); -typedef void (APIENTRY * PFNWGLFREEMEMORYNVPROC) (void *pointer); -#endif - -/* WGL_ARB_render_texture */ -#ifndef WGL_ARB_render_texture -#define WGL_ARB_render_texture 1 -typedef BOOL (WINAPI * PFNWGLBINDTEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); -typedef BOOL (WINAPI * PFNWGLRELEASETEXIMAGEARBPROC) (HPBUFFERARB hPbuffer, int iBuffer); -typedef BOOL (WINAPI * PFNWGLSETPBUFFERATTRIBARBPROC) (HPBUFFERARB hPbuffer, const int * piAttribList); -#endif - -#ifndef WGL_NV_render_texture_rectangle -#define WGL_NV_render_texture_rectangle 1 -#endif - -#ifndef WGL_NV_render_depth_texture -#define WGL_NV_render_depth_texture 1 -#endif - -#ifdef __cplusplus -} -#endif - -#endif - - diff --git a/btgui/OpenGLWindow/GlewWindows/glew.c b/btgui/OpenGLWindow/GlewWindows/glew.c index 1aaee11c3..7726e6375 100644 --- a/btgui/OpenGLWindow/GlewWindows/glew.c +++ b/btgui/OpenGLWindow/GlewWindows/glew.c @@ -29,12 +29,12 @@ ** THE POSSIBILITY OF SUCH DAMAGE. */ -#include +#include "GL/glew.h" #if defined(_WIN32) # include -#elif !defined(__ANDROID__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) -# include "GL/glxew.h" +#elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) +# include #endif /* @@ -166,6 +166,8 @@ void* NSGLGetProcAddress (const GLubyte *name) # define glewGetProcAddress(name) dlGetProcAddress(name) #elif defined(__ANDROID__) # define glewGetProcAddress(name) NULL /* TODO */ +#elif defined(__native_client__) +# define glewGetProcAddress(name) NULL /* TODO */ #else /* __linux */ # define glewGetProcAddress(name) (*glXGetProcAddressARB)(name) #endif @@ -585,6 +587,8 @@ PFNGLBLENDEQUATIONSEPARATEINDEXEDAMDPROC __glewBlendEquationSeparateIndexedAMD = PFNGLBLENDFUNCINDEXEDAMDPROC __glewBlendFuncIndexedAMD = NULL; PFNGLBLENDFUNCSEPARATEINDEXEDAMDPROC __glewBlendFuncSeparateIndexedAMD = NULL; +PFNGLVERTEXATTRIBPARAMETERIAMDPROC __glewVertexAttribParameteriAMD = NULL; + PFNGLMULTIDRAWARRAYSINDIRECTAMDPROC __glewMultiDrawArraysIndirectAMD = NULL; PFNGLMULTIDRAWELEMENTSINDIRECTAMDPROC __glewMultiDrawElementsIndirectAMD = NULL; @@ -606,11 +610,36 @@ PFNGLSELECTPERFMONITORCOUNTERSAMDPROC __glewSelectPerfMonitorCountersAMD = NULL; PFNGLSETMULTISAMPLEFVAMDPROC __glewSetMultisamplefvAMD = NULL; +PFNGLTEXSTORAGESPARSEAMDPROC __glewTexStorageSparseAMD = NULL; +PFNGLTEXTURESTORAGESPARSEAMDPROC __glewTextureStorageSparseAMD = NULL; + PFNGLSTENCILOPVALUEAMDPROC __glewStencilOpValueAMD = NULL; PFNGLTESSELLATIONFACTORAMDPROC __glewTessellationFactorAMD = NULL; PFNGLTESSELLATIONMODEAMDPROC __glewTessellationModeAMD = NULL; +PFNGLBLITFRAMEBUFFERANGLEPROC __glewBlitFramebufferANGLE = NULL; + +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC __glewRenderbufferStorageMultisampleANGLE = NULL; + +PFNGLDRAWARRAYSINSTANCEDANGLEPROC __glewDrawArraysInstancedANGLE = NULL; +PFNGLDRAWELEMENTSINSTANCEDANGLEPROC __glewDrawElementsInstancedANGLE = NULL; +PFNGLVERTEXATTRIBDIVISORANGLEPROC __glewVertexAttribDivisorANGLE = NULL; + +PFNGLBEGINQUERYANGLEPROC __glewBeginQueryANGLE = NULL; +PFNGLDELETEQUERIESANGLEPROC __glewDeleteQueriesANGLE = NULL; +PFNGLENDQUERYANGLEPROC __glewEndQueryANGLE = NULL; +PFNGLGENQUERIESANGLEPROC __glewGenQueriesANGLE = NULL; +PFNGLGETQUERYOBJECTI64VANGLEPROC __glewGetQueryObjecti64vANGLE = NULL; +PFNGLGETQUERYOBJECTIVANGLEPROC __glewGetQueryObjectivANGLE = NULL; +PFNGLGETQUERYOBJECTUI64VANGLEPROC __glewGetQueryObjectui64vANGLE = NULL; +PFNGLGETQUERYOBJECTUIVANGLEPROC __glewGetQueryObjectuivANGLE = NULL; +PFNGLGETQUERYIVANGLEPROC __glewGetQueryivANGLE = NULL; +PFNGLISQUERYANGLEPROC __glewIsQueryANGLE = NULL; +PFNGLQUERYCOUNTERANGLEPROC __glewQueryCounterANGLE = NULL; + +PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC __glewGetTranslatedShaderSourceANGLE = NULL; + PFNGLDRAWELEMENTARRAYAPPLEPROC __glewDrawElementArrayAPPLE = NULL; PFNGLDRAWRANGEELEMENTARRAYAPPLEPROC __glewDrawRangeElementArrayAPPLE = NULL; PFNGLELEMENTPOINTERAPPLEPROC __glewElementPointerAPPLE = NULL; @@ -663,9 +692,29 @@ PFNGLDRAWARRAYSINSTANCEDBASEINSTANCEPROC __glewDrawArraysInstancedBaseInstance = PFNGLDRAWELEMENTSINSTANCEDBASEINSTANCEPROC __glewDrawElementsInstancedBaseInstance = NULL; PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC __glewDrawElementsInstancedBaseVertexBaseInstance = NULL; +PFNGLGETIMAGEHANDLEARBPROC __glewGetImageHandleARB = NULL; +PFNGLGETTEXTUREHANDLEARBPROC __glewGetTextureHandleARB = NULL; +PFNGLGETTEXTURESAMPLERHANDLEARBPROC __glewGetTextureSamplerHandleARB = NULL; +PFNGLGETVERTEXATTRIBLUI64VARBPROC __glewGetVertexAttribLui64vARB = NULL; +PFNGLISIMAGEHANDLERESIDENTARBPROC __glewIsImageHandleResidentARB = NULL; +PFNGLISTEXTUREHANDLERESIDENTARBPROC __glewIsTextureHandleResidentARB = NULL; +PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC __glewMakeImageHandleNonResidentARB = NULL; +PFNGLMAKEIMAGEHANDLERESIDENTARBPROC __glewMakeImageHandleResidentARB = NULL; +PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC __glewMakeTextureHandleNonResidentARB = NULL; +PFNGLMAKETEXTUREHANDLERESIDENTARBPROC __glewMakeTextureHandleResidentARB = NULL; +PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC __glewProgramUniformHandleui64ARB = NULL; +PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC __glewProgramUniformHandleui64vARB = NULL; +PFNGLUNIFORMHANDLEUI64ARBPROC __glewUniformHandleui64ARB = NULL; +PFNGLUNIFORMHANDLEUI64VARBPROC __glewUniformHandleui64vARB = NULL; +PFNGLVERTEXATTRIBL1UI64ARBPROC __glewVertexAttribL1ui64ARB = NULL; +PFNGLVERTEXATTRIBL1UI64VARBPROC __glewVertexAttribL1ui64vARB = NULL; + PFNGLBINDFRAGDATALOCATIONINDEXEDPROC __glewBindFragDataLocationIndexed = NULL; PFNGLGETFRAGDATAINDEXPROC __glewGetFragDataIndex = NULL; +PFNGLBUFFERSTORAGEPROC __glewBufferStorage = NULL; +PFNGLNAMEDBUFFERSTORAGEEXTPROC __glewNamedBufferStorageEXT = NULL; + PFNGLCREATESYNCFROMCLEVENTARBPROC __glewCreateSyncFromCLeventARB = NULL; PFNGLCLEARBUFFERDATAPROC __glewClearBufferData = NULL; @@ -673,11 +722,16 @@ PFNGLCLEARBUFFERSUBDATAPROC __glewClearBufferSubData = NULL; PFNGLCLEARNAMEDBUFFERDATAEXTPROC __glewClearNamedBufferDataEXT = NULL; PFNGLCLEARNAMEDBUFFERSUBDATAEXTPROC __glewClearNamedBufferSubDataEXT = NULL; +PFNGLCLEARTEXIMAGEPROC __glewClearTexImage = NULL; +PFNGLCLEARTEXSUBIMAGEPROC __glewClearTexSubImage = NULL; + PFNGLCLAMPCOLORARBPROC __glewClampColorARB = NULL; PFNGLDISPATCHCOMPUTEPROC __glewDispatchCompute = NULL; PFNGLDISPATCHCOMPUTEINDIRECTPROC __glewDispatchComputeIndirect = NULL; +PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC __glewDispatchComputeGroupSizeARB = NULL; + PFNGLCOPYBUFFERSUBDATAPROC __glewCopyBufferSubData = NULL; PFNGLCOPYIMAGESUBDATAPROC __glewCopyImageSubData = NULL; @@ -789,6 +843,9 @@ PFNGLRESETHISTOGRAMPROC __glewResetHistogram = NULL; PFNGLRESETMINMAXPROC __glewResetMinmax = NULL; PFNGLSEPARABLEFILTER2DPROC __glewSeparableFilter2D = NULL; +PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC __glewMultiDrawArraysIndirectCountARB = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC __glewMultiDrawElementsIndirectCountARB = NULL; + PFNGLDRAWARRAYSINSTANCEDARBPROC __glewDrawArraysInstancedARB = NULL; PFNGLDRAWELEMENTSINSTANCEDARBPROC __glewDrawElementsInstancedARB = NULL; PFNGLVERTEXATTRIBDIVISORARBPROC __glewVertexAttribDivisorARB = NULL; @@ -813,6 +870,13 @@ PFNGLMATRIXINDEXUBVARBPROC __glewMatrixIndexubvARB = NULL; PFNGLMATRIXINDEXUIVARBPROC __glewMatrixIndexuivARB = NULL; PFNGLMATRIXINDEXUSVARBPROC __glewMatrixIndexusvARB = NULL; +PFNGLBINDBUFFERSBASEPROC __glewBindBuffersBase = NULL; +PFNGLBINDBUFFERSRANGEPROC __glewBindBuffersRange = NULL; +PFNGLBINDIMAGETEXTURESPROC __glewBindImageTextures = NULL; +PFNGLBINDSAMPLERSPROC __glewBindSamplers = NULL; +PFNGLBINDTEXTURESPROC __glewBindTextures = NULL; +PFNGLBINDVERTEXBUFFERSPROC __glewBindVertexBuffers = NULL; + PFNGLMULTIDRAWARRAYSINDIRECTPROC __glewMultiDrawArraysIndirect = NULL; PFNGLMULTIDRAWELEMENTSINDIRECTPROC __glewMultiDrawElementsIndirect = NULL; @@ -1036,6 +1100,9 @@ PFNGLGETNAMEDSTRINGIVARBPROC __glewGetNamedStringivARB = NULL; PFNGLISNAMEDSTRINGARBPROC __glewIsNamedStringARB = NULL; PFNGLNAMEDSTRINGARBPROC __glewNamedStringARB = NULL; +PFNGLTEXPAGECOMMITMENTARBPROC __glewTexPageCommitmentARB = NULL; +PFNGLTEXTUREPAGECOMMITMENTEXTPROC __glewTexturePageCommitmentEXT = NULL; + PFNGLCLIENTWAITSYNCPROC __glewClientWaitSync = NULL; PFNGLDELETESYNCPROC __glewDeleteSync = NULL; PFNGLFENCESYNCPROC __glewFenceSync = NULL; @@ -1596,55 +1663,38 @@ PFNGLNAMEDPROGRAMSTRINGEXTPROC __glewNamedProgramStringEXT = NULL; PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC __glewNamedRenderbufferStorageEXT = NULL; PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC __glewNamedRenderbufferStorageMultisampleCoverageEXT = NULL; PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC __glewNamedRenderbufferStorageMultisampleEXT = NULL; -PFNGLPROGRAMUNIFORM1DEXTPROC __glewProgramUniform1dEXT = NULL; -PFNGLPROGRAMUNIFORM1DVEXTPROC __glewProgramUniform1dvEXT = NULL; PFNGLPROGRAMUNIFORM1FEXTPROC __glewProgramUniform1fEXT = NULL; PFNGLPROGRAMUNIFORM1FVEXTPROC __glewProgramUniform1fvEXT = NULL; PFNGLPROGRAMUNIFORM1IEXTPROC __glewProgramUniform1iEXT = NULL; PFNGLPROGRAMUNIFORM1IVEXTPROC __glewProgramUniform1ivEXT = NULL; PFNGLPROGRAMUNIFORM1UIEXTPROC __glewProgramUniform1uiEXT = NULL; PFNGLPROGRAMUNIFORM1UIVEXTPROC __glewProgramUniform1uivEXT = NULL; -PFNGLPROGRAMUNIFORM2DEXTPROC __glewProgramUniform2dEXT = NULL; -PFNGLPROGRAMUNIFORM2DVEXTPROC __glewProgramUniform2dvEXT = NULL; PFNGLPROGRAMUNIFORM2FEXTPROC __glewProgramUniform2fEXT = NULL; PFNGLPROGRAMUNIFORM2FVEXTPROC __glewProgramUniform2fvEXT = NULL; PFNGLPROGRAMUNIFORM2IEXTPROC __glewProgramUniform2iEXT = NULL; PFNGLPROGRAMUNIFORM2IVEXTPROC __glewProgramUniform2ivEXT = NULL; PFNGLPROGRAMUNIFORM2UIEXTPROC __glewProgramUniform2uiEXT = NULL; PFNGLPROGRAMUNIFORM2UIVEXTPROC __glewProgramUniform2uivEXT = NULL; -PFNGLPROGRAMUNIFORM3DEXTPROC __glewProgramUniform3dEXT = NULL; -PFNGLPROGRAMUNIFORM3DVEXTPROC __glewProgramUniform3dvEXT = NULL; PFNGLPROGRAMUNIFORM3FEXTPROC __glewProgramUniform3fEXT = NULL; PFNGLPROGRAMUNIFORM3FVEXTPROC __glewProgramUniform3fvEXT = NULL; PFNGLPROGRAMUNIFORM3IEXTPROC __glewProgramUniform3iEXT = NULL; PFNGLPROGRAMUNIFORM3IVEXTPROC __glewProgramUniform3ivEXT = NULL; PFNGLPROGRAMUNIFORM3UIEXTPROC __glewProgramUniform3uiEXT = NULL; PFNGLPROGRAMUNIFORM3UIVEXTPROC __glewProgramUniform3uivEXT = NULL; -PFNGLPROGRAMUNIFORM4DEXTPROC __glewProgramUniform4dEXT = NULL; -PFNGLPROGRAMUNIFORM4DVEXTPROC __glewProgramUniform4dvEXT = NULL; PFNGLPROGRAMUNIFORM4FEXTPROC __glewProgramUniform4fEXT = NULL; PFNGLPROGRAMUNIFORM4FVEXTPROC __glewProgramUniform4fvEXT = NULL; PFNGLPROGRAMUNIFORM4IEXTPROC __glewProgramUniform4iEXT = NULL; PFNGLPROGRAMUNIFORM4IVEXTPROC __glewProgramUniform4ivEXT = NULL; PFNGLPROGRAMUNIFORM4UIEXTPROC __glewProgramUniform4uiEXT = NULL; PFNGLPROGRAMUNIFORM4UIVEXTPROC __glewProgramUniform4uivEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC __glewProgramUniformMatrix2dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC __glewProgramUniformMatrix2fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC __glewProgramUniformMatrix2x3dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC __glewProgramUniformMatrix2x3fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC __glewProgramUniformMatrix2x4dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC __glewProgramUniformMatrix2x4fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC __glewProgramUniformMatrix3dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC __glewProgramUniformMatrix3fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC __glewProgramUniformMatrix3x2dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC __glewProgramUniformMatrix3x2fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC __glewProgramUniformMatrix3x4dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC __glewProgramUniformMatrix3x4fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC __glewProgramUniformMatrix4dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC __glewProgramUniformMatrix4fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC __glewProgramUniformMatrix4x2dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC __glewProgramUniformMatrix4x2fvEXT = NULL; -PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC __glewProgramUniformMatrix4x3dvEXT = NULL; PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC __glewProgramUniformMatrix4x3fvEXT = NULL; PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC __glewPushClientAttribDefaultEXT = NULL; PFNGLTEXTUREBUFFEREXTPROC __glewTextureBufferEXT = NULL; @@ -1979,6 +2029,10 @@ PFNGLSECONDARYCOLORPOINTERLISTIBMPROC __glewSecondaryColorPointerListIBM = NULL; PFNGLTEXCOORDPOINTERLISTIBMPROC __glewTexCoordPointerListIBM = NULL; PFNGLVERTEXPOINTERLISTIBMPROC __glewVertexPointerListIBM = NULL; +PFNGLMAPTEXTURE2DINTELPROC __glewMapTexture2DINTEL = NULL; +PFNGLSYNCTEXTUREINTELPROC __glewSyncTextureINTEL = NULL; +PFNGLUNMAPTEXTURE2DINTELPROC __glewUnmapTexture2DINTEL = NULL; + PFNGLCOLORPOINTERVINTELPROC __glewColorPointervINTEL = NULL; PFNGLNORMALPOINTERVINTELPROC __glewNormalPointervINTEL = NULL; PFNGLTEXCOORDPOINTERVINTELPROC __glewTexCoordPointervINTEL = NULL; @@ -1993,9 +2047,9 @@ PFNGLDEBUGMESSAGEINSERTPROC __glewDebugMessageInsert = NULL; PFNGLGETDEBUGMESSAGELOGPROC __glewGetDebugMessageLog = NULL; PFNGLGETOBJECTLABELPROC __glewGetObjectLabel = NULL; PFNGLGETOBJECTPTRLABELPROC __glewGetObjectPtrLabel = NULL; -PFNGLGETPOINTERVPROC __glewGetPointerv = NULL; PFNGLOBJECTLABELPROC __glewObjectLabel = NULL; PFNGLOBJECTPTRLABELPROC __glewObjectPtrLabel = NULL; +PFNGLPOPDEBUGGROUPPROC __glewPopDebugGroup = NULL; PFNGLPUSHDEBUGGROUPPROC __glewPushDebugGroup = NULL; PFNGLBUFFERREGIONENABLEDPROC __glewBufferRegionEnabled = NULL; @@ -2031,6 +2085,12 @@ PFNGLWINDOWPOS4IVMESAPROC __glewWindowPos4ivMESA = NULL; PFNGLWINDOWPOS4SMESAPROC __glewWindowPos4sMESA = NULL; PFNGLWINDOWPOS4SVMESAPROC __glewWindowPos4svMESA = NULL; +PFNGLBEGINCONDITIONALRENDERNVXPROC __glewBeginConditionalRenderNVX = NULL; +PFNGLENDCONDITIONALRENDERNVXPROC __glewEndConditionalRenderNVX = NULL; + +PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC __glewMultiDrawArraysIndirectBindlessNV = NULL; +PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC __glewMultiDrawElementsIndirectBindlessNV = NULL; + PFNGLGETIMAGEHANDLENVPROC __glewGetImageHandleNV = NULL; PFNGLGETTEXTUREHANDLENVPROC __glewGetTextureHandleNV = NULL; PFNGLGETTEXTURESAMPLERHANDLENVPROC __glewGetTextureSamplerHandleNV = NULL; @@ -2045,6 +2105,9 @@ PFNGLPROGRAMUNIFORMHANDLEUI64VNVPROC __glewProgramUniformHandleui64vNV = NULL; PFNGLUNIFORMHANDLEUI64NVPROC __glewUniformHandleui64NV = NULL; PFNGLUNIFORMHANDLEUI64VNVPROC __glewUniformHandleui64vNV = NULL; +PFNGLBLENDBARRIERNVPROC __glewBlendBarrierNV = NULL; +PFNGLBLENDPARAMETERINVPROC __glewBlendParameteriNV = NULL; + PFNGLBEGINCONDITIONALRENDERNVPROC __glewBeginConditionalRenderNV = NULL; PFNGLENDCONDITIONALRENDERNVPROC __glewEndConditionalRenderNV = NULL; @@ -2054,6 +2117,8 @@ PFNGLCLEARDEPTHDNVPROC __glewClearDepthdNV = NULL; PFNGLDEPTHBOUNDSDNVPROC __glewDepthBoundsdNV = NULL; PFNGLDEPTHRANGEDNVPROC __glewDepthRangedNV = NULL; +PFNGLDRAWTEXTURENVPROC __glewDrawTextureNV = NULL; + PFNGLEVALMAPSNVPROC __glewEvalMapsNV = NULL; PFNGLGETMAPATTRIBPARAMETERFVNVPROC __glewGetMapAttribParameterfvNV = NULL; PFNGLGETMAPATTRIBPARAMETERIVNVPROC __glewGetMapAttribParameterivNV = NULL; @@ -2452,11 +2517,59 @@ PFNGLFRUSTUMFOESPROC __glewFrustumfOES = NULL; PFNGLGETCLIPPLANEFOESPROC __glewGetClipPlanefOES = NULL; PFNGLORTHOFOESPROC __glewOrthofOES = NULL; +PFNGLALPHAFUNCXPROC __glewAlphaFuncx = NULL; +PFNGLCLEARCOLORXPROC __glewClearColorx = NULL; +PFNGLCLEARDEPTHXPROC __glewClearDepthx = NULL; +PFNGLCOLOR4XPROC __glewColor4x = NULL; +PFNGLDEPTHRANGEXPROC __glewDepthRangex = NULL; +PFNGLFOGXPROC __glewFogx = NULL; +PFNGLFOGXVPROC __glewFogxv = NULL; +PFNGLFRUSTUMFPROC __glewFrustumf = NULL; +PFNGLFRUSTUMXPROC __glewFrustumx = NULL; +PFNGLLIGHTMODELXPROC __glewLightModelx = NULL; +PFNGLLIGHTMODELXVPROC __glewLightModelxv = NULL; +PFNGLLIGHTXPROC __glewLightx = NULL; +PFNGLLIGHTXVPROC __glewLightxv = NULL; +PFNGLLINEWIDTHXPROC __glewLineWidthx = NULL; +PFNGLLOADMATRIXXPROC __glewLoadMatrixx = NULL; +PFNGLMATERIALXPROC __glewMaterialx = NULL; +PFNGLMATERIALXVPROC __glewMaterialxv = NULL; +PFNGLMULTMATRIXXPROC __glewMultMatrixx = NULL; +PFNGLMULTITEXCOORD4XPROC __glewMultiTexCoord4x = NULL; +PFNGLNORMAL3XPROC __glewNormal3x = NULL; +PFNGLORTHOFPROC __glewOrthof = NULL; +PFNGLORTHOXPROC __glewOrthox = NULL; +PFNGLPOINTSIZEXPROC __glewPointSizex = NULL; +PFNGLPOLYGONOFFSETXPROC __glewPolygonOffsetx = NULL; +PFNGLROTATEXPROC __glewRotatex = NULL; +PFNGLSAMPLECOVERAGEXPROC __glewSampleCoveragex = NULL; +PFNGLSCALEXPROC __glewScalex = NULL; +PFNGLTEXENVXPROC __glewTexEnvx = NULL; +PFNGLTEXENVXVPROC __glewTexEnvxv = NULL; +PFNGLTEXPARAMETERXPROC __glewTexParameterx = NULL; +PFNGLTRANSLATEXPROC __glewTranslatex = NULL; + +PFNGLCLIPPLANEFPROC __glewClipPlanef = NULL; +PFNGLCLIPPLANEXPROC __glewClipPlanex = NULL; +PFNGLGETCLIPPLANEFPROC __glewGetClipPlanef = NULL; +PFNGLGETCLIPPLANEXPROC __glewGetClipPlanex = NULL; +PFNGLGETFIXEDVPROC __glewGetFixedv = NULL; +PFNGLGETLIGHTXVPROC __glewGetLightxv = NULL; +PFNGLGETMATERIALXVPROC __glewGetMaterialxv = NULL; +PFNGLGETTEXENVXVPROC __glewGetTexEnvxv = NULL; +PFNGLGETTEXPARAMETERXVPROC __glewGetTexParameterxv = NULL; +PFNGLPOINTPARAMETERXPROC __glewPointParameterx = NULL; +PFNGLPOINTPARAMETERXVPROC __glewPointParameterxv = NULL; +PFNGLPOINTSIZEPOINTEROESPROC __glewPointSizePointerOES = NULL; +PFNGLTEXPARAMETERXVPROC __glewTexParameterxv = NULL; + PFNGLERRORSTRINGREGALPROC __glewErrorStringREGAL = NULL; PFNGLGETEXTENSIONREGALPROC __glewGetExtensionREGAL = NULL; PFNGLISSUPPORTEDREGALPROC __glewIsSupportedREGAL = NULL; +PFNGLLOGMESSAGECALLBACKREGALPROC __glewLogMessageCallbackREGAL = NULL; + PFNGLDETAILTEXFUNCSGISPROC __glewDetailTexFuncSGIS = NULL; PFNGLGETDETAILTEXFUNCSGISPROC __glewGetDetailTexFuncSGIS = NULL; @@ -2609,6 +2722,7 @@ GLboolean __GLEW_VERSION_4_0 = GL_FALSE; GLboolean __GLEW_VERSION_4_1 = GL_FALSE; GLboolean __GLEW_VERSION_4_2 = GL_FALSE; GLboolean __GLEW_VERSION_4_3 = GL_FALSE; +GLboolean __GLEW_VERSION_4_4 = GL_FALSE; GLboolean __GLEW_3DFX_multisample = GL_FALSE; GLboolean __GLEW_3DFX_tbuffer = GL_FALSE; GLboolean __GLEW_3DFX_texture_compression_FXT1 = GL_FALSE; @@ -2617,6 +2731,7 @@ GLboolean __GLEW_AMD_conservative_depth = GL_FALSE; GLboolean __GLEW_AMD_debug_output = GL_FALSE; GLboolean __GLEW_AMD_depth_clamp_separate = GL_FALSE; GLboolean __GLEW_AMD_draw_buffers_blend = GL_FALSE; +GLboolean __GLEW_AMD_interleaved_elements = GL_FALSE; GLboolean __GLEW_AMD_multi_draw_indirect = GL_FALSE; GLboolean __GLEW_AMD_name_gen_delete = GL_FALSE; GLboolean __GLEW_AMD_performance_monitor = GL_FALSE; @@ -2625,12 +2740,26 @@ GLboolean __GLEW_AMD_query_buffer_object = GL_FALSE; GLboolean __GLEW_AMD_sample_positions = GL_FALSE; GLboolean __GLEW_AMD_seamless_cubemap_per_texture = GL_FALSE; GLboolean __GLEW_AMD_shader_stencil_export = GL_FALSE; +GLboolean __GLEW_AMD_shader_trinary_minmax = GL_FALSE; +GLboolean __GLEW_AMD_sparse_texture = GL_FALSE; GLboolean __GLEW_AMD_stencil_operation_extended = GL_FALSE; GLboolean __GLEW_AMD_texture_texture4 = GL_FALSE; GLboolean __GLEW_AMD_transform_feedback3_lines_triangles = GL_FALSE; GLboolean __GLEW_AMD_vertex_shader_layer = GL_FALSE; GLboolean __GLEW_AMD_vertex_shader_tessellator = GL_FALSE; GLboolean __GLEW_AMD_vertex_shader_viewport_index = GL_FALSE; +GLboolean __GLEW_ANGLE_depth_texture = GL_FALSE; +GLboolean __GLEW_ANGLE_framebuffer_blit = GL_FALSE; +GLboolean __GLEW_ANGLE_framebuffer_multisample = GL_FALSE; +GLboolean __GLEW_ANGLE_instanced_arrays = GL_FALSE; +GLboolean __GLEW_ANGLE_pack_reverse_row_order = GL_FALSE; +GLboolean __GLEW_ANGLE_program_binary = GL_FALSE; +GLboolean __GLEW_ANGLE_texture_compression_dxt1 = GL_FALSE; +GLboolean __GLEW_ANGLE_texture_compression_dxt3 = GL_FALSE; +GLboolean __GLEW_ANGLE_texture_compression_dxt5 = GL_FALSE; +GLboolean __GLEW_ANGLE_texture_usage = GL_FALSE; +GLboolean __GLEW_ANGLE_timer_query = GL_FALSE; +GLboolean __GLEW_ANGLE_translated_shader_source = GL_FALSE; GLboolean __GLEW_APPLE_aux_depth_stencil = GL_FALSE; GLboolean __GLEW_APPLE_client_storage = GL_FALSE; GLboolean __GLEW_APPLE_element_array = GL_FALSE; @@ -2652,13 +2781,17 @@ GLboolean __GLEW_ARB_ES2_compatibility = GL_FALSE; GLboolean __GLEW_ARB_ES3_compatibility = GL_FALSE; GLboolean __GLEW_ARB_arrays_of_arrays = GL_FALSE; GLboolean __GLEW_ARB_base_instance = GL_FALSE; +GLboolean __GLEW_ARB_bindless_texture = GL_FALSE; GLboolean __GLEW_ARB_blend_func_extended = GL_FALSE; +GLboolean __GLEW_ARB_buffer_storage = GL_FALSE; GLboolean __GLEW_ARB_cl_event = GL_FALSE; GLboolean __GLEW_ARB_clear_buffer_object = GL_FALSE; +GLboolean __GLEW_ARB_clear_texture = GL_FALSE; GLboolean __GLEW_ARB_color_buffer_float = GL_FALSE; GLboolean __GLEW_ARB_compatibility = GL_FALSE; GLboolean __GLEW_ARB_compressed_texture_pixel_storage = GL_FALSE; GLboolean __GLEW_ARB_compute_shader = GL_FALSE; +GLboolean __GLEW_ARB_compute_variable_group_size = GL_FALSE; GLboolean __GLEW_ARB_conservative_depth = GL_FALSE; GLboolean __GLEW_ARB_copy_buffer = GL_FALSE; GLboolean __GLEW_ARB_copy_image = GL_FALSE; @@ -2671,6 +2804,7 @@ GLboolean __GLEW_ARB_draw_buffers_blend = GL_FALSE; GLboolean __GLEW_ARB_draw_elements_base_vertex = GL_FALSE; GLboolean __GLEW_ARB_draw_indirect = GL_FALSE; GLboolean __GLEW_ARB_draw_instanced = GL_FALSE; +GLboolean __GLEW_ARB_enhanced_layouts = GL_FALSE; GLboolean __GLEW_ARB_explicit_attrib_location = GL_FALSE; GLboolean __GLEW_ARB_explicit_uniform_location = GL_FALSE; GLboolean __GLEW_ARB_fragment_coord_conventions = GL_FALSE; @@ -2688,6 +2822,7 @@ GLboolean __GLEW_ARB_gpu_shader_fp64 = GL_FALSE; GLboolean __GLEW_ARB_half_float_pixel = GL_FALSE; GLboolean __GLEW_ARB_half_float_vertex = GL_FALSE; GLboolean __GLEW_ARB_imaging = GL_FALSE; +GLboolean __GLEW_ARB_indirect_parameters = GL_FALSE; GLboolean __GLEW_ARB_instanced_arrays = GL_FALSE; GLboolean __GLEW_ARB_internalformat_query = GL_FALSE; GLboolean __GLEW_ARB_internalformat_query2 = GL_FALSE; @@ -2695,6 +2830,7 @@ GLboolean __GLEW_ARB_invalidate_subdata = GL_FALSE; GLboolean __GLEW_ARB_map_buffer_alignment = GL_FALSE; GLboolean __GLEW_ARB_map_buffer_range = GL_FALSE; GLboolean __GLEW_ARB_matrix_palette = GL_FALSE; +GLboolean __GLEW_ARB_multi_bind = GL_FALSE; GLboolean __GLEW_ARB_multi_draw_indirect = GL_FALSE; GLboolean __GLEW_ARB_multisample = GL_FALSE; GLboolean __GLEW_ARB_multitexture = GL_FALSE; @@ -2705,6 +2841,7 @@ GLboolean __GLEW_ARB_point_parameters = GL_FALSE; GLboolean __GLEW_ARB_point_sprite = GL_FALSE; GLboolean __GLEW_ARB_program_interface_query = GL_FALSE; GLboolean __GLEW_ARB_provoking_vertex = GL_FALSE; +GLboolean __GLEW_ARB_query_buffer_object = GL_FALSE; GLboolean __GLEW_ARB_robust_buffer_access_behavior = GL_FALSE; GLboolean __GLEW_ARB_robustness = GL_FALSE; GLboolean __GLEW_ARB_robustness_application_isolation = GL_FALSE; @@ -2712,9 +2849,12 @@ GLboolean __GLEW_ARB_robustness_share_group_isolation = GL_FALSE; GLboolean __GLEW_ARB_sample_shading = GL_FALSE; GLboolean __GLEW_ARB_sampler_objects = GL_FALSE; GLboolean __GLEW_ARB_seamless_cube_map = GL_FALSE; +GLboolean __GLEW_ARB_seamless_cubemap_per_texture = GL_FALSE; GLboolean __GLEW_ARB_separate_shader_objects = GL_FALSE; GLboolean __GLEW_ARB_shader_atomic_counters = GL_FALSE; GLboolean __GLEW_ARB_shader_bit_encoding = GL_FALSE; +GLboolean __GLEW_ARB_shader_draw_parameters = GL_FALSE; +GLboolean __GLEW_ARB_shader_group_vote = GL_FALSE; GLboolean __GLEW_ARB_shader_image_load_store = GL_FALSE; GLboolean __GLEW_ARB_shader_image_size = GL_FALSE; GLboolean __GLEW_ARB_shader_objects = GL_FALSE; @@ -2729,6 +2869,7 @@ GLboolean __GLEW_ARB_shading_language_include = GL_FALSE; GLboolean __GLEW_ARB_shading_language_packing = GL_FALSE; GLboolean __GLEW_ARB_shadow = GL_FALSE; GLboolean __GLEW_ARB_shadow_ambient = GL_FALSE; +GLboolean __GLEW_ARB_sparse_texture = GL_FALSE; GLboolean __GLEW_ARB_stencil_texturing = GL_FALSE; GLboolean __GLEW_ARB_sync = GL_FALSE; GLboolean __GLEW_ARB_tessellation_shader = GL_FALSE; @@ -2747,6 +2888,7 @@ GLboolean __GLEW_ARB_texture_env_crossbar = GL_FALSE; GLboolean __GLEW_ARB_texture_env_dot3 = GL_FALSE; GLboolean __GLEW_ARB_texture_float = GL_FALSE; GLboolean __GLEW_ARB_texture_gather = GL_FALSE; +GLboolean __GLEW_ARB_texture_mirror_clamp_to_edge = GL_FALSE; GLboolean __GLEW_ARB_texture_mirrored_repeat = GL_FALSE; GLboolean __GLEW_ARB_texture_multisample = GL_FALSE; GLboolean __GLEW_ARB_texture_non_power_of_two = GL_FALSE; @@ -2755,6 +2897,7 @@ GLboolean __GLEW_ARB_texture_query_lod = GL_FALSE; GLboolean __GLEW_ARB_texture_rectangle = GL_FALSE; GLboolean __GLEW_ARB_texture_rg = GL_FALSE; GLboolean __GLEW_ARB_texture_rgb10_a2ui = GL_FALSE; +GLboolean __GLEW_ARB_texture_stencil8 = GL_FALSE; GLboolean __GLEW_ARB_texture_storage = GL_FALSE; GLboolean __GLEW_ARB_texture_storage_multisample = GL_FALSE; GLboolean __GLEW_ARB_texture_swizzle = GL_FALSE; @@ -2773,6 +2916,7 @@ GLboolean __GLEW_ARB_vertex_blend = GL_FALSE; GLboolean __GLEW_ARB_vertex_buffer_object = GL_FALSE; GLboolean __GLEW_ARB_vertex_program = GL_FALSE; GLboolean __GLEW_ARB_vertex_shader = GL_FALSE; +GLboolean __GLEW_ARB_vertex_type_10f_11f_11f_rev = GL_FALSE; GLboolean __GLEW_ARB_vertex_type_2_10_10_10_rev = GL_FALSE; GLboolean __GLEW_ARB_viewport_array = GL_FALSE; GLboolean __GLEW_ARB_window_pos = GL_FALSE; @@ -2911,6 +3055,7 @@ GLboolean __GLEW_IBM_texture_mirrored_repeat = GL_FALSE; GLboolean __GLEW_IBM_vertex_array_lists = GL_FALSE; GLboolean __GLEW_INGR_color_clamp = GL_FALSE; GLboolean __GLEW_INGR_interlace_read = GL_FALSE; +GLboolean __GLEW_INTEL_map_texture = GL_FALSE; GLboolean __GLEW_INTEL_parallel_arrays = GL_FALSE; GLboolean __GLEW_INTEL_texture_scissor = GL_FALSE; GLboolean __GLEW_KHR_debug = GL_FALSE; @@ -2921,15 +3066,22 @@ GLboolean __GLEW_MESA_pack_invert = GL_FALSE; GLboolean __GLEW_MESA_resize_buffers = GL_FALSE; GLboolean __GLEW_MESA_window_pos = GL_FALSE; GLboolean __GLEW_MESA_ycbcr_texture = GL_FALSE; +GLboolean __GLEW_NVX_conditional_render = GL_FALSE; GLboolean __GLEW_NVX_gpu_memory_info = GL_FALSE; +GLboolean __GLEW_NV_bindless_multi_draw_indirect = GL_FALSE; GLboolean __GLEW_NV_bindless_texture = GL_FALSE; +GLboolean __GLEW_NV_blend_equation_advanced = GL_FALSE; +GLboolean __GLEW_NV_blend_equation_advanced_coherent = GL_FALSE; GLboolean __GLEW_NV_blend_square = GL_FALSE; +GLboolean __GLEW_NV_compute_program5 = GL_FALSE; GLboolean __GLEW_NV_conditional_render = GL_FALSE; GLboolean __GLEW_NV_copy_depth_to_color = GL_FALSE; GLboolean __GLEW_NV_copy_image = GL_FALSE; +GLboolean __GLEW_NV_deep_texture3D = GL_FALSE; GLboolean __GLEW_NV_depth_buffer_float = GL_FALSE; GLboolean __GLEW_NV_depth_clamp = GL_FALSE; GLboolean __GLEW_NV_depth_range_unclamped = GL_FALSE; +GLboolean __GLEW_NV_draw_texture = GL_FALSE; GLboolean __GLEW_NV_evaluators = GL_FALSE; GLboolean __GLEW_NV_explicit_multisample = GL_FALSE; GLboolean __GLEW_NV_fence = GL_FALSE; @@ -2944,6 +3096,7 @@ GLboolean __GLEW_NV_geometry_program4 = GL_FALSE; GLboolean __GLEW_NV_geometry_shader4 = GL_FALSE; GLboolean __GLEW_NV_gpu_program4 = GL_FALSE; GLboolean __GLEW_NV_gpu_program5 = GL_FALSE; +GLboolean __GLEW_NV_gpu_program5_mem_extended = GL_FALSE; GLboolean __GLEW_NV_gpu_program_fp64 = GL_FALSE; GLboolean __GLEW_NV_gpu_shader5 = GL_FALSE; GLboolean __GLEW_NV_half_float = GL_FALSE; @@ -2961,8 +3114,10 @@ GLboolean __GLEW_NV_present_video = GL_FALSE; GLboolean __GLEW_NV_primitive_restart = GL_FALSE; GLboolean __GLEW_NV_register_combiners = GL_FALSE; GLboolean __GLEW_NV_register_combiners2 = GL_FALSE; +GLboolean __GLEW_NV_shader_atomic_counters = GL_FALSE; GLboolean __GLEW_NV_shader_atomic_float = GL_FALSE; GLboolean __GLEW_NV_shader_buffer_load = GL_FALSE; +GLboolean __GLEW_NV_shader_storage_buffer_object = GL_FALSE; GLboolean __GLEW_NV_tessellation_program5 = GL_FALSE; GLboolean __GLEW_NV_texgen_emboss = GL_FALSE; GLboolean __GLEW_NV_texgen_reflection = GL_FALSE; @@ -2998,6 +3153,9 @@ GLboolean __GLEW_OML_resample = GL_FALSE; GLboolean __GLEW_OML_subsample = GL_FALSE; GLboolean __GLEW_PGI_misc_hints = GL_FALSE; GLboolean __GLEW_PGI_vertex_hints = GL_FALSE; +GLboolean __GLEW_REGAL_ES1_0_compatibility = GL_FALSE; +GLboolean __GLEW_REGAL_ES1_1_compatibility = GL_FALSE; +GLboolean __GLEW_REGAL_enable = GL_FALSE; GLboolean __GLEW_REGAL_error_string = GL_FALSE; GLboolean __GLEW_REGAL_extension_query = GL_FALSE; GLboolean __GLEW_REGAL_log = GL_FALSE; @@ -3497,6 +3655,10 @@ static GLboolean _glewInit_GL_VERSION_4_0 (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_VERSION_4_3 */ +#ifdef GL_VERSION_4_4 + +#endif /* GL_VERSION_4_4 */ + #ifdef GL_3DFX_multisample #endif /* GL_3DFX_multisample */ @@ -3562,6 +3724,19 @@ static GLboolean _glewInit_GL_AMD_draw_buffers_blend (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_AMD_draw_buffers_blend */ +#ifdef GL_AMD_interleaved_elements + +static GLboolean _glewInit_GL_AMD_interleaved_elements (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glVertexAttribParameteriAMD = (PFNGLVERTEXATTRIBPARAMETERIAMDPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribParameteriAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_interleaved_elements */ + #ifdef GL_AMD_multi_draw_indirect static GLboolean _glewInit_GL_AMD_multi_draw_indirect (GLEW_CONTEXT_ARG_DEF_INIT) @@ -3643,6 +3818,24 @@ static GLboolean _glewInit_GL_AMD_sample_positions (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_AMD_shader_stencil_export */ +#ifdef GL_AMD_shader_trinary_minmax + +#endif /* GL_AMD_shader_trinary_minmax */ + +#ifdef GL_AMD_sparse_texture + +static GLboolean _glewInit_GL_AMD_sparse_texture (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glTexStorageSparseAMD = (PFNGLTEXSTORAGESPARSEAMDPROC)glewGetProcAddress((const GLubyte*)"glTexStorageSparseAMD")) == NULL) || r; + r = ((glTextureStorageSparseAMD = (PFNGLTEXTURESTORAGESPARSEAMDPROC)glewGetProcAddress((const GLubyte*)"glTextureStorageSparseAMD")) == NULL) || r; + + return r; +} + +#endif /* GL_AMD_sparse_texture */ + #ifdef GL_AMD_stencil_operation_extended static GLboolean _glewInit_GL_AMD_stencil_operation_extended (GLEW_CONTEXT_ARG_DEF_INIT) @@ -3686,6 +3879,111 @@ static GLboolean _glewInit_GL_AMD_vertex_shader_tessellator (GLEW_CONTEXT_ARG_DE #endif /* GL_AMD_vertex_shader_viewport_index */ +#ifdef GL_ANGLE_depth_texture + +#endif /* GL_ANGLE_depth_texture */ + +#ifdef GL_ANGLE_framebuffer_blit + +static GLboolean _glewInit_GL_ANGLE_framebuffer_blit (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glBlitFramebufferANGLE = (PFNGLBLITFRAMEBUFFERANGLEPROC)glewGetProcAddress((const GLubyte*)"glBlitFramebufferANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_framebuffer_blit */ + +#ifdef GL_ANGLE_framebuffer_multisample + +static GLboolean _glewInit_GL_ANGLE_framebuffer_multisample (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glRenderbufferStorageMultisampleANGLE = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC)glewGetProcAddress((const GLubyte*)"glRenderbufferStorageMultisampleANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_framebuffer_multisample */ + +#ifdef GL_ANGLE_instanced_arrays + +static GLboolean _glewInit_GL_ANGLE_instanced_arrays (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glDrawArraysInstancedANGLE = (PFNGLDRAWARRAYSINSTANCEDANGLEPROC)glewGetProcAddress((const GLubyte*)"glDrawArraysInstancedANGLE")) == NULL) || r; + r = ((glDrawElementsInstancedANGLE = (PFNGLDRAWELEMENTSINSTANCEDANGLEPROC)glewGetProcAddress((const GLubyte*)"glDrawElementsInstancedANGLE")) == NULL) || r; + r = ((glVertexAttribDivisorANGLE = (PFNGLVERTEXATTRIBDIVISORANGLEPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribDivisorANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_instanced_arrays */ + +#ifdef GL_ANGLE_pack_reverse_row_order + +#endif /* GL_ANGLE_pack_reverse_row_order */ + +#ifdef GL_ANGLE_program_binary + +#endif /* GL_ANGLE_program_binary */ + +#ifdef GL_ANGLE_texture_compression_dxt1 + +#endif /* GL_ANGLE_texture_compression_dxt1 */ + +#ifdef GL_ANGLE_texture_compression_dxt3 + +#endif /* GL_ANGLE_texture_compression_dxt3 */ + +#ifdef GL_ANGLE_texture_compression_dxt5 + +#endif /* GL_ANGLE_texture_compression_dxt5 */ + +#ifdef GL_ANGLE_texture_usage + +#endif /* GL_ANGLE_texture_usage */ + +#ifdef GL_ANGLE_timer_query + +static GLboolean _glewInit_GL_ANGLE_timer_query (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glBeginQueryANGLE = (PFNGLBEGINQUERYANGLEPROC)glewGetProcAddress((const GLubyte*)"glBeginQueryANGLE")) == NULL) || r; + r = ((glDeleteQueriesANGLE = (PFNGLDELETEQUERIESANGLEPROC)glewGetProcAddress((const GLubyte*)"glDeleteQueriesANGLE")) == NULL) || r; + r = ((glEndQueryANGLE = (PFNGLENDQUERYANGLEPROC)glewGetProcAddress((const GLubyte*)"glEndQueryANGLE")) == NULL) || r; + r = ((glGenQueriesANGLE = (PFNGLGENQUERIESANGLEPROC)glewGetProcAddress((const GLubyte*)"glGenQueriesANGLE")) == NULL) || r; + r = ((glGetQueryObjecti64vANGLE = (PFNGLGETQUERYOBJECTI64VANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjecti64vANGLE")) == NULL) || r; + r = ((glGetQueryObjectivANGLE = (PFNGLGETQUERYOBJECTIVANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectivANGLE")) == NULL) || r; + r = ((glGetQueryObjectui64vANGLE = (PFNGLGETQUERYOBJECTUI64VANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectui64vANGLE")) == NULL) || r; + r = ((glGetQueryObjectuivANGLE = (PFNGLGETQUERYOBJECTUIVANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryObjectuivANGLE")) == NULL) || r; + r = ((glGetQueryivANGLE = (PFNGLGETQUERYIVANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetQueryivANGLE")) == NULL) || r; + r = ((glIsQueryANGLE = (PFNGLISQUERYANGLEPROC)glewGetProcAddress((const GLubyte*)"glIsQueryANGLE")) == NULL) || r; + r = ((glQueryCounterANGLE = (PFNGLQUERYCOUNTERANGLEPROC)glewGetProcAddress((const GLubyte*)"glQueryCounterANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_timer_query */ + +#ifdef GL_ANGLE_translated_shader_source + +static GLboolean _glewInit_GL_ANGLE_translated_shader_source (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glGetTranslatedShaderSourceANGLE = (PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC)glewGetProcAddress((const GLubyte*)"glGetTranslatedShaderSourceANGLE")) == NULL) || r; + + return r; +} + +#endif /* GL_ANGLE_translated_shader_source */ + #ifdef GL_APPLE_aux_depth_stencil #endif /* GL_APPLE_aux_depth_stencil */ @@ -3892,6 +4190,34 @@ static GLboolean _glewInit_GL_ARB_base_instance (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_ARB_base_instance */ +#ifdef GL_ARB_bindless_texture + +static GLboolean _glewInit_GL_ARB_bindless_texture (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glGetImageHandleARB = (PFNGLGETIMAGEHANDLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetImageHandleARB")) == NULL) || r; + r = ((glGetTextureHandleARB = (PFNGLGETTEXTUREHANDLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetTextureHandleARB")) == NULL) || r; + r = ((glGetTextureSamplerHandleARB = (PFNGLGETTEXTURESAMPLERHANDLEARBPROC)glewGetProcAddress((const GLubyte*)"glGetTextureSamplerHandleARB")) == NULL) || r; + r = ((glGetVertexAttribLui64vARB = (PFNGLGETVERTEXATTRIBLUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glGetVertexAttribLui64vARB")) == NULL) || r; + r = ((glIsImageHandleResidentARB = (PFNGLISIMAGEHANDLERESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glIsImageHandleResidentARB")) == NULL) || r; + r = ((glIsTextureHandleResidentARB = (PFNGLISTEXTUREHANDLERESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glIsTextureHandleResidentARB")) == NULL) || r; + r = ((glMakeImageHandleNonResidentARB = (PFNGLMAKEIMAGEHANDLENONRESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glMakeImageHandleNonResidentARB")) == NULL) || r; + r = ((glMakeImageHandleResidentARB = (PFNGLMAKEIMAGEHANDLERESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glMakeImageHandleResidentARB")) == NULL) || r; + r = ((glMakeTextureHandleNonResidentARB = (PFNGLMAKETEXTUREHANDLENONRESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glMakeTextureHandleNonResidentARB")) == NULL) || r; + r = ((glMakeTextureHandleResidentARB = (PFNGLMAKETEXTUREHANDLERESIDENTARBPROC)glewGetProcAddress((const GLubyte*)"glMakeTextureHandleResidentARB")) == NULL) || r; + r = ((glProgramUniformHandleui64ARB = (PFNGLPROGRAMUNIFORMHANDLEUI64ARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformHandleui64ARB")) == NULL) || r; + r = ((glProgramUniformHandleui64vARB = (PFNGLPROGRAMUNIFORMHANDLEUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformHandleui64vARB")) == NULL) || r; + r = ((glUniformHandleui64ARB = (PFNGLUNIFORMHANDLEUI64ARBPROC)glewGetProcAddress((const GLubyte*)"glUniformHandleui64ARB")) == NULL) || r; + r = ((glUniformHandleui64vARB = (PFNGLUNIFORMHANDLEUI64VARBPROC)glewGetProcAddress((const GLubyte*)"glUniformHandleui64vARB")) == NULL) || r; + r = ((glVertexAttribL1ui64ARB = (PFNGLVERTEXATTRIBL1UI64ARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1ui64ARB")) == NULL) || r; + r = ((glVertexAttribL1ui64vARB = (PFNGLVERTEXATTRIBL1UI64VARBPROC)glewGetProcAddress((const GLubyte*)"glVertexAttribL1ui64vARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_bindless_texture */ + #ifdef GL_ARB_blend_func_extended static GLboolean _glewInit_GL_ARB_blend_func_extended (GLEW_CONTEXT_ARG_DEF_INIT) @@ -3906,6 +4232,20 @@ static GLboolean _glewInit_GL_ARB_blend_func_extended (GLEW_CONTEXT_ARG_DEF_INIT #endif /* GL_ARB_blend_func_extended */ +#ifdef GL_ARB_buffer_storage + +static GLboolean _glewInit_GL_ARB_buffer_storage (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glBufferStorage = (PFNGLBUFFERSTORAGEPROC)glewGetProcAddress((const GLubyte*)"glBufferStorage")) == NULL) || r; + r = ((glNamedBufferStorageEXT = (PFNGLNAMEDBUFFERSTORAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedBufferStorageEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_buffer_storage */ + #ifdef GL_ARB_cl_event static GLboolean _glewInit_GL_ARB_cl_event (GLEW_CONTEXT_ARG_DEF_INIT) @@ -3935,6 +4275,20 @@ static GLboolean _glewInit_GL_ARB_clear_buffer_object (GLEW_CONTEXT_ARG_DEF_INIT #endif /* GL_ARB_clear_buffer_object */ +#ifdef GL_ARB_clear_texture + +static GLboolean _glewInit_GL_ARB_clear_texture (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)glewGetProcAddress((const GLubyte*)"glClearTexImage")) == NULL) || r; + r = ((glClearTexSubImage = (PFNGLCLEARTEXSUBIMAGEPROC)glewGetProcAddress((const GLubyte*)"glClearTexSubImage")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_clear_texture */ + #ifdef GL_ARB_color_buffer_float static GLboolean _glewInit_GL_ARB_color_buffer_float (GLEW_CONTEXT_ARG_DEF_INIT) @@ -3970,6 +4324,19 @@ static GLboolean _glewInit_GL_ARB_compute_shader (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_ARB_compute_shader */ +#ifdef GL_ARB_compute_variable_group_size + +static GLboolean _glewInit_GL_ARB_compute_variable_group_size (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glDispatchComputeGroupSizeARB = (PFNGLDISPATCHCOMPUTEGROUPSIZEARBPROC)glewGetProcAddress((const GLubyte*)"glDispatchComputeGroupSizeARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_compute_variable_group_size */ + #ifdef GL_ARB_conservative_depth #endif /* GL_ARB_conservative_depth */ @@ -4091,6 +4458,10 @@ static GLboolean _glewInit_GL_ARB_draw_indirect (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_ARB_draw_instanced */ +#ifdef GL_ARB_enhanced_layouts + +#endif /* GL_ARB_enhanced_layouts */ + #ifdef GL_ARB_explicit_attrib_location #endif /* GL_ARB_explicit_attrib_location */ @@ -4289,6 +4660,20 @@ static GLboolean _glewInit_GL_ARB_imaging (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_ARB_imaging */ +#ifdef GL_ARB_indirect_parameters + +static GLboolean _glewInit_GL_ARB_indirect_parameters (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirectCountARB = (PFNGLMULTIDRAWARRAYSINDIRECTCOUNTARBPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectCountARB")) == NULL) || r; + r = ((glMultiDrawElementsIndirectCountARB = (PFNGLMULTIDRAWELEMENTSINDIRECTCOUNTARBPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectCountARB")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_indirect_parameters */ + #ifdef GL_ARB_instanced_arrays static GLboolean _glewInit_GL_ARB_instanced_arrays (GLEW_CONTEXT_ARG_DEF_INIT) @@ -4383,6 +4768,24 @@ static GLboolean _glewInit_GL_ARB_matrix_palette (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_ARB_matrix_palette */ +#ifdef GL_ARB_multi_bind + +static GLboolean _glewInit_GL_ARB_multi_bind (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glBindBuffersBase = (PFNGLBINDBUFFERSBASEPROC)glewGetProcAddress((const GLubyte*)"glBindBuffersBase")) == NULL) || r; + r = ((glBindBuffersRange = (PFNGLBINDBUFFERSRANGEPROC)glewGetProcAddress((const GLubyte*)"glBindBuffersRange")) == NULL) || r; + r = ((glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)glewGetProcAddress((const GLubyte*)"glBindImageTextures")) == NULL) || r; + r = ((glBindSamplers = (PFNGLBINDSAMPLERSPROC)glewGetProcAddress((const GLubyte*)"glBindSamplers")) == NULL) || r; + r = ((glBindTextures = (PFNGLBINDTEXTURESPROC)glewGetProcAddress((const GLubyte*)"glBindTextures")) == NULL) || r; + r = ((glBindVertexBuffers = (PFNGLBINDVERTEXBUFFERSPROC)glewGetProcAddress((const GLubyte*)"glBindVertexBuffers")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_multi_bind */ + #ifdef GL_ARB_multi_draw_indirect static GLboolean _glewInit_GL_ARB_multi_draw_indirect (GLEW_CONTEXT_ARG_DEF_INIT) @@ -4533,6 +4936,10 @@ static GLboolean _glewInit_GL_ARB_provoking_vertex (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_ARB_provoking_vertex */ +#ifdef GL_ARB_query_buffer_object + +#endif /* GL_ARB_query_buffer_object */ + #ifdef GL_ARB_robust_buffer_access_behavior #endif /* GL_ARB_robust_buffer_access_behavior */ @@ -4620,6 +5027,10 @@ static GLboolean _glewInit_GL_ARB_sampler_objects (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_ARB_seamless_cube_map */ +#ifdef GL_ARB_seamless_cubemap_per_texture + +#endif /* GL_ARB_seamless_cubemap_per_texture */ + #ifdef GL_ARB_separate_shader_objects static GLboolean _glewInit_GL_ARB_separate_shader_objects (GLEW_CONTEXT_ARG_DEF_INIT) @@ -4709,6 +5120,14 @@ static GLboolean _glewInit_GL_ARB_shader_atomic_counters (GLEW_CONTEXT_ARG_DEF_I #endif /* GL_ARB_shader_bit_encoding */ +#ifdef GL_ARB_shader_draw_parameters + +#endif /* GL_ARB_shader_draw_parameters */ + +#ifdef GL_ARB_shader_group_vote + +#endif /* GL_ARB_shader_group_vote */ + #ifdef GL_ARB_shader_image_load_store static GLboolean _glewInit_GL_ARB_shader_image_load_store (GLEW_CONTEXT_ARG_DEF_INIT) @@ -4861,6 +5280,20 @@ static GLboolean _glewInit_GL_ARB_shading_language_include (GLEW_CONTEXT_ARG_DEF #endif /* GL_ARB_shadow_ambient */ +#ifdef GL_ARB_sparse_texture + +static GLboolean _glewInit_GL_ARB_sparse_texture (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glTexPageCommitmentARB = (PFNGLTEXPAGECOMMITMENTARBPROC)glewGetProcAddress((const GLubyte*)"glTexPageCommitmentARB")) == NULL) || r; + r = ((glTexturePageCommitmentEXT = (PFNGLTEXTUREPAGECOMMITMENTEXTPROC)glewGetProcAddress((const GLubyte*)"glTexturePageCommitmentEXT")) == NULL) || r; + + return r; +} + +#endif /* GL_ARB_sparse_texture */ + #ifdef GL_ARB_stencil_texturing #endif /* GL_ARB_stencil_texturing */ @@ -4992,6 +5425,10 @@ static GLboolean _glewInit_GL_ARB_texture_compression (GLEW_CONTEXT_ARG_DEF_INIT #endif /* GL_ARB_texture_gather */ +#ifdef GL_ARB_texture_mirror_clamp_to_edge + +#endif /* GL_ARB_texture_mirror_clamp_to_edge */ + #ifdef GL_ARB_texture_mirrored_repeat #endif /* GL_ARB_texture_mirrored_repeat */ @@ -5036,6 +5473,10 @@ static GLboolean _glewInit_GL_ARB_texture_multisample (GLEW_CONTEXT_ARG_DEF_INIT #endif /* GL_ARB_texture_rgb10_a2ui */ +#ifdef GL_ARB_texture_stencil8 + +#endif /* GL_ARB_texture_stencil8 */ + #ifdef GL_ARB_texture_storage static GLboolean _glewInit_GL_ARB_texture_storage (GLEW_CONTEXT_ARG_DEF_INIT) @@ -5383,6 +5824,10 @@ static GLboolean _glewInit_GL_ARB_vertex_shader (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_ARB_vertex_shader */ +#ifdef GL_ARB_vertex_type_10f_11f_11f_rev + +#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ + #ifdef GL_ARB_vertex_type_2_10_10_10_rev static GLboolean _glewInit_GL_ARB_vertex_type_2_10_10_10_rev (GLEW_CONTEXT_ARG_DEF_INIT) @@ -6119,55 +6564,38 @@ static GLboolean _glewInit_GL_EXT_direct_state_access (GLEW_CONTEXT_ARG_DEF_INIT r = ((glNamedRenderbufferStorageEXT = (PFNGLNAMEDRENDERBUFFERSTORAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorageEXT")) == NULL) || r; r = ((glNamedRenderbufferStorageMultisampleCoverageEXT = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLECOVERAGEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorageMultisampleCoverageEXT")) == NULL) || r; r = ((glNamedRenderbufferStorageMultisampleEXT = (PFNGLNAMEDRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)glewGetProcAddress((const GLubyte*)"glNamedRenderbufferStorageMultisampleEXT")) == NULL) || r; - r = ((glProgramUniform1dEXT = (PFNGLPROGRAMUNIFORM1DEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1dEXT")) == NULL) || r; - r = ((glProgramUniform1dvEXT = (PFNGLPROGRAMUNIFORM1DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1dvEXT")) == NULL) || r; r = ((glProgramUniform1fEXT = (PFNGLPROGRAMUNIFORM1FEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1fEXT")) == NULL) || r; r = ((glProgramUniform1fvEXT = (PFNGLPROGRAMUNIFORM1FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1fvEXT")) == NULL) || r; r = ((glProgramUniform1iEXT = (PFNGLPROGRAMUNIFORM1IEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1iEXT")) == NULL) || r; r = ((glProgramUniform1ivEXT = (PFNGLPROGRAMUNIFORM1IVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1ivEXT")) == NULL) || r; r = ((glProgramUniform1uiEXT = (PFNGLPROGRAMUNIFORM1UIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1uiEXT")) == NULL) || r; r = ((glProgramUniform1uivEXT = (PFNGLPROGRAMUNIFORM1UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform1uivEXT")) == NULL) || r; - r = ((glProgramUniform2dEXT = (PFNGLPROGRAMUNIFORM2DEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2dEXT")) == NULL) || r; - r = ((glProgramUniform2dvEXT = (PFNGLPROGRAMUNIFORM2DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2dvEXT")) == NULL) || r; r = ((glProgramUniform2fEXT = (PFNGLPROGRAMUNIFORM2FEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2fEXT")) == NULL) || r; r = ((glProgramUniform2fvEXT = (PFNGLPROGRAMUNIFORM2FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2fvEXT")) == NULL) || r; r = ((glProgramUniform2iEXT = (PFNGLPROGRAMUNIFORM2IEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2iEXT")) == NULL) || r; r = ((glProgramUniform2ivEXT = (PFNGLPROGRAMUNIFORM2IVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2ivEXT")) == NULL) || r; r = ((glProgramUniform2uiEXT = (PFNGLPROGRAMUNIFORM2UIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2uiEXT")) == NULL) || r; r = ((glProgramUniform2uivEXT = (PFNGLPROGRAMUNIFORM2UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform2uivEXT")) == NULL) || r; - r = ((glProgramUniform3dEXT = (PFNGLPROGRAMUNIFORM3DEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3dEXT")) == NULL) || r; - r = ((glProgramUniform3dvEXT = (PFNGLPROGRAMUNIFORM3DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3dvEXT")) == NULL) || r; r = ((glProgramUniform3fEXT = (PFNGLPROGRAMUNIFORM3FEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3fEXT")) == NULL) || r; r = ((glProgramUniform3fvEXT = (PFNGLPROGRAMUNIFORM3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3fvEXT")) == NULL) || r; r = ((glProgramUniform3iEXT = (PFNGLPROGRAMUNIFORM3IEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3iEXT")) == NULL) || r; r = ((glProgramUniform3ivEXT = (PFNGLPROGRAMUNIFORM3IVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3ivEXT")) == NULL) || r; r = ((glProgramUniform3uiEXT = (PFNGLPROGRAMUNIFORM3UIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3uiEXT")) == NULL) || r; r = ((glProgramUniform3uivEXT = (PFNGLPROGRAMUNIFORM3UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform3uivEXT")) == NULL) || r; - r = ((glProgramUniform4dEXT = (PFNGLPROGRAMUNIFORM4DEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4dEXT")) == NULL) || r; - r = ((glProgramUniform4dvEXT = (PFNGLPROGRAMUNIFORM4DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4dvEXT")) == NULL) || r; r = ((glProgramUniform4fEXT = (PFNGLPROGRAMUNIFORM4FEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4fEXT")) == NULL) || r; r = ((glProgramUniform4fvEXT = (PFNGLPROGRAMUNIFORM4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4fvEXT")) == NULL) || r; r = ((glProgramUniform4iEXT = (PFNGLPROGRAMUNIFORM4IEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4iEXT")) == NULL) || r; r = ((glProgramUniform4ivEXT = (PFNGLPROGRAMUNIFORM4IVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4ivEXT")) == NULL) || r; r = ((glProgramUniform4uiEXT = (PFNGLPROGRAMUNIFORM4UIEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4uiEXT")) == NULL) || r; r = ((glProgramUniform4uivEXT = (PFNGLPROGRAMUNIFORM4UIVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniform4uivEXT")) == NULL) || r; - r = ((glProgramUniformMatrix2dvEXT = (PFNGLPROGRAMUNIFORMMATRIX2DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2fvEXT")) == NULL) || r; - r = ((glProgramUniformMatrix2x3dvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X3DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x3dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix2x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x3fvEXT")) == NULL) || r; - r = ((glProgramUniformMatrix2x4dvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X4DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x4dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix2x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX2X4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix2x4fvEXT")) == NULL) || r; - r = ((glProgramUniformMatrix3dvEXT = (PFNGLPROGRAMUNIFORMMATRIX3DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3fvEXT")) == NULL) || r; - r = ((glProgramUniformMatrix3x2dvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X2DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x2dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix3x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X2FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x2fvEXT")) == NULL) || r; - r = ((glProgramUniformMatrix3x4dvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X4DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x4dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix3x4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX3X4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix3x4fvEXT")) == NULL) || r; - r = ((glProgramUniformMatrix4dvEXT = (PFNGLPROGRAMUNIFORMMATRIX4DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix4fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4fvEXT")) == NULL) || r; - r = ((glProgramUniformMatrix4x2dvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X2DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x2dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix4x2fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X2FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x2fvEXT")) == NULL) || r; - r = ((glProgramUniformMatrix4x3dvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X3DVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x3dvEXT")) == NULL) || r; r = ((glProgramUniformMatrix4x3fvEXT = (PFNGLPROGRAMUNIFORMMATRIX4X3FVEXTPROC)glewGetProcAddress((const GLubyte*)"glProgramUniformMatrix4x3fvEXT")) == NULL) || r; r = ((glPushClientAttribDefaultEXT = (PFNGLPUSHCLIENTATTRIBDEFAULTEXTPROC)glewGetProcAddress((const GLubyte*)"glPushClientAttribDefaultEXT")) == NULL) || r; r = ((glTextureBufferEXT = (PFNGLTEXTUREBUFFEREXTPROC)glewGetProcAddress((const GLubyte*)"glTextureBufferEXT")) == NULL) || r; @@ -7197,6 +7625,21 @@ static GLboolean _glewInit_GL_IBM_vertex_array_lists (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_INGR_interlace_read */ +#ifdef GL_INTEL_map_texture + +static GLboolean _glewInit_GL_INTEL_map_texture (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glMapTexture2DINTEL = (PFNGLMAPTEXTURE2DINTELPROC)glewGetProcAddress((const GLubyte*)"glMapTexture2DINTEL")) == NULL) || r; + r = ((glSyncTextureINTEL = (PFNGLSYNCTEXTUREINTELPROC)glewGetProcAddress((const GLubyte*)"glSyncTextureINTEL")) == NULL) || r; + r = ((glUnmapTexture2DINTEL = (PFNGLUNMAPTEXTURE2DINTELPROC)glewGetProcAddress((const GLubyte*)"glUnmapTexture2DINTEL")) == NULL) || r; + + return r; +} + +#endif /* GL_INTEL_map_texture */ + #ifdef GL_INTEL_parallel_arrays static GLboolean _glewInit_GL_INTEL_parallel_arrays (GLEW_CONTEXT_ARG_DEF_INIT) @@ -7239,9 +7682,9 @@ static GLboolean _glewInit_GL_KHR_debug (GLEW_CONTEXT_ARG_DEF_INIT) r = ((glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC)glewGetProcAddress((const GLubyte*)"glGetDebugMessageLog")) == NULL) || r; r = ((glGetObjectLabel = (PFNGLGETOBJECTLABELPROC)glewGetProcAddress((const GLubyte*)"glGetObjectLabel")) == NULL) || r; r = ((glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC)glewGetProcAddress((const GLubyte*)"glGetObjectPtrLabel")) == NULL) || r; - r = ((glGetPointerv = (PFNGLGETPOINTERVPROC)glewGetProcAddress((const GLubyte*)"glGetPointerv")) == NULL) || r; r = ((glObjectLabel = (PFNGLOBJECTLABELPROC)glewGetProcAddress((const GLubyte*)"glObjectLabel")) == NULL) || r; r = ((glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC)glewGetProcAddress((const GLubyte*)"glObjectPtrLabel")) == NULL) || r; + r = ((glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC)glewGetProcAddress((const GLubyte*)"glPopDebugGroup")) == NULL) || r; r = ((glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC)glewGetProcAddress((const GLubyte*)"glPushDebugGroup")) == NULL) || r; return r; @@ -7331,10 +7774,38 @@ static GLboolean _glewInit_GL_MESA_window_pos (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_MESA_ycbcr_texture */ +#ifdef GL_NVX_conditional_render + +static GLboolean _glewInit_GL_NVX_conditional_render (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glBeginConditionalRenderNVX = (PFNGLBEGINCONDITIONALRENDERNVXPROC)glewGetProcAddress((const GLubyte*)"glBeginConditionalRenderNVX")) == NULL) || r; + r = ((glEndConditionalRenderNVX = (PFNGLENDCONDITIONALRENDERNVXPROC)glewGetProcAddress((const GLubyte*)"glEndConditionalRenderNVX")) == NULL) || r; + + return r; +} + +#endif /* GL_NVX_conditional_render */ + #ifdef GL_NVX_gpu_memory_info #endif /* GL_NVX_gpu_memory_info */ +#ifdef GL_NV_bindless_multi_draw_indirect + +static GLboolean _glewInit_GL_NV_bindless_multi_draw_indirect (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glMultiDrawArraysIndirectBindlessNV = (PFNGLMULTIDRAWARRAYSINDIRECTBINDLESSNVPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawArraysIndirectBindlessNV")) == NULL) || r; + r = ((glMultiDrawElementsIndirectBindlessNV = (PFNGLMULTIDRAWELEMENTSINDIRECTBINDLESSNVPROC)glewGetProcAddress((const GLubyte*)"glMultiDrawElementsIndirectBindlessNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_bindless_multi_draw_indirect */ + #ifdef GL_NV_bindless_texture static GLboolean _glewInit_GL_NV_bindless_texture (GLEW_CONTEXT_ARG_DEF_INIT) @@ -7360,10 +7831,32 @@ static GLboolean _glewInit_GL_NV_bindless_texture (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_NV_bindless_texture */ +#ifdef GL_NV_blend_equation_advanced + +static GLboolean _glewInit_GL_NV_blend_equation_advanced (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glBlendBarrierNV = (PFNGLBLENDBARRIERNVPROC)glewGetProcAddress((const GLubyte*)"glBlendBarrierNV")) == NULL) || r; + r = ((glBlendParameteriNV = (PFNGLBLENDPARAMETERINVPROC)glewGetProcAddress((const GLubyte*)"glBlendParameteriNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_blend_equation_advanced */ + +#ifdef GL_NV_blend_equation_advanced_coherent + +#endif /* GL_NV_blend_equation_advanced_coherent */ + #ifdef GL_NV_blend_square #endif /* GL_NV_blend_square */ +#ifdef GL_NV_compute_program5 + +#endif /* GL_NV_compute_program5 */ + #ifdef GL_NV_conditional_render static GLboolean _glewInit_GL_NV_conditional_render (GLEW_CONTEXT_ARG_DEF_INIT) @@ -7395,6 +7888,10 @@ static GLboolean _glewInit_GL_NV_copy_image (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_NV_copy_image */ +#ifdef GL_NV_deep_texture3D + +#endif /* GL_NV_deep_texture3D */ + #ifdef GL_NV_depth_buffer_float static GLboolean _glewInit_GL_NV_depth_buffer_float (GLEW_CONTEXT_ARG_DEF_INIT) @@ -7418,6 +7915,19 @@ static GLboolean _glewInit_GL_NV_depth_buffer_float (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_NV_depth_range_unclamped */ +#ifdef GL_NV_draw_texture + +static GLboolean _glewInit_GL_NV_draw_texture (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glDrawTextureNV = (PFNGLDRAWTEXTURENVPROC)glewGetProcAddress((const GLubyte*)"glDrawTextureNV")) == NULL) || r; + + return r; +} + +#endif /* GL_NV_draw_texture */ + #ifdef GL_NV_evaluators static GLboolean _glewInit_GL_NV_evaluators (GLEW_CONTEXT_ARG_DEF_INIT) @@ -7569,6 +8079,10 @@ static GLboolean _glewInit_GL_NV_gpu_program4 (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_NV_gpu_program5 */ +#ifdef GL_NV_gpu_program5_mem_extended + +#endif /* GL_NV_gpu_program5_mem_extended */ + #ifdef GL_NV_gpu_program_fp64 #endif /* GL_NV_gpu_program_fp64 */ @@ -7891,6 +8405,10 @@ static GLboolean _glewInit_GL_NV_register_combiners2 (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_NV_register_combiners2 */ +#ifdef GL_NV_shader_atomic_counters + +#endif /* GL_NV_shader_atomic_counters */ + #ifdef GL_NV_shader_atomic_float #endif /* GL_NV_shader_atomic_float */ @@ -7920,6 +8438,10 @@ static GLboolean _glewInit_GL_NV_shader_buffer_load (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_NV_shader_buffer_load */ +#ifdef GL_NV_shader_storage_buffer_object + +#endif /* GL_NV_shader_storage_buffer_object */ + #ifdef GL_NV_tessellation_program5 #endif /* GL_NV_tessellation_program5 */ @@ -8298,6 +8820,78 @@ static GLboolean _glewInit_GL_OES_single_precision (GLEW_CONTEXT_ARG_DEF_INIT) #endif /* GL_PGI_vertex_hints */ +#ifdef GL_REGAL_ES1_0_compatibility + +static GLboolean _glewInit_GL_REGAL_ES1_0_compatibility (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glAlphaFuncx = (PFNGLALPHAFUNCXPROC)glewGetProcAddress((const GLubyte*)"glAlphaFuncx")) == NULL) || r; + r = ((glClearColorx = (PFNGLCLEARCOLORXPROC)glewGetProcAddress((const GLubyte*)"glClearColorx")) == NULL) || r; + r = ((glClearDepthx = (PFNGLCLEARDEPTHXPROC)glewGetProcAddress((const GLubyte*)"glClearDepthx")) == NULL) || r; + r = ((glColor4x = (PFNGLCOLOR4XPROC)glewGetProcAddress((const GLubyte*)"glColor4x")) == NULL) || r; + r = ((glDepthRangex = (PFNGLDEPTHRANGEXPROC)glewGetProcAddress((const GLubyte*)"glDepthRangex")) == NULL) || r; + r = ((glFogx = (PFNGLFOGXPROC)glewGetProcAddress((const GLubyte*)"glFogx")) == NULL) || r; + r = ((glFogxv = (PFNGLFOGXVPROC)glewGetProcAddress((const GLubyte*)"glFogxv")) == NULL) || r; + r = ((glFrustumf = (PFNGLFRUSTUMFPROC)glewGetProcAddress((const GLubyte*)"glFrustumf")) == NULL) || r; + r = ((glFrustumx = (PFNGLFRUSTUMXPROC)glewGetProcAddress((const GLubyte*)"glFrustumx")) == NULL) || r; + r = ((glLightModelx = (PFNGLLIGHTMODELXPROC)glewGetProcAddress((const GLubyte*)"glLightModelx")) == NULL) || r; + r = ((glLightModelxv = (PFNGLLIGHTMODELXVPROC)glewGetProcAddress((const GLubyte*)"glLightModelxv")) == NULL) || r; + r = ((glLightx = (PFNGLLIGHTXPROC)glewGetProcAddress((const GLubyte*)"glLightx")) == NULL) || r; + r = ((glLightxv = (PFNGLLIGHTXVPROC)glewGetProcAddress((const GLubyte*)"glLightxv")) == NULL) || r; + r = ((glLineWidthx = (PFNGLLINEWIDTHXPROC)glewGetProcAddress((const GLubyte*)"glLineWidthx")) == NULL) || r; + r = ((glLoadMatrixx = (PFNGLLOADMATRIXXPROC)glewGetProcAddress((const GLubyte*)"glLoadMatrixx")) == NULL) || r; + r = ((glMaterialx = (PFNGLMATERIALXPROC)glewGetProcAddress((const GLubyte*)"glMaterialx")) == NULL) || r; + r = ((glMaterialxv = (PFNGLMATERIALXVPROC)glewGetProcAddress((const GLubyte*)"glMaterialxv")) == NULL) || r; + r = ((glMultMatrixx = (PFNGLMULTMATRIXXPROC)glewGetProcAddress((const GLubyte*)"glMultMatrixx")) == NULL) || r; + r = ((glMultiTexCoord4x = (PFNGLMULTITEXCOORD4XPROC)glewGetProcAddress((const GLubyte*)"glMultiTexCoord4x")) == NULL) || r; + r = ((glNormal3x = (PFNGLNORMAL3XPROC)glewGetProcAddress((const GLubyte*)"glNormal3x")) == NULL) || r; + r = ((glOrthof = (PFNGLORTHOFPROC)glewGetProcAddress((const GLubyte*)"glOrthof")) == NULL) || r; + r = ((glOrthox = (PFNGLORTHOXPROC)glewGetProcAddress((const GLubyte*)"glOrthox")) == NULL) || r; + r = ((glPointSizex = (PFNGLPOINTSIZEXPROC)glewGetProcAddress((const GLubyte*)"glPointSizex")) == NULL) || r; + r = ((glPolygonOffsetx = (PFNGLPOLYGONOFFSETXPROC)glewGetProcAddress((const GLubyte*)"glPolygonOffsetx")) == NULL) || r; + r = ((glRotatex = (PFNGLROTATEXPROC)glewGetProcAddress((const GLubyte*)"glRotatex")) == NULL) || r; + r = ((glSampleCoveragex = (PFNGLSAMPLECOVERAGEXPROC)glewGetProcAddress((const GLubyte*)"glSampleCoveragex")) == NULL) || r; + r = ((glScalex = (PFNGLSCALEXPROC)glewGetProcAddress((const GLubyte*)"glScalex")) == NULL) || r; + r = ((glTexEnvx = (PFNGLTEXENVXPROC)glewGetProcAddress((const GLubyte*)"glTexEnvx")) == NULL) || r; + r = ((glTexEnvxv = (PFNGLTEXENVXVPROC)glewGetProcAddress((const GLubyte*)"glTexEnvxv")) == NULL) || r; + r = ((glTexParameterx = (PFNGLTEXPARAMETERXPROC)glewGetProcAddress((const GLubyte*)"glTexParameterx")) == NULL) || r; + r = ((glTranslatex = (PFNGLTRANSLATEXPROC)glewGetProcAddress((const GLubyte*)"glTranslatex")) == NULL) || r; + + return r; +} + +#endif /* GL_REGAL_ES1_0_compatibility */ + +#ifdef GL_REGAL_ES1_1_compatibility + +static GLboolean _glewInit_GL_REGAL_ES1_1_compatibility (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glClipPlanef = (PFNGLCLIPPLANEFPROC)glewGetProcAddress((const GLubyte*)"glClipPlanef")) == NULL) || r; + r = ((glClipPlanex = (PFNGLCLIPPLANEXPROC)glewGetProcAddress((const GLubyte*)"glClipPlanex")) == NULL) || r; + r = ((glGetClipPlanef = (PFNGLGETCLIPPLANEFPROC)glewGetProcAddress((const GLubyte*)"glGetClipPlanef")) == NULL) || r; + r = ((glGetClipPlanex = (PFNGLGETCLIPPLANEXPROC)glewGetProcAddress((const GLubyte*)"glGetClipPlanex")) == NULL) || r; + r = ((glGetFixedv = (PFNGLGETFIXEDVPROC)glewGetProcAddress((const GLubyte*)"glGetFixedv")) == NULL) || r; + r = ((glGetLightxv = (PFNGLGETLIGHTXVPROC)glewGetProcAddress((const GLubyte*)"glGetLightxv")) == NULL) || r; + r = ((glGetMaterialxv = (PFNGLGETMATERIALXVPROC)glewGetProcAddress((const GLubyte*)"glGetMaterialxv")) == NULL) || r; + r = ((glGetTexEnvxv = (PFNGLGETTEXENVXVPROC)glewGetProcAddress((const GLubyte*)"glGetTexEnvxv")) == NULL) || r; + r = ((glGetTexParameterxv = (PFNGLGETTEXPARAMETERXVPROC)glewGetProcAddress((const GLubyte*)"glGetTexParameterxv")) == NULL) || r; + r = ((glPointParameterx = (PFNGLPOINTPARAMETERXPROC)glewGetProcAddress((const GLubyte*)"glPointParameterx")) == NULL) || r; + r = ((glPointParameterxv = (PFNGLPOINTPARAMETERXVPROC)glewGetProcAddress((const GLubyte*)"glPointParameterxv")) == NULL) || r; + r = ((glPointSizePointerOES = (PFNGLPOINTSIZEPOINTEROESPROC)glewGetProcAddress((const GLubyte*)"glPointSizePointerOES")) == NULL) || r; + r = ((glTexParameterxv = (PFNGLTEXPARAMETERXVPROC)glewGetProcAddress((const GLubyte*)"glTexParameterxv")) == NULL) || r; + + return r; +} + +#endif /* GL_REGAL_ES1_1_compatibility */ + +#ifdef GL_REGAL_enable + +#endif /* GL_REGAL_enable */ + #ifdef GL_REGAL_error_string static GLboolean _glewInit_GL_REGAL_error_string (GLEW_CONTEXT_ARG_DEF_INIT) @@ -8327,6 +8921,15 @@ static GLboolean _glewInit_GL_REGAL_extension_query (GLEW_CONTEXT_ARG_DEF_INIT) #ifdef GL_REGAL_log +static GLboolean _glewInit_GL_REGAL_log (GLEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glLogMessageCallbackREGAL = (PFNGLLOGMESSAGECALLBACKREGALPROC)glewGetProcAddress((const GLubyte*)"glLogMessageCallbackREGAL")) == NULL) || r; + + return r; +} + #endif /* GL_REGAL_log */ #ifdef GL_REND_screen_coordinates @@ -8909,7 +9512,8 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) } else { - CONST_CAST(GLEW_VERSION_4_3) = ( major > 4 ) || ( major == 4 && minor >= 3 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_4_4) = ( major > 4 ) || ( major == 4 && minor >= 4 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_4_3) = GLEW_VERSION_4_4 == GL_TRUE || ( major == 4 && minor >= 3 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_4_2) = GLEW_VERSION_4_3 == GL_TRUE || ( major == 4 && minor >= 2 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_4_1) = GLEW_VERSION_4_2 == GL_TRUE || ( major == 4 && minor >= 1 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_4_0) = GLEW_VERSION_4_1 == GL_TRUE || ( major == 4 ) ? GL_TRUE : GL_FALSE; @@ -8975,6 +9579,8 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #endif /* GL_VERSION_4_2 */ #ifdef GL_VERSION_4_3 #endif /* GL_VERSION_4_3 */ +#ifdef GL_VERSION_4_4 +#endif /* GL_VERSION_4_4 */ #ifdef GL_3DFX_multisample CONST_CAST(GLEW_3DFX_multisample) = _glewSearchExtension("GL_3DFX_multisample", extStart, extEnd); #endif /* GL_3DFX_multisample */ @@ -9002,6 +9608,10 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_AMD_draw_buffers_blend) = _glewSearchExtension("GL_AMD_draw_buffers_blend", extStart, extEnd); if (glewExperimental || GLEW_AMD_draw_buffers_blend) CONST_CAST(GLEW_AMD_draw_buffers_blend) = !_glewInit_GL_AMD_draw_buffers_blend(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_AMD_draw_buffers_blend */ +#ifdef GL_AMD_interleaved_elements + CONST_CAST(GLEW_AMD_interleaved_elements) = _glewSearchExtension("GL_AMD_interleaved_elements", extStart, extEnd); + if (glewExperimental || GLEW_AMD_interleaved_elements) CONST_CAST(GLEW_AMD_interleaved_elements) = !_glewInit_GL_AMD_interleaved_elements(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_AMD_interleaved_elements */ #ifdef GL_AMD_multi_draw_indirect CONST_CAST(GLEW_AMD_multi_draw_indirect) = _glewSearchExtension("GL_AMD_multi_draw_indirect", extStart, extEnd); if (glewExperimental || GLEW_AMD_multi_draw_indirect) CONST_CAST(GLEW_AMD_multi_draw_indirect) = !_glewInit_GL_AMD_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9030,6 +9640,13 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_AMD_shader_stencil_export CONST_CAST(GLEW_AMD_shader_stencil_export) = _glewSearchExtension("GL_AMD_shader_stencil_export", extStart, extEnd); #endif /* GL_AMD_shader_stencil_export */ +#ifdef GL_AMD_shader_trinary_minmax + CONST_CAST(GLEW_AMD_shader_trinary_minmax) = _glewSearchExtension("GL_AMD_shader_trinary_minmax", extStart, extEnd); +#endif /* GL_AMD_shader_trinary_minmax */ +#ifdef GL_AMD_sparse_texture + CONST_CAST(GLEW_AMD_sparse_texture) = _glewSearchExtension("GL_AMD_sparse_texture", extStart, extEnd); + if (glewExperimental || GLEW_AMD_sparse_texture) CONST_CAST(GLEW_AMD_sparse_texture) = !_glewInit_GL_AMD_sparse_texture(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_AMD_sparse_texture */ #ifdef GL_AMD_stencil_operation_extended CONST_CAST(GLEW_AMD_stencil_operation_extended) = _glewSearchExtension("GL_AMD_stencil_operation_extended", extStart, extEnd); if (glewExperimental || GLEW_AMD_stencil_operation_extended) CONST_CAST(GLEW_AMD_stencil_operation_extended) = !_glewInit_GL_AMD_stencil_operation_extended(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9050,6 +9667,47 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_AMD_vertex_shader_viewport_index CONST_CAST(GLEW_AMD_vertex_shader_viewport_index) = _glewSearchExtension("GL_AMD_vertex_shader_viewport_index", extStart, extEnd); #endif /* GL_AMD_vertex_shader_viewport_index */ +#ifdef GL_ANGLE_depth_texture + CONST_CAST(GLEW_ANGLE_depth_texture) = _glewSearchExtension("GL_ANGLE_depth_texture", extStart, extEnd); +#endif /* GL_ANGLE_depth_texture */ +#ifdef GL_ANGLE_framebuffer_blit + CONST_CAST(GLEW_ANGLE_framebuffer_blit) = _glewSearchExtension("GL_ANGLE_framebuffer_blit", extStart, extEnd); + if (glewExperimental || GLEW_ANGLE_framebuffer_blit) CONST_CAST(GLEW_ANGLE_framebuffer_blit) = !_glewInit_GL_ANGLE_framebuffer_blit(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ANGLE_framebuffer_blit */ +#ifdef GL_ANGLE_framebuffer_multisample + CONST_CAST(GLEW_ANGLE_framebuffer_multisample) = _glewSearchExtension("GL_ANGLE_framebuffer_multisample", extStart, extEnd); + if (glewExperimental || GLEW_ANGLE_framebuffer_multisample) CONST_CAST(GLEW_ANGLE_framebuffer_multisample) = !_glewInit_GL_ANGLE_framebuffer_multisample(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ANGLE_framebuffer_multisample */ +#ifdef GL_ANGLE_instanced_arrays + CONST_CAST(GLEW_ANGLE_instanced_arrays) = _glewSearchExtension("GL_ANGLE_instanced_arrays", extStart, extEnd); + if (glewExperimental || GLEW_ANGLE_instanced_arrays) CONST_CAST(GLEW_ANGLE_instanced_arrays) = !_glewInit_GL_ANGLE_instanced_arrays(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ANGLE_instanced_arrays */ +#ifdef GL_ANGLE_pack_reverse_row_order + CONST_CAST(GLEW_ANGLE_pack_reverse_row_order) = _glewSearchExtension("GL_ANGLE_pack_reverse_row_order", extStart, extEnd); +#endif /* GL_ANGLE_pack_reverse_row_order */ +#ifdef GL_ANGLE_program_binary + CONST_CAST(GLEW_ANGLE_program_binary) = _glewSearchExtension("GL_ANGLE_program_binary", extStart, extEnd); +#endif /* GL_ANGLE_program_binary */ +#ifdef GL_ANGLE_texture_compression_dxt1 + CONST_CAST(GLEW_ANGLE_texture_compression_dxt1) = _glewSearchExtension("GL_ANGLE_texture_compression_dxt1", extStart, extEnd); +#endif /* GL_ANGLE_texture_compression_dxt1 */ +#ifdef GL_ANGLE_texture_compression_dxt3 + CONST_CAST(GLEW_ANGLE_texture_compression_dxt3) = _glewSearchExtension("GL_ANGLE_texture_compression_dxt3", extStart, extEnd); +#endif /* GL_ANGLE_texture_compression_dxt3 */ +#ifdef GL_ANGLE_texture_compression_dxt5 + CONST_CAST(GLEW_ANGLE_texture_compression_dxt5) = _glewSearchExtension("GL_ANGLE_texture_compression_dxt5", extStart, extEnd); +#endif /* GL_ANGLE_texture_compression_dxt5 */ +#ifdef GL_ANGLE_texture_usage + CONST_CAST(GLEW_ANGLE_texture_usage) = _glewSearchExtension("GL_ANGLE_texture_usage", extStart, extEnd); +#endif /* GL_ANGLE_texture_usage */ +#ifdef GL_ANGLE_timer_query + CONST_CAST(GLEW_ANGLE_timer_query) = _glewSearchExtension("GL_ANGLE_timer_query", extStart, extEnd); + if (glewExperimental || GLEW_ANGLE_timer_query) CONST_CAST(GLEW_ANGLE_timer_query) = !_glewInit_GL_ANGLE_timer_query(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ANGLE_timer_query */ +#ifdef GL_ANGLE_translated_shader_source + CONST_CAST(GLEW_ANGLE_translated_shader_source) = _glewSearchExtension("GL_ANGLE_translated_shader_source", extStart, extEnd); + if (glewExperimental || GLEW_ANGLE_translated_shader_source) CONST_CAST(GLEW_ANGLE_translated_shader_source) = !_glewInit_GL_ANGLE_translated_shader_source(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ANGLE_translated_shader_source */ #ifdef GL_APPLE_aux_depth_stencil CONST_CAST(GLEW_APPLE_aux_depth_stencil) = _glewSearchExtension("GL_APPLE_aux_depth_stencil", extStart, extEnd); #endif /* GL_APPLE_aux_depth_stencil */ @@ -9123,10 +9781,18 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_ARB_base_instance) = _glewSearchExtension("GL_ARB_base_instance", extStart, extEnd); if (glewExperimental || GLEW_ARB_base_instance) CONST_CAST(GLEW_ARB_base_instance) = !_glewInit_GL_ARB_base_instance(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_ARB_base_instance */ +#ifdef GL_ARB_bindless_texture + CONST_CAST(GLEW_ARB_bindless_texture) = _glewSearchExtension("GL_ARB_bindless_texture", extStart, extEnd); + if (glewExperimental || GLEW_ARB_bindless_texture) CONST_CAST(GLEW_ARB_bindless_texture) = !_glewInit_GL_ARB_bindless_texture(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ARB_bindless_texture */ #ifdef GL_ARB_blend_func_extended CONST_CAST(GLEW_ARB_blend_func_extended) = _glewSearchExtension("GL_ARB_blend_func_extended", extStart, extEnd); if (glewExperimental || GLEW_ARB_blend_func_extended) CONST_CAST(GLEW_ARB_blend_func_extended) = !_glewInit_GL_ARB_blend_func_extended(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_ARB_blend_func_extended */ +#ifdef GL_ARB_buffer_storage + CONST_CAST(GLEW_ARB_buffer_storage) = _glewSearchExtension("GL_ARB_buffer_storage", extStart, extEnd); + if (glewExperimental || GLEW_ARB_buffer_storage) CONST_CAST(GLEW_ARB_buffer_storage) = !_glewInit_GL_ARB_buffer_storage(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ARB_buffer_storage */ #ifdef GL_ARB_cl_event CONST_CAST(GLEW_ARB_cl_event) = _glewSearchExtension("GL_ARB_cl_event", extStart, extEnd); if (glewExperimental || GLEW_ARB_cl_event) CONST_CAST(GLEW_ARB_cl_event) = !_glewInit_GL_ARB_cl_event(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9135,6 +9801,10 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_ARB_clear_buffer_object) = _glewSearchExtension("GL_ARB_clear_buffer_object", extStart, extEnd); if (glewExperimental || GLEW_ARB_clear_buffer_object) CONST_CAST(GLEW_ARB_clear_buffer_object) = !_glewInit_GL_ARB_clear_buffer_object(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_ARB_clear_buffer_object */ +#ifdef GL_ARB_clear_texture + CONST_CAST(GLEW_ARB_clear_texture) = _glewSearchExtension("GL_ARB_clear_texture", extStart, extEnd); + if (glewExperimental || GLEW_ARB_clear_texture) CONST_CAST(GLEW_ARB_clear_texture) = !_glewInit_GL_ARB_clear_texture(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ARB_clear_texture */ #ifdef GL_ARB_color_buffer_float CONST_CAST(GLEW_ARB_color_buffer_float) = _glewSearchExtension("GL_ARB_color_buffer_float", extStart, extEnd); if (glewExperimental || GLEW_ARB_color_buffer_float) CONST_CAST(GLEW_ARB_color_buffer_float) = !_glewInit_GL_ARB_color_buffer_float(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9149,6 +9819,10 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_ARB_compute_shader) = _glewSearchExtension("GL_ARB_compute_shader", extStart, extEnd); if (glewExperimental || GLEW_ARB_compute_shader) CONST_CAST(GLEW_ARB_compute_shader) = !_glewInit_GL_ARB_compute_shader(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_ARB_compute_shader */ +#ifdef GL_ARB_compute_variable_group_size + CONST_CAST(GLEW_ARB_compute_variable_group_size) = _glewSearchExtension("GL_ARB_compute_variable_group_size", extStart, extEnd); + if (glewExperimental || GLEW_ARB_compute_variable_group_size) CONST_CAST(GLEW_ARB_compute_variable_group_size) = !_glewInit_GL_ARB_compute_variable_group_size(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ARB_compute_variable_group_size */ #ifdef GL_ARB_conservative_depth CONST_CAST(GLEW_ARB_conservative_depth) = _glewSearchExtension("GL_ARB_conservative_depth", extStart, extEnd); #endif /* GL_ARB_conservative_depth */ @@ -9192,6 +9866,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_ARB_draw_instanced CONST_CAST(GLEW_ARB_draw_instanced) = _glewSearchExtension("GL_ARB_draw_instanced", extStart, extEnd); #endif /* GL_ARB_draw_instanced */ +#ifdef GL_ARB_enhanced_layouts + CONST_CAST(GLEW_ARB_enhanced_layouts) = _glewSearchExtension("GL_ARB_enhanced_layouts", extStart, extEnd); +#endif /* GL_ARB_enhanced_layouts */ #ifdef GL_ARB_explicit_attrib_location CONST_CAST(GLEW_ARB_explicit_attrib_location) = _glewSearchExtension("GL_ARB_explicit_attrib_location", extStart, extEnd); #endif /* GL_ARB_explicit_attrib_location */ @@ -9249,6 +9926,10 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_ARB_imaging) = _glewSearchExtension("GL_ARB_imaging", extStart, extEnd); if (glewExperimental || GLEW_ARB_imaging) CONST_CAST(GLEW_ARB_imaging) = !_glewInit_GL_ARB_imaging(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_ARB_imaging */ +#ifdef GL_ARB_indirect_parameters + CONST_CAST(GLEW_ARB_indirect_parameters) = _glewSearchExtension("GL_ARB_indirect_parameters", extStart, extEnd); + if (glewExperimental || GLEW_ARB_indirect_parameters) CONST_CAST(GLEW_ARB_indirect_parameters) = !_glewInit_GL_ARB_indirect_parameters(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ARB_indirect_parameters */ #ifdef GL_ARB_instanced_arrays CONST_CAST(GLEW_ARB_instanced_arrays) = _glewSearchExtension("GL_ARB_instanced_arrays", extStart, extEnd); if (glewExperimental || GLEW_ARB_instanced_arrays) CONST_CAST(GLEW_ARB_instanced_arrays) = !_glewInit_GL_ARB_instanced_arrays(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9276,6 +9957,10 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_ARB_matrix_palette) = _glewSearchExtension("GL_ARB_matrix_palette", extStart, extEnd); if (glewExperimental || GLEW_ARB_matrix_palette) CONST_CAST(GLEW_ARB_matrix_palette) = !_glewInit_GL_ARB_matrix_palette(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_ARB_matrix_palette */ +#ifdef GL_ARB_multi_bind + CONST_CAST(GLEW_ARB_multi_bind) = _glewSearchExtension("GL_ARB_multi_bind", extStart, extEnd); + if (glewExperimental || GLEW_ARB_multi_bind) CONST_CAST(GLEW_ARB_multi_bind) = !_glewInit_GL_ARB_multi_bind(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ARB_multi_bind */ #ifdef GL_ARB_multi_draw_indirect CONST_CAST(GLEW_ARB_multi_draw_indirect) = _glewSearchExtension("GL_ARB_multi_draw_indirect", extStart, extEnd); if (glewExperimental || GLEW_ARB_multi_draw_indirect) CONST_CAST(GLEW_ARB_multi_draw_indirect) = !_glewInit_GL_ARB_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9313,6 +9998,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_ARB_provoking_vertex) = _glewSearchExtension("GL_ARB_provoking_vertex", extStart, extEnd); if (glewExperimental || GLEW_ARB_provoking_vertex) CONST_CAST(GLEW_ARB_provoking_vertex) = !_glewInit_GL_ARB_provoking_vertex(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_ARB_provoking_vertex */ +#ifdef GL_ARB_query_buffer_object + CONST_CAST(GLEW_ARB_query_buffer_object) = _glewSearchExtension("GL_ARB_query_buffer_object", extStart, extEnd); +#endif /* GL_ARB_query_buffer_object */ #ifdef GL_ARB_robust_buffer_access_behavior CONST_CAST(GLEW_ARB_robust_buffer_access_behavior) = _glewSearchExtension("GL_ARB_robust_buffer_access_behavior", extStart, extEnd); #endif /* GL_ARB_robust_buffer_access_behavior */ @@ -9337,6 +10025,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_ARB_seamless_cube_map CONST_CAST(GLEW_ARB_seamless_cube_map) = _glewSearchExtension("GL_ARB_seamless_cube_map", extStart, extEnd); #endif /* GL_ARB_seamless_cube_map */ +#ifdef GL_ARB_seamless_cubemap_per_texture + CONST_CAST(GLEW_ARB_seamless_cubemap_per_texture) = _glewSearchExtension("GL_ARB_seamless_cubemap_per_texture", extStart, extEnd); +#endif /* GL_ARB_seamless_cubemap_per_texture */ #ifdef GL_ARB_separate_shader_objects CONST_CAST(GLEW_ARB_separate_shader_objects) = _glewSearchExtension("GL_ARB_separate_shader_objects", extStart, extEnd); if (glewExperimental || GLEW_ARB_separate_shader_objects) CONST_CAST(GLEW_ARB_separate_shader_objects) = !_glewInit_GL_ARB_separate_shader_objects(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9348,6 +10039,12 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_ARB_shader_bit_encoding CONST_CAST(GLEW_ARB_shader_bit_encoding) = _glewSearchExtension("GL_ARB_shader_bit_encoding", extStart, extEnd); #endif /* GL_ARB_shader_bit_encoding */ +#ifdef GL_ARB_shader_draw_parameters + CONST_CAST(GLEW_ARB_shader_draw_parameters) = _glewSearchExtension("GL_ARB_shader_draw_parameters", extStart, extEnd); +#endif /* GL_ARB_shader_draw_parameters */ +#ifdef GL_ARB_shader_group_vote + CONST_CAST(GLEW_ARB_shader_group_vote) = _glewSearchExtension("GL_ARB_shader_group_vote", extStart, extEnd); +#endif /* GL_ARB_shader_group_vote */ #ifdef GL_ARB_shader_image_load_store CONST_CAST(GLEW_ARB_shader_image_load_store) = _glewSearchExtension("GL_ARB_shader_image_load_store", extStart, extEnd); if (glewExperimental || GLEW_ARB_shader_image_load_store) CONST_CAST(GLEW_ARB_shader_image_load_store) = !_glewInit_GL_ARB_shader_image_load_store(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9395,6 +10092,10 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_ARB_shadow_ambient CONST_CAST(GLEW_ARB_shadow_ambient) = _glewSearchExtension("GL_ARB_shadow_ambient", extStart, extEnd); #endif /* GL_ARB_shadow_ambient */ +#ifdef GL_ARB_sparse_texture + CONST_CAST(GLEW_ARB_sparse_texture) = _glewSearchExtension("GL_ARB_sparse_texture", extStart, extEnd); + if (glewExperimental || GLEW_ARB_sparse_texture) CONST_CAST(GLEW_ARB_sparse_texture) = !_glewInit_GL_ARB_sparse_texture(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_ARB_sparse_texture */ #ifdef GL_ARB_stencil_texturing CONST_CAST(GLEW_ARB_stencil_texturing) = _glewSearchExtension("GL_ARB_stencil_texturing", extStart, extEnd); #endif /* GL_ARB_stencil_texturing */ @@ -9454,6 +10155,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_ARB_texture_gather CONST_CAST(GLEW_ARB_texture_gather) = _glewSearchExtension("GL_ARB_texture_gather", extStart, extEnd); #endif /* GL_ARB_texture_gather */ +#ifdef GL_ARB_texture_mirror_clamp_to_edge + CONST_CAST(GLEW_ARB_texture_mirror_clamp_to_edge) = _glewSearchExtension("GL_ARB_texture_mirror_clamp_to_edge", extStart, extEnd); +#endif /* GL_ARB_texture_mirror_clamp_to_edge */ #ifdef GL_ARB_texture_mirrored_repeat CONST_CAST(GLEW_ARB_texture_mirrored_repeat) = _glewSearchExtension("GL_ARB_texture_mirrored_repeat", extStart, extEnd); #endif /* GL_ARB_texture_mirrored_repeat */ @@ -9479,6 +10183,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_ARB_texture_rgb10_a2ui CONST_CAST(GLEW_ARB_texture_rgb10_a2ui) = _glewSearchExtension("GL_ARB_texture_rgb10_a2ui", extStart, extEnd); #endif /* GL_ARB_texture_rgb10_a2ui */ +#ifdef GL_ARB_texture_stencil8 + CONST_CAST(GLEW_ARB_texture_stencil8) = _glewSearchExtension("GL_ARB_texture_stencil8", extStart, extEnd); +#endif /* GL_ARB_texture_stencil8 */ #ifdef GL_ARB_texture_storage CONST_CAST(GLEW_ARB_texture_storage) = _glewSearchExtension("GL_ARB_texture_storage", extStart, extEnd); if (glewExperimental || GLEW_ARB_texture_storage) CONST_CAST(GLEW_ARB_texture_storage) = !_glewInit_GL_ARB_texture_storage(GLEW_CONTEXT_ARG_VAR_INIT); @@ -9549,6 +10256,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_ARB_vertex_shader) = _glewSearchExtension("GL_ARB_vertex_shader", extStart, extEnd); if (glewExperimental || GLEW_ARB_vertex_shader) CONST_CAST(GLEW_ARB_vertex_shader) = !_glewInit_GL_ARB_vertex_shader(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_ARB_vertex_shader */ +#ifdef GL_ARB_vertex_type_10f_11f_11f_rev + CONST_CAST(GLEW_ARB_vertex_type_10f_11f_11f_rev) = _glewSearchExtension("GL_ARB_vertex_type_10f_11f_11f_rev", extStart, extEnd); +#endif /* GL_ARB_vertex_type_10f_11f_11f_rev */ #ifdef GL_ARB_vertex_type_2_10_10_10_rev CONST_CAST(GLEW_ARB_vertex_type_2_10_10_10_rev) = _glewSearchExtension("GL_ARB_vertex_type_2_10_10_10_rev", extStart, extEnd); if (glewExperimental || GLEW_ARB_vertex_type_2_10_10_10_rev) CONST_CAST(GLEW_ARB_vertex_type_2_10_10_10_rev) = !_glewInit_GL_ARB_vertex_type_2_10_10_10_rev(GLEW_CONTEXT_ARG_VAR_INIT); @@ -10036,6 +10746,10 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_INGR_interlace_read CONST_CAST(GLEW_INGR_interlace_read) = _glewSearchExtension("GL_INGR_interlace_read", extStart, extEnd); #endif /* GL_INGR_interlace_read */ +#ifdef GL_INTEL_map_texture + CONST_CAST(GLEW_INTEL_map_texture) = _glewSearchExtension("GL_INTEL_map_texture", extStart, extEnd); + if (glewExperimental || GLEW_INTEL_map_texture) CONST_CAST(GLEW_INTEL_map_texture) = !_glewInit_GL_INTEL_map_texture(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_INTEL_map_texture */ #ifdef GL_INTEL_parallel_arrays CONST_CAST(GLEW_INTEL_parallel_arrays) = _glewSearchExtension("GL_INTEL_parallel_arrays", extStart, extEnd); if (glewExperimental || GLEW_INTEL_parallel_arrays) CONST_CAST(GLEW_INTEL_parallel_arrays) = !_glewInit_GL_INTEL_parallel_arrays(GLEW_CONTEXT_ARG_VAR_INIT); @@ -10072,16 +10786,34 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_MESA_ycbcr_texture CONST_CAST(GLEW_MESA_ycbcr_texture) = _glewSearchExtension("GL_MESA_ycbcr_texture", extStart, extEnd); #endif /* GL_MESA_ycbcr_texture */ +#ifdef GL_NVX_conditional_render + CONST_CAST(GLEW_NVX_conditional_render) = _glewSearchExtension("GL_NVX_conditional_render", extStart, extEnd); + if (glewExperimental || GLEW_NVX_conditional_render) CONST_CAST(GLEW_NVX_conditional_render) = !_glewInit_GL_NVX_conditional_render(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_NVX_conditional_render */ #ifdef GL_NVX_gpu_memory_info CONST_CAST(GLEW_NVX_gpu_memory_info) = _glewSearchExtension("GL_NVX_gpu_memory_info", extStart, extEnd); #endif /* GL_NVX_gpu_memory_info */ +#ifdef GL_NV_bindless_multi_draw_indirect + CONST_CAST(GLEW_NV_bindless_multi_draw_indirect) = _glewSearchExtension("GL_NV_bindless_multi_draw_indirect", extStart, extEnd); + if (glewExperimental || GLEW_NV_bindless_multi_draw_indirect) CONST_CAST(GLEW_NV_bindless_multi_draw_indirect) = !_glewInit_GL_NV_bindless_multi_draw_indirect(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_NV_bindless_multi_draw_indirect */ #ifdef GL_NV_bindless_texture CONST_CAST(GLEW_NV_bindless_texture) = _glewSearchExtension("GL_NV_bindless_texture", extStart, extEnd); if (glewExperimental || GLEW_NV_bindless_texture) CONST_CAST(GLEW_NV_bindless_texture) = !_glewInit_GL_NV_bindless_texture(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_NV_bindless_texture */ +#ifdef GL_NV_blend_equation_advanced + CONST_CAST(GLEW_NV_blend_equation_advanced) = _glewSearchExtension("GL_NV_blend_equation_advanced", extStart, extEnd); + if (glewExperimental || GLEW_NV_blend_equation_advanced) CONST_CAST(GLEW_NV_blend_equation_advanced) = !_glewInit_GL_NV_blend_equation_advanced(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_NV_blend_equation_advanced */ +#ifdef GL_NV_blend_equation_advanced_coherent + CONST_CAST(GLEW_NV_blend_equation_advanced_coherent) = _glewSearchExtension("GL_NV_blend_equation_advanced_coherent", extStart, extEnd); +#endif /* GL_NV_blend_equation_advanced_coherent */ #ifdef GL_NV_blend_square CONST_CAST(GLEW_NV_blend_square) = _glewSearchExtension("GL_NV_blend_square", extStart, extEnd); #endif /* GL_NV_blend_square */ +#ifdef GL_NV_compute_program5 + CONST_CAST(GLEW_NV_compute_program5) = _glewSearchExtension("GL_NV_compute_program5", extStart, extEnd); +#endif /* GL_NV_compute_program5 */ #ifdef GL_NV_conditional_render CONST_CAST(GLEW_NV_conditional_render) = _glewSearchExtension("GL_NV_conditional_render", extStart, extEnd); if (glewExperimental || GLEW_NV_conditional_render) CONST_CAST(GLEW_NV_conditional_render) = !_glewInit_GL_NV_conditional_render(GLEW_CONTEXT_ARG_VAR_INIT); @@ -10093,6 +10825,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_NV_copy_image) = _glewSearchExtension("GL_NV_copy_image", extStart, extEnd); if (glewExperimental || GLEW_NV_copy_image) CONST_CAST(GLEW_NV_copy_image) = !_glewInit_GL_NV_copy_image(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_NV_copy_image */ +#ifdef GL_NV_deep_texture3D + CONST_CAST(GLEW_NV_deep_texture3D) = _glewSearchExtension("GL_NV_deep_texture3D", extStart, extEnd); +#endif /* GL_NV_deep_texture3D */ #ifdef GL_NV_depth_buffer_float CONST_CAST(GLEW_NV_depth_buffer_float) = _glewSearchExtension("GL_NV_depth_buffer_float", extStart, extEnd); if (glewExperimental || GLEW_NV_depth_buffer_float) CONST_CAST(GLEW_NV_depth_buffer_float) = !_glewInit_GL_NV_depth_buffer_float(GLEW_CONTEXT_ARG_VAR_INIT); @@ -10103,6 +10838,10 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_NV_depth_range_unclamped CONST_CAST(GLEW_NV_depth_range_unclamped) = _glewSearchExtension("GL_NV_depth_range_unclamped", extStart, extEnd); #endif /* GL_NV_depth_range_unclamped */ +#ifdef GL_NV_draw_texture + CONST_CAST(GLEW_NV_draw_texture) = _glewSearchExtension("GL_NV_draw_texture", extStart, extEnd); + if (glewExperimental || GLEW_NV_draw_texture) CONST_CAST(GLEW_NV_draw_texture) = !_glewInit_GL_NV_draw_texture(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_NV_draw_texture */ #ifdef GL_NV_evaluators CONST_CAST(GLEW_NV_evaluators) = _glewSearchExtension("GL_NV_evaluators", extStart, extEnd); if (glewExperimental || GLEW_NV_evaluators) CONST_CAST(GLEW_NV_evaluators) = !_glewInit_GL_NV_evaluators(GLEW_CONTEXT_ARG_VAR_INIT); @@ -10152,6 +10891,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_NV_gpu_program5 CONST_CAST(GLEW_NV_gpu_program5) = _glewSearchExtension("GL_NV_gpu_program5", extStart, extEnd); #endif /* GL_NV_gpu_program5 */ +#ifdef GL_NV_gpu_program5_mem_extended + CONST_CAST(GLEW_NV_gpu_program5_mem_extended) = _glewSearchExtension("GL_NV_gpu_program5_mem_extended", extStart, extEnd); +#endif /* GL_NV_gpu_program5_mem_extended */ #ifdef GL_NV_gpu_program_fp64 CONST_CAST(GLEW_NV_gpu_program_fp64) = _glewSearchExtension("GL_NV_gpu_program_fp64", extStart, extEnd); #endif /* GL_NV_gpu_program_fp64 */ @@ -10214,6 +10956,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_NV_register_combiners2) = _glewSearchExtension("GL_NV_register_combiners2", extStart, extEnd); if (glewExperimental || GLEW_NV_register_combiners2) CONST_CAST(GLEW_NV_register_combiners2) = !_glewInit_GL_NV_register_combiners2(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_NV_register_combiners2 */ +#ifdef GL_NV_shader_atomic_counters + CONST_CAST(GLEW_NV_shader_atomic_counters) = _glewSearchExtension("GL_NV_shader_atomic_counters", extStart, extEnd); +#endif /* GL_NV_shader_atomic_counters */ #ifdef GL_NV_shader_atomic_float CONST_CAST(GLEW_NV_shader_atomic_float) = _glewSearchExtension("GL_NV_shader_atomic_float", extStart, extEnd); #endif /* GL_NV_shader_atomic_float */ @@ -10221,6 +10966,9 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_NV_shader_buffer_load) = _glewSearchExtension("GL_NV_shader_buffer_load", extStart, extEnd); if (glewExperimental || GLEW_NV_shader_buffer_load) CONST_CAST(GLEW_NV_shader_buffer_load) = !_glewInit_GL_NV_shader_buffer_load(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_NV_shader_buffer_load */ +#ifdef GL_NV_shader_storage_buffer_object + CONST_CAST(GLEW_NV_shader_storage_buffer_object) = _glewSearchExtension("GL_NV_shader_storage_buffer_object", extStart, extEnd); +#endif /* GL_NV_shader_storage_buffer_object */ #ifdef GL_NV_tessellation_program5 CONST_CAST(GLEW_NV_tessellation_program5) = _glewSearchExtension("GL_NV_gpu_program5", extStart, extEnd); #endif /* GL_NV_tessellation_program5 */ @@ -10337,6 +11085,17 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #ifdef GL_PGI_vertex_hints CONST_CAST(GLEW_PGI_vertex_hints) = _glewSearchExtension("GL_PGI_vertex_hints", extStart, extEnd); #endif /* GL_PGI_vertex_hints */ +#ifdef GL_REGAL_ES1_0_compatibility + CONST_CAST(GLEW_REGAL_ES1_0_compatibility) = _glewSearchExtension("GL_REGAL_ES1_0_compatibility", extStart, extEnd); + if (glewExperimental || GLEW_REGAL_ES1_0_compatibility) CONST_CAST(GLEW_REGAL_ES1_0_compatibility) = !_glewInit_GL_REGAL_ES1_0_compatibility(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_REGAL_ES1_0_compatibility */ +#ifdef GL_REGAL_ES1_1_compatibility + CONST_CAST(GLEW_REGAL_ES1_1_compatibility) = _glewSearchExtension("GL_REGAL_ES1_1_compatibility", extStart, extEnd); + if (glewExperimental || GLEW_REGAL_ES1_1_compatibility) CONST_CAST(GLEW_REGAL_ES1_1_compatibility) = !_glewInit_GL_REGAL_ES1_1_compatibility(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GL_REGAL_ES1_1_compatibility */ +#ifdef GL_REGAL_enable + CONST_CAST(GLEW_REGAL_enable) = _glewSearchExtension("GL_REGAL_enable", extStart, extEnd); +#endif /* GL_REGAL_enable */ #ifdef GL_REGAL_error_string CONST_CAST(GLEW_REGAL_error_string) = _glewSearchExtension("GL_REGAL_error_string", extStart, extEnd); if (glewExperimental || GLEW_REGAL_error_string) CONST_CAST(GLEW_REGAL_error_string) = !_glewInit_GL_REGAL_error_string(GLEW_CONTEXT_ARG_VAR_INIT); @@ -10347,6 +11106,7 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) #endif /* GL_REGAL_extension_query */ #ifdef GL_REGAL_log CONST_CAST(GLEW_REGAL_log) = _glewSearchExtension("GL_REGAL_log", extStart, extEnd); + if (glewExperimental || GLEW_REGAL_log) CONST_CAST(GLEW_REGAL_log) = !_glewInit_GL_REGAL_log(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GL_REGAL_log */ #ifdef GL_REND_screen_coordinates CONST_CAST(GLEW_REND_screen_coordinates) = _glewSearchExtension("GL_REND_screen_coordinates", extStart, extEnd); @@ -10727,6 +11487,8 @@ GLboolean __WGLEW_ARB_pbuffer = GL_FALSE; GLboolean __WGLEW_ARB_pixel_format = GL_FALSE; GLboolean __WGLEW_ARB_pixel_format_float = GL_FALSE; GLboolean __WGLEW_ARB_render_texture = GL_FALSE; +GLboolean __WGLEW_ARB_robustness_application_isolation = GL_FALSE; +GLboolean __WGLEW_ARB_robustness_share_group_isolation = GL_FALSE; GLboolean __WGLEW_ATI_pixel_format_float = GL_FALSE; GLboolean __WGLEW_ATI_render_texture_rectangle = GL_FALSE; GLboolean __WGLEW_EXT_create_context_es2_profile = GL_FALSE; @@ -10926,6 +11688,14 @@ static GLboolean _glewInit_WGL_ARB_render_texture (WGLEW_CONTEXT_ARG_DEF_INIT) #endif /* WGL_ARB_render_texture */ +#ifdef WGL_ARB_robustness_application_isolation + +#endif /* WGL_ARB_robustness_application_isolation */ + +#ifdef WGL_ARB_robustness_share_group_isolation + +#endif /* WGL_ARB_robustness_share_group_isolation */ + #ifdef WGL_ATI_pixel_format_float #endif /* WGL_ATI_pixel_format_float */ @@ -11418,6 +12188,12 @@ GLenum GLEWAPIENTRY wglewContextInit (WGLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(WGLEW_ARB_render_texture) = _glewSearchExtension("WGL_ARB_render_texture", extStart, extEnd); if (glewExperimental || WGLEW_ARB_render_texture|| crippled) CONST_CAST(WGLEW_ARB_render_texture)= !_glewInit_WGL_ARB_render_texture(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* WGL_ARB_render_texture */ +#ifdef WGL_ARB_robustness_application_isolation + CONST_CAST(WGLEW_ARB_robustness_application_isolation) = _glewSearchExtension("WGL_ARB_robustness_application_isolation", extStart, extEnd); +#endif /* WGL_ARB_robustness_application_isolation */ +#ifdef WGL_ARB_robustness_share_group_isolation + CONST_CAST(WGLEW_ARB_robustness_share_group_isolation) = _glewSearchExtension("WGL_ARB_robustness_share_group_isolation", extStart, extEnd); +#endif /* WGL_ARB_robustness_share_group_isolation */ #ifdef WGL_ATI_pixel_format_float CONST_CAST(WGLEW_ATI_pixel_format_float) = _glewSearchExtension("WGL_ATI_pixel_format_float", extStart, extEnd); #endif /* WGL_ATI_pixel_format_float */ @@ -11548,7 +12324,7 @@ GLenum GLEWAPIENTRY wglewContextInit (WGLEW_CONTEXT_ARG_DEF_LIST) return GLEW_OK; } -#elif !defined(__ANDROID__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) +#elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) PFNGLXGETCURRENTDISPLAYPROC __glewXGetCurrentDisplay = NULL; @@ -11570,6 +12346,16 @@ PFNGLXQUERYCONTEXTPROC __glewXQueryContext = NULL; PFNGLXQUERYDRAWABLEPROC __glewXQueryDrawable = NULL; PFNGLXSELECTEVENTPROC __glewXSelectEvent = NULL; +PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC __glewXBlitContextFramebufferAMD = NULL; +PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC __glewXCreateAssociatedContextAMD = NULL; +PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC __glewXCreateAssociatedContextAttribsAMD = NULL; +PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC __glewXDeleteAssociatedContextAMD = NULL; +PFNGLXGETCONTEXTGPUIDAMDPROC __glewXGetContextGPUIDAMD = NULL; +PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC __glewXGetCurrentAssociatedContextAMD = NULL; +PFNGLXGETGPUIDSAMDPROC __glewXGetGPUIDsAMD = NULL; +PFNGLXGETGPUINFOAMDPROC __glewXGetGPUInfoAMD = NULL; +PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC __glewXMakeAssociatedContextCurrentAMD = NULL; + PFNGLXCREATECONTEXTATTRIBSARBPROC __glewXCreateContextAttribsARB = NULL; PFNGLXBINDTEXIMAGEATIPROC __glewXBindTexImageATI = NULL; @@ -11702,6 +12488,7 @@ GLboolean __GLXEW_ARB_robustness_share_group_isolation = GL_FALSE; GLboolean __GLXEW_ARB_vertex_buffer_object = GL_FALSE; GLboolean __GLXEW_ATI_pixel_format_float = GL_FALSE; GLboolean __GLXEW_ATI_render_texture = GL_FALSE; +GLboolean __GLXEW_EXT_buffer_age = GL_FALSE; GLboolean __GLXEW_EXT_create_context_es2_profile = GL_FALSE; GLboolean __GLXEW_EXT_create_context_es_profile = GL_FALSE; GLboolean __GLXEW_EXT_fbconfig_packed_float = GL_FALSE; @@ -11727,7 +12514,7 @@ GLboolean __GLXEW_NV_present_video = GL_FALSE; GLboolean __GLXEW_NV_swap_group = GL_FALSE; GLboolean __GLXEW_NV_vertex_array_range = GL_FALSE; GLboolean __GLXEW_NV_video_capture = GL_FALSE; -GLboolean __GLXEW_NV_video_out = GL_FALSE; +GLboolean __GLXEW_NV_video_output = GL_FALSE; GLboolean __GLXEW_OML_swap_method = GL_FALSE; GLboolean __GLXEW_OML_sync_control = GL_FALSE; GLboolean __GLXEW_SGIS_blended_overlay = GL_FALSE; @@ -11802,6 +12589,23 @@ static GLboolean _glewInit_GLX_VERSION_1_3 (GLXEW_CONTEXT_ARG_DEF_INIT) #ifdef GLX_AMD_gpu_association +static GLboolean _glewInit_GLX_AMD_gpu_association (GLXEW_CONTEXT_ARG_DEF_INIT) +{ + GLboolean r = GL_FALSE; + + r = ((glXBlitContextFramebufferAMD = (PFNGLXBLITCONTEXTFRAMEBUFFERAMDPROC)glewGetProcAddress((const GLubyte*)"glXBlitContextFramebufferAMD")) == NULL) || r; + r = ((glXCreateAssociatedContextAMD = (PFNGLXCREATEASSOCIATEDCONTEXTAMDPROC)glewGetProcAddress((const GLubyte*)"glXCreateAssociatedContextAMD")) == NULL) || r; + r = ((glXCreateAssociatedContextAttribsAMD = (PFNGLXCREATEASSOCIATEDCONTEXTATTRIBSAMDPROC)glewGetProcAddress((const GLubyte*)"glXCreateAssociatedContextAttribsAMD")) == NULL) || r; + r = ((glXDeleteAssociatedContextAMD = (PFNGLXDELETEASSOCIATEDCONTEXTAMDPROC)glewGetProcAddress((const GLubyte*)"glXDeleteAssociatedContextAMD")) == NULL) || r; + r = ((glXGetContextGPUIDAMD = (PFNGLXGETCONTEXTGPUIDAMDPROC)glewGetProcAddress((const GLubyte*)"glXGetContextGPUIDAMD")) == NULL) || r; + r = ((glXGetCurrentAssociatedContextAMD = (PFNGLXGETCURRENTASSOCIATEDCONTEXTAMDPROC)glewGetProcAddress((const GLubyte*)"glXGetCurrentAssociatedContextAMD")) == NULL) || r; + r = ((glXGetGPUIDsAMD = (PFNGLXGETGPUIDSAMDPROC)glewGetProcAddress((const GLubyte*)"glXGetGPUIDsAMD")) == NULL) || r; + r = ((glXGetGPUInfoAMD = (PFNGLXGETGPUINFOAMDPROC)glewGetProcAddress((const GLubyte*)"glXGetGPUInfoAMD")) == NULL) || r; + r = ((glXMakeAssociatedContextCurrentAMD = (PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC)glewGetProcAddress((const GLubyte*)"glXMakeAssociatedContextCurrentAMD")) == NULL) || r; + + return r; +} + #endif /* GLX_AMD_gpu_association */ #ifdef GLX_ARB_create_context @@ -11872,6 +12676,10 @@ static GLboolean _glewInit_GLX_ATI_render_texture (GLXEW_CONTEXT_ARG_DEF_INIT) #endif /* GLX_ATI_render_texture */ +#ifdef GLX_EXT_buffer_age + +#endif /* GLX_EXT_buffer_age */ + #ifdef GLX_EXT_create_context_es2_profile #endif /* GLX_EXT_create_context_es2_profile */ @@ -12114,9 +12922,9 @@ static GLboolean _glewInit_GLX_NV_video_capture (GLXEW_CONTEXT_ARG_DEF_INIT) #endif /* GLX_NV_video_capture */ -#ifdef GLX_NV_video_out +#ifdef GLX_NV_video_output -static GLboolean _glewInit_GLX_NV_video_out (GLXEW_CONTEXT_ARG_DEF_INIT) +static GLboolean _glewInit_GLX_NV_video_output (GLXEW_CONTEXT_ARG_DEF_INIT) { GLboolean r = GL_FALSE; @@ -12130,7 +12938,7 @@ static GLboolean _glewInit_GLX_NV_video_out (GLXEW_CONTEXT_ARG_DEF_INIT) return r; } -#endif /* GLX_NV_video_out */ +#endif /* GLX_NV_video_output */ #ifdef GLX_OML_swap_method @@ -12414,6 +13222,7 @@ GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST) #endif /* GLX_3DFX_multisample */ #ifdef GLX_AMD_gpu_association CONST_CAST(GLXEW_AMD_gpu_association) = _glewSearchExtension("GLX_AMD_gpu_association", extStart, extEnd); + if (glewExperimental || GLXEW_AMD_gpu_association) CONST_CAST(GLXEW_AMD_gpu_association) = !_glewInit_GLX_AMD_gpu_association(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GLX_AMD_gpu_association */ #ifdef GLX_ARB_create_context CONST_CAST(GLXEW_ARB_create_context) = _glewSearchExtension("GLX_ARB_create_context", extStart, extEnd); @@ -12453,6 +13262,9 @@ GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLXEW_ATI_render_texture) = _glewSearchExtension("GLX_ATI_render_texture", extStart, extEnd); if (glewExperimental || GLXEW_ATI_render_texture) CONST_CAST(GLXEW_ATI_render_texture) = !_glewInit_GLX_ATI_render_texture(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GLX_ATI_render_texture */ +#ifdef GLX_EXT_buffer_age + CONST_CAST(GLXEW_EXT_buffer_age) = _glewSearchExtension("GLX_EXT_buffer_age", extStart, extEnd); +#endif /* GLX_EXT_buffer_age */ #ifdef GLX_EXT_create_context_es2_profile CONST_CAST(GLXEW_EXT_create_context_es2_profile) = _glewSearchExtension("GLX_EXT_create_context_es2_profile", extStart, extEnd); #endif /* GLX_EXT_create_context_es2_profile */ @@ -12542,10 +13354,10 @@ GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLXEW_NV_video_capture) = _glewSearchExtension("GLX_NV_video_capture", extStart, extEnd); if (glewExperimental || GLXEW_NV_video_capture) CONST_CAST(GLXEW_NV_video_capture) = !_glewInit_GLX_NV_video_capture(GLEW_CONTEXT_ARG_VAR_INIT); #endif /* GLX_NV_video_capture */ -#ifdef GLX_NV_video_out - CONST_CAST(GLXEW_NV_video_out) = _glewSearchExtension("GLX_NV_video_out", extStart, extEnd); - if (glewExperimental || GLXEW_NV_video_out) CONST_CAST(GLXEW_NV_video_out) = !_glewInit_GLX_NV_video_out(GLEW_CONTEXT_ARG_VAR_INIT); -#endif /* GLX_NV_video_out */ +#ifdef GLX_NV_video_output + CONST_CAST(GLXEW_NV_video_output) = _glewSearchExtension("GLX_NV_video_output", extStart, extEnd); + if (glewExperimental || GLXEW_NV_video_output) CONST_CAST(GLXEW_NV_video_output) = !_glewInit_GLX_NV_video_output(GLEW_CONTEXT_ARG_VAR_INIT); +#endif /* GLX_NV_video_output */ #ifdef GLX_OML_swap_method CONST_CAST(GLXEW_OML_swap_method) = _glewSearchExtension("GLX_OML_swap_method", extStart, extEnd); #endif /* GLX_OML_swap_method */ @@ -12620,7 +13432,7 @@ GLenum glxewContextInit (GLXEW_CONTEXT_ARG_DEF_LIST) return GLEW_OK; } -#endif /* !defined(__ANDROID__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) */ +#endif /* !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) */ /* ------------------------------------------------------------------------ */ @@ -12643,9 +13455,9 @@ const GLubyte * GLEWAPIENTRY glewGetString (GLenum name) static const GLubyte* _glewString[] = { (const GLubyte*)NULL, - (const GLubyte*)"1.9.0", + (const GLubyte*)"1.10.0", (const GLubyte*)"1", - (const GLubyte*)"9", + (const GLubyte*)"10", (const GLubyte*)"0" }; const int max_string = sizeof(_glewString)/sizeof(*_glewString) - 1; @@ -12660,11 +13472,10 @@ GLboolean glewExperimental = GL_FALSE; #if defined(_WIN32) extern GLenum GLEWAPIENTRY wglewContextInit (void); -#elif !defined(__ANDROID__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) +#elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) extern GLenum GLEWAPIENTRY glxewContextInit (void); #endif /* _WIN32 */ - GLenum GLEWAPIENTRY glewInit (void) { GLenum r; @@ -12672,7 +13483,7 @@ GLenum GLEWAPIENTRY glewInit (void) if ( r != 0 ) return r; #if defined(_WIN32) return wglewContextInit(); -#elif !defined(__ANDROID__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) /* _UNIX */ +#elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) /* _UNIX */ return glxewContextInit(); #else return r; @@ -12799,6 +13610,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) ret = GLEW_VERSION_4_3; continue; } +#endif +#ifdef GL_VERSION_4_4 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"4_4", 3)) + { + ret = GLEW_VERSION_4_4; + continue; + } #endif } if (_glewStrSame2(&pos, &len, (const GLubyte*)"3DFX_", 5)) @@ -12862,6 +13680,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_AMD_interleaved_elements + if (_glewStrSame3(&pos, &len, (const GLubyte*)"interleaved_elements", 20)) + { + ret = GLEW_AMD_interleaved_elements; + continue; + } +#endif #ifdef GL_AMD_multi_draw_indirect if (_glewStrSame3(&pos, &len, (const GLubyte*)"multi_draw_indirect", 19)) { @@ -12918,6 +13743,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_AMD_shader_trinary_minmax + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_trinary_minmax", 21)) + { + ret = GLEW_AMD_shader_trinary_minmax; + continue; + } +#endif +#ifdef GL_AMD_sparse_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture", 14)) + { + ret = GLEW_AMD_sparse_texture; + continue; + } +#endif #ifdef GL_AMD_stencil_operation_extended if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_operation_extended", 26)) { @@ -12959,6 +13798,93 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) ret = GLEW_AMD_vertex_shader_viewport_index; continue; } +#endif + } + if (_glewStrSame2(&pos, &len, (const GLubyte*)"ANGLE_", 6)) + { +#ifdef GL_ANGLE_depth_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_texture", 13)) + { + ret = GLEW_ANGLE_depth_texture; + continue; + } +#endif +#ifdef GL_ANGLE_framebuffer_blit + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_blit", 16)) + { + ret = GLEW_ANGLE_framebuffer_blit; + continue; + } +#endif +#ifdef GL_ANGLE_framebuffer_multisample + if (_glewStrSame3(&pos, &len, (const GLubyte*)"framebuffer_multisample", 23)) + { + ret = GLEW_ANGLE_framebuffer_multisample; + continue; + } +#endif +#ifdef GL_ANGLE_instanced_arrays + if (_glewStrSame3(&pos, &len, (const GLubyte*)"instanced_arrays", 16)) + { + ret = GLEW_ANGLE_instanced_arrays; + continue; + } +#endif +#ifdef GL_ANGLE_pack_reverse_row_order + if (_glewStrSame3(&pos, &len, (const GLubyte*)"pack_reverse_row_order", 22)) + { + ret = GLEW_ANGLE_pack_reverse_row_order; + continue; + } +#endif +#ifdef GL_ANGLE_program_binary + if (_glewStrSame3(&pos, &len, (const GLubyte*)"program_binary", 14)) + { + ret = GLEW_ANGLE_program_binary; + continue; + } +#endif +#ifdef GL_ANGLE_texture_compression_dxt1 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_dxt1", 24)) + { + ret = GLEW_ANGLE_texture_compression_dxt1; + continue; + } +#endif +#ifdef GL_ANGLE_texture_compression_dxt3 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_dxt3", 24)) + { + ret = GLEW_ANGLE_texture_compression_dxt3; + continue; + } +#endif +#ifdef GL_ANGLE_texture_compression_dxt5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_compression_dxt5", 24)) + { + ret = GLEW_ANGLE_texture_compression_dxt5; + continue; + } +#endif +#ifdef GL_ANGLE_texture_usage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_usage", 13)) + { + ret = GLEW_ANGLE_texture_usage; + continue; + } +#endif +#ifdef GL_ANGLE_timer_query + if (_glewStrSame3(&pos, &len, (const GLubyte*)"timer_query", 11)) + { + ret = GLEW_ANGLE_timer_query; + continue; + } +#endif +#ifdef GL_ANGLE_translated_shader_source + if (_glewStrSame3(&pos, &len, (const GLubyte*)"translated_shader_source", 24)) + { + ret = GLEW_ANGLE_translated_shader_source; + continue; + } #endif } if (_glewStrSame2(&pos, &len, (const GLubyte*)"APPLE_", 6)) @@ -13113,6 +14039,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_bindless_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_texture", 16)) + { + ret = GLEW_ARB_bindless_texture; + continue; + } +#endif #ifdef GL_ARB_blend_func_extended if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_func_extended", 19)) { @@ -13120,6 +14053,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_buffer_storage + if (_glewStrSame3(&pos, &len, (const GLubyte*)"buffer_storage", 14)) + { + ret = GLEW_ARB_buffer_storage; + continue; + } +#endif #ifdef GL_ARB_cl_event if (_glewStrSame3(&pos, &len, (const GLubyte*)"cl_event", 8)) { @@ -13134,6 +14074,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_clear_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"clear_texture", 13)) + { + ret = GLEW_ARB_clear_texture; + continue; + } +#endif #ifdef GL_ARB_color_buffer_float if (_glewStrSame3(&pos, &len, (const GLubyte*)"color_buffer_float", 18)) { @@ -13162,6 +14109,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_compute_variable_group_size + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compute_variable_group_size", 27)) + { + ret = GLEW_ARB_compute_variable_group_size; + continue; + } +#endif #ifdef GL_ARB_conservative_depth if (_glewStrSame3(&pos, &len, (const GLubyte*)"conservative_depth", 18)) { @@ -13246,6 +14200,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_enhanced_layouts + if (_glewStrSame3(&pos, &len, (const GLubyte*)"enhanced_layouts", 16)) + { + ret = GLEW_ARB_enhanced_layouts; + continue; + } +#endif #ifdef GL_ARB_explicit_attrib_location if (_glewStrSame3(&pos, &len, (const GLubyte*)"explicit_attrib_location", 24)) { @@ -13365,6 +14326,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_indirect_parameters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"indirect_parameters", 19)) + { + ret = GLEW_ARB_indirect_parameters; + continue; + } +#endif #ifdef GL_ARB_instanced_arrays if (_glewStrSame3(&pos, &len, (const GLubyte*)"instanced_arrays", 16)) { @@ -13414,6 +14382,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_multi_bind + if (_glewStrSame3(&pos, &len, (const GLubyte*)"multi_bind", 10)) + { + ret = GLEW_ARB_multi_bind; + continue; + } +#endif #ifdef GL_ARB_multi_draw_indirect if (_glewStrSame3(&pos, &len, (const GLubyte*)"multi_draw_indirect", 19)) { @@ -13484,6 +14459,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_query_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"query_buffer_object", 19)) + { + ret = GLEW_ARB_query_buffer_object; + continue; + } +#endif #ifdef GL_ARB_robust_buffer_access_behavior if (_glewStrSame3(&pos, &len, (const GLubyte*)"robust_buffer_access_behavior", 29)) { @@ -13533,6 +14515,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_seamless_cubemap_per_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"seamless_cubemap_per_texture", 28)) + { + ret = GLEW_ARB_seamless_cubemap_per_texture; + continue; + } +#endif #ifdef GL_ARB_separate_shader_objects if (_glewStrSame3(&pos, &len, (const GLubyte*)"separate_shader_objects", 23)) { @@ -13554,6 +14543,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_shader_draw_parameters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_draw_parameters", 22)) + { + ret = GLEW_ARB_shader_draw_parameters; + continue; + } +#endif +#ifdef GL_ARB_shader_group_vote + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_group_vote", 17)) + { + ret = GLEW_ARB_shader_group_vote; + continue; + } +#endif #ifdef GL_ARB_shader_image_load_store if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_image_load_store", 23)) { @@ -13652,6 +14655,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_sparse_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"sparse_texture", 14)) + { + ret = GLEW_ARB_sparse_texture; + continue; + } +#endif #ifdef GL_ARB_stencil_texturing if (_glewStrSame3(&pos, &len, (const GLubyte*)"stencil_texturing", 17)) { @@ -13778,6 +14788,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_texture_mirror_clamp_to_edge + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_mirror_clamp_to_edge", 28)) + { + ret = GLEW_ARB_texture_mirror_clamp_to_edge; + continue; + } +#endif #ifdef GL_ARB_texture_mirrored_repeat if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_mirrored_repeat", 23)) { @@ -13834,6 +14851,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_texture_stencil8 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_stencil8", 16)) + { + ret = GLEW_ARB_texture_stencil8; + continue; + } +#endif #ifdef GL_ARB_texture_storage if (_glewStrSame3(&pos, &len, (const GLubyte*)"texture_storage", 15)) { @@ -13960,6 +14984,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_ARB_vertex_type_10f_11f_11f_rev + if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_type_10f_11f_11f_rev", 27)) + { + ret = GLEW_ARB_vertex_type_10f_11f_11f_rev; + continue; + } +#endif #ifdef GL_ARB_vertex_type_2_10_10_10_rev if (_glewStrSame3(&pos, &len, (const GLubyte*)"vertex_type_2_10_10_10_rev", 26)) { @@ -14950,6 +15981,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) } if (_glewStrSame2(&pos, &len, (const GLubyte*)"INTEL_", 6)) { +#ifdef GL_INTEL_map_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"map_texture", 11)) + { + ret = GLEW_INTEL_map_texture; + continue; + } +#endif #ifdef GL_INTEL_parallel_arrays if (_glewStrSame3(&pos, &len, (const GLubyte*)"parallel_arrays", 15)) { @@ -15035,6 +16073,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) } if (_glewStrSame2(&pos, &len, (const GLubyte*)"NVX_", 4)) { +#ifdef GL_NVX_conditional_render + if (_glewStrSame3(&pos, &len, (const GLubyte*)"conditional_render", 18)) + { + ret = GLEW_NVX_conditional_render; + continue; + } +#endif #ifdef GL_NVX_gpu_memory_info if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_memory_info", 15)) { @@ -15045,6 +16090,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) } if (_glewStrSame2(&pos, &len, (const GLubyte*)"NV_", 3)) { +#ifdef GL_NV_bindless_multi_draw_indirect + if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_multi_draw_indirect", 28)) + { + ret = GLEW_NV_bindless_multi_draw_indirect; + continue; + } +#endif #ifdef GL_NV_bindless_texture if (_glewStrSame3(&pos, &len, (const GLubyte*)"bindless_texture", 16)) { @@ -15052,6 +16104,20 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_NV_blend_equation_advanced + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced", 23)) + { + ret = GLEW_NV_blend_equation_advanced; + continue; + } +#endif +#ifdef GL_NV_blend_equation_advanced_coherent + if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_equation_advanced_coherent", 32)) + { + ret = GLEW_NV_blend_equation_advanced_coherent; + continue; + } +#endif #ifdef GL_NV_blend_square if (_glewStrSame3(&pos, &len, (const GLubyte*)"blend_square", 12)) { @@ -15059,6 +16125,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_NV_compute_program5 + if (_glewStrSame3(&pos, &len, (const GLubyte*)"compute_program5", 16)) + { + ret = GLEW_NV_compute_program5; + continue; + } +#endif #ifdef GL_NV_conditional_render if (_glewStrSame3(&pos, &len, (const GLubyte*)"conditional_render", 18)) { @@ -15080,6 +16153,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_NV_deep_texture3D + if (_glewStrSame3(&pos, &len, (const GLubyte*)"deep_texture3D", 14)) + { + ret = GLEW_NV_deep_texture3D; + continue; + } +#endif #ifdef GL_NV_depth_buffer_float if (_glewStrSame3(&pos, &len, (const GLubyte*)"depth_buffer_float", 18)) { @@ -15101,6 +16181,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_NV_draw_texture + if (_glewStrSame3(&pos, &len, (const GLubyte*)"draw_texture", 12)) + { + ret = GLEW_NV_draw_texture; + continue; + } +#endif #ifdef GL_NV_evaluators if (_glewStrSame3(&pos, &len, (const GLubyte*)"evaluators", 10)) { @@ -15199,6 +16286,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_NV_gpu_program5_mem_extended + if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_program5_mem_extended", 25)) + { + ret = GLEW_NV_gpu_program5_mem_extended; + continue; + } +#endif #ifdef GL_NV_gpu_program_fp64 if (_glewStrSame3(&pos, &len, (const GLubyte*)"gpu_program_fp64", 16)) { @@ -15318,6 +16412,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_NV_shader_atomic_counters + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_counters", 22)) + { + ret = GLEW_NV_shader_atomic_counters; + continue; + } +#endif #ifdef GL_NV_shader_atomic_float if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_atomic_float", 19)) { @@ -15332,6 +16433,13 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) continue; } #endif +#ifdef GL_NV_shader_storage_buffer_object + if (_glewStrSame3(&pos, &len, (const GLubyte*)"shader_storage_buffer_object", 28)) + { + ret = GLEW_NV_shader_storage_buffer_object; + continue; + } +#endif #ifdef GL_NV_tessellation_program5 if (_glewStrSame3(&pos, &len, (const GLubyte*)"tessellation_program5", 21)) { @@ -15589,6 +16697,27 @@ GLboolean GLEWAPIENTRY glewIsSupported (const char* name) } if (_glewStrSame2(&pos, &len, (const GLubyte*)"REGAL_", 6)) { +#ifdef GL_REGAL_ES1_0_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES1_0_compatibility", 19)) + { + ret = GLEW_REGAL_ES1_0_compatibility; + continue; + } +#endif +#ifdef GL_REGAL_ES1_1_compatibility + if (_glewStrSame3(&pos, &len, (const GLubyte*)"ES1_1_compatibility", 19)) + { + ret = GLEW_REGAL_ES1_1_compatibility; + continue; + } +#endif +#ifdef GL_REGAL_enable + if (_glewStrSame3(&pos, &len, (const GLubyte*)"enable", 6)) + { + ret = GLEW_REGAL_enable; + continue; + } +#endif #ifdef GL_REGAL_error_string if (_glewStrSame3(&pos, &len, (const GLubyte*)"error_string", 12)) { @@ -16205,6 +17334,20 @@ GLboolean GLEWAPIENTRY wglewIsSupported (const char* name) ret = WGLEW_ARB_render_texture; continue; } +#endif +#ifdef WGL_ARB_robustness_application_isolation + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robustness_application_isolation", 32)) + { + ret = WGLEW_ARB_robustness_application_isolation; + continue; + } +#endif +#ifdef WGL_ARB_robustness_share_group_isolation + if (_glewStrSame3(&pos, &len, (const GLubyte*)"robustness_share_group_isolation", 32)) + { + ret = WGLEW_ARB_robustness_share_group_isolation; + continue; + } #endif } if (_glewStrSame2(&pos, &len, (const GLubyte*)"ATI_", 4)) @@ -16473,7 +17616,7 @@ GLboolean GLEWAPIENTRY wglewIsSupported (const char* name) return ret; } -#elif !defined(__ANDROID__) && !defined(__APPLE__) || defined(GLEW_APPLE_GLX) +#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__APPLE__) || defined(GLEW_APPLE_GLX) #if defined(GLEW_MX) GLboolean glxewContextIsSupported (const GLXEWContext* ctx, const char* name) @@ -16624,6 +17767,13 @@ GLboolean glxewIsSupported (const char* name) } if (_glewStrSame2(&pos, &len, (const GLubyte*)"EXT_", 4)) { +#ifdef GLX_EXT_buffer_age + if (_glewStrSame3(&pos, &len, (const GLubyte*)"buffer_age", 10)) + { + ret = GLXEW_EXT_buffer_age; + continue; + } +#endif #ifdef GLX_EXT_create_context_es2_profile if (_glewStrSame3(&pos, &len, (const GLubyte*)"create_context_es2_profile", 26)) { @@ -16808,10 +17958,10 @@ GLboolean glxewIsSupported (const char* name) continue; } #endif -#ifdef GLX_NV_video_out - if (_glewStrSame3(&pos, &len, (const GLubyte*)"video_out", 9)) +#ifdef GLX_NV_video_output + if (_glewStrSame3(&pos, &len, (const GLubyte*)"video_output", 12)) { - ret = GLXEW_NV_video_out; + ret = GLXEW_NV_video_output; continue; } #endif From dca234ec022a2e715679da0cab00322b96678131 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 1 Jul 2014 13:01:42 -0700 Subject: [PATCH 081/116] use included glew on Linux, only if glew is not installed in /usr/include/GL/glew.h --- build3/findOpenGLGlewGlut.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/build3/findOpenGLGlewGlut.lua b/build3/findOpenGLGlewGlut.lua index dada07921..c4e8d6f60 100644 --- a/build3/findOpenGLGlewGlut.lua +++ b/build3/findOpenGLGlewGlut.lua @@ -52,7 +52,18 @@ files { projectRootDir .. "btgui/OpenGLWindow/GlewWindows/glew.c"} end if os.is("Linux") then - links{"GLEW"} + configuration{"Linux"} + if os.isdir("/usr/include") and os.isfile("/usr/include/GL/glew.h") then + links {"GLEW"} + else + defines { "GLEW_STATIC"} + --,"GLEW_NO_GLU"} + includedirs { + projectRootDir .. "btgui/OpenGLWindow/GlewWindows" + } + files { projectRootDir .. "btgui/OpenGLWindow/GlewWindows/glew.c"} + end + end configuration{} end From bae303c5da3fcfd35677da7759515f43541e2fff Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 3 Jul 2014 16:42:50 -0700 Subject: [PATCH 082/116] add preliminary glut replacement test for Bullet 2.x demos --- Demos/OpenGL/DemoApplication.cpp | 3 + Demos/OpenGL/DemoApplication.h | 6 + Demos/OpenGL/GLDebugFont.cpp | 15 +- Demos/OpenGL/GlutStuff.cpp | 5 +- Demos/OpenGL/GlutStuff.h | 81 ++++--- Demos/OpenGL/RenderTexture.h | 5 + Demos3/BasicDemoConsole/main.cpp | 14 ++ Demos3/BasicDemoConsole/premake4.lua | 26 +++ Demos3/BasicDemoCustomOpenGL2/main.cpp | 255 +++++++++++++++++++++ Demos3/BasicDemoCustomOpenGL2/premake4.lua | 34 +++ btgui/OpenGLWindow/Win32Window.cpp | 4 +- build3/premake4.lua | 5 + 12 files changed, 416 insertions(+), 37 deletions(-) create mode 100644 Demos3/BasicDemoConsole/main.cpp create mode 100644 Demos3/BasicDemoConsole/premake4.lua create mode 100644 Demos3/BasicDemoCustomOpenGL2/main.cpp create mode 100644 Demos3/BasicDemoCustomOpenGL2/premake4.lua diff --git a/Demos/OpenGL/DemoApplication.cpp b/Demos/OpenGL/DemoApplication.cpp index e373a08e3..a231c8789 100644 --- a/Demos/OpenGL/DemoApplication.cpp +++ b/Demos/OpenGL/DemoApplication.cpp @@ -14,6 +14,7 @@ subject to the following restrictions: */ + #include "DemoApplication.h" #include "LinearMath/btIDebugDraw.h" #include "BulletDynamics/Dynamics/btDynamicsWorld.h" @@ -112,6 +113,8 @@ DemoApplication::~DemoApplication() if (m_shapeDrawer) delete m_shapeDrawer; + + //GLDebugResetFont(0,0); } diff --git a/Demos/OpenGL/DemoApplication.h b/Demos/OpenGL/DemoApplication.h index a86ff8e79..acbcc80e7 100644 --- a/Demos/OpenGL/DemoApplication.h +++ b/Demos/OpenGL/DemoApplication.h @@ -112,6 +112,12 @@ public: virtual ~DemoApplication(); + void setDynamicsWorld(btDynamicsWorld* world) + { + m_dynamicsWorld=world; + } + + btDynamicsWorld* getDynamicsWorld() { return m_dynamicsWorld; diff --git a/Demos/OpenGL/GLDebugFont.cpp b/Demos/OpenGL/GLDebugFont.cpp index 616006810..68ee650e9 100644 --- a/Demos/OpenGL/GLDebugFont.cpp +++ b/Demos/OpenGL/GLDebugFont.cpp @@ -41,7 +41,7 @@ subject to the following restrictions: #include #else #include -#include +#include #endif #endif @@ -59,6 +59,19 @@ static int sScreenHeight = -1; void GLDebugResetFont(int screenWidth,int screenHeight) { + if (screenWidth==0 && screenHeight==0) + { + sScreenWidth = screenWidth; + sScreenHeight = screenHeight; + + if (sTexturesInitialized) + { + glDeleteTextures(1, &sTexture); + glBindTexture(GL_TEXTURE_2D,0); + sTexturesInitialized = false; + } + return; + } if ((sScreenWidth == screenWidth) && (sScreenHeight == screenHeight)) return; diff --git a/Demos/OpenGL/GlutStuff.cpp b/Demos/OpenGL/GlutStuff.cpp index 95658f1f2..b9d5496b9 100644 --- a/Demos/OpenGL/GlutStuff.cpp +++ b/Demos/OpenGL/GlutStuff.cpp @@ -13,7 +13,7 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -#ifndef _WINDOWS +#ifndef DONT_USE_GLUT #include "DemoApplication.h" @@ -71,6 +71,7 @@ static void glutDisplayCallback(void) gDemoApplication->displayCallback(); } +#include int glutmain(int argc, char **argv,int width,int height,const char* title,DemoApplication* demoApp) { @@ -117,4 +118,4 @@ CGLSetParameter(cgl_context, kCGLCPSwapInterval, &swap_interval); } -#endif //_WINDOWS +#endif //DONT_USE_GLUT diff --git a/Demos/OpenGL/GlutStuff.h b/Demos/OpenGL/GlutStuff.h index 76435ceeb..49631b17f 100644 --- a/Demos/OpenGL/GlutStuff.h +++ b/Demos/OpenGL/GlutStuff.h @@ -15,51 +15,68 @@ subject to the following restrictions: #ifndef GLUT_STUFF_H #define GLUT_STUFF_H +#ifdef DONT_USE_GLUT #ifdef _WIN32//for glut.h #include #endif +#endif //DONT_USE_GLUT //think different #if defined(__APPLE__) && !defined (VMDMESA) #include #include #include -#include -#else +#ifndef DONT_USE_GLUT + #include +#endif//DONT_USE_GLUT +#else//(__APPLE__) && !defined (VMDMESA) + #ifdef _WINDOWS -#include -#include -#include -#else -#include -#include -#endif //_WINDOWS -#endif //APPLE + #include + #include + #include + #define BT_ACTIVE_ALT VK_LMENU + #define BT_ACTIVE_SHIFT VK_LSHIFT + #define BT_ACTIVE_CTRL VK_LCONTROL +#else //_WINDOWS + +#ifdef DONT_USE_GLUT + #include + #include + #define BT_ACTIVE_ALT 8192 + #define BT_ACTIVE_SHIFT 8193 + #define BT_ACTIVE_CTRL 8194 +#else//DONT_USE_GLUT + #ifdef _WIN32 + #include + #endif//_WIN32 + #include + #include + #define BT_KEY_K 'k' + #define BT_KEY_LEFT GLUT_KEY_LEFT + #define BT_KEY_RIGHT GLUT_KEY_RIGHT + #define BT_KEY_UP GLUT_KEY_UP + #define BT_KEY_DOWN GLUT_KEY_DOWN + #define BT_KEY_F1 GLUT_KEY_F1 + #define BT_KEY_F2 GLUT_KEY_F2 + #define BT_KEY_F3 GLUT_KEY_F3 + #define BT_KEY_F4 GLUT_KEY_F4 + #define BT_KEY_F5 GLUT_KEY_F5 + #define BT_KEY_PAGEUP GLUT_KEY_PAGE_UP + #define BT_KEY_PAGEDOWN GLUT_KEY_PAGE_DOWN + #define BT_KEY_END GLUT_KEY_END + #define BT_KEY_HOME GLUT_KEY_HOME + #define BT_ACTIVE_ALT GLUT_ACTIVE_ALT + #define BT_ACTIVE_CTRL GLUT_ACTIVE_ALT + #define BT_ACTIVE_SHIFT GLUT_ACTIVE_SHIFT + +#endif//DONT_USE_GLUT +#endif//_WINDOWS +#endif //(__APPLE__) && !defined (VMDMESA) + -#ifdef _WINDOWS -#define BT_ACTIVE_ALT VK_LMENU -#define BT_ACTIVE_SHIFT VK_LSHIFT -#else -#define BT_KEY_K 'k' -#define BT_KEY_LEFT GLUT_KEY_LEFT -#define BT_KEY_RIGHT GLUT_KEY_RIGHT -#define BT_KEY_UP GLUT_KEY_UP -#define BT_KEY_DOWN GLUT_KEY_DOWN -#define BT_KEY_F1 GLUT_KEY_F1 -#define BT_KEY_F2 GLUT_KEY_F2 -#define BT_KEY_F3 GLUT_KEY_F3 -#define BT_KEY_F4 GLUT_KEY_F4 -#define BT_KEY_F5 GLUT_KEY_F5 -#define BT_KEY_PAGEUP GLUT_KEY_PAGE_UP -#define BT_KEY_PAGEDOWN GLUT_KEY_PAGE_DOWN -#define BT_KEY_END GLUT_KEY_END -#define BT_KEY_HOME GLUT_KEY_HOME -#define BT_ACTIVE_ALT GLUT_ACTIVE_ALT -#define BT_ACTIVE_CTRL GLUT_ACTIVE_ALT -#define BT_ACTIVE_SHIFT GLUT_ACTIVE_SHIFT -#endif #if BT_USE_FREEGLUT #include "GL/freeglut_ext.h" //to be able to return from glutMainLoop() diff --git a/Demos/OpenGL/RenderTexture.h b/Demos/OpenGL/RenderTexture.h index 1aee51d79..1153018a1 100644 --- a/Demos/OpenGL/RenderTexture.h +++ b/Demos/OpenGL/RenderTexture.h @@ -36,6 +36,11 @@ public: ///rgba input is in range [0..1] for each component inline void setPixel(int x,int y,const btVector4& rgba) { + btAssert(x>=0); + btAssert(y>=0); + btAssert(x +#include "../../Demos/BasicDemo/BasicDemoPhysicsSetup.h" + +int main(int argc, char* argv[]) +{ + BasicDemoPhysicsSetup physicsSetup; + GraphicsPhysicsBridge br; + physicsSetup.initPhysics(br); + physicsSetup.stepSimulation(1./60.); + physicsSetup.exitPhysics(); + + printf("hello\n"); +} \ No newline at end of file diff --git a/Demos3/BasicDemoConsole/premake4.lua b/Demos3/BasicDemoConsole/premake4.lua new file mode 100644 index 000000000..330128b24 --- /dev/null +++ b/Demos3/BasicDemoConsole/premake4.lua @@ -0,0 +1,26 @@ +project "App_BasicDemoConsole" + + kind "ConsoleApp" + targetdir "../../bin" + + includedirs {"../../src"} + configuration { "Windows" } +-- links { "opengl32","glu32","gdi32","winmm", "user32" } + files { "../../build3/bullet.rc" } +-- configuration {"MacOSX"} + --print "hello" + -- linkoptions { "-framework Carbon -framework OpenGL -framework AGL -framework Glut" } +-- configuration {"not Windows", "not MacOSX"} +-- links {"GL","GLU","glut"} + configuration{} + + links { + "BulletDynamics", "BulletCollision", "LinearMath" + } + + files { + "*.cpp" , + "*.h", + "../../Demos/BasicDemo/BasicDemoPhysicsSetup.cpp", + "../../Demos/BasicDemo/BasicDemoPhysicsSetup.h" + } diff --git a/Demos3/BasicDemoCustomOpenGL2/main.cpp b/Demos3/BasicDemoCustomOpenGL2/main.cpp new file mode 100644 index 000000000..aabb85135 --- /dev/null +++ b/Demos3/BasicDemoCustomOpenGL2/main.cpp @@ -0,0 +1,255 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2014 Erwin Coumans http://bulletphysics.org + +//This file is Copyright (c) 2014 Google Inc. + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. +*/ + +///This main.cpp replaces glut by Bullet 3 own platform management for OpenGL and input devices + +#include +#include "../../Demos/BasicDemo/BasicDemoPhysicsSetup.h" + + +#ifdef __APPLE__ +#include "OpenGLWindow/MacOpenGLWindow.h" +#else + +#include "GL/glew.h" +#ifdef _WIN32 +#include "OpenGLWindow/Win32OpenGLWindow.h" +#else +//let's cross the fingers it is Linux/X11 +#include "OpenGLWindow/X11OpenGLWindow.h" +#endif //_WIN32 +#endif//__APPLE__ + +#include "../../Demos/OpenGL/DemoApplication.h" +#include "../../Demos/OpenGL/GLDebugDrawer.h" + +int sWidth = 800; +int sHeight = 600; +DemoApplication* gApp = 0; +bool isShiftPressed = false; +bool isCtrlPressed = false; +bool isAltPressed = false; + +/* +todo: add wheel callback +typedef void (*b3WheelCallback)(float deltax, float deltay); +*/ + +void MyKeyboardCallback(int orgKeycode, int state) +{ + int keycode = orgKeycode; + + if (gApp) + { + + switch (orgKeycode) + { + case B3G_SHIFT: + { + isShiftPressed = (state==1); + break; + } + case B3G_ALT: + { + isAltPressed = (state==1); + break; + } + case B3G_CONTROL: + { + isCtrlPressed = (state==1); + break; + } + default: + { + } + }; + + if (state) + { + gApp->keyboardCallback(keycode,0,0); + } else + { + gApp->keyboardUpCallback(keycode,0,0); + } + } +} +void MyMouseMoveCallback( float x, float y) +{ + if (gApp) + { + //printf("mouseMotionFunc %f,%f\n",x,y); + gApp->mouseMotionFunc(x,y); + } +} + +void MyMouseButtonCallback(int button, int state, float x, float y) +{ + if (gApp) + { + //printf("mouseFunc %d,%d, %f,%f\n",button,state,x,y); + gApp->mouseFunc(button,1-state,x,y); + } +} + +void MyResizeCallback(float width, float height) +{ + sWidth = width; + sHeight = height; + if (gApp) + { + gApp->reshape(width,height); + } +} + +int main(int argc, char* argv[]) +{ + + b3gDefaultOpenGLWindow* window = new b3gDefaultOpenGLWindow(); + //window->setKeyboardCallback(keyCallback); + b3gWindowConstructionInfo wci; + wci.m_openglVersion = 2; + wci.m_width = sWidth; + wci.m_height = sHeight; + // wci.m_resizeCallback = MyResizeCallback; + + window->createWindow(wci); + window->setResizeCallback(MyResizeCallback); + window->setMouseButtonCallback(MyMouseButtonCallback); + + window->setMouseMoveCallback(MyMouseMoveCallback); + window->setKeyboardCallback(MyKeyboardCallback); + + //window->setWindowTitle("render test"); + + int majorGlVersion, minorGlVersion; + + if (!sscanf((const char*)glGetString(GL_VERSION), "%d.%d", &majorGlVersion, &minorGlVersion)==2) + { + printf("Exit: Error cannot extract OpenGL version from GL_VERSION string\n"); + exit(0); + } + if (majorGlVersion>=3 && wci.m_openglVersion>=3) + { + float retinaScale = 1.f; + +#ifndef __APPLE__ +#ifndef _WIN32 + //we need glewExperimental on Linux + glewExperimental = GL_TRUE; +#endif // _WIN32 + glewInit(); +#endif + + //we ned to call glGetError twice, because of some Ubuntu/Intel/OpenGL issue + + GLuint err = glGetError(); + err = glGetError(); + btAssert(err==GL_NO_ERROR); + + + retinaScale = window->getRetinaScale(); + + //primRenderer = new GLPrimitiveRenderer(sWidth,sHeight); + //sth_stash* font = initFont(primRenderer ); + //gwenRenderer = new GwenOpenGL3CoreRenderer(primRenderer,font,sWidth,sHeight,retinaScale); + + } else + { + //OpenGL 2.x + /*gwenRenderer = new Gwen::Renderer::OpenGL_DebugFont(); + skin.SetRender( gwenRenderer ); + + pCanvas = new Gwen::Controls::Canvas( &skin ); + pCanvas->SetSize( sWidth, sHeight); + pCanvas->SetDrawBackground( true ); + pCanvas->SetBackgroundColor( Gwen::Color( 150, 170, 170, 255 ) ); + */ + + } + + +// glClearColor(0.2,0.2,0.2,1); + + + + BasicDemoPhysicsSetup physicsSetup; + GraphicsPhysicsBridge br; + physicsSetup.initPhysics(br); + + + struct MyAppie : public DemoApplication + { + virtual void initPhysics() + { + } + virtual void clientMoveAndDisplay() + { + } + virtual void swapBuffers() + { + } + virtual void updateModifierKeys() + { + m_modifierKeys = 0; + if (isAltPressed) + m_modifierKeys |= BT_ACTIVE_ALT; + + if (isCtrlPressed) + m_modifierKeys |= BT_ACTIVE_CTRL; + + if (isShiftPressed) + m_modifierKeys |= BT_ACTIVE_SHIFT; + + } + + }; + + { + MyAppie appie; + appie.setDynamicsWorld(physicsSetup.m_dynamicsWorld); + appie.reshape(sWidth,sHeight); + appie.setShadows(true); + gApp = &appie; + GLDebugDrawer draw; + physicsSetup.m_dynamicsWorld->setDebugDrawer(&draw); + btClock timer; + unsigned long prevTime = timer.getTimeMicroseconds(); + + do + { + unsigned long curTime = timer.getTimeMicroseconds(); + if (!appie.isIdle()) + { + physicsSetup.stepSimulation((curTime-prevTime)*(1./1000000.)); + } + prevTime = curTime; + window->startRendering(); + br.syncPhysicsToGraphics(physicsSetup.m_dynamicsWorld); + appie.renderme(); + physicsSetup.m_dynamicsWorld->debugDrawWorld(); + window->endRendering(); + + } while (!window->requestedExit()); + } + window->closeWindow(); + delete window; + + physicsSetup.exitPhysics(); + + + printf("hello\n"); +} \ No newline at end of file diff --git a/Demos3/BasicDemoCustomOpenGL2/premake4.lua b/Demos3/BasicDemoCustomOpenGL2/premake4.lua new file mode 100644 index 000000000..c2cd23b10 --- /dev/null +++ b/Demos3/BasicDemoCustomOpenGL2/premake4.lua @@ -0,0 +1,34 @@ +project "App_BasicDemoCustomOpenGL2" + + kind "ConsoleApp" + targetdir "../../bin" + + includedirs { + "../../src", + "../../btgui" + } + + defines { "DONT_USE_GLUT"} + + initOpenGL() + initGlew() + + links { + "OpenGL_Window","BulletDynamics", "BulletCollision", "LinearMath" + } + + files { + "*.cpp" , + "*.h", + "../../Demos/BasicDemo/BasicDemoPhysicsSetup.cpp", + "../../Demos/BasicDemo/BasicDemoPhysicsSetup.h", + "../../Demos/OpenGL/DemoApplication.cpp", + "../../Demos/OpenGL/DemoApplication.h", + "../../Demos/OpenGL/GL_ShapeDrawer.cpp", + "../../Demos/OpenGL/GL_ShapeDrawer.h", + "../../Demos/OpenGL/GL_ShapeDrawer.cpp", + "../../Demos/OpenGL/GLDebugDrawer.cpp", + "../../Demos/OpenGL/GLDebugDrawer.h", + "../../Demos/OpenGL/GLDebugFont.cpp", + "../../Demos/OpenGL/GLDebugFont.h" + } diff --git a/btgui/OpenGLWindow/Win32Window.cpp b/btgui/OpenGLWindow/Win32Window.cpp index 1d94ae3c4..19615e18c 100644 --- a/btgui/OpenGLWindow/Win32Window.cpp +++ b/btgui/OpenGLWindow/Win32Window.cpp @@ -65,7 +65,7 @@ int getAsciiCodeFromVirtualKeycode(int virtualKeyCode) } if (virtualKeyCode >= 'A' && virtualKeyCode <= 'Z') { - return virtualKeyCode; + return virtualKeyCode+32;//todo: fix the ascii A vs a input } switch (virtualKeyCode) { @@ -170,7 +170,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int keycode = getAsciiCodeFromVirtualKeycode(wParam); - if (keycode>=0 && sData && sData->m_keyboardCallback && ((HIWORD(lParam) & KF_REPEAT) == 0)) + if (keycode>=0 && sData && sData->m_keyboardCallback)// && ((HIWORD(lParam) & KF_REPEAT) == 0)) { int state = 1; (*sData->m_keyboardCallback)(keycode,state); diff --git a/build3/premake4.lua b/build3/premake4.lua index 6b679d976..d6a880a22 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -104,6 +104,11 @@ if findOpenGL() then include "../Demos3/AllBullet2Demos" include "../Demos3/GpuDemos" + --include"../Demos3/BasicDemoConsole" + --include"../Demos3/BasicDemoCustomOpenGL2" + + + -- include "../Demos3/CpuDemos" -- include "../Demos3/Wavefront" -- include "../btgui/MultiThreading" From b438b910094cc28a38e99fbc0bd758528579f6a7 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 3 Jul 2014 22:30:50 -0700 Subject: [PATCH 083/116] fix Mac build --- Demos/OpenGL/GL_ShapeDrawer.cpp | 4 +- Demos/OpenGL/GlutStuff.cpp | 2 +- Demos/OpenGL/GlutStuff.h | 53 ++++++++++++---------- Demos3/BasicDemoCustomOpenGL2/premake4.lua | 5 ++ btgui/OpenGLWindow/MacOpenGLWindow.mm | 2 +- build3/premake4.lua | 4 +- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/Demos/OpenGL/GL_ShapeDrawer.cpp b/Demos/OpenGL/GL_ShapeDrawer.cpp index f9acd1250..c23355503 100644 --- a/Demos/OpenGL/GL_ShapeDrawer.cpp +++ b/Demos/OpenGL/GL_ShapeDrawer.cpp @@ -515,8 +515,8 @@ void GL_ShapeDrawer::drawOpenGL(btScalar* m, const btCollisionShape* shape, cons glGenTextures(1,(GLuint*)&m_texturehandle); glBindTexture(GL_TEXTURE_2D,m_texturehandle); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); + //glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); + //glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); gluBuild2DMipmaps(GL_TEXTURE_2D,3,256,256,GL_RGB,GL_UNSIGNED_BYTE,image); diff --git a/Demos/OpenGL/GlutStuff.cpp b/Demos/OpenGL/GlutStuff.cpp index b9d5496b9..c40de30e5 100644 --- a/Demos/OpenGL/GlutStuff.cpp +++ b/Demos/OpenGL/GlutStuff.cpp @@ -71,7 +71,7 @@ static void glutDisplayCallback(void) gDemoApplication->displayCallback(); } -#include +//#include int glutmain(int argc, char **argv,int width,int height,const char* title,DemoApplication* demoApp) { diff --git a/Demos/OpenGL/GlutStuff.h b/Demos/OpenGL/GlutStuff.h index 49631b17f..0cf19c304 100644 --- a/Demos/OpenGL/GlutStuff.h +++ b/Demos/OpenGL/GlutStuff.h @@ -37,46 +37,51 @@ subject to the following restrictions: #include #include #include - #define BT_ACTIVE_ALT VK_LMENU - #define BT_ACTIVE_SHIFT VK_LSHIFT - #define BT_ACTIVE_CTRL VK_LCONTROL #else //_WINDOWS #ifdef DONT_USE_GLUT #include #include - #define BT_ACTIVE_ALT 8192 - #define BT_ACTIVE_SHIFT 8193 - #define BT_ACTIVE_CTRL 8194 #else//DONT_USE_GLUT #ifdef _WIN32 #include #endif//_WIN32 #include #include - #define BT_KEY_K 'k' - #define BT_KEY_LEFT GLUT_KEY_LEFT - #define BT_KEY_RIGHT GLUT_KEY_RIGHT - #define BT_KEY_UP GLUT_KEY_UP - #define BT_KEY_DOWN GLUT_KEY_DOWN - #define BT_KEY_F1 GLUT_KEY_F1 - #define BT_KEY_F2 GLUT_KEY_F2 - #define BT_KEY_F3 GLUT_KEY_F3 - #define BT_KEY_F4 GLUT_KEY_F4 - #define BT_KEY_F5 GLUT_KEY_F5 - #define BT_KEY_PAGEUP GLUT_KEY_PAGE_UP - #define BT_KEY_PAGEDOWN GLUT_KEY_PAGE_DOWN - #define BT_KEY_END GLUT_KEY_END - #define BT_KEY_HOME GLUT_KEY_HOME - #define BT_ACTIVE_ALT GLUT_ACTIVE_ALT - #define BT_ACTIVE_CTRL GLUT_ACTIVE_ALT - #define BT_ACTIVE_SHIFT GLUT_ACTIVE_SHIFT #endif//DONT_USE_GLUT #endif//_WINDOWS #endif //(__APPLE__) && !defined (VMDMESA) - +#ifdef _WINDOWS + #define BT_ACTIVE_ALT VK_LMENU + #define BT_ACTIVE_SHIFT VK_LSHIFT + #define BT_ACTIVE_CTRL VK_LCONTROL +#else //_WINDOWS +#ifdef DONT_USE_GLUT + #define BT_ACTIVE_ALT 8192 + #define BT_ACTIVE_SHIFT 8193 + #define BT_ACTIVE_CTRL 8194 +#else//DONT_USE_GLUT + #define BT_KEY_K 'k' + #define BT_KEY_LEFT GLUT_KEY_LEFT + #define BT_KEY_RIGHT GLUT_KEY_RIGHT + #define BT_KEY_UP GLUT_KEY_UP + #define BT_KEY_DOWN GLUT_KEY_DOWN + #define BT_KEY_F1 GLUT_KEY_F1 + #define BT_KEY_F2 GLUT_KEY_F2 + #define BT_KEY_F3 GLUT_KEY_F3 + #define BT_KEY_F4 GLUT_KEY_F4 + #define BT_KEY_F5 GLUT_KEY_F5 + #define BT_KEY_PAGEUP GLUT_KEY_PAGE_UP + #define BT_KEY_PAGEDOWN GLUT_KEY_PAGE_DOWN + #define BT_KEY_END GLUT_KEY_END + #define BT_KEY_HOME GLUT_KEY_HOME + #define BT_ACTIVE_ALT GLUT_ACTIVE_ALT + #define BT_ACTIVE_CTRL GLUT_ACTIVE_ALT + #define BT_ACTIVE_SHIFT GLUT_ACTIVE_SHIFT +#endif +#endif #if BT_USE_FREEGLUT #include "GL/freeglut_ext.h" //to be able to return from glutMainLoop() diff --git a/Demos3/BasicDemoCustomOpenGL2/premake4.lua b/Demos3/BasicDemoCustomOpenGL2/premake4.lua index c2cd23b10..e59c3e9ab 100644 --- a/Demos3/BasicDemoCustomOpenGL2/premake4.lua +++ b/Demos3/BasicDemoCustomOpenGL2/premake4.lua @@ -32,3 +32,8 @@ project "App_BasicDemoCustomOpenGL2" "../../Demos/OpenGL/GLDebugFont.cpp", "../../Demos/OpenGL/GLDebugFont.h" } +if os.is("Linux") then links{"X11","pthread"} end + +if os.is("MacOSX") then + links{"Cocoa.framework"} +end diff --git a/btgui/OpenGLWindow/MacOpenGLWindow.mm b/btgui/OpenGLWindow/MacOpenGLWindow.mm index 1327041fa..8cab0de5e 100644 --- a/btgui/OpenGLWindow/MacOpenGLWindow.mm +++ b/btgui/OpenGLWindow/MacOpenGLWindow.mm @@ -942,7 +942,7 @@ void MacOpenGLWindow::startRendering() assert(err==GL_NO_ERROR); - glClearColor(1,1,1,1); + // glClearColor(1,1,1,1); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //clear buffers err = glGetError(); diff --git a/build3/premake4.lua b/build3/premake4.lua index d6a880a22..9d17c5e3c 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -104,8 +104,8 @@ if findOpenGL() then include "../Demos3/AllBullet2Demos" include "../Demos3/GpuDemos" - --include"../Demos3/BasicDemoConsole" - --include"../Demos3/BasicDemoCustomOpenGL2" + include"../Demos3/BasicDemoConsole" + include"../Demos3/BasicDemoCustomOpenGL2" From f89d70b8954e4c15d598527fa9431dd8a5e30cfe Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Thu, 3 Jul 2014 22:41:07 -0700 Subject: [PATCH 084/116] fix Linux build --- build3/findOpenGLGlewGlut.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build3/findOpenGLGlewGlut.lua b/build3/findOpenGLGlewGlut.lua index c4e8d6f60..d34884c48 100644 --- a/build3/findOpenGLGlewGlut.lua +++ b/build3/findOpenGLGlewGlut.lua @@ -16,7 +16,7 @@ configuration {"MacOSX"} links { "OpenGL.framework"} configuration {"not Windows", "not MacOSX"} - links {"GL"} + links {"GL","GLU"} configuration{} end @@ -37,7 +37,7 @@ configuration {"MacOSX"} links { "Glut.framework" } configuration {"Linux"} - links {"glut","GLU"} + links {"glut"} configuration{} end From 27b0e4d1e6fa1b8a6722915eb0120f59598552f5 Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Tue, 8 Jul 2014 16:42:57 -0700 Subject: [PATCH 085/116] experiments with params in AllBullet2Demos (quick hack for testing, will clean this up soon) yet another workaround to make Intel GPU work with glDrawBuffers on Ubuntu --- Demos/CommonRigidBodySetup.h | 4 + Demos3/AllBullet2Demos/main.cpp | 121 ++++++++++++++++++++--- Demos3/GpuDemos/gwenUserInterface.cpp | 2 +- btgui/OpenGLWindow/GLRenderToTexture.cpp | 21 ++-- 4 files changed, 120 insertions(+), 28 deletions(-) diff --git a/Demos/CommonRigidBodySetup.h b/Demos/CommonRigidBodySetup.h index bf28d5f59..3ba22cb6a 100644 --- a/Demos/CommonRigidBodySetup.h +++ b/Demos/CommonRigidBodySetup.h @@ -71,6 +71,10 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup //remove the rigidbodies from the dynamics world and delete them int i; + for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--) + { + m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i)); + } if (m_dynamicsWorld) { diff --git a/Demos3/AllBullet2Demos/main.cpp b/Demos3/AllBullet2Demos/main.cpp index 4029b2bac..41dc09498 100644 --- a/Demos3/AllBullet2Demos/main.cpp +++ b/Demos3/AllBullet2Demos/main.cpp @@ -14,6 +14,7 @@ static int sCurrentDemoIndex = 0; static int sCurrentHightlighted = 0; static BulletDemoInterface* sCurrentDemo = 0; static b3AlignedObjectArray allNames; +double motorA=0,motorB=0; bool drawGUI=true; @@ -64,9 +65,9 @@ void MyKeyboardCallback(int key, int state) { app->m_window->setRequestExit(); } - + b3DefaultKeyboardCallback(key,state); - + } static void MyMouseMoveCallback( float x, float y) @@ -98,10 +99,12 @@ static void MyMouseButtonCallback(int button, int state, float x, float y) void selectDemo(int demoIndex) { sCurrentDemoIndex = demoIndex; + sCurrentHightlighted = demoIndex; int numDemos = sizeof(allDemos)/sizeof(BulletDemoEntry); if (demoIndex>numDemos) + { demoIndex = 0; - + } if (sCurrentDemo) { sCurrentDemo->exitPhysics(); @@ -109,19 +112,20 @@ void selectDemo(int demoIndex) delete sCurrentDemo; sCurrentDemo=0; } - if (allDemos[demoIndex].m_createFunc && app) { sCurrentDemo = (*allDemos[demoIndex].m_createFunc)(app); if (sCurrentDemo) + { sCurrentDemo->initPhysics(); - + } } + } void MyComboBoxCallback(int comboId, const char* item) { - printf("comboId = %d, item = %s\n",comboId, item); + //printf("comboId = %d, item = %s\n",comboId, item); if (comboId==DEMO_SELECTION_COMBOBOX) { //find selected item @@ -135,7 +139,7 @@ void MyComboBoxCallback(int comboId, const char* item) } } } - + } @@ -215,13 +219,92 @@ struct MyMenuItemHander :public Gwen::Event::Handler //printf("onButtonG !\n"); } - + }; + +template +struct MySliderEventHandler : public Gwen::Event::Handler +{ + Gwen::Controls::TextBox* m_label; + Gwen::Controls::Slider* m_pSlider; + char m_variableName[1024]; + T* m_targetValue; + + MySliderEventHandler(const char* varName, Gwen::Controls::TextBox* label, Gwen::Controls::Slider* pSlider,T* target) + :m_label(label), + m_pSlider(pSlider), + m_targetValue(target) + { + memcpy(m_variableName,varName,strlen(varName)+1); + } + + + void SliderMoved( Gwen::Controls::Base* pControl ) + { + Gwen::Controls::Slider* pSlider = (Gwen::Controls::Slider*)pControl; + //printf("value = %f\n", pSlider->GetValue());//UnitPrint( Utility::Format( L"Slider Value: %.2f", pSlider->GetValue() ) ); + float bla = pSlider->GetValue(); + T v = T(bla); + SetValue(v); + + } + + void SetValue(T v) + { + if (v < m_pSlider->GetRangeMin()) + { + printf("?\n"); + } + + if (v > m_pSlider->GetRangeMax()) + { + printf("?\n"); + + } + m_pSlider->SetValue(v,true); + (*m_targetValue) = v; + int val = int(v);//todo: specialize on template type + char txt[1024]; + sprintf(txt,"%s : %d", m_variableName,val); + m_label->SetText(txt); + + } +}; +void MyParameter(const char* name, GwenInternalData* data, double* param) +{ + Gwen::Controls::TextBox* label = new Gwen::Controls::TextBox(data->m_demoPage->GetPage()); + //m_data->m_myControls.push_back(label); + label->SetText( name); + label->SetPos( 10, 10 + 25 ); + label->SetWidth(110); + label->SetPos(10,data->m_curYposition); + data->m_curYposition+=22; + + Gwen::Controls::HorizontalSlider* pSlider = new Gwen::Controls::HorizontalSlider( data->m_demoPage->GetPage()); + //m_data->m_myControls.push_back(pSlider); + pSlider->SetPos( 10, data->m_curYposition ); + pSlider->SetSize( 100, 20 ); + pSlider->SetRange( -10, 10 ); + pSlider->SetNotchCount(10); + pSlider->SetClampToNotches( true ); + pSlider->SetValue( *param);//dimensions[i] ); + char labelName[1024]; + sprintf(labelName,"%s",name);//axisNames[0]); + MySliderEventHandler* handler = new MySliderEventHandler(labelName,label,pSlider,param); + pSlider->onValueChanged.Add( handler, &MySliderEventHandler::SliderMoved ); + handler->SliderMoved(pSlider); + float v = pSlider->GetValue(); + data->m_curYposition+=22; +} + +extern float shadowMapWorldSize; int main(int argc, char* argv[]) { + shadowMapWorldSize = 25; + b3Clock clock; float dt = 1./120.f; @@ -238,14 +321,17 @@ int main(int argc, char* argv[]) GLint err = glGetError(); assert(err==GL_NO_ERROR); - + sth_stash* fontstash=app->getFontStash(); gui = new GwenUserInterface; gui->init(width,height,fontstash,app->m_window->getRetinaScale()); // gui->getInternalData()->m_explorerPage Gwen::Controls::TreeControl* tree = gui->getInternalData()->m_explorerTreeCtrl; + + //gui->getInternalData()->m_demoPage; + int numDemos = sizeof(allDemos)/sizeof(BulletDemoEntry); - + char nodeText[1024]; int curDemo = 0; int selectedDemo = loadCurrentDemoEntry(startFileName); @@ -292,11 +378,11 @@ int main(int argc, char* argv[]) { allNames.push_back(allDemos[i].m_name); } - */ + */ //selectDemo(loadCurrentDemoEntry(startFileName)); /* gui->registerComboBox(DEMO_SELECTION_COMBOBOX,allNames.size(),&allNames[0],sCurrentDemoIndex); - + //const char* names2[] = {"comboF", "comboG","comboH"}; //gui->registerComboBox(2,3,&names2[0],0); @@ -304,6 +390,9 @@ int main(int argc, char* argv[]) */ unsigned long int prevTimeInMicroseconds = clock.getTimeMicroseconds(); + MyParameter("Motor A",gui->getInternalData(),&motorA); + MyParameter("Motor B",gui->getInternalData(),&motorB); + do { @@ -311,18 +400,18 @@ int main(int argc, char* argv[]) assert(err==GL_NO_ERROR); app->m_instancingRenderer->init(); app->m_instancingRenderer->updateCamera(); - + app->drawGrid(); - + static int frameCount = 0; frameCount++; if (0) { char bla[1024]; - + sprintf(bla,"Simple test frame %d", frameCount); - + app->drawText(bla,10,10); } diff --git a/Demos3/GpuDemos/gwenUserInterface.cpp b/Demos3/GpuDemos/gwenUserInterface.cpp index a0aa18e2e..dc306994a 100644 --- a/Demos3/GpuDemos/gwenUserInterface.cpp +++ b/Demos3/GpuDemos/gwenUserInterface.cpp @@ -175,7 +175,7 @@ void GwenUserInterface::init(int width, int height,struct sth_stash* stash,float tab->Dock( Gwen::Pos::Fill ); //tab->SetMargin( Gwen::Margin( 2, 2, 2, 2 ) ); - Gwen::UnicodeString str1(L"Main"); + Gwen::UnicodeString str1(L"Params"); m_data->m_demoPage = tab->AddPage(str1); diff --git a/btgui/OpenGLWindow/GLRenderToTexture.cpp b/btgui/OpenGLWindow/GLRenderToTexture.cpp index e8b3080d6..3ca338eba 100644 --- a/btgui/OpenGLWindow/GLRenderToTexture.cpp +++ b/btgui/OpenGLWindow/GLRenderToTexture.cpp @@ -24,19 +24,19 @@ GLRenderToTexture::GLRenderToTexture() #endif//!defined(_WIN32) && !defined(__APPLE__) } - + void GLRenderToTexture::init(int width, int height, GLuint textureId, int renderTextureType) { m_renderTextureType = renderTextureType; glGenFramebuffers(1, &m_framebufferName); glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferName); - - + + // The depth buffer // glGenRenderbuffers(1, &m_depthrenderbuffer); - + // glBindRenderbuffer(GL_RENDERBUFFER, m_depthrenderbuffer); // glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); // glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthrenderbuffer); @@ -71,7 +71,7 @@ bool GLRenderToTexture::enable() glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferName); - + switch (m_renderTextureType) { case RENDERTEXTURE_COLOR: @@ -86,11 +86,10 @@ bool GLRenderToTexture::enable() //Intel OpenGL driver crashes when using GL_NONE for glDrawBuffer on Linux, so use a workaround if (gIntelLinuxglDrawBufferWorkaround) { - GLenum drawBuffers[2] = { GL_DEPTH_ATTACHMENT,0}; - glDrawBuffers(1, drawBuffers); - + GLenum drawBuffers[2] = { GL_COLOR_ATTACHMENT0,0}; + glDrawBuffers(1, drawBuffers); } else - { + { glDrawBuffer(GL_NONE); } break; @@ -117,7 +116,7 @@ void GLRenderToTexture::disable() { glBindFramebuffer( GL_FRAMEBUFFER, 0 ); } - + GLRenderToTexture::~GLRenderToTexture() { glBindFramebuffer( GL_FRAMEBUFFER, 0 ); @@ -129,7 +128,7 @@ GLRenderToTexture::~GLRenderToTexture() if( m_framebufferName) - { + { glDeleteFramebuffers(1, &m_framebufferName); } } From 9b9fa7509f9ee15ea7de757030ac003d49fc97d1 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 10 Jul 2014 11:45:35 -0700 Subject: [PATCH 086/116] Add option to let glew initialize the OpenGL 1.1 function pointers (not just all OpenGL 1.2 and above function pointers) so you can avoid linking against OpenGL / libGL library at link-time. See also http://sourceforge.net/p/glew/mailman/message/22729161/ and http://portal.nersc.gov/svn/visit/branches/2.6RC/src/third_party_builtin/glew/glew/ Thanks to Tom Fogal for the help. --- btgui/OpenGLWindow/GlewWindows/GL/glew.h | 1027 +++++++++++++++++++++- btgui/OpenGLWindow/GlewWindows/glew.c | 689 +++++++++++++++ 2 files changed, 1715 insertions(+), 1 deletion(-) diff --git a/btgui/OpenGLWindow/GlewWindows/GL/glew.h b/btgui/OpenGLWindow/GlewWindows/GL/glew.h index 90ce65a73..2b0c6301a 100644 --- a/btgui/OpenGLWindow/GlewWindows/GL/glew.h +++ b/btgui/OpenGLWindow/GlewWindows/GL/glew.h @@ -30,6 +30,8 @@ */ #define GLEW_NO_GLU +//#define GLEW_INIT_OPENGL11_FUNCTIONS 1 + /* * Mesa 3-D graphics library * Version: 7.0 @@ -838,6 +840,685 @@ typedef char GLchar; #define GL_ALL_ATTRIB_BITS 0x000fffff #define GL_CLIENT_ALL_ATTRIB_BITS 0xffffffff +#ifdef GLEW_INIT_OPENGL11_FUNCTIONS + +typedef void (GLAPIENTRY * PFNGLACCUMPROC) (GLenum op, GLfloat value); +typedef void (GLAPIENTRY * PFNGLALPHAFUNCPROC) (GLenum func, GLclampf ref); +typedef GLboolean (GLAPIENTRY * PFNGLARETEXTURESRESIDENTPROC) (GLsizei n, const GLuint *textures, GLboolean *residences); +typedef void (GLAPIENTRY * PFNGLARRAYELEMENTPROC) (GLint i); +typedef void (GLAPIENTRY * PFNGLBEGINPROC) (GLenum mode); +typedef void (GLAPIENTRY * PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture); +typedef void (GLAPIENTRY * PFNGLBITMAPPROC) (GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +typedef void (GLAPIENTRY * PFNGLBLENDFUNCPROC) (GLenum sfactor, GLenum dfactor); +typedef void (GLAPIENTRY * PFNGLCALLLISTPROC) (GLuint list); +typedef void (GLAPIENTRY * PFNGLCALLLISTSPROC) (GLsizei n, GLenum type, const GLvoid *lists); +typedef void (GLAPIENTRY * PFNGLCLEARPROC) (GLbitfield mask); +typedef void (GLAPIENTRY * PFNGLCLEARACCUMPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +typedef void (GLAPIENTRY * PFNGLCLEARDEPTHPROC) (GLclampd depth); +typedef void (GLAPIENTRY * PFNGLCLEARINDEXPROC) (GLfloat c); +typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint s); +typedef void (GLAPIENTRY * PFNGLCLIPPLANEPROC) (GLenum plane, const GLdouble *equation); +typedef void (GLAPIENTRY * PFNGLCOLOR3BPROC) (GLbyte red, GLbyte green, GLbyte blue); +typedef void (GLAPIENTRY * PFNGLCOLOR3BVPROC) (const GLbyte *v); +typedef void (GLAPIENTRY * PFNGLCOLOR3DPROC) (GLdouble red, GLdouble green, GLdouble blue); +typedef void (GLAPIENTRY * PFNGLCOLOR3DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLCOLOR3FPROC) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (GLAPIENTRY * PFNGLCOLOR3FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLCOLOR3IPROC) (GLint red, GLint green, GLint blue); +typedef void (GLAPIENTRY * PFNGLCOLOR3IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLCOLOR3SPROC) (GLshort red, GLshort green, GLshort blue); +typedef void (GLAPIENTRY * PFNGLCOLOR3SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLCOLOR3UBPROC) (GLubyte red, GLubyte green, GLubyte blue); +typedef void (GLAPIENTRY * PFNGLCOLOR3UBVPROC) (const GLubyte *v); +typedef void (GLAPIENTRY * PFNGLCOLOR3UIPROC) (GLuint red, GLuint green, GLuint blue); +typedef void (GLAPIENTRY * PFNGLCOLOR3UIVPROC) (const GLuint *v); +typedef void (GLAPIENTRY * PFNGLCOLOR3USPROC) (GLushort red, GLushort green, GLushort blue); +typedef void (GLAPIENTRY * PFNGLCOLOR3USVPROC) (const GLushort *v); +typedef void (GLAPIENTRY * PFNGLCOLOR4BPROC) (GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +typedef void (GLAPIENTRY * PFNGLCOLOR4BVPROC) (const GLbyte *v); +typedef void (GLAPIENTRY * PFNGLCOLOR4DPROC) (GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +typedef void (GLAPIENTRY * PFNGLCOLOR4DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLCOLOR4FPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (GLAPIENTRY * PFNGLCOLOR4FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLCOLOR4IPROC) (GLint red, GLint green, GLint blue, GLint alpha); +typedef void (GLAPIENTRY * PFNGLCOLOR4IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLCOLOR4SPROC) (GLshort red, GLshort green, GLshort blue, GLshort alpha); +typedef void (GLAPIENTRY * PFNGLCOLOR4SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLCOLOR4UBPROC) (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +typedef void (GLAPIENTRY * PFNGLCOLOR4UBVPROC) (const GLubyte *v); +typedef void (GLAPIENTRY * PFNGLCOLOR4UIPROC) (GLuint red, GLuint green, GLuint blue, GLuint alpha); +typedef void (GLAPIENTRY * PFNGLCOLOR4UIVPROC) (const GLuint *v); +typedef void (GLAPIENTRY * PFNGLCOLOR4USPROC) (GLushort red, GLushort green, GLushort blue, GLushort alpha); +typedef void (GLAPIENTRY * PFNGLCOLOR4USVPROC) (const GLushort *v); +typedef void (GLAPIENTRY * PFNGLCOLORMASKPROC) (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +typedef void (GLAPIENTRY * PFNGLCOLORMATERIALPROC) (GLenum face, GLenum mode); +typedef void (GLAPIENTRY * PFNGLCOLORPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLCOPYPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +typedef void (GLAPIENTRY * PFNGLCOPYTEXIMAGE1DPROC) (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +typedef void (GLAPIENTRY * PFNGLCOPYTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +typedef void (GLAPIENTRY * PFNGLCOPYTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * PFNGLCULLFACEPROC) (GLenum mode); +typedef void (GLAPIENTRY * PFNGLDELETELISTSPROC) (GLuint list, GLsizei range); +typedef void (GLAPIENTRY * PFNGLDELETETEXTURESPROC) (GLsizei n, const GLuint *textures); +typedef void (GLAPIENTRY * PFNGLDEPTHFUNCPROC) (GLenum func); +typedef void (GLAPIENTRY * PFNGLDEPTHMASKPROC) (GLboolean flag); +typedef void (GLAPIENTRY * PFNGLDEPTHRANGEPROC) (GLclampd zNear, GLclampd zFar); +typedef void (GLAPIENTRY * PFNGLDISABLEPROC) (GLenum cap); +typedef void (GLAPIENTRY * PFNGLDISABLECLIENTSTATEPROC) (GLenum array); +typedef void (GLAPIENTRY * PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count); +typedef void (GLAPIENTRY * PFNGLDRAWBUFFERPROC) (GLenum mode); +typedef void (GLAPIENTRY * PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (GLAPIENTRY * PFNGLDRAWPIXELSPROC) (GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLEDGEFLAGPROC) (GLboolean flag); +typedef void (GLAPIENTRY * PFNGLEDGEFLAGPOINTERPROC) (GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLEDGEFLAGVPROC) (const GLboolean *flag); +typedef void (GLAPIENTRY * PFNGLENABLEPROC) (GLenum cap); +typedef void (GLAPIENTRY * PFNGLENABLECLIENTSTATEPROC) (GLenum array); +typedef void (GLAPIENTRY * PFNGLENDPROC) (void); +typedef void (GLAPIENTRY * PFNGLENDLISTPROC) (void); +typedef void (GLAPIENTRY * PFNGLEVALCOORD1DPROC) (GLdouble u); +typedef void (GLAPIENTRY * PFNGLEVALCOORD1DVPROC) (const GLdouble *u); +typedef void (GLAPIENTRY * PFNGLEVALCOORD1FPROC) (GLfloat u); +typedef void (GLAPIENTRY * PFNGLEVALCOORD1FVPROC) (const GLfloat *u); +typedef void (GLAPIENTRY * PFNGLEVALCOORD2DPROC) (GLdouble u, GLdouble v); +typedef void (GLAPIENTRY * PFNGLEVALCOORD2DVPROC) (const GLdouble *u); +typedef void (GLAPIENTRY * PFNGLEVALCOORD2FPROC) (GLfloat u, GLfloat v); +typedef void (GLAPIENTRY * PFNGLEVALCOORD2FVPROC) (const GLfloat *u); +typedef void (GLAPIENTRY * PFNGLEVALMESH1PROC) (GLenum mode, GLint i1, GLint i2); +typedef void (GLAPIENTRY * PFNGLEVALMESH2PROC) (GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +typedef void (GLAPIENTRY * PFNGLEVALPOINT1PROC) (GLint i); +typedef void (GLAPIENTRY * PFNGLEVALPOINT2PROC) (GLint i, GLint j); +typedef void (GLAPIENTRY * PFNGLFEEDBACKBUFFERPROC) (GLsizei size, GLenum type, GLfloat *buffer); +typedef void (GLAPIENTRY * PFNGLFINISHPROC) (void); +typedef void (GLAPIENTRY * PFNGLFLUSHPROC) (void); +typedef void (GLAPIENTRY * PFNGLFOGFPROC) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLFOGFVPROC) (GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * PFNGLFOGIPROC) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLFOGIVPROC) (GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * PFNGLFRONTFACEPROC) (GLenum mode); +typedef void (GLAPIENTRY * PFNGLFRUSTUMPROC) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef GLuint (GLAPIENTRY * PFNGLGENLISTSPROC) (GLsizei range); +typedef void (GLAPIENTRY * PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures); +typedef void (GLAPIENTRY * PFNGLGETBOOLEANVPROC) (GLenum pname, GLboolean *params); +typedef void (GLAPIENTRY * PFNGLGETCLIPPLANEPROC) (GLenum plane, GLdouble *equation); +typedef void (GLAPIENTRY * PFNGLGETDOUBLEVPROC) (GLenum pname, GLdouble *params); +typedef GLenum (GLAPIENTRY * PFNGLGETERRORPROC) (void); +typedef void (GLAPIENTRY * PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * PFNGLGETINTEGERVPROC) (GLenum pname, GLint *params); +typedef void (GLAPIENTRY * PFNGLGETLIGHTFVPROC) (GLenum light, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * PFNGLGETLIGHTIVPROC) (GLenum light, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * PFNGLGETMAPDVPROC) (GLenum target, GLenum query, GLdouble *v); +typedef void (GLAPIENTRY * PFNGLGETMAPFVPROC) (GLenum target, GLenum query, GLfloat *v); +typedef void (GLAPIENTRY * PFNGLGETMAPIVPROC) (GLenum target, GLenum query, GLint *v); +typedef void (GLAPIENTRY * PFNGLGETMATERIALFVPROC) (GLenum face, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * PFNGLGETMATERIALIVPROC) (GLenum face, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * PFNGLGETPIXELMAPFVPROC) (GLenum map, GLfloat *values); +typedef void (GLAPIENTRY * PFNGLGETPIXELMAPUIVPROC) (GLenum map, GLuint *values); +typedef void (GLAPIENTRY * PFNGLGETPIXELMAPUSVPROC) (GLenum map, GLushort *values); +typedef void (GLAPIENTRY * PFNGLGETPOINTERVPROC) (GLenum pname, GLvoid* *params); +typedef void (GLAPIENTRY * PFNGLGETPOLYGONSTIPPLEPROC) (GLubyte *mask); +typedef GLubyte* (GLAPIENTRY * PFNGLGETSTRINGPROC) (GLenum s); +typedef void (GLAPIENTRY * PFNGLGETTEXENVFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * PFNGLGETTEXENVIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * PFNGLGETTEXGENDVPROC) (GLenum coord, GLenum pname, GLdouble *params); +typedef void (GLAPIENTRY * PFNGLGETTEXGENFVPROC) (GLenum coord, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * PFNGLGETTEXGENIVPROC) (GLenum coord, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * PFNGLGETTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLGETTEXLEVELPARAMETERFVPROC) (GLenum target, GLint level, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * PFNGLGETTEXLEVELPARAMETERIVPROC) (GLenum target, GLint level, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERFVPROC) (GLenum target, GLenum pname, GLfloat *params); +typedef void (GLAPIENTRY * PFNGLGETTEXPARAMETERIVPROC) (GLenum target, GLenum pname, GLint *params); +typedef void (GLAPIENTRY * PFNGLHINTPROC) (GLenum target, GLenum mode); +typedef void (GLAPIENTRY * PFNGLINDEXMASKPROC) (GLuint mask); +typedef void (GLAPIENTRY * PFNGLINDEXPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLINDEXDPROC) (GLdouble c); +typedef void (GLAPIENTRY * PFNGLINDEXDVPROC) (const GLdouble *c); +typedef void (GLAPIENTRY * PFNGLINDEXFPROC) (GLfloat c); +typedef void (GLAPIENTRY * PFNGLINDEXFVPROC) (const GLfloat *c); +typedef void (GLAPIENTRY * PFNGLINDEXIPROC) (GLint c); +typedef void (GLAPIENTRY * PFNGLINDEXIVPROC) (const GLint *c); +typedef void (GLAPIENTRY * PFNGLINDEXSPROC) (GLshort c); +typedef void (GLAPIENTRY * PFNGLINDEXSVPROC) (const GLshort *c); +typedef void (GLAPIENTRY * PFNGLINDEXUBPROC) (GLubyte c); +typedef void (GLAPIENTRY * PFNGLINDEXUBVPROC) (const GLubyte *c); +typedef void (GLAPIENTRY * PFNGLINITNAMESPROC) (void); +typedef void (GLAPIENTRY * PFNGLINTERLEAVEDARRAYSPROC) (GLenum format, GLsizei stride, const GLvoid *pointer); +typedef GLboolean (GLAPIENTRY * PFNGLISENABLEDPROC) (GLenum cap); +typedef GLboolean (GLAPIENTRY * PFNGLISLISTPROC) (GLuint list); +typedef GLboolean (GLAPIENTRY * PFNGLISTEXTUREPROC) (GLuint texture); +typedef void (GLAPIENTRY * PFNGLLIGHTMODELFPROC) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLLIGHTMODELFVPROC) (GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * PFNGLLIGHTMODELIPROC) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLLIGHTMODELIVPROC) (GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * PFNGLLIGHTFPROC) (GLenum light, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLLIGHTFVPROC) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * PFNGLLIGHTIPROC) (GLenum light, GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLLIGHTIVPROC) (GLenum light, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * PFNGLLINESTIPPLEPROC) (GLint factor, GLushort pattern); +typedef void (GLAPIENTRY * PFNGLLINEWIDTHPROC) (GLfloat width); +typedef void (GLAPIENTRY * PFNGLLISTBASEPROC) (GLuint base); +typedef void (GLAPIENTRY * PFNGLLOADIDENTITYPROC) (void); +typedef void (GLAPIENTRY * PFNGLLOADMATRIXDPROC) (const GLdouble *m); +typedef void (GLAPIENTRY * PFNGLLOADMATRIXFPROC) (const GLfloat *m); +typedef void (GLAPIENTRY * PFNGLLOADNAMEPROC) (GLuint name); +typedef void (GLAPIENTRY * PFNGLLOGICOPPROC) (GLenum opcode); +typedef void (GLAPIENTRY * PFNGLMAP1DPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +typedef void (GLAPIENTRY * PFNGLMAP1FPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +typedef void (GLAPIENTRY * PFNGLMAP2DPROC) (GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +typedef void (GLAPIENTRY * PFNGLMAP2FPROC) (GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +typedef void (GLAPIENTRY * PFNGLMAPGRID1DPROC) (GLint un, GLdouble u1, GLdouble u2); +typedef void (GLAPIENTRY * PFNGLMAPGRID1FPROC) (GLint un, GLfloat u1, GLfloat u2); +typedef void (GLAPIENTRY * PFNGLMAPGRID2DPROC) (GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +typedef void (GLAPIENTRY * PFNGLMAPGRID2FPROC) (GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +typedef void (GLAPIENTRY * PFNGLMATERIALFPROC) (GLenum face, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLMATERIALFVPROC) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * PFNGLMATERIALIPROC) (GLenum face, GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLMATERIALIVPROC) (GLenum face, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * PFNGLMATRIXMODEPROC) (GLenum mode); +typedef void (GLAPIENTRY * PFNGLMULTMATRIXDPROC) (const GLdouble *m); +typedef void (GLAPIENTRY * PFNGLMULTMATRIXFPROC) (const GLfloat *m); +typedef void (GLAPIENTRY * PFNGLNEWLISTPROC) (GLuint list, GLenum mode); +typedef void (GLAPIENTRY * PFNGLNORMAL3BPROC) (GLbyte nx, GLbyte ny, GLbyte nz); +typedef void (GLAPIENTRY * PFNGLNORMAL3BVPROC) (const GLbyte *v); +typedef void (GLAPIENTRY * PFNGLNORMAL3DPROC) (GLdouble nx, GLdouble ny, GLdouble nz); +typedef void (GLAPIENTRY * PFNGLNORMAL3DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLNORMAL3FPROC) (GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (GLAPIENTRY * PFNGLNORMAL3FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLNORMAL3IPROC) (GLint nx, GLint ny, GLint nz); +typedef void (GLAPIENTRY * PFNGLNORMAL3IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLNORMAL3SPROC) (GLshort nx, GLshort ny, GLshort nz); +typedef void (GLAPIENTRY * PFNGLNORMAL3SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLNORMALPOINTERPROC) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLORTHOPROC) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (GLAPIENTRY * PFNGLPASSTHROUGHPROC) (GLfloat token); +typedef void (GLAPIENTRY * PFNGLPIXELMAPFVPROC) (GLenum map, GLsizei mapsize, const GLfloat *values); +typedef void (GLAPIENTRY * PFNGLPIXELMAPUIVPROC) (GLenum map, GLsizei mapsize, const GLuint *values); +typedef void (GLAPIENTRY * PFNGLPIXELMAPUSVPROC) (GLenum map, GLsizei mapsize, const GLushort *values); +typedef void (GLAPIENTRY * PFNGLPIXELSTOREFPROC) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLPIXELTRANSFERFPROC) (GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLPIXELTRANSFERIPROC) (GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLPIXELZOOMPROC) (GLfloat xfactor, GLfloat yfactor); +typedef void (GLAPIENTRY * PFNGLPOINTSIZEPROC) (GLfloat size); +typedef void (GLAPIENTRY * PFNGLPOLYGONMODEPROC) (GLenum face, GLenum mode); +typedef void (GLAPIENTRY * PFNGLPOLYGONOFFSETPROC) (GLfloat factor, GLfloat units); +typedef void (GLAPIENTRY * PFNGLPOLYGONSTIPPLEPROC) (const GLubyte *mask); +typedef void (GLAPIENTRY * PFNGLPOPATTRIBPROC) (void); +typedef void (GLAPIENTRY * PFNGLPOPCLIENTATTRIBPROC) (void); +typedef void (GLAPIENTRY * PFNGLPOPMATRIXPROC) (void); +typedef void (GLAPIENTRY * PFNGLPOPNAMEPROC) (void); +typedef void (GLAPIENTRY * PFNGLPRIORITIZETEXTURESPROC) (GLsizei n, const GLuint *textures, const GLclampf *priorities); +typedef void (GLAPIENTRY * PFNGLPUSHATTRIBPROC) (GLbitfield mask); +typedef void (GLAPIENTRY * PFNGLPUSHCLIENTATTRIBPROC) (GLbitfield mask); +typedef void (GLAPIENTRY * PFNGLPUSHMATRIXPROC) (void); +typedef void (GLAPIENTRY * PFNGLPUSHNAMEPROC) (GLuint name); +typedef void (GLAPIENTRY * PFNGLRASTERPOS2DPROC) (GLdouble x, GLdouble y); +typedef void (GLAPIENTRY * PFNGLRASTERPOS2DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS2FPROC) (GLfloat x, GLfloat y); +typedef void (GLAPIENTRY * PFNGLRASTERPOS2FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS2IPROC) (GLint x, GLint y); +typedef void (GLAPIENTRY * PFNGLRASTERPOS2IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS2SPROC) (GLshort x, GLshort y); +typedef void (GLAPIENTRY * PFNGLRASTERPOS2SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS3DPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * PFNGLRASTERPOS3DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS3FPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * PFNGLRASTERPOS3FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS3IPROC) (GLint x, GLint y, GLint z); +typedef void (GLAPIENTRY * PFNGLRASTERPOS3IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS3SPROC) (GLshort x, GLshort y, GLshort z); +typedef void (GLAPIENTRY * PFNGLRASTERPOS3SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS4DPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAPIENTRY * PFNGLRASTERPOS4DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS4FPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAPIENTRY * PFNGLRASTERPOS4FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS4IPROC) (GLint x, GLint y, GLint z, GLint w); +typedef void (GLAPIENTRY * PFNGLRASTERPOS4IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLRASTERPOS4SPROC) (GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAPIENTRY * PFNGLRASTERPOS4SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLREADBUFFERPROC) (GLenum mode); +typedef void (GLAPIENTRY * PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLRECTDPROC) (GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +typedef void (GLAPIENTRY * PFNGLRECTDVPROC) (const GLdouble *v1, const GLdouble *v2); +typedef void (GLAPIENTRY * PFNGLRECTFPROC) (GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +typedef void (GLAPIENTRY * PFNGLRECTFVPROC) (const GLfloat *v1, const GLfloat *v2); +typedef void (GLAPIENTRY * PFNGLRECTIPROC) (GLint x1, GLint y1, GLint x2, GLint y2); +typedef void (GLAPIENTRY * PFNGLRECTIVPROC) (const GLint *v1, const GLint *v2); +typedef void (GLAPIENTRY * PFNGLRECTSPROC) (GLshort x1, GLshort y1, GLshort x2, GLshort y2); +typedef void (GLAPIENTRY * PFNGLRECTSVPROC) (const GLshort *v1, const GLshort *v2); +typedef GLint (GLAPIENTRY * PFNGLRENDERMODEPROC) (GLenum mode); +typedef void (GLAPIENTRY * PFNGLROTATEDPROC) (GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * PFNGLROTATEFPROC) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * PFNGLSCALEDPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * PFNGLSCALEFPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * PFNGLSCISSORPROC) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GLAPIENTRY * PFNGLSELECTBUFFERPROC) (GLsizei size, GLuint *buffer); +typedef void (GLAPIENTRY * PFNGLSHADEMODELPROC) (GLenum mode); +typedef void (GLAPIENTRY * PFNGLSTENCILFUNCPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (GLAPIENTRY * PFNGLSTENCILMASKPROC) (GLuint mask); +typedef void (GLAPIENTRY * PFNGLSTENCILOPPROC) (GLenum fail, GLenum zfail, GLenum zpass); +typedef void (GLAPIENTRY * PFNGLTEXCOORD1DPROC) (GLdouble s); +typedef void (GLAPIENTRY * PFNGLTEXCOORD1DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD1FPROC) (GLfloat s); +typedef void (GLAPIENTRY * PFNGLTEXCOORD1FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD1IPROC) (GLint s); +typedef void (GLAPIENTRY * PFNGLTEXCOORD1IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD1SPROC) (GLshort s); +typedef void (GLAPIENTRY * PFNGLTEXCOORD1SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD2DPROC) (GLdouble s, GLdouble t); +typedef void (GLAPIENTRY * PFNGLTEXCOORD2DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD2FPROC) (GLfloat s, GLfloat t); +typedef void (GLAPIENTRY * PFNGLTEXCOORD2FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD2IPROC) (GLint s, GLint t); +typedef void (GLAPIENTRY * PFNGLTEXCOORD2IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD2SPROC) (GLshort s, GLshort t); +typedef void (GLAPIENTRY * PFNGLTEXCOORD2SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD3DPROC) (GLdouble s, GLdouble t, GLdouble r); +typedef void (GLAPIENTRY * PFNGLTEXCOORD3DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD3FPROC) (GLfloat s, GLfloat t, GLfloat r); +typedef void (GLAPIENTRY * PFNGLTEXCOORD3FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD3IPROC) (GLint s, GLint t, GLint r); +typedef void (GLAPIENTRY * PFNGLTEXCOORD3IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD3SPROC) (GLshort s, GLshort t, GLshort r); +typedef void (GLAPIENTRY * PFNGLTEXCOORD3SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD4DPROC) (GLdouble s, GLdouble t, GLdouble r, GLdouble q); +typedef void (GLAPIENTRY * PFNGLTEXCOORD4DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD4FPROC) (GLfloat s, GLfloat t, GLfloat r, GLfloat q); +typedef void (GLAPIENTRY * PFNGLTEXCOORD4FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD4IPROC) (GLint s, GLint t, GLint r, GLint q); +typedef void (GLAPIENTRY * PFNGLTEXCOORD4IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORD4SPROC) (GLshort s, GLshort t, GLshort r, GLshort q); +typedef void (GLAPIENTRY * PFNGLTEXCOORD4SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLTEXCOORDPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLTEXENVFPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLTEXENVFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * PFNGLTEXENVIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLTEXENVIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * PFNGLTEXGENDPROC) (GLenum coord, GLenum pname, GLdouble param); +typedef void (GLAPIENTRY * PFNGLTEXGENDVPROC) (GLenum coord, GLenum pname, const GLdouble *params); +typedef void (GLAPIENTRY * PFNGLTEXGENFPROC) (GLenum coord, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLTEXGENFVPROC) (GLenum coord, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * PFNGLTEXGENIPROC) (GLenum coord, GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLTEXGENIVPROC) (GLenum coord, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * PFNGLTEXIMAGE1DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXIMAGE2DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXPARAMETERFPROC) (GLenum target, GLenum pname, GLfloat param); +typedef void (GLAPIENTRY * PFNGLTEXPARAMETERFVPROC) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param); +typedef void (GLAPIENTRY * PFNGLTEXPARAMETERIVPROC) (GLenum target, GLenum pname, const GLint *params); +typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE1DPROC) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTEXSUBIMAGE2DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (GLAPIENTRY * PFNGLTRANSLATEDPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * PFNGLTRANSLATEFPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * PFNGLVERTEX2DPROC) (GLdouble x, GLdouble y); +typedef void (GLAPIENTRY * PFNGLVERTEX2DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLVERTEX2FPROC) (GLfloat x, GLfloat y); +typedef void (GLAPIENTRY * PFNGLVERTEX2FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLVERTEX2IPROC) (GLint x, GLint y); +typedef void (GLAPIENTRY * PFNGLVERTEX2IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLVERTEX2SPROC) (GLshort x, GLshort y); +typedef void (GLAPIENTRY * PFNGLVERTEX2SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLVERTEX3DPROC) (GLdouble x, GLdouble y, GLdouble z); +typedef void (GLAPIENTRY * PFNGLVERTEX3DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLVERTEX3FPROC) (GLfloat x, GLfloat y, GLfloat z); +typedef void (GLAPIENTRY * PFNGLVERTEX3FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLVERTEX3IPROC) (GLint x, GLint y, GLint z); +typedef void (GLAPIENTRY * PFNGLVERTEX3IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLVERTEX3SPROC) (GLshort x, GLshort y, GLshort z); +typedef void (GLAPIENTRY * PFNGLVERTEX3SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLVERTEX4DPROC) (GLdouble x, GLdouble y, GLdouble z, GLdouble w); +typedef void (GLAPIENTRY * PFNGLVERTEX4DVPROC) (const GLdouble *v); +typedef void (GLAPIENTRY * PFNGLVERTEX4FPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat w); +typedef void (GLAPIENTRY * PFNGLVERTEX4FVPROC) (const GLfloat *v); +typedef void (GLAPIENTRY * PFNGLVERTEX4IPROC) (GLint x, GLint y, GLint z, GLint w); +typedef void (GLAPIENTRY * PFNGLVERTEX4IVPROC) (const GLint *v); +typedef void (GLAPIENTRY * PFNGLVERTEX4SPROC) (GLshort x, GLshort y, GLshort z, GLshort w); +typedef void (GLAPIENTRY * PFNGLVERTEX4SVPROC) (const GLshort *v); +typedef void (GLAPIENTRY * PFNGLVERTEXPOINTERPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (GLAPIENTRY * PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height); + +#define glAccum GLEW_GET_FUN(__glewAccum) +#define glAlphaFunc GLEW_GET_FUN(__glewAlphaFunc) +#define glAreTexturesResident GLEW_GET_FUN(__glewAreTexturesResident) +#define glArrayElement GLEW_GET_FUN(__glewArrayElement) +#define glBegin GLEW_GET_FUN(__glewBegin) +#define glBindTexture GLEW_GET_FUN(__glewBindTexture) +#define glBitmap GLEW_GET_FUN(__glewBitmap) +#define glBlendFunc GLEW_GET_FUN(__glewBlendFunc) +#define glCallList GLEW_GET_FUN(__glewCallList) +#define glCallLists GLEW_GET_FUN(__glewCallLists) +#define glClear GLEW_GET_FUN(__glewClear) +#define glClearAccum GLEW_GET_FUN(__glewClearAccum) +#define glClearColor GLEW_GET_FUN(__glewClearColor) +#define glClearDepth GLEW_GET_FUN(__glewClearDepth) +#define glClearIndex GLEW_GET_FUN(__glewClearIndex) +#define glClearStencil GLEW_GET_FUN(__glewClearStencil) +#define glClipPlane GLEW_GET_FUN(__glewClipPlane) +#define glColor3b GLEW_GET_FUN(__glewColor3b) +#define glColor3bv GLEW_GET_FUN(__glewColor3bv) +#define glColor3d GLEW_GET_FUN(__glewColor3d) +#define glColor3dv GLEW_GET_FUN(__glewColor3dv) +#define glColor3f GLEW_GET_FUN(__glewColor3f) +#define glColor3fv GLEW_GET_FUN(__glewColor3fv) +#define glColor3i GLEW_GET_FUN(__glewColor3i) +#define glColor3iv GLEW_GET_FUN(__glewColor3iv) +#define glColor3s GLEW_GET_FUN(__glewColor3s) +#define glColor3sv GLEW_GET_FUN(__glewColor3sv) +#define glColor3ub GLEW_GET_FUN(__glewColor3ub) +#define glColor3ubv GLEW_GET_FUN(__glewColor3ubv) +#define glColor3ui GLEW_GET_FUN(__glewColor3ui) +#define glColor3uiv GLEW_GET_FUN(__glewColor3uiv) +#define glColor3us GLEW_GET_FUN(__glewColor3us) +#define glColor3usv GLEW_GET_FUN(__glewColor3usv) +#define glColor4b GLEW_GET_FUN(__glewColor4b) +#define glColor4bv GLEW_GET_FUN(__glewColor4bv) +#define glColor4d GLEW_GET_FUN(__glewColor4d) +#define glColor4dv GLEW_GET_FUN(__glewColor4dv) +#define glColor4f GLEW_GET_FUN(__glewColor4f) +#define glColor4fv GLEW_GET_FUN(__glewColor4fv) +#define glColor4i GLEW_GET_FUN(__glewColor4i) +#define glColor4iv GLEW_GET_FUN(__glewColor4iv) +#define glColor4s GLEW_GET_FUN(__glewColor4s) +#define glColor4sv GLEW_GET_FUN(__glewColor4sv) +#define glColor4ub GLEW_GET_FUN(__glewColor4ub) +#define glColor4ubv GLEW_GET_FUN(__glewColor4ubv) +#define glColor4ui GLEW_GET_FUN(__glewColor4ui) +#define glColor4uiv GLEW_GET_FUN(__glewColor4uiv) +#define glColor4us GLEW_GET_FUN(__glewColor4us) +#define glColor4usv GLEW_GET_FUN(__glewColor4usv) +#define glColorMask GLEW_GET_FUN(__glewColorMask) +#define glColorMaterial GLEW_GET_FUN(__glewColorMaterial) +#define glColorPointer GLEW_GET_FUN(__glewColorPointer) +#define glCopyPixels GLEW_GET_FUN(__glewCopyPixels) +#define glCopyTexImage1D GLEW_GET_FUN(__glewCopyTexImage1D) +#define glCopyTexImage2D GLEW_GET_FUN(__glewCopyTexImage2D) +#define glCopyTexSubImage1D GLEW_GET_FUN(__glewCopyTexSubImage1D) +#define glCopyTexSubImage2D GLEW_GET_FUN(__glewCopyTexSubImage2D) +#define glCullFace GLEW_GET_FUN(__glewCullFace) +#define glDeleteLists GLEW_GET_FUN(__glewDeleteLists) +#define glDeleteTextures GLEW_GET_FUN(__glewDeleteTextures) +#define glDepthFunc GLEW_GET_FUN(__glewDepthFunc) +#define glDepthMask GLEW_GET_FUN(__glewDepthMask) +#define glDepthRange GLEW_GET_FUN(__glewDepthRange) +#define glDisable GLEW_GET_FUN(__glewDisable) +#define glDisableClientState GLEW_GET_FUN(__glewDisableClientState) +#define glDrawArrays GLEW_GET_FUN(__glewDrawArrays) +#define glDrawBuffer GLEW_GET_FUN(__glewDrawBuffer) +#define glDrawElements GLEW_GET_FUN(__glewDrawElements) +#define glDrawPixels GLEW_GET_FUN(__glewDrawPixels) +#define glEdgeFlag GLEW_GET_FUN(__glewEdgeFlag) +#define glEdgeFlagPointer GLEW_GET_FUN(__glewEdgeFlagPointer) +#define glEdgeFlagv GLEW_GET_FUN(__glewEdgeFlagv) +#define glEnable GLEW_GET_FUN(__glewEnable) +#define glEnableClientState GLEW_GET_FUN(__glewEnableClientState) +#define glEnd GLEW_GET_FUN(__glewEnd) +#define glEndList GLEW_GET_FUN(__glewEndList) +#define glEvalCoord1d GLEW_GET_FUN(__glewEvalCoord1d) +#define glEvalCoord1dv GLEW_GET_FUN(__glewEvalCoord1dv) +#define glEvalCoord1f GLEW_GET_FUN(__glewEvalCoord1f) +#define glEvalCoord1fv GLEW_GET_FUN(__glewEvalCoord1fv) +#define glEvalCoord2d GLEW_GET_FUN(__glewEvalCoord2d) +#define glEvalCoord2dv GLEW_GET_FUN(__glewEvalCoord2dv) +#define glEvalCoord2f GLEW_GET_FUN(__glewEvalCoord2f) +#define glEvalCoord2fv GLEW_GET_FUN(__glewEvalCoord2fv) +#define glEvalMesh1 GLEW_GET_FUN(__glewEvalMesh1) +#define glEvalMesh2 GLEW_GET_FUN(__glewEvalMesh2) +#define glEvalPoint1 GLEW_GET_FUN(__glewEvalPoint1) +#define glEvalPoint2 GLEW_GET_FUN(__glewEvalPoint2) +#define glFeedbackBuffer GLEW_GET_FUN(__glewFeedbackBuffer) +#define glFinish GLEW_GET_FUN(__glewFinish) +#define glFlush GLEW_GET_FUN(__glewFlush) +#define glFogf GLEW_GET_FUN(__glewFogf) +#define glFogfv GLEW_GET_FUN(__glewFogfv) +#define glFogi GLEW_GET_FUN(__glewFogi) +#define glFogiv GLEW_GET_FUN(__glewFogiv) +#define glFrontFace GLEW_GET_FUN(__glewFrontFace) +#define glFrustum GLEW_GET_FUN(__glewFrustum) +#define glGenLists GLEW_GET_FUN(__glewGenLists) +#define glGenTextures GLEW_GET_FUN(__glewGenTextures) +#define glGetBooleanv GLEW_GET_FUN(__glewGetBooleanv) +#define glGetClipPlane GLEW_GET_FUN(__glewGetClipPlane) +#define glGetDoublev GLEW_GET_FUN(__glewGetDoublev) +#define glGetError GLEW_GET_FUN(__glewGetError) +#define glGetFloatv GLEW_GET_FUN(__glewGetFloatv) +#define glGetIntegerv GLEW_GET_FUN(__glewGetIntegerv) +#define glGetLightfv GLEW_GET_FUN(__glewGetLightfv) +#define glGetLightiv GLEW_GET_FUN(__glewGetLightiv) +#define glGetMapdv GLEW_GET_FUN(__glewGetMapdv) +#define glGetMapfv GLEW_GET_FUN(__glewGetMapfv) +#define glGetMapiv GLEW_GET_FUN(__glewGetMapiv) +#define glGetMaterialfv GLEW_GET_FUN(__glewGetMaterialfv) +#define glGetMaterialiv GLEW_GET_FUN(__glewGetMaterialiv) +#define glGetPixelMapfv GLEW_GET_FUN(__glewGetPixelMapfv) +#define glGetPixelMapuiv GLEW_GET_FUN(__glewGetPixelMapuiv) +#define glGetPixelMapusv GLEW_GET_FUN(__glewGetPixelMapusv) +#define glGetPointerv GLEW_GET_FUN(__glewGetPointerv) +#define glGetPolygonStipple GLEW_GET_FUN(__glewGetPolygonStipple) +#define glGetString GLEW_GET_FUN(__glewGetString) +#define glGetTexEnvfv GLEW_GET_FUN(__glewGetTexEnvfv) +#define glGetTexEnviv GLEW_GET_FUN(__glewGetTexEnviv) +#define glGetTexGendv GLEW_GET_FUN(__glewGetTexGendv) +#define glGetTexGenfv GLEW_GET_FUN(__glewGetTexGenfv) +#define glGetTexGeniv GLEW_GET_FUN(__glewGetTexGeniv) +#define glGetTexImage GLEW_GET_FUN(__glewGetTexImage) +#define glGetTexLevelParameterfv GLEW_GET_FUN(__glewGetTexLevelParameterfv) +#define glGetTexLevelParameteriv GLEW_GET_FUN(__glewGetTexLevelParameteriv) +#define glGetTexParameterfv GLEW_GET_FUN(__glewGetTexParameterfv) +#define glGetTexParameteriv GLEW_GET_FUN(__glewGetTexParameteriv) +#define glHint GLEW_GET_FUN(__glewHint) +#define glIndexMask GLEW_GET_FUN(__glewIndexMask) +#define glIndexPointer GLEW_GET_FUN(__glewIndexPointer) +#define glIndexd GLEW_GET_FUN(__glewIndexd) +#define glIndexdv GLEW_GET_FUN(__glewIndexdv) +#define glIndexf GLEW_GET_FUN(__glewIndexf) +#define glIndexfv GLEW_GET_FUN(__glewIndexfv) +#define glIndexi GLEW_GET_FUN(__glewIndexi) +#define glIndexiv GLEW_GET_FUN(__glewIndexiv) +#define glIndexs GLEW_GET_FUN(__glewIndexs) +#define glIndexsv GLEW_GET_FUN(__glewIndexsv) +#define glIndexub GLEW_GET_FUN(__glewIndexub) +#define glIndexubv GLEW_GET_FUN(__glewIndexubv) +#define glInitNames GLEW_GET_FUN(__glewInitNames) +#define glInterleavedArrays GLEW_GET_FUN(__glewInterleavedArrays) +#define glIsEnabled GLEW_GET_FUN(__glewIsEnabled) +#define glIsList GLEW_GET_FUN(__glewIsList) +#define glIsTexture GLEW_GET_FUN(__glewIsTexture) +#define glLightModelf GLEW_GET_FUN(__glewLightModelf) +#define glLightModelfv GLEW_GET_FUN(__glewLightModelfv) +#define glLightModeli GLEW_GET_FUN(__glewLightModeli) +#define glLightModeliv GLEW_GET_FUN(__glewLightModeliv) +#define glLightf GLEW_GET_FUN(__glewLightf) +#define glLightfv GLEW_GET_FUN(__glewLightfv) +#define glLighti GLEW_GET_FUN(__glewLighti) +#define glLightiv GLEW_GET_FUN(__glewLightiv) +#define glLineStipple GLEW_GET_FUN(__glewLineStipple) +#define glLineWidth GLEW_GET_FUN(__glewLineWidth) +#define glListBase GLEW_GET_FUN(__glewListBase) +#define glLoadIdentity GLEW_GET_FUN(__glewLoadIdentity) +#define glLoadMatrixd GLEW_GET_FUN(__glewLoadMatrixd) +#define glLoadMatrixf GLEW_GET_FUN(__glewLoadMatrixf) +#define glLoadName GLEW_GET_FUN(__glewLoadName) +#define glLogicOp GLEW_GET_FUN(__glewLogicOp) +#define glMap1d GLEW_GET_FUN(__glewMap1d) +#define glMap1f GLEW_GET_FUN(__glewMap1f) +#define glMap2d GLEW_GET_FUN(__glewMap2d) +#define glMap2f GLEW_GET_FUN(__glewMap2f) +#define glMapGrid1d GLEW_GET_FUN(__glewMapGrid1d) +#define glMapGrid1f GLEW_GET_FUN(__glewMapGrid1f) +#define glMapGrid2d GLEW_GET_FUN(__glewMapGrid2d) +#define glMapGrid2f GLEW_GET_FUN(__glewMapGrid2f) +#define glMaterialf GLEW_GET_FUN(__glewMaterialf) +#define glMaterialfv GLEW_GET_FUN(__glewMaterialfv) +#define glMateriali GLEW_GET_FUN(__glewMateriali) +#define glMaterialiv GLEW_GET_FUN(__glewMaterialiv) +#define glMatrixMode GLEW_GET_FUN(__glewMatrixMode) +#define glMultMatrixd GLEW_GET_FUN(__glewMultMatrixd) +#define glMultMatrixf GLEW_GET_FUN(__glewMultMatrixf) +#define glNewList GLEW_GET_FUN(__glewNewList) +#define glNormal3b GLEW_GET_FUN(__glewNormal3b) +#define glNormal3bv GLEW_GET_FUN(__glewNormal3bv) +#define glNormal3d GLEW_GET_FUN(__glewNormal3d) +#define glNormal3dv GLEW_GET_FUN(__glewNormal3dv) +#define glNormal3f GLEW_GET_FUN(__glewNormal3f) +#define glNormal3fv GLEW_GET_FUN(__glewNormal3fv) +#define glNormal3i GLEW_GET_FUN(__glewNormal3i) +#define glNormal3iv GLEW_GET_FUN(__glewNormal3iv) +#define glNormal3s GLEW_GET_FUN(__glewNormal3s) +#define glNormal3sv GLEW_GET_FUN(__glewNormal3sv) +#define glNormalPointer GLEW_GET_FUN(__glewNormalPointer) +#define glOrtho GLEW_GET_FUN(__glewOrtho) +#define glPassThrough GLEW_GET_FUN(__glewPassThrough) +#define glPixelMapfv GLEW_GET_FUN(__glewPixelMapfv) +#define glPixelMapuiv GLEW_GET_FUN(__glewPixelMapuiv) +#define glPixelMapusv GLEW_GET_FUN(__glewPixelMapusv) +#define glPixelStoref GLEW_GET_FUN(__glewPixelStoref) +#define glPixelStorei GLEW_GET_FUN(__glewPixelStorei) +#define glPixelTransferf GLEW_GET_FUN(__glewPixelTransferf) +#define glPixelTransferi GLEW_GET_FUN(__glewPixelTransferi) +#define glPixelZoom GLEW_GET_FUN(__glewPixelZoom) +#define glPointSize GLEW_GET_FUN(__glewPointSize) +#define glPolygonMode GLEW_GET_FUN(__glewPolygonMode) +#define glPolygonOffset GLEW_GET_FUN(__glewPolygonOffset) +#define glPolygonStipple GLEW_GET_FUN(__glewPolygonStipple) +#define glPopAttrib GLEW_GET_FUN(__glewPopAttrib) +#define glPopClientAttrib GLEW_GET_FUN(__glewPopClientAttrib) +#define glPopMatrix GLEW_GET_FUN(__glewPopMatrix) +#define glPopName GLEW_GET_FUN(__glewPopName) +#define glPrioritizeTextures GLEW_GET_FUN(__glewPrioritizeTextures) +#define glPushAttrib GLEW_GET_FUN(__glewPushAttrib) +#define glPushClientAttrib GLEW_GET_FUN(__glewPushClientAttrib) +#define glPushMatrix GLEW_GET_FUN(__glewPushMatrix) +#define glPushName GLEW_GET_FUN(__glewPushName) +#define glRasterPos2d GLEW_GET_FUN(__glewRasterPos2d) +#define glRasterPos2dv GLEW_GET_FUN(__glewRasterPos2dv) +#define glRasterPos2f GLEW_GET_FUN(__glewRasterPos2f) +#define glRasterPos2fv GLEW_GET_FUN(__glewRasterPos2fv) +#define glRasterPos2i GLEW_GET_FUN(__glewRasterPos2i) +#define glRasterPos2iv GLEW_GET_FUN(__glewRasterPos2iv) +#define glRasterPos2s GLEW_GET_FUN(__glewRasterPos2s) +#define glRasterPos2sv GLEW_GET_FUN(__glewRasterPos2sv) +#define glRasterPos3d GLEW_GET_FUN(__glewRasterPos3d) +#define glRasterPos3dv GLEW_GET_FUN(__glewRasterPos3dv) +#define glRasterPos3f GLEW_GET_FUN(__glewRasterPos3f) +#define glRasterPos3fv GLEW_GET_FUN(__glewRasterPos3fv) +#define glRasterPos3i GLEW_GET_FUN(__glewRasterPos3i) +#define glRasterPos3iv GLEW_GET_FUN(__glewRasterPos3iv) +#define glRasterPos3s GLEW_GET_FUN(__glewRasterPos3s) +#define glRasterPos3sv GLEW_GET_FUN(__glewRasterPos3sv) +#define glRasterPos4d GLEW_GET_FUN(__glewRasterPos4d) +#define glRasterPos4dv GLEW_GET_FUN(__glewRasterPos4dv) +#define glRasterPos4f GLEW_GET_FUN(__glewRasterPos4f) +#define glRasterPos4fv GLEW_GET_FUN(__glewRasterPos4fv) +#define glRasterPos4i GLEW_GET_FUN(__glewRasterPos4i) +#define glRasterPos4iv GLEW_GET_FUN(__glewRasterPos4iv) +#define glRasterPos4s GLEW_GET_FUN(__glewRasterPos4s) +#define glRasterPos4sv GLEW_GET_FUN(__glewRasterPos4sv) +#define glReadBuffer GLEW_GET_FUN(__glewReadBuffer) +#define glReadPixels GLEW_GET_FUN(__glewReadPixels) +#define glRectd GLEW_GET_FUN(__glewRectd) +#define glRectdv GLEW_GET_FUN(__glewRectdv) +#define glRectf GLEW_GET_FUN(__glewRectf) +#define glRectfv GLEW_GET_FUN(__glewRectfv) +#define glRecti GLEW_GET_FUN(__glewRecti) +#define glRectiv GLEW_GET_FUN(__glewRectiv) +#define glRects GLEW_GET_FUN(__glewRects) +#define glRectsv GLEW_GET_FUN(__glewRectsv) +#define glRenderMode GLEW_GET_FUN(__glewRenderMode) +#define glRotated GLEW_GET_FUN(__glewRotated) +#define glRotatef GLEW_GET_FUN(__glewRotatef) +#define glScaled GLEW_GET_FUN(__glewScaled) +#define glScalef GLEW_GET_FUN(__glewScalef) +#define glScissor GLEW_GET_FUN(__glewScissor) +#define glSelectBuffer GLEW_GET_FUN(__glewSelectBuffer) +#define glShadeModel GLEW_GET_FUN(__glewShadeModel) +#define glStencilFunc GLEW_GET_FUN(__glewStencilFunc) +#define glStencilMask GLEW_GET_FUN(__glewStencilMask) +#define glStencilOp GLEW_GET_FUN(__glewStencilOp) +#define glTexCoord1d GLEW_GET_FUN(__glewTexCoord1d) +#define glTexCoord1dv GLEW_GET_FUN(__glewTexCoord1dv) +#define glTexCoord1f GLEW_GET_FUN(__glewTexCoord1f) +#define glTexCoord1fv GLEW_GET_FUN(__glewTexCoord1fv) +#define glTexCoord1i GLEW_GET_FUN(__glewTexCoord1i) +#define glTexCoord1iv GLEW_GET_FUN(__glewTexCoord1iv) +#define glTexCoord1s GLEW_GET_FUN(__glewTexCoord1s) +#define glTexCoord1sv GLEW_GET_FUN(__glewTexCoord1sv) +#define glTexCoord2d GLEW_GET_FUN(__glewTexCoord2d) +#define glTexCoord2dv GLEW_GET_FUN(__glewTexCoord2dv) +#define glTexCoord2f GLEW_GET_FUN(__glewTexCoord2f) +#define glTexCoord2fv GLEW_GET_FUN(__glewTexCoord2fv) +#define glTexCoord2i GLEW_GET_FUN(__glewTexCoord2i) +#define glTexCoord2iv GLEW_GET_FUN(__glewTexCoord2iv) +#define glTexCoord2s GLEW_GET_FUN(__glewTexCoord2s) +#define glTexCoord2sv GLEW_GET_FUN(__glewTexCoord2sv) +#define glTexCoord3d GLEW_GET_FUN(__glewTexCoord3d) +#define glTexCoord3dv GLEW_GET_FUN(__glewTexCoord3dv) +#define glTexCoord3f GLEW_GET_FUN(__glewTexCoord3f) +#define glTexCoord3fv GLEW_GET_FUN(__glewTexCoord3fv) +#define glTexCoord3i GLEW_GET_FUN(__glewTexCoord3i) +#define glTexCoord3iv GLEW_GET_FUN(__glewTexCoord3iv) +#define glTexCoord3s GLEW_GET_FUN(__glewTexCoord3s) +#define glTexCoord3sv GLEW_GET_FUN(__glewTexCoord3sv) +#define glTexCoord4d GLEW_GET_FUN(__glewTexCoord4d) +#define glTexCoord4dv GLEW_GET_FUN(__glewTexCoord4dv) +#define glTexCoord4f GLEW_GET_FUN(__glewTexCoord4f) +#define glTexCoord4fv GLEW_GET_FUN(__glewTexCoord4fv) +#define glTexCoord4i GLEW_GET_FUN(__glewTexCoord4i) +#define glTexCoord4iv GLEW_GET_FUN(__glewTexCoord4iv) +#define glTexCoord4s GLEW_GET_FUN(__glewTexCoord4s) +#define glTexCoord4sv GLEW_GET_FUN(__glewTexCoord4sv) +#define glTexCoordPointer GLEW_GET_FUN(__glewTexCoordPointer) +#define glTexEnvf GLEW_GET_FUN(__glewTexEnvf) +#define glTexEnvfv GLEW_GET_FUN(__glewTexEnvfv) +#define glTexEnvi GLEW_GET_FUN(__glewTexEnvi) +#define glTexEnviv GLEW_GET_FUN(__glewTexEnviv) +#define glTexGend GLEW_GET_FUN(__glewTexGend) +#define glTexGendv GLEW_GET_FUN(__glewTexGendv) +#define glTexGenf GLEW_GET_FUN(__glewTexGenf) +#define glTexGenfv GLEW_GET_FUN(__glewTexGenfv) +#define glTexGeni GLEW_GET_FUN(__glewTexGeni) +#define glTexGeniv GLEW_GET_FUN(__glewTexGeniv) +#define glTexImage1D GLEW_GET_FUN(__glewTexImage1D) +#define glTexImage2D GLEW_GET_FUN(__glewTexImage2D) +#define glTexParameterf GLEW_GET_FUN(__glewTexParameterf) +#define glTexParameterfv GLEW_GET_FUN(__glewTexParameterfv) +#define glTexParameteri GLEW_GET_FUN(__glewTexParameteri) +#define glTexParameteriv GLEW_GET_FUN(__glewTexParameteriv) +#define glTexSubImage1D GLEW_GET_FUN(__glewTexSubImage1D) +#define glTexSubImage2D GLEW_GET_FUN(__glewTexSubImage2D) +#define glTranslated GLEW_GET_FUN(__glewTranslated) +#define glTranslatef GLEW_GET_FUN(__glewTranslatef) +#define glVertex2d GLEW_GET_FUN(__glewVertex2d) +#define glVertex2dv GLEW_GET_FUN(__glewVertex2dv) +#define glVertex2f GLEW_GET_FUN(__glewVertex2f) +#define glVertex2fv GLEW_GET_FUN(__glewVertex2fv) +#define glVertex2i GLEW_GET_FUN(__glewVertex2i) +#define glVertex2iv GLEW_GET_FUN(__glewVertex2iv) +#define glVertex2s GLEW_GET_FUN(__glewVertex2s) +#define glVertex2sv GLEW_GET_FUN(__glewVertex2sv) +#define glVertex3d GLEW_GET_FUN(__glewVertex3d) +#define glVertex3dv GLEW_GET_FUN(__glewVertex3dv) +#define glVertex3f GLEW_GET_FUN(__glewVertex3f) +#define glVertex3fv GLEW_GET_FUN(__glewVertex3fv) +#define glVertex3i GLEW_GET_FUN(__glewVertex3i) +#define glVertex3iv GLEW_GET_FUN(__glewVertex3iv) +#define glVertex3s GLEW_GET_FUN(__glewVertex3s) +#define glVertex3sv GLEW_GET_FUN(__glewVertex3sv) +#define glVertex4d GLEW_GET_FUN(__glewVertex4d) +#define glVertex4dv GLEW_GET_FUN(__glewVertex4dv) +#define glVertex4f GLEW_GET_FUN(__glewVertex4f) +#define glVertex4fv GLEW_GET_FUN(__glewVertex4fv) +#define glVertex4i GLEW_GET_FUN(__glewVertex4i) +#define glVertex4iv GLEW_GET_FUN(__glewVertex4iv) +#define glVertex4s GLEW_GET_FUN(__glewVertex4s) +#define glVertex4sv GLEW_GET_FUN(__glewVertex4sv) +#define glVertexPointer GLEW_GET_FUN(__glewVertexPointer) +#define glViewport GLEW_GET_FUN(__glewViewport) + + +#else //GLEW_INIT_OPENGL11_FUNCTIONS + GLAPI void GLAPIENTRY glAccum (GLenum op, GLfloat value); GLAPI void GLAPIENTRY glAlphaFunc (GLenum func, GLclampf ref); GLAPI GLboolean GLAPIENTRY glAreTexturesResident (GLsizei n, const GLuint *textures, GLboolean *residences); @@ -1174,7 +1855,7 @@ GLAPI void GLAPIENTRY glVertex4s (GLshort x, GLshort y, GLshort z, GLshort w); GLAPI void GLAPIENTRY glVertex4sv (const GLshort *v); GLAPI void GLAPIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); GLAPI void GLAPIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); - +#endif //GLEW_INIT_OPENGL11_FUNCTIONS #define GLEW_VERSION_1_1 GLEW_GET_VAR(__GLEW_VERSION_1_1) #endif /* GL_VERSION_1_1 */ @@ -15041,6 +15722,346 @@ struct GLEWContextStruct { #endif /* GLEW_MX */ +#ifdef GLEW_INIT_OPENGL11_FUNCTIONS + +GLEW_FUN_EXPORT PFNGLACCUMPROC __glewAccum; +GLEW_FUN_EXPORT PFNGLALPHAFUNCPROC __glewAlphaFunc; +GLEW_FUN_EXPORT PFNGLARETEXTURESRESIDENTPROC __glewAreTexturesResident; +GLEW_FUN_EXPORT PFNGLARRAYELEMENTPROC __glewArrayElement; +GLEW_FUN_EXPORT PFNGLBEGINPROC __glewBegin; +GLEW_FUN_EXPORT PFNGLBINDTEXTUREPROC __glewBindTexture; +GLEW_FUN_EXPORT PFNGLBITMAPPROC __glewBitmap; +GLEW_FUN_EXPORT PFNGLBLENDFUNCPROC __glewBlendFunc; +GLEW_FUN_EXPORT PFNGLCALLLISTPROC __glewCallList; +GLEW_FUN_EXPORT PFNGLCALLLISTSPROC __glewCallLists; +GLEW_FUN_EXPORT PFNGLCLEARPROC __glewClear; +GLEW_FUN_EXPORT PFNGLCLEARACCUMPROC __glewClearAccum; +GLEW_FUN_EXPORT PFNGLCLEARCOLORPROC __glewClearColor; +GLEW_FUN_EXPORT PFNGLCLEARDEPTHPROC __glewClearDepth; +GLEW_FUN_EXPORT PFNGLCLEARINDEXPROC __glewClearIndex; +GLEW_FUN_EXPORT PFNGLCLEARSTENCILPROC __glewClearStencil; +GLEW_FUN_EXPORT PFNGLCLIPPLANEPROC __glewClipPlane; +GLEW_FUN_EXPORT PFNGLCOLOR3BPROC __glewColor3b; +GLEW_FUN_EXPORT PFNGLCOLOR3BVPROC __glewColor3bv; +GLEW_FUN_EXPORT PFNGLCOLOR3DPROC __glewColor3d; +GLEW_FUN_EXPORT PFNGLCOLOR3DVPROC __glewColor3dv; +GLEW_FUN_EXPORT PFNGLCOLOR3FPROC __glewColor3f; +GLEW_FUN_EXPORT PFNGLCOLOR3FVPROC __glewColor3fv; +GLEW_FUN_EXPORT PFNGLCOLOR3IPROC __glewColor3i; +GLEW_FUN_EXPORT PFNGLCOLOR3IVPROC __glewColor3iv; +GLEW_FUN_EXPORT PFNGLCOLOR3SPROC __glewColor3s; +GLEW_FUN_EXPORT PFNGLCOLOR3SVPROC __glewColor3sv; +GLEW_FUN_EXPORT PFNGLCOLOR3UBPROC __glewColor3ub; +GLEW_FUN_EXPORT PFNGLCOLOR3UBVPROC __glewColor3ubv; +GLEW_FUN_EXPORT PFNGLCOLOR3UIPROC __glewColor3ui; +GLEW_FUN_EXPORT PFNGLCOLOR3UIVPROC __glewColor3uiv; +GLEW_FUN_EXPORT PFNGLCOLOR3USPROC __glewColor3us; +GLEW_FUN_EXPORT PFNGLCOLOR3USVPROC __glewColor3usv; +GLEW_FUN_EXPORT PFNGLCOLOR4BPROC __glewColor4b; +GLEW_FUN_EXPORT PFNGLCOLOR4BVPROC __glewColor4bv; +GLEW_FUN_EXPORT PFNGLCOLOR4DPROC __glewColor4d; +GLEW_FUN_EXPORT PFNGLCOLOR4DVPROC __glewColor4dv; +GLEW_FUN_EXPORT PFNGLCOLOR4FPROC __glewColor4f; +GLEW_FUN_EXPORT PFNGLCOLOR4FVPROC __glewColor4fv; +GLEW_FUN_EXPORT PFNGLCOLOR4IPROC __glewColor4i; +GLEW_FUN_EXPORT PFNGLCOLOR4IVPROC __glewColor4iv; +GLEW_FUN_EXPORT PFNGLCOLOR4SPROC __glewColor4s; +GLEW_FUN_EXPORT PFNGLCOLOR4SVPROC __glewColor4sv; +GLEW_FUN_EXPORT PFNGLCOLOR4UBPROC __glewColor4ub; +GLEW_FUN_EXPORT PFNGLCOLOR4UBVPROC __glewColor4ubv; +GLEW_FUN_EXPORT PFNGLCOLOR4UIPROC __glewColor4ui; +GLEW_FUN_EXPORT PFNGLCOLOR4UIVPROC __glewColor4uiv; +GLEW_FUN_EXPORT PFNGLCOLOR4USPROC __glewColor4us; +GLEW_FUN_EXPORT PFNGLCOLOR4USVPROC __glewColor4usv; +GLEW_FUN_EXPORT PFNGLCOLORMASKPROC __glewColorMask; +GLEW_FUN_EXPORT PFNGLCOLORMATERIALPROC __glewColorMaterial; +GLEW_FUN_EXPORT PFNGLCOLORPOINTERPROC __glewColorPointer; +GLEW_FUN_EXPORT PFNGLCOPYPIXELSPROC __glewCopyPixels; +GLEW_FUN_EXPORT PFNGLCOPYTEXIMAGE1DPROC __glewCopyTexImage1D; +GLEW_FUN_EXPORT PFNGLCOPYTEXIMAGE2DPROC __glewCopyTexImage2D; +GLEW_FUN_EXPORT PFNGLCOPYTEXSUBIMAGE1DPROC __glewCopyTexSubImage1D; +GLEW_FUN_EXPORT PFNGLCOPYTEXSUBIMAGE2DPROC __glewCopyTexSubImage2D; +GLEW_FUN_EXPORT PFNGLCULLFACEPROC __glewCullFace; +GLEW_FUN_EXPORT PFNGLDELETELISTSPROC __glewDeleteLists; +GLEW_FUN_EXPORT PFNGLDELETETEXTURESPROC __glewDeleteTextures; +GLEW_FUN_EXPORT PFNGLDEPTHFUNCPROC __glewDepthFunc; +GLEW_FUN_EXPORT PFNGLDEPTHMASKPROC __glewDepthMask; +GLEW_FUN_EXPORT PFNGLDEPTHRANGEPROC __glewDepthRange; +GLEW_FUN_EXPORT PFNGLDISABLEPROC __glewDisable; +GLEW_FUN_EXPORT PFNGLDISABLECLIENTSTATEPROC __glewDisableClientState; +GLEW_FUN_EXPORT PFNGLDRAWARRAYSPROC __glewDrawArrays; +GLEW_FUN_EXPORT PFNGLDRAWBUFFERPROC __glewDrawBuffer; +GLEW_FUN_EXPORT PFNGLDRAWELEMENTSPROC __glewDrawElements; +GLEW_FUN_EXPORT PFNGLDRAWPIXELSPROC __glewDrawPixels; +GLEW_FUN_EXPORT PFNGLEDGEFLAGPROC __glewEdgeFlag; +GLEW_FUN_EXPORT PFNGLEDGEFLAGPOINTERPROC __glewEdgeFlagPointer; +GLEW_FUN_EXPORT PFNGLEDGEFLAGVPROC __glewEdgeFlagv; +GLEW_FUN_EXPORT PFNGLENABLEPROC __glewEnable; +GLEW_FUN_EXPORT PFNGLENABLECLIENTSTATEPROC __glewEnableClientState; +GLEW_FUN_EXPORT PFNGLENDPROC __glewEnd; +GLEW_FUN_EXPORT PFNGLENDLISTPROC __glewEndList; +GLEW_FUN_EXPORT PFNGLEVALCOORD1DPROC __glewEvalCoord1d; +GLEW_FUN_EXPORT PFNGLEVALCOORD1DVPROC __glewEvalCoord1dv; +GLEW_FUN_EXPORT PFNGLEVALCOORD1FPROC __glewEvalCoord1f; +GLEW_FUN_EXPORT PFNGLEVALCOORD1FVPROC __glewEvalCoord1fv; +GLEW_FUN_EXPORT PFNGLEVALCOORD2DPROC __glewEvalCoord2d; +GLEW_FUN_EXPORT PFNGLEVALCOORD2DVPROC __glewEvalCoord2dv; +GLEW_FUN_EXPORT PFNGLEVALCOORD2FPROC __glewEvalCoord2f; +GLEW_FUN_EXPORT PFNGLEVALCOORD2FVPROC __glewEvalCoord2fv; +GLEW_FUN_EXPORT PFNGLEVALMESH1PROC __glewEvalMesh1; +GLEW_FUN_EXPORT PFNGLEVALMESH2PROC __glewEvalMesh2; +GLEW_FUN_EXPORT PFNGLEVALPOINT1PROC __glewEvalPoint1; +GLEW_FUN_EXPORT PFNGLEVALPOINT2PROC __glewEvalPoint2; +GLEW_FUN_EXPORT PFNGLFEEDBACKBUFFERPROC __glewFeedbackBuffer; +GLEW_FUN_EXPORT PFNGLFINISHPROC __glewFinish; +GLEW_FUN_EXPORT PFNGLFLUSHPROC __glewFlush; +GLEW_FUN_EXPORT PFNGLFOGFPROC __glewFogf; +GLEW_FUN_EXPORT PFNGLFOGFVPROC __glewFogfv; +GLEW_FUN_EXPORT PFNGLFOGIPROC __glewFogi; +GLEW_FUN_EXPORT PFNGLFOGIVPROC __glewFogiv; +GLEW_FUN_EXPORT PFNGLFRONTFACEPROC __glewFrontFace; +GLEW_FUN_EXPORT PFNGLFRUSTUMPROC __glewFrustum; +GLEW_FUN_EXPORT PFNGLGENLISTSPROC __glewGenLists; +GLEW_FUN_EXPORT PFNGLGENTEXTURESPROC __glewGenTextures; +GLEW_FUN_EXPORT PFNGLGETBOOLEANVPROC __glewGetBooleanv; +GLEW_FUN_EXPORT PFNGLGETCLIPPLANEPROC __glewGetClipPlane; +GLEW_FUN_EXPORT PFNGLGETDOUBLEVPROC __glewGetDoublev; +GLEW_FUN_EXPORT PFNGLGETERRORPROC __glewGetError; +GLEW_FUN_EXPORT PFNGLGETFLOATVPROC __glewGetFloatv; +GLEW_FUN_EXPORT PFNGLGETINTEGERVPROC __glewGetIntegerv; +GLEW_FUN_EXPORT PFNGLGETLIGHTFVPROC __glewGetLightfv; +GLEW_FUN_EXPORT PFNGLGETLIGHTIVPROC __glewGetLightiv; +GLEW_FUN_EXPORT PFNGLGETMAPDVPROC __glewGetMapdv; +GLEW_FUN_EXPORT PFNGLGETMAPFVPROC __glewGetMapfv; +GLEW_FUN_EXPORT PFNGLGETMAPIVPROC __glewGetMapiv; +GLEW_FUN_EXPORT PFNGLGETMATERIALFVPROC __glewGetMaterialfv; +GLEW_FUN_EXPORT PFNGLGETMATERIALIVPROC __glewGetMaterialiv; +GLEW_FUN_EXPORT PFNGLGETPIXELMAPFVPROC __glewGetPixelMapfv; +GLEW_FUN_EXPORT PFNGLGETPIXELMAPUIVPROC __glewGetPixelMapuiv; +GLEW_FUN_EXPORT PFNGLGETPIXELMAPUSVPROC __glewGetPixelMapusv; +GLEW_FUN_EXPORT PFNGLGETPOINTERVPROC __glewGetPointerv; +GLEW_FUN_EXPORT PFNGLGETPOLYGONSTIPPLEPROC __glewGetPolygonStipple; +GLEW_FUN_EXPORT PFNGLGETSTRINGPROC __glewGetString; +GLEW_FUN_EXPORT PFNGLGETTEXENVFVPROC __glewGetTexEnvfv; +GLEW_FUN_EXPORT PFNGLGETTEXENVIVPROC __glewGetTexEnviv; +GLEW_FUN_EXPORT PFNGLGETTEXGENDVPROC __glewGetTexGendv; +GLEW_FUN_EXPORT PFNGLGETTEXGENFVPROC __glewGetTexGenfv; +GLEW_FUN_EXPORT PFNGLGETTEXGENIVPROC __glewGetTexGeniv; +GLEW_FUN_EXPORT PFNGLGETTEXIMAGEPROC __glewGetTexImage; +GLEW_FUN_EXPORT PFNGLGETTEXLEVELPARAMETERFVPROC __glewGetTexLevelParameterfv; +GLEW_FUN_EXPORT PFNGLGETTEXLEVELPARAMETERIVPROC __glewGetTexLevelParameteriv; +GLEW_FUN_EXPORT PFNGLGETTEXPARAMETERFVPROC __glewGetTexParameterfv; +GLEW_FUN_EXPORT PFNGLGETTEXPARAMETERIVPROC __glewGetTexParameteriv; +GLEW_FUN_EXPORT PFNGLHINTPROC __glewHint; +GLEW_FUN_EXPORT PFNGLINDEXMASKPROC __glewIndexMask; +GLEW_FUN_EXPORT PFNGLINDEXPOINTERPROC __glewIndexPointer; +GLEW_FUN_EXPORT PFNGLINDEXDPROC __glewIndexd; +GLEW_FUN_EXPORT PFNGLINDEXDVPROC __glewIndexdv; +GLEW_FUN_EXPORT PFNGLINDEXFPROC __glewIndexf; +GLEW_FUN_EXPORT PFNGLINDEXFVPROC __glewIndexfv; +GLEW_FUN_EXPORT PFNGLINDEXIPROC __glewIndexi; +GLEW_FUN_EXPORT PFNGLINDEXIVPROC __glewIndexiv; +GLEW_FUN_EXPORT PFNGLINDEXSPROC __glewIndexs; +GLEW_FUN_EXPORT PFNGLINDEXSVPROC __glewIndexsv; +GLEW_FUN_EXPORT PFNGLINDEXUBPROC __glewIndexub; +GLEW_FUN_EXPORT PFNGLINDEXUBVPROC __glewIndexubv; +GLEW_FUN_EXPORT PFNGLINITNAMESPROC __glewInitNames; +GLEW_FUN_EXPORT PFNGLINTERLEAVEDARRAYSPROC __glewInterleavedArrays; +GLEW_FUN_EXPORT PFNGLISENABLEDPROC __glewIsEnabled; +GLEW_FUN_EXPORT PFNGLISLISTPROC __glewIsList; +GLEW_FUN_EXPORT PFNGLISTEXTUREPROC __glewIsTexture; +GLEW_FUN_EXPORT PFNGLLIGHTMODELFPROC __glewLightModelf; +GLEW_FUN_EXPORT PFNGLLIGHTMODELFVPROC __glewLightModelfv; +GLEW_FUN_EXPORT PFNGLLIGHTMODELIPROC __glewLightModeli; +GLEW_FUN_EXPORT PFNGLLIGHTMODELIVPROC __glewLightModeliv; +GLEW_FUN_EXPORT PFNGLLIGHTFPROC __glewLightf; +GLEW_FUN_EXPORT PFNGLLIGHTFVPROC __glewLightfv; +GLEW_FUN_EXPORT PFNGLLIGHTIPROC __glewLighti; +GLEW_FUN_EXPORT PFNGLLIGHTIVPROC __glewLightiv; +GLEW_FUN_EXPORT PFNGLLINESTIPPLEPROC __glewLineStipple; +GLEW_FUN_EXPORT PFNGLLINEWIDTHPROC __glewLineWidth; +GLEW_FUN_EXPORT PFNGLLISTBASEPROC __glewListBase; +GLEW_FUN_EXPORT PFNGLLOADIDENTITYPROC __glewLoadIdentity; +GLEW_FUN_EXPORT PFNGLLOADMATRIXDPROC __glewLoadMatrixd; +GLEW_FUN_EXPORT PFNGLLOADMATRIXFPROC __glewLoadMatrixf; +GLEW_FUN_EXPORT PFNGLLOADNAMEPROC __glewLoadName; +GLEW_FUN_EXPORT PFNGLLOGICOPPROC __glewLogicOp; +GLEW_FUN_EXPORT PFNGLMAP1DPROC __glewMap1d; +GLEW_FUN_EXPORT PFNGLMAP1FPROC __glewMap1f; +GLEW_FUN_EXPORT PFNGLMAP2DPROC __glewMap2d; +GLEW_FUN_EXPORT PFNGLMAP2FPROC __glewMap2f; +GLEW_FUN_EXPORT PFNGLMAPGRID1DPROC __glewMapGrid1d; +GLEW_FUN_EXPORT PFNGLMAPGRID1FPROC __glewMapGrid1f; +GLEW_FUN_EXPORT PFNGLMAPGRID2DPROC __glewMapGrid2d; +GLEW_FUN_EXPORT PFNGLMAPGRID2FPROC __glewMapGrid2f; +GLEW_FUN_EXPORT PFNGLMATERIALFPROC __glewMaterialf; +GLEW_FUN_EXPORT PFNGLMATERIALFVPROC __glewMaterialfv; +GLEW_FUN_EXPORT PFNGLMATERIALIPROC __glewMateriali; +GLEW_FUN_EXPORT PFNGLMATERIALIVPROC __glewMaterialiv; +GLEW_FUN_EXPORT PFNGLMATRIXMODEPROC __glewMatrixMode; +GLEW_FUN_EXPORT PFNGLMULTMATRIXDPROC __glewMultMatrixd; +GLEW_FUN_EXPORT PFNGLMULTMATRIXFPROC __glewMultMatrixf; +GLEW_FUN_EXPORT PFNGLNEWLISTPROC __glewNewList; +GLEW_FUN_EXPORT PFNGLNORMAL3BPROC __glewNormal3b; +GLEW_FUN_EXPORT PFNGLNORMAL3BVPROC __glewNormal3bv; +GLEW_FUN_EXPORT PFNGLNORMAL3DPROC __glewNormal3d; +GLEW_FUN_EXPORT PFNGLNORMAL3DVPROC __glewNormal3dv; +GLEW_FUN_EXPORT PFNGLNORMAL3FPROC __glewNormal3f; +GLEW_FUN_EXPORT PFNGLNORMAL3FVPROC __glewNormal3fv; +GLEW_FUN_EXPORT PFNGLNORMAL3IPROC __glewNormal3i; +GLEW_FUN_EXPORT PFNGLNORMAL3IVPROC __glewNormal3iv; +GLEW_FUN_EXPORT PFNGLNORMAL3SPROC __glewNormal3s; +GLEW_FUN_EXPORT PFNGLNORMAL3SVPROC __glewNormal3sv; +GLEW_FUN_EXPORT PFNGLNORMALPOINTERPROC __glewNormalPointer; +GLEW_FUN_EXPORT PFNGLORTHOPROC __glewOrtho; +GLEW_FUN_EXPORT PFNGLPASSTHROUGHPROC __glewPassThrough; +GLEW_FUN_EXPORT PFNGLPIXELMAPFVPROC __glewPixelMapfv; +GLEW_FUN_EXPORT PFNGLPIXELMAPUIVPROC __glewPixelMapuiv; +GLEW_FUN_EXPORT PFNGLPIXELMAPUSVPROC __glewPixelMapusv; +GLEW_FUN_EXPORT PFNGLPIXELSTOREFPROC __glewPixelStoref; +GLEW_FUN_EXPORT PFNGLPIXELSTOREIPROC __glewPixelStorei; +GLEW_FUN_EXPORT PFNGLPIXELTRANSFERFPROC __glewPixelTransferf; +GLEW_FUN_EXPORT PFNGLPIXELTRANSFERIPROC __glewPixelTransferi; +GLEW_FUN_EXPORT PFNGLPIXELZOOMPROC __glewPixelZoom; +GLEW_FUN_EXPORT PFNGLPOINTSIZEPROC __glewPointSize; +GLEW_FUN_EXPORT PFNGLPOLYGONMODEPROC __glewPolygonMode; +GLEW_FUN_EXPORT PFNGLPOLYGONOFFSETPROC __glewPolygonOffset; +GLEW_FUN_EXPORT PFNGLPOLYGONSTIPPLEPROC __glewPolygonStipple; +GLEW_FUN_EXPORT PFNGLPOPATTRIBPROC __glewPopAttrib; +GLEW_FUN_EXPORT PFNGLPOPCLIENTATTRIBPROC __glewPopClientAttrib; +GLEW_FUN_EXPORT PFNGLPOPMATRIXPROC __glewPopMatrix; +GLEW_FUN_EXPORT PFNGLPOPNAMEPROC __glewPopName; +GLEW_FUN_EXPORT PFNGLPRIORITIZETEXTURESPROC __glewPrioritizeTextures; +GLEW_FUN_EXPORT PFNGLPUSHATTRIBPROC __glewPushAttrib; +GLEW_FUN_EXPORT PFNGLPUSHCLIENTATTRIBPROC __glewPushClientAttrib; +GLEW_FUN_EXPORT PFNGLPUSHMATRIXPROC __glewPushMatrix; +GLEW_FUN_EXPORT PFNGLPUSHNAMEPROC __glewPushName; +GLEW_FUN_EXPORT PFNGLRASTERPOS2DPROC __glewRasterPos2d; +GLEW_FUN_EXPORT PFNGLRASTERPOS2DVPROC __glewRasterPos2dv; +GLEW_FUN_EXPORT PFNGLRASTERPOS2FPROC __glewRasterPos2f; +GLEW_FUN_EXPORT PFNGLRASTERPOS2FVPROC __glewRasterPos2fv; +GLEW_FUN_EXPORT PFNGLRASTERPOS2IPROC __glewRasterPos2i; +GLEW_FUN_EXPORT PFNGLRASTERPOS2IVPROC __glewRasterPos2iv; +GLEW_FUN_EXPORT PFNGLRASTERPOS2SPROC __glewRasterPos2s; +GLEW_FUN_EXPORT PFNGLRASTERPOS2SVPROC __glewRasterPos2sv; +GLEW_FUN_EXPORT PFNGLRASTERPOS3DPROC __glewRasterPos3d; +GLEW_FUN_EXPORT PFNGLRASTERPOS3DVPROC __glewRasterPos3dv; +GLEW_FUN_EXPORT PFNGLRASTERPOS3FPROC __glewRasterPos3f; +GLEW_FUN_EXPORT PFNGLRASTERPOS3FVPROC __glewRasterPos3fv; +GLEW_FUN_EXPORT PFNGLRASTERPOS3IPROC __glewRasterPos3i; +GLEW_FUN_EXPORT PFNGLRASTERPOS3IVPROC __glewRasterPos3iv; +GLEW_FUN_EXPORT PFNGLRASTERPOS3SPROC __glewRasterPos3s; +GLEW_FUN_EXPORT PFNGLRASTERPOS3SVPROC __glewRasterPos3sv; +GLEW_FUN_EXPORT PFNGLRASTERPOS4DPROC __glewRasterPos4d; +GLEW_FUN_EXPORT PFNGLRASTERPOS4DVPROC __glewRasterPos4dv; +GLEW_FUN_EXPORT PFNGLRASTERPOS4FPROC __glewRasterPos4f; +GLEW_FUN_EXPORT PFNGLRASTERPOS4FVPROC __glewRasterPos4fv; +GLEW_FUN_EXPORT PFNGLRASTERPOS4IPROC __glewRasterPos4i; +GLEW_FUN_EXPORT PFNGLRASTERPOS4IVPROC __glewRasterPos4iv; +GLEW_FUN_EXPORT PFNGLRASTERPOS4SPROC __glewRasterPos4s; +GLEW_FUN_EXPORT PFNGLRASTERPOS4SVPROC __glewRasterPos4sv; +GLEW_FUN_EXPORT PFNGLREADBUFFERPROC __glewReadBuffer; +GLEW_FUN_EXPORT PFNGLREADPIXELSPROC __glewReadPixels; +GLEW_FUN_EXPORT PFNGLRECTDPROC __glewRectd; +GLEW_FUN_EXPORT PFNGLRECTDVPROC __glewRectdv; +GLEW_FUN_EXPORT PFNGLRECTFPROC __glewRectf; +GLEW_FUN_EXPORT PFNGLRECTFVPROC __glewRectfv; +GLEW_FUN_EXPORT PFNGLRECTIPROC __glewRecti; +GLEW_FUN_EXPORT PFNGLRECTIVPROC __glewRectiv; +GLEW_FUN_EXPORT PFNGLRECTSPROC __glewRects; +GLEW_FUN_EXPORT PFNGLRECTSVPROC __glewRectsv; +GLEW_FUN_EXPORT PFNGLRENDERMODEPROC __glewRenderMode; +GLEW_FUN_EXPORT PFNGLROTATEDPROC __glewRotated; +GLEW_FUN_EXPORT PFNGLROTATEFPROC __glewRotatef; +GLEW_FUN_EXPORT PFNGLSCALEDPROC __glewScaled; +GLEW_FUN_EXPORT PFNGLSCALEFPROC __glewScalef; +GLEW_FUN_EXPORT PFNGLSCISSORPROC __glewScissor; +GLEW_FUN_EXPORT PFNGLSELECTBUFFERPROC __glewSelectBuffer; +GLEW_FUN_EXPORT PFNGLSHADEMODELPROC __glewShadeModel; +GLEW_FUN_EXPORT PFNGLSTENCILFUNCPROC __glewStencilFunc; +GLEW_FUN_EXPORT PFNGLSTENCILMASKPROC __glewStencilMask; +GLEW_FUN_EXPORT PFNGLSTENCILOPPROC __glewStencilOp; +GLEW_FUN_EXPORT PFNGLTEXCOORD1DPROC __glewTexCoord1d; +GLEW_FUN_EXPORT PFNGLTEXCOORD1DVPROC __glewTexCoord1dv; +GLEW_FUN_EXPORT PFNGLTEXCOORD1FPROC __glewTexCoord1f; +GLEW_FUN_EXPORT PFNGLTEXCOORD1FVPROC __glewTexCoord1fv; +GLEW_FUN_EXPORT PFNGLTEXCOORD1IPROC __glewTexCoord1i; +GLEW_FUN_EXPORT PFNGLTEXCOORD1IVPROC __glewTexCoord1iv; +GLEW_FUN_EXPORT PFNGLTEXCOORD1SPROC __glewTexCoord1s; +GLEW_FUN_EXPORT PFNGLTEXCOORD1SVPROC __glewTexCoord1sv; +GLEW_FUN_EXPORT PFNGLTEXCOORD2DPROC __glewTexCoord2d; +GLEW_FUN_EXPORT PFNGLTEXCOORD2DVPROC __glewTexCoord2dv; +GLEW_FUN_EXPORT PFNGLTEXCOORD2FPROC __glewTexCoord2f; +GLEW_FUN_EXPORT PFNGLTEXCOORD2FVPROC __glewTexCoord2fv; +GLEW_FUN_EXPORT PFNGLTEXCOORD2IPROC __glewTexCoord2i; +GLEW_FUN_EXPORT PFNGLTEXCOORD2IVPROC __glewTexCoord2iv; +GLEW_FUN_EXPORT PFNGLTEXCOORD2SPROC __glewTexCoord2s; +GLEW_FUN_EXPORT PFNGLTEXCOORD2SVPROC __glewTexCoord2sv; +GLEW_FUN_EXPORT PFNGLTEXCOORD3DPROC __glewTexCoord3d; +GLEW_FUN_EXPORT PFNGLTEXCOORD3DVPROC __glewTexCoord3dv; +GLEW_FUN_EXPORT PFNGLTEXCOORD3FPROC __glewTexCoord3f; +GLEW_FUN_EXPORT PFNGLTEXCOORD3FVPROC __glewTexCoord3fv; +GLEW_FUN_EXPORT PFNGLTEXCOORD3IPROC __glewTexCoord3i; +GLEW_FUN_EXPORT PFNGLTEXCOORD3IVPROC __glewTexCoord3iv; +GLEW_FUN_EXPORT PFNGLTEXCOORD3SPROC __glewTexCoord3s; +GLEW_FUN_EXPORT PFNGLTEXCOORD3SVPROC __glewTexCoord3sv; +GLEW_FUN_EXPORT PFNGLTEXCOORD4DPROC __glewTexCoord4d; +GLEW_FUN_EXPORT PFNGLTEXCOORD4DVPROC __glewTexCoord4dv; +GLEW_FUN_EXPORT PFNGLTEXCOORD4FPROC __glewTexCoord4f; +GLEW_FUN_EXPORT PFNGLTEXCOORD4FVPROC __glewTexCoord4fv; +GLEW_FUN_EXPORT PFNGLTEXCOORD4IPROC __glewTexCoord4i; +GLEW_FUN_EXPORT PFNGLTEXCOORD4IVPROC __glewTexCoord4iv; +GLEW_FUN_EXPORT PFNGLTEXCOORD4SPROC __glewTexCoord4s; +GLEW_FUN_EXPORT PFNGLTEXCOORD4SVPROC __glewTexCoord4sv; +GLEW_FUN_EXPORT PFNGLTEXCOORDPOINTERPROC __glewTexCoordPointer; +GLEW_FUN_EXPORT PFNGLTEXENVFPROC __glewTexEnvf; +GLEW_FUN_EXPORT PFNGLTEXENVFVPROC __glewTexEnvfv; +GLEW_FUN_EXPORT PFNGLTEXENVIPROC __glewTexEnvi; +GLEW_FUN_EXPORT PFNGLTEXENVIVPROC __glewTexEnviv; +GLEW_FUN_EXPORT PFNGLTEXGENDPROC __glewTexGend; +GLEW_FUN_EXPORT PFNGLTEXGENDVPROC __glewTexGendv; +GLEW_FUN_EXPORT PFNGLTEXGENFPROC __glewTexGenf; +GLEW_FUN_EXPORT PFNGLTEXGENFVPROC __glewTexGenfv; +GLEW_FUN_EXPORT PFNGLTEXGENIPROC __glewTexGeni; +GLEW_FUN_EXPORT PFNGLTEXGENIVPROC __glewTexGeniv; +GLEW_FUN_EXPORT PFNGLTEXIMAGE1DPROC __glewTexImage1D; +GLEW_FUN_EXPORT PFNGLTEXIMAGE2DPROC __glewTexImage2D; +GLEW_FUN_EXPORT PFNGLTEXPARAMETERFPROC __glewTexParameterf; +GLEW_FUN_EXPORT PFNGLTEXPARAMETERFVPROC __glewTexParameterfv; +GLEW_FUN_EXPORT PFNGLTEXPARAMETERIPROC __glewTexParameteri; +GLEW_FUN_EXPORT PFNGLTEXPARAMETERIVPROC __glewTexParameteriv; +GLEW_FUN_EXPORT PFNGLTEXSUBIMAGE1DPROC __glewTexSubImage1D; +GLEW_FUN_EXPORT PFNGLTEXSUBIMAGE2DPROC __glewTexSubImage2D; +GLEW_FUN_EXPORT PFNGLTRANSLATEDPROC __glewTranslated; +GLEW_FUN_EXPORT PFNGLTRANSLATEFPROC __glewTranslatef; +GLEW_FUN_EXPORT PFNGLVERTEX2DPROC __glewVertex2d; +GLEW_FUN_EXPORT PFNGLVERTEX2DVPROC __glewVertex2dv; +GLEW_FUN_EXPORT PFNGLVERTEX2FPROC __glewVertex2f; +GLEW_FUN_EXPORT PFNGLVERTEX2FVPROC __glewVertex2fv; +GLEW_FUN_EXPORT PFNGLVERTEX2IPROC __glewVertex2i; +GLEW_FUN_EXPORT PFNGLVERTEX2IVPROC __glewVertex2iv; +GLEW_FUN_EXPORT PFNGLVERTEX2SPROC __glewVertex2s; +GLEW_FUN_EXPORT PFNGLVERTEX2SVPROC __glewVertex2sv; +GLEW_FUN_EXPORT PFNGLVERTEX3DPROC __glewVertex3d; +GLEW_FUN_EXPORT PFNGLVERTEX3DVPROC __glewVertex3dv; +GLEW_FUN_EXPORT PFNGLVERTEX3FPROC __glewVertex3f; +GLEW_FUN_EXPORT PFNGLVERTEX3FVPROC __glewVertex3fv; +GLEW_FUN_EXPORT PFNGLVERTEX3IPROC __glewVertex3i; +GLEW_FUN_EXPORT PFNGLVERTEX3IVPROC __glewVertex3iv; +GLEW_FUN_EXPORT PFNGLVERTEX3SPROC __glewVertex3s; +GLEW_FUN_EXPORT PFNGLVERTEX3SVPROC __glewVertex3sv; +GLEW_FUN_EXPORT PFNGLVERTEX4DPROC __glewVertex4d; +GLEW_FUN_EXPORT PFNGLVERTEX4DVPROC __glewVertex4dv; +GLEW_FUN_EXPORT PFNGLVERTEX4FPROC __glewVertex4f; +GLEW_FUN_EXPORT PFNGLVERTEX4FVPROC __glewVertex4fv; +GLEW_FUN_EXPORT PFNGLVERTEX4IPROC __glewVertex4i; +GLEW_FUN_EXPORT PFNGLVERTEX4IVPROC __glewVertex4iv; +GLEW_FUN_EXPORT PFNGLVERTEX4SPROC __glewVertex4s; +GLEW_FUN_EXPORT PFNGLVERTEX4SVPROC __glewVertex4sv; +GLEW_FUN_EXPORT PFNGLVERTEXPOINTERPROC __glewVertexPointer; +GLEW_FUN_EXPORT PFNGLVIEWPORTPROC __glewViewport; +#endif //#ifdef GLEW_INIT_OPENGL11_FUNCTIONS + GLEW_FUN_EXPORT PFNGLCOPYTEXSUBIMAGE3DPROC __glewCopyTexSubImage3D; GLEW_FUN_EXPORT PFNGLDRAWRANGEELEMENTSPROC __glewDrawRangeElements; GLEW_FUN_EXPORT PFNGLTEXIMAGE3DPROC __glewTexImage3D; @@ -18036,6 +19057,10 @@ GLEWAPI GLboolean GLEWAPIENTRY glewGetExtension (const char *name); GLEWAPI const GLubyte * GLEWAPIENTRY glewGetErrorString (GLenum error); GLEWAPI const GLubyte * GLEWAPIENTRY glewGetString (GLenum name); +#ifdef GLEW_INIT_OPENGL11_FUNCTIONS +GLEWAPI GLboolean GLEWAPIENTRY glewOpenGL11Init(void); +#endif //GLEW_INIT_OPENGL11_FUNCTIONS + #ifdef __cplusplus } #endif diff --git a/btgui/OpenGLWindow/GlewWindows/glew.c b/btgui/OpenGLWindow/GlewWindows/glew.c index 7726e6375..a21474376 100644 --- a/btgui/OpenGLWindow/GlewWindows/glew.c +++ b/btgui/OpenGLWindow/GlewWindows/glew.c @@ -13476,6 +13476,695 @@ extern GLenum GLEWAPIENTRY wglewContextInit (void); extern GLenum GLEWAPIENTRY glxewContextInit (void); #endif /* _WIN32 */ + +#ifdef GLEW_INIT_OPENGL11_FUNCTIONS + +PFNGLACCUMPROC __glewAccum = NULL; +PFNGLALPHAFUNCPROC __glewAlphaFunc = NULL; +PFNGLARETEXTURESRESIDENTPROC __glewAreTexturesResident = NULL; +PFNGLARRAYELEMENTPROC __glewArrayElement = NULL; +PFNGLBEGINPROC __glewBegin = NULL; +PFNGLBINDTEXTUREPROC __glewBindTexture = NULL; +PFNGLBITMAPPROC __glewBitmap = NULL; +PFNGLBLENDFUNCPROC __glewBlendFunc = NULL; +PFNGLCALLLISTPROC __glewCallList = NULL; +PFNGLCALLLISTSPROC __glewCallLists = NULL; +PFNGLCLEARPROC __glewClear = NULL; +PFNGLCLEARACCUMPROC __glewClearAccum = NULL; +PFNGLCLEARCOLORPROC __glewClearColor = NULL; +PFNGLCLEARDEPTHPROC __glewClearDepth = NULL; +PFNGLCLEARINDEXPROC __glewClearIndex = NULL; +PFNGLCLEARSTENCILPROC __glewClearStencil = NULL; +PFNGLCLIPPLANEPROC __glewClipPlane = NULL; +PFNGLCOLOR3BPROC __glewColor3b = NULL; +PFNGLCOLOR3BVPROC __glewColor3bv = NULL; +PFNGLCOLOR3DPROC __glewColor3d = NULL; +PFNGLCOLOR3DVPROC __glewColor3dv = NULL; +PFNGLCOLOR3FPROC __glewColor3f = NULL; +PFNGLCOLOR3FVPROC __glewColor3fv = NULL; +PFNGLCOLOR3IPROC __glewColor3i = NULL; +PFNGLCOLOR3IVPROC __glewColor3iv = NULL; +PFNGLCOLOR3SPROC __glewColor3s = NULL; +PFNGLCOLOR3SVPROC __glewColor3sv = NULL; +PFNGLCOLOR3UBPROC __glewColor3ub = NULL; +PFNGLCOLOR3UBVPROC __glewColor3ubv = NULL; +PFNGLCOLOR3UIPROC __glewColor3ui = NULL; +PFNGLCOLOR3UIVPROC __glewColor3uiv = NULL; +PFNGLCOLOR3USPROC __glewColor3us = NULL; +PFNGLCOLOR3USVPROC __glewColor3usv = NULL; +PFNGLCOLOR4BPROC __glewColor4b = NULL; +PFNGLCOLOR4BVPROC __glewColor4bv = NULL; +PFNGLCOLOR4DPROC __glewColor4d = NULL; +PFNGLCOLOR4DVPROC __glewColor4dv = NULL; +PFNGLCOLOR4FPROC __glewColor4f = NULL; +PFNGLCOLOR4FVPROC __glewColor4fv = NULL; +PFNGLCOLOR4IPROC __glewColor4i = NULL; +PFNGLCOLOR4IVPROC __glewColor4iv = NULL; +PFNGLCOLOR4SPROC __glewColor4s = NULL; +PFNGLCOLOR4SVPROC __glewColor4sv = NULL; +PFNGLCOLOR4UBPROC __glewColor4ub = NULL; +PFNGLCOLOR4UBVPROC __glewColor4ubv = NULL; +PFNGLCOLOR4UIPROC __glewColor4ui = NULL; +PFNGLCOLOR4UIVPROC __glewColor4uiv = NULL; +PFNGLCOLOR4USPROC __glewColor4us = NULL; +PFNGLCOLOR4USVPROC __glewColor4usv = NULL; +PFNGLCOLORMASKPROC __glewColorMask = NULL; +PFNGLCOLORMATERIALPROC __glewColorMaterial = NULL; +PFNGLCOLORPOINTERPROC __glewColorPointer = NULL; +PFNGLCOPYPIXELSPROC __glewCopyPixels = NULL; +PFNGLCOPYTEXIMAGE1DPROC __glewCopyTexImage1D = NULL; +PFNGLCOPYTEXIMAGE2DPROC __glewCopyTexImage2D = NULL; +PFNGLCOPYTEXSUBIMAGE1DPROC __glewCopyTexSubImage1D = NULL; +PFNGLCOPYTEXSUBIMAGE2DPROC __glewCopyTexSubImage2D = NULL; +PFNGLCULLFACEPROC __glewCullFace = NULL; +PFNGLDELETELISTSPROC __glewDeleteLists = NULL; +PFNGLDELETETEXTURESPROC __glewDeleteTextures = NULL; +PFNGLDEPTHFUNCPROC __glewDepthFunc = NULL; +PFNGLDEPTHMASKPROC __glewDepthMask = NULL; +PFNGLDEPTHRANGEPROC __glewDepthRange = NULL; +PFNGLDISABLEPROC __glewDisable = NULL; +PFNGLDISABLECLIENTSTATEPROC __glewDisableClientState = NULL; +PFNGLDRAWARRAYSPROC __glewDrawArrays = NULL; +PFNGLDRAWBUFFERPROC __glewDrawBuffer = NULL; +PFNGLDRAWELEMENTSPROC __glewDrawElements = NULL; +PFNGLDRAWPIXELSPROC __glewDrawPixels = NULL; +PFNGLEDGEFLAGPROC __glewEdgeFlag = NULL; +PFNGLEDGEFLAGPOINTERPROC __glewEdgeFlagPointer = NULL; +PFNGLEDGEFLAGVPROC __glewEdgeFlagv = NULL; +PFNGLENABLEPROC __glewEnable = NULL; +PFNGLENABLECLIENTSTATEPROC __glewEnableClientState = NULL; +PFNGLENDPROC __glewEnd = NULL; +PFNGLENDLISTPROC __glewEndList = NULL; +PFNGLEVALCOORD1DPROC __glewEvalCoord1d = NULL; +PFNGLEVALCOORD1DVPROC __glewEvalCoord1dv = NULL; +PFNGLEVALCOORD1FPROC __glewEvalCoord1f = NULL; +PFNGLEVALCOORD1FVPROC __glewEvalCoord1fv = NULL; +PFNGLEVALCOORD2DPROC __glewEvalCoord2d = NULL; +PFNGLEVALCOORD2DVPROC __glewEvalCoord2dv = NULL; +PFNGLEVALCOORD2FPROC __glewEvalCoord2f = NULL; +PFNGLEVALCOORD2FVPROC __glewEvalCoord2fv = NULL; +PFNGLEVALMESH1PROC __glewEvalMesh1 = NULL; +PFNGLEVALMESH2PROC __glewEvalMesh2 = NULL; +PFNGLEVALPOINT1PROC __glewEvalPoint1 = NULL; +PFNGLEVALPOINT2PROC __glewEvalPoint2 = NULL; +PFNGLFEEDBACKBUFFERPROC __glewFeedbackBuffer = NULL; +PFNGLFINISHPROC __glewFinish = NULL; +PFNGLFLUSHPROC __glewFlush = NULL; +PFNGLFOGFPROC __glewFogf = NULL; +PFNGLFOGFVPROC __glewFogfv = NULL; +PFNGLFOGIPROC __glewFogi = NULL; +PFNGLFOGIVPROC __glewFogiv = NULL; +PFNGLFRONTFACEPROC __glewFrontFace = NULL; +PFNGLFRUSTUMPROC __glewFrustum = NULL; +PFNGLGENLISTSPROC __glewGenLists = NULL; +PFNGLGENTEXTURESPROC __glewGenTextures = NULL; +PFNGLGETBOOLEANVPROC __glewGetBooleanv = NULL; +PFNGLGETCLIPPLANEPROC __glewGetClipPlane = NULL; +PFNGLGETDOUBLEVPROC __glewGetDoublev = NULL; +PFNGLGETERRORPROC __glewGetError = NULL; +PFNGLGETFLOATVPROC __glewGetFloatv = NULL; +PFNGLGETINTEGERVPROC __glewGetIntegerv = NULL; +PFNGLGETLIGHTFVPROC __glewGetLightfv = NULL; +PFNGLGETLIGHTIVPROC __glewGetLightiv = NULL; +PFNGLGETMAPDVPROC __glewGetMapdv = NULL; +PFNGLGETMAPFVPROC __glewGetMapfv = NULL; +PFNGLGETMAPIVPROC __glewGetMapiv = NULL; +PFNGLGETMATERIALFVPROC __glewGetMaterialfv = NULL; +PFNGLGETMATERIALIVPROC __glewGetMaterialiv = NULL; +PFNGLGETPIXELMAPFVPROC __glewGetPixelMapfv = NULL; +PFNGLGETPIXELMAPUIVPROC __glewGetPixelMapuiv = NULL; +PFNGLGETPIXELMAPUSVPROC __glewGetPixelMapusv = NULL; +PFNGLGETPOINTERVPROC __glewGetPointerv = NULL; +PFNGLGETPOLYGONSTIPPLEPROC __glewGetPolygonStipple = NULL; +PFNGLGETSTRINGPROC __glewGetString = NULL; +PFNGLGETTEXENVFVPROC __glewGetTexEnvfv = NULL; +PFNGLGETTEXENVIVPROC __glewGetTexEnviv = NULL; +PFNGLGETTEXGENDVPROC __glewGetTexGendv = NULL; +PFNGLGETTEXGENFVPROC __glewGetTexGenfv = NULL; +PFNGLGETTEXGENIVPROC __glewGetTexGeniv = NULL; +PFNGLGETTEXIMAGEPROC __glewGetTexImage = NULL; +PFNGLGETTEXLEVELPARAMETERFVPROC __glewGetTexLevelParameterfv = NULL; +PFNGLGETTEXLEVELPARAMETERIVPROC __glewGetTexLevelParameteriv = NULL; +PFNGLGETTEXPARAMETERFVPROC __glewGetTexParameterfv = NULL; +PFNGLGETTEXPARAMETERIVPROC __glewGetTexParameteriv = NULL; +PFNGLHINTPROC __glewHint = NULL; +PFNGLINDEXMASKPROC __glewIndexMask = NULL; +PFNGLINDEXPOINTERPROC __glewIndexPointer = NULL; +PFNGLINDEXDPROC __glewIndexd = NULL; +PFNGLINDEXDVPROC __glewIndexdv = NULL; +PFNGLINDEXFPROC __glewIndexf = NULL; +PFNGLINDEXFVPROC __glewIndexfv = NULL; +PFNGLINDEXIPROC __glewIndexi = NULL; +PFNGLINDEXIVPROC __glewIndexiv = NULL; +PFNGLINDEXSPROC __glewIndexs = NULL; +PFNGLINDEXSVPROC __glewIndexsv = NULL; +PFNGLINDEXUBPROC __glewIndexub = NULL; +PFNGLINDEXUBVPROC __glewIndexubv = NULL; +PFNGLINITNAMESPROC __glewInitNames = NULL; +PFNGLINTERLEAVEDARRAYSPROC __glewInterleavedArrays = NULL; +PFNGLISENABLEDPROC __glewIsEnabled = NULL; +PFNGLISLISTPROC __glewIsList = NULL; +PFNGLISTEXTUREPROC __glewIsTexture = NULL; +PFNGLLIGHTMODELFPROC __glewLightModelf = NULL; +PFNGLLIGHTMODELFVPROC __glewLightModelfv = NULL; +PFNGLLIGHTMODELIPROC __glewLightModeli = NULL; +PFNGLLIGHTMODELIVPROC __glewLightModeliv = NULL; +PFNGLLIGHTFPROC __glewLightf = NULL; +PFNGLLIGHTFVPROC __glewLightfv = NULL; +PFNGLLIGHTIPROC __glewLighti = NULL; +PFNGLLIGHTIVPROC __glewLightiv = NULL; +PFNGLLINESTIPPLEPROC __glewLineStipple = NULL; +PFNGLLINEWIDTHPROC __glewLineWidth = NULL; +PFNGLLISTBASEPROC __glewListBase = NULL; +PFNGLLOADIDENTITYPROC __glewLoadIdentity = NULL; +PFNGLLOADMATRIXDPROC __glewLoadMatrixd = NULL; +PFNGLLOADMATRIXFPROC __glewLoadMatrixf = NULL; +PFNGLLOADNAMEPROC __glewLoadName = NULL; +PFNGLLOGICOPPROC __glewLogicOp = NULL; +PFNGLMAP1DPROC __glewMap1d = NULL; +PFNGLMAP1FPROC __glewMap1f = NULL; +PFNGLMAP2DPROC __glewMap2d = NULL; +PFNGLMAP2FPROC __glewMap2f = NULL; +PFNGLMAPGRID1DPROC __glewMapGrid1d = NULL; +PFNGLMAPGRID1FPROC __glewMapGrid1f = NULL; +PFNGLMAPGRID2DPROC __glewMapGrid2d = NULL; +PFNGLMAPGRID2FPROC __glewMapGrid2f = NULL; +PFNGLMATERIALFPROC __glewMaterialf = NULL; +PFNGLMATERIALFVPROC __glewMaterialfv = NULL; +PFNGLMATERIALIPROC __glewMateriali = NULL; +PFNGLMATERIALIVPROC __glewMaterialiv = NULL; +PFNGLMATRIXMODEPROC __glewMatrixMode = NULL; +PFNGLMULTMATRIXDPROC __glewMultMatrixd = NULL; +PFNGLMULTMATRIXFPROC __glewMultMatrixf = NULL; +PFNGLNEWLISTPROC __glewNewList = NULL; +PFNGLNORMAL3BPROC __glewNormal3b = NULL; +PFNGLNORMAL3BVPROC __glewNormal3bv = NULL; +PFNGLNORMAL3DPROC __glewNormal3d = NULL; +PFNGLNORMAL3DVPROC __glewNormal3dv = NULL; +PFNGLNORMAL3FPROC __glewNormal3f = NULL; +PFNGLNORMAL3FVPROC __glewNormal3fv = NULL; +PFNGLNORMAL3IPROC __glewNormal3i = NULL; +PFNGLNORMAL3IVPROC __glewNormal3iv = NULL; +PFNGLNORMAL3SPROC __glewNormal3s = NULL; +PFNGLNORMAL3SVPROC __glewNormal3sv = NULL; +PFNGLNORMALPOINTERPROC __glewNormalPointer = NULL; +PFNGLORTHOPROC __glewOrtho = NULL; +PFNGLPASSTHROUGHPROC __glewPassThrough = NULL; +PFNGLPIXELMAPFVPROC __glewPixelMapfv = NULL; +PFNGLPIXELMAPUIVPROC __glewPixelMapuiv = NULL; +PFNGLPIXELMAPUSVPROC __glewPixelMapusv = NULL; +PFNGLPIXELSTOREFPROC __glewPixelStoref = NULL; +PFNGLPIXELSTOREIPROC __glewPixelStorei = NULL; +PFNGLPIXELTRANSFERFPROC __glewPixelTransferf = NULL; +PFNGLPIXELTRANSFERIPROC __glewPixelTransferi = NULL; +PFNGLPIXELZOOMPROC __glewPixelZoom = NULL; +PFNGLPOINTSIZEPROC __glewPointSize = NULL; +PFNGLPOLYGONMODEPROC __glewPolygonMode = NULL; +PFNGLPOLYGONOFFSETPROC __glewPolygonOffset = NULL; +PFNGLPOLYGONSTIPPLEPROC __glewPolygonStipple = NULL; +PFNGLPOPATTRIBPROC __glewPopAttrib = NULL; +PFNGLPOPCLIENTATTRIBPROC __glewPopClientAttrib = NULL; +PFNGLPOPMATRIXPROC __glewPopMatrix = NULL; +PFNGLPOPNAMEPROC __glewPopName = NULL; +PFNGLPRIORITIZETEXTURESPROC __glewPrioritizeTextures = NULL; +PFNGLPUSHATTRIBPROC __glewPushAttrib = NULL; +PFNGLPUSHCLIENTATTRIBPROC __glewPushClientAttrib = NULL; +PFNGLPUSHMATRIXPROC __glewPushMatrix = NULL; +PFNGLPUSHNAMEPROC __glewPushName = NULL; +PFNGLRASTERPOS2DPROC __glewRasterPos2d = NULL; +PFNGLRASTERPOS2DVPROC __glewRasterPos2dv = NULL; +PFNGLRASTERPOS2FPROC __glewRasterPos2f = NULL; +PFNGLRASTERPOS2FVPROC __glewRasterPos2fv = NULL; +PFNGLRASTERPOS2IPROC __glewRasterPos2i = NULL; +PFNGLRASTERPOS2IVPROC __glewRasterPos2iv = NULL; +PFNGLRASTERPOS2SPROC __glewRasterPos2s = NULL; +PFNGLRASTERPOS2SVPROC __glewRasterPos2sv = NULL; +PFNGLRASTERPOS3DPROC __glewRasterPos3d = NULL; +PFNGLRASTERPOS3DVPROC __glewRasterPos3dv = NULL; +PFNGLRASTERPOS3FPROC __glewRasterPos3f = NULL; +PFNGLRASTERPOS3FVPROC __glewRasterPos3fv = NULL; +PFNGLRASTERPOS3IPROC __glewRasterPos3i = NULL; +PFNGLRASTERPOS3IVPROC __glewRasterPos3iv = NULL; +PFNGLRASTERPOS3SPROC __glewRasterPos3s = NULL; +PFNGLRASTERPOS3SVPROC __glewRasterPos3sv = NULL; +PFNGLRASTERPOS4DPROC __glewRasterPos4d = NULL; +PFNGLRASTERPOS4DVPROC __glewRasterPos4dv = NULL; +PFNGLRASTERPOS4FPROC __glewRasterPos4f = NULL; +PFNGLRASTERPOS4FVPROC __glewRasterPos4fv = NULL; +PFNGLRASTERPOS4IPROC __glewRasterPos4i = NULL; +PFNGLRASTERPOS4IVPROC __glewRasterPos4iv = NULL; +PFNGLRASTERPOS4SPROC __glewRasterPos4s = NULL; +PFNGLRASTERPOS4SVPROC __glewRasterPos4sv = NULL; +PFNGLREADBUFFERPROC __glewReadBuffer = NULL; +PFNGLREADPIXELSPROC __glewReadPixels = NULL; +PFNGLRECTDPROC __glewRectd = NULL; +PFNGLRECTDVPROC __glewRectdv = NULL; +PFNGLRECTFPROC __glewRectf = NULL; +PFNGLRECTFVPROC __glewRectfv = NULL; +PFNGLRECTIPROC __glewRecti = NULL; +PFNGLRECTIVPROC __glewRectiv = NULL; +PFNGLRECTSPROC __glewRects = NULL; +PFNGLRECTSVPROC __glewRectsv = NULL; +PFNGLRENDERMODEPROC __glewRenderMode = NULL; +PFNGLROTATEDPROC __glewRotated = NULL; +PFNGLROTATEFPROC __glewRotatef = NULL; +PFNGLSCALEDPROC __glewScaled = NULL; +PFNGLSCALEFPROC __glewScalef = NULL; +PFNGLSCISSORPROC __glewScissor = NULL; +PFNGLSELECTBUFFERPROC __glewSelectBuffer = NULL; +PFNGLSHADEMODELPROC __glewShadeModel = NULL; +PFNGLSTENCILFUNCPROC __glewStencilFunc = NULL; +PFNGLSTENCILMASKPROC __glewStencilMask = NULL; +PFNGLSTENCILOPPROC __glewStencilOp = NULL; +PFNGLTEXCOORD1DPROC __glewTexCoord1d = NULL; +PFNGLTEXCOORD1DVPROC __glewTexCoord1dv = NULL; +PFNGLTEXCOORD1FPROC __glewTexCoord1f = NULL; +PFNGLTEXCOORD1FVPROC __glewTexCoord1fv = NULL; +PFNGLTEXCOORD1IPROC __glewTexCoord1i = NULL; +PFNGLTEXCOORD1IVPROC __glewTexCoord1iv = NULL; +PFNGLTEXCOORD1SPROC __glewTexCoord1s = NULL; +PFNGLTEXCOORD1SVPROC __glewTexCoord1sv = NULL; +PFNGLTEXCOORD2DPROC __glewTexCoord2d = NULL; +PFNGLTEXCOORD2DVPROC __glewTexCoord2dv = NULL; +PFNGLTEXCOORD2FPROC __glewTexCoord2f = NULL; +PFNGLTEXCOORD2FVPROC __glewTexCoord2fv = NULL; +PFNGLTEXCOORD2IPROC __glewTexCoord2i = NULL; +PFNGLTEXCOORD2IVPROC __glewTexCoord2iv = NULL; +PFNGLTEXCOORD2SPROC __glewTexCoord2s = NULL; +PFNGLTEXCOORD2SVPROC __glewTexCoord2sv = NULL; +PFNGLTEXCOORD3DPROC __glewTexCoord3d = NULL; +PFNGLTEXCOORD3DVPROC __glewTexCoord3dv = NULL; +PFNGLTEXCOORD3FPROC __glewTexCoord3f = NULL; +PFNGLTEXCOORD3FVPROC __glewTexCoord3fv = NULL; +PFNGLTEXCOORD3IPROC __glewTexCoord3i = NULL; +PFNGLTEXCOORD3IVPROC __glewTexCoord3iv = NULL; +PFNGLTEXCOORD3SPROC __glewTexCoord3s = NULL; +PFNGLTEXCOORD3SVPROC __glewTexCoord3sv = NULL; +PFNGLTEXCOORD4DPROC __glewTexCoord4d = NULL; +PFNGLTEXCOORD4DVPROC __glewTexCoord4dv = NULL; +PFNGLTEXCOORD4FPROC __glewTexCoord4f = NULL; +PFNGLTEXCOORD4FVPROC __glewTexCoord4fv = NULL; +PFNGLTEXCOORD4IPROC __glewTexCoord4i = NULL; +PFNGLTEXCOORD4IVPROC __glewTexCoord4iv = NULL; +PFNGLTEXCOORD4SPROC __glewTexCoord4s = NULL; +PFNGLTEXCOORD4SVPROC __glewTexCoord4sv = NULL; +PFNGLTEXCOORDPOINTERPROC __glewTexCoordPointer = NULL; +PFNGLTEXENVFPROC __glewTexEnvf = NULL; +PFNGLTEXENVFVPROC __glewTexEnvfv = NULL; +PFNGLTEXENVIPROC __glewTexEnvi = NULL; +PFNGLTEXENVIVPROC __glewTexEnviv = NULL; +PFNGLTEXGENDPROC __glewTexGend = NULL; +PFNGLTEXGENDVPROC __glewTexGendv = NULL; +PFNGLTEXGENFPROC __glewTexGenf = NULL; +PFNGLTEXGENFVPROC __glewTexGenfv = NULL; +PFNGLTEXGENIPROC __glewTexGeni = NULL; +PFNGLTEXGENIVPROC __glewTexGeniv = NULL; +PFNGLTEXIMAGE1DPROC __glewTexImage1D = NULL; +PFNGLTEXIMAGE2DPROC __glewTexImage2D = NULL; +PFNGLTEXPARAMETERFPROC __glewTexParameterf = NULL; +PFNGLTEXPARAMETERFVPROC __glewTexParameterfv = NULL; +PFNGLTEXPARAMETERIPROC __glewTexParameteri = NULL; +PFNGLTEXPARAMETERIVPROC __glewTexParameteriv = NULL; +PFNGLTEXSUBIMAGE1DPROC __glewTexSubImage1D = NULL; +PFNGLTEXSUBIMAGE2DPROC __glewTexSubImage2D = NULL; +PFNGLTRANSLATEDPROC __glewTranslated = NULL; +PFNGLTRANSLATEFPROC __glewTranslatef = NULL; +PFNGLVERTEX2DPROC __glewVertex2d = NULL; +PFNGLVERTEX2DVPROC __glewVertex2dv = NULL; +PFNGLVERTEX2FPROC __glewVertex2f = NULL; +PFNGLVERTEX2FVPROC __glewVertex2fv = NULL; +PFNGLVERTEX2IPROC __glewVertex2i = NULL; +PFNGLVERTEX2IVPROC __glewVertex2iv = NULL; +PFNGLVERTEX2SPROC __glewVertex2s = NULL; +PFNGLVERTEX2SVPROC __glewVertex2sv = NULL; +PFNGLVERTEX3DPROC __glewVertex3d = NULL; +PFNGLVERTEX3DVPROC __glewVertex3dv = NULL; +PFNGLVERTEX3FPROC __glewVertex3f = NULL; +PFNGLVERTEX3FVPROC __glewVertex3fv = NULL; +PFNGLVERTEX3IPROC __glewVertex3i = NULL; +PFNGLVERTEX3IVPROC __glewVertex3iv = NULL; +PFNGLVERTEX3SPROC __glewVertex3s = NULL; +PFNGLVERTEX3SVPROC __glewVertex3sv = NULL; +PFNGLVERTEX4DPROC __glewVertex4d = NULL; +PFNGLVERTEX4DVPROC __glewVertex4dv = NULL; +PFNGLVERTEX4FPROC __glewVertex4f = NULL; +PFNGLVERTEX4FVPROC __glewVertex4fv = NULL; +PFNGLVERTEX4IPROC __glewVertex4i = NULL; +PFNGLVERTEX4IVPROC __glewVertex4iv = NULL; +PFNGLVERTEX4SPROC __glewVertex4s = NULL; +PFNGLVERTEX4SVPROC __glewVertex4sv = NULL; +PFNGLVERTEXPOINTERPROC __glewVertexPointer = NULL; +PFNGLVIEWPORTPROC __glewViewport = NULL; + +#define fqn_from_convention(convention, fqn) \ + (const GLubyte*)fqn + +GLboolean GLEWAPIENTRY glewOpenGL11Init(void) +{ + GLboolean r = GL_FALSE; + + r = ((glAccum = (PFNGLACCUMPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glAccum"))) == NULL) || r; + r = ((glAlphaFunc = (PFNGLALPHAFUNCPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glAlphaFunc"))) == NULL) || r; + r = ((glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glAreTexturesResident"))) == NULL) || r; + r = ((glArrayElement = (PFNGLARRAYELEMENTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glArrayElement"))) == NULL) || r; + r = ((glBegin = (PFNGLBEGINPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glBegin"))) == NULL) || r; + r = ((glBindTexture = (PFNGLBINDTEXTUREPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glBindTexture"))) == NULL) || r; + r = ((glBitmap = (PFNGLBITMAPPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glBitmap"))) == NULL) || r; + r = ((glBlendFunc = (PFNGLBLENDFUNCPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glBlendFunc"))) == NULL) || r; + r = ((glCallList = (PFNGLCALLLISTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glCallList"))) == NULL) || r; + r = ((glCallLists = (PFNGLCALLLISTSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glCallLists"))) == NULL) || r; + r = ((glClear = (PFNGLCLEARPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glClear"))) == NULL) || r; + r = ((glClearAccum = (PFNGLCLEARACCUMPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glClearAccum"))) == NULL) || r; + r = ((glClearColor = (PFNGLCLEARCOLORPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glClearColor"))) == NULL) || r; + r = ((glClearDepth = (PFNGLCLEARDEPTHPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glClearDepth"))) == NULL) || r; + r = ((glClearIndex = (PFNGLCLEARINDEXPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glClearIndex"))) == NULL) || r; + r = ((glClearStencil = (PFNGLCLEARSTENCILPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glClearStencil"))) == NULL) || r; + r = ((glClipPlane = (PFNGLCLIPPLANEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glClipPlane"))) == NULL) || r; + r = ((glColor3b = (PFNGLCOLOR3BPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3b"))) == NULL) || r; + r = ((glColor3bv = (PFNGLCOLOR3BVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3bv"))) == NULL) || r; + r = ((glColor3d = (PFNGLCOLOR3DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3d"))) == NULL) || r; + r = ((glColor3dv = (PFNGLCOLOR3DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3dv"))) == NULL) || r; + r = ((glColor3f = (PFNGLCOLOR3FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3f"))) == NULL) || r; + r = ((glColor3fv = (PFNGLCOLOR3FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3fv"))) == NULL) || r; + r = ((glColor3i = (PFNGLCOLOR3IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3i"))) == NULL) || r; + r = ((glColor3iv = (PFNGLCOLOR3IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3iv"))) == NULL) || r; + r = ((glColor3s = (PFNGLCOLOR3SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3s"))) == NULL) || r; + r = ((glColor3sv = (PFNGLCOLOR3SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3sv"))) == NULL) || r; + r = ((glColor3ub = (PFNGLCOLOR3UBPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3ub"))) == NULL) || r; + r = ((glColor3ubv = (PFNGLCOLOR3UBVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3ubv"))) == NULL) || r; + r = ((glColor3ui = (PFNGLCOLOR3UIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3ui"))) == NULL) || r; + r = ((glColor3uiv = (PFNGLCOLOR3UIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3uiv"))) == NULL) || r; + r = ((glColor3us = (PFNGLCOLOR3USPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3us"))) == NULL) || r; + r = ((glColor3usv = (PFNGLCOLOR3USVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor3usv"))) == NULL) || r; + r = ((glColor4b = (PFNGLCOLOR4BPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4b"))) == NULL) || r; + r = ((glColor4bv = (PFNGLCOLOR4BVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4bv"))) == NULL) || r; + r = ((glColor4d = (PFNGLCOLOR4DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4d"))) == NULL) || r; + r = ((glColor4dv = (PFNGLCOLOR4DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4dv"))) == NULL) || r; + r = ((glColor4f = (PFNGLCOLOR4FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4f"))) == NULL) || r; + r = ((glColor4fv = (PFNGLCOLOR4FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4fv"))) == NULL) || r; + r = ((glColor4i = (PFNGLCOLOR4IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4i"))) == NULL) || r; + r = ((glColor4iv = (PFNGLCOLOR4IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4iv"))) == NULL) || r; + r = ((glColor4s = (PFNGLCOLOR4SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4s"))) == NULL) || r; + r = ((glColor4sv = (PFNGLCOLOR4SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4sv"))) == NULL) || r; + r = ((glColor4ub = (PFNGLCOLOR4UBPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4ub"))) == NULL) || r; + r = ((glColor4ubv = (PFNGLCOLOR4UBVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4ubv"))) == NULL) || r; + r = ((glColor4ui = (PFNGLCOLOR4UIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4ui"))) == NULL) || r; + r = ((glColor4uiv = (PFNGLCOLOR4UIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4uiv"))) == NULL) || r; + r = ((glColor4us = (PFNGLCOLOR4USPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4us"))) == NULL) || r; + r = ((glColor4usv = (PFNGLCOLOR4USVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColor4usv"))) == NULL) || r; + r = ((glColorMask = (PFNGLCOLORMASKPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColorMask"))) == NULL) || r; + r = ((glColorMaterial = (PFNGLCOLORMATERIALPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColorMaterial"))) == NULL) || r; + r = ((glColorPointer = (PFNGLCOLORPOINTERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glColorPointer"))) == NULL) || r; + r = ((glCopyPixels = (PFNGLCOPYPIXELSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glCopyPixels"))) == NULL) || r; + r = ((glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glCopyTexImage1D"))) == NULL) || r; + r = ((glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glCopyTexImage2D"))) == NULL) || r; + r = ((glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glCopyTexSubImage1D"))) == NULL) || r; + r = ((glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glCopyTexSubImage2D"))) == NULL) || r; + r = ((glCullFace = (PFNGLCULLFACEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glCullFace"))) == NULL) || r; + r = ((glDeleteLists = (PFNGLDELETELISTSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDeleteLists"))) == NULL) || r; + r = ((glDeleteTextures = (PFNGLDELETETEXTURESPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDeleteTextures"))) == NULL) || r; + r = ((glDepthFunc = (PFNGLDEPTHFUNCPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDepthFunc"))) == NULL) || r; + r = ((glDepthMask = (PFNGLDEPTHMASKPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDepthMask"))) == NULL) || r; + r = ((glDepthRange = (PFNGLDEPTHRANGEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDepthRange"))) == NULL) || r; + r = ((glDisable = (PFNGLDISABLEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDisable"))) == NULL) || r; + r = ((glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDisableClientState"))) == NULL) || r; + r = ((glDrawArrays = (PFNGLDRAWARRAYSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDrawArrays"))) == NULL) || r; + r = ((glDrawBuffer = (PFNGLDRAWBUFFERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDrawBuffer"))) == NULL) || r; + r = ((glDrawElements = (PFNGLDRAWELEMENTSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDrawElements"))) == NULL) || r; + r = ((glDrawPixels = (PFNGLDRAWPIXELSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glDrawPixels"))) == NULL) || r; + r = ((glEdgeFlag = (PFNGLEDGEFLAGPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEdgeFlag"))) == NULL) || r; + r = ((glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEdgeFlagPointer"))) == NULL) || r; + r = ((glEdgeFlagv = (PFNGLEDGEFLAGVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEdgeFlagv"))) == NULL) || r; + r = ((glEnable = (PFNGLENABLEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEnable"))) == NULL) || r; + r = ((glEnableClientState = (PFNGLENABLECLIENTSTATEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEnableClientState"))) == NULL) || r; + r = ((glEnd = (PFNGLENDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEnd"))) == NULL) || r; + r = ((glEndList = (PFNGLENDLISTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEndList"))) == NULL) || r; + r = ((glEvalCoord1d = (PFNGLEVALCOORD1DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalCoord1d"))) == NULL) || r; + r = ((glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalCoord1dv"))) == NULL) || r; + r = ((glEvalCoord1f = (PFNGLEVALCOORD1FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalCoord1f"))) == NULL) || r; + r = ((glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalCoord1fv"))) == NULL) || r; + r = ((glEvalCoord2d = (PFNGLEVALCOORD2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalCoord2d"))) == NULL) || r; + r = ((glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalCoord2dv"))) == NULL) || r; + r = ((glEvalCoord2f = (PFNGLEVALCOORD2FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalCoord2f"))) == NULL) || r; + r = ((glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalCoord2fv"))) == NULL) || r; + r = ((glEvalMesh1 = (PFNGLEVALMESH1PROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalMesh1"))) == NULL) || r; + r = ((glEvalMesh2 = (PFNGLEVALMESH2PROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalMesh2"))) == NULL) || r; + r = ((glEvalPoint1 = (PFNGLEVALPOINT1PROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalPoint1"))) == NULL) || r; + r = ((glEvalPoint2 = (PFNGLEVALPOINT2PROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glEvalPoint2"))) == NULL) || r; + r = ((glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFeedbackBuffer"))) == NULL) || r; + r = ((glFinish = (PFNGLFINISHPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFinish"))) == NULL) || r; + r = ((glFlush = (PFNGLFLUSHPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFlush"))) == NULL) || r; + r = ((glFogf = (PFNGLFOGFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFogf"))) == NULL) || r; + r = ((glFogfv = (PFNGLFOGFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFogfv"))) == NULL) || r; + r = ((glFogi = (PFNGLFOGIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFogi"))) == NULL) || r; + r = ((glFogiv = (PFNGLFOGIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFogiv"))) == NULL) || r; + r = ((glFrontFace = (PFNGLFRONTFACEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFrontFace"))) == NULL) || r; + r = ((glFrustum = (PFNGLFRUSTUMPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glFrustum"))) == NULL) || r; + r = ((glGenLists = (PFNGLGENLISTSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGenLists"))) == NULL) || r; + r = ((glGenTextures = (PFNGLGENTEXTURESPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGenTextures"))) == NULL) || r; + r = ((glGetBooleanv = (PFNGLGETBOOLEANVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetBooleanv"))) == NULL) || r; + r = ((glGetClipPlane = (PFNGLGETCLIPPLANEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetClipPlane"))) == NULL) || r; + r = ((glGetDoublev = (PFNGLGETDOUBLEVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetDoublev"))) == NULL) || r; + r = ((glGetError = (PFNGLGETERRORPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetError"))) == NULL) || r; + r = ((glGetFloatv = (PFNGLGETFLOATVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetFloatv"))) == NULL) || r; + r = ((glGetIntegerv = (PFNGLGETINTEGERVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetIntegerv"))) == NULL) || r; + r = ((glGetLightfv = (PFNGLGETLIGHTFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetLightfv"))) == NULL) || r; + r = ((glGetLightiv = (PFNGLGETLIGHTIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetLightiv"))) == NULL) || r; + r = ((glGetMapdv = (PFNGLGETMAPDVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetMapdv"))) == NULL) || r; + r = ((glGetMapfv = (PFNGLGETMAPFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetMapfv"))) == NULL) || r; + r = ((glGetMapiv = (PFNGLGETMAPIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetMapiv"))) == NULL) || r; + r = ((glGetMaterialfv = (PFNGLGETMATERIALFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetMaterialfv"))) == NULL) || r; + r = ((glGetMaterialiv = (PFNGLGETMATERIALIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetMaterialiv"))) == NULL) || r; + r = ((glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetPixelMapfv"))) == NULL) || r; + r = ((glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetPixelMapuiv"))) == NULL) || r; + r = ((glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetPixelMapusv"))) == NULL) || r; + r = ((glGetPointerv = (PFNGLGETPOINTERVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetPointerv"))) == NULL) || r; + r = ((glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetPolygonStipple"))) == NULL) || r; + r = ((glGetString = (PFNGLGETSTRINGPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetString"))) == NULL) || r; + r = ((glGetTexEnvfv = (PFNGLGETTEXENVFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexEnvfv"))) == NULL) || r; + r = ((glGetTexEnviv = (PFNGLGETTEXENVIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexEnviv"))) == NULL) || r; + r = ((glGetTexGendv = (PFNGLGETTEXGENDVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexGendv"))) == NULL) || r; + r = ((glGetTexGenfv = (PFNGLGETTEXGENFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexGenfv"))) == NULL) || r; + r = ((glGetTexGeniv = (PFNGLGETTEXGENIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexGeniv"))) == NULL) || r; + r = ((glGetTexImage = (PFNGLGETTEXIMAGEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexImage"))) == NULL) || r; + r = ((glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexLevelParameterfv"))) == NULL) || r; + r = ((glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexLevelParameteriv"))) == NULL) || r; + r = ((glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexParameterfv"))) == NULL) || r; + r = ((glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glGetTexParameteriv"))) == NULL) || r; + r = ((glHint = (PFNGLHINTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glHint"))) == NULL) || r; + r = ((glIndexMask = (PFNGLINDEXMASKPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexMask"))) == NULL) || r; + r = ((glIndexPointer = (PFNGLINDEXPOINTERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexPointer"))) == NULL) || r; + r = ((glIndexd = (PFNGLINDEXDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexd"))) == NULL) || r; + r = ((glIndexdv = (PFNGLINDEXDVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexdv"))) == NULL) || r; + r = ((glIndexf = (PFNGLINDEXFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexf"))) == NULL) || r; + r = ((glIndexfv = (PFNGLINDEXFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexfv"))) == NULL) || r; + r = ((glIndexi = (PFNGLINDEXIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexi"))) == NULL) || r; + r = ((glIndexiv = (PFNGLINDEXIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexiv"))) == NULL) || r; + r = ((glIndexs = (PFNGLINDEXSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexs"))) == NULL) || r; + r = ((glIndexsv = (PFNGLINDEXSVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexsv"))) == NULL) || r; + r = ((glIndexub = (PFNGLINDEXUBPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexub"))) == NULL) || r; + r = ((glIndexubv = (PFNGLINDEXUBVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIndexubv"))) == NULL) || r; + r = ((glInitNames = (PFNGLINITNAMESPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glInitNames"))) == NULL) || r; + r = ((glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glInterleavedArrays"))) == NULL) || r; + r = ((glIsEnabled = (PFNGLISENABLEDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIsEnabled"))) == NULL) || r; + r = ((glIsList = (PFNGLISLISTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIsList"))) == NULL) || r; + r = ((glIsTexture = (PFNGLISTEXTUREPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glIsTexture"))) == NULL) || r; + r = ((glLightModelf = (PFNGLLIGHTMODELFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLightModelf"))) == NULL) || r; + r = ((glLightModelfv = (PFNGLLIGHTMODELFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLightModelfv"))) == NULL) || r; + r = ((glLightModeli = (PFNGLLIGHTMODELIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLightModeli"))) == NULL) || r; + r = ((glLightModeliv = (PFNGLLIGHTMODELIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLightModeliv"))) == NULL) || r; + r = ((glLightf = (PFNGLLIGHTFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLightf"))) == NULL) || r; + r = ((glLightfv = (PFNGLLIGHTFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLightfv"))) == NULL) || r; + r = ((glLighti = (PFNGLLIGHTIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLighti"))) == NULL) || r; + r = ((glLightiv = (PFNGLLIGHTIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLightiv"))) == NULL) || r; + r = ((glLineStipple = (PFNGLLINESTIPPLEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLineStipple"))) == NULL) || r; + r = ((glLineWidth = (PFNGLLINEWIDTHPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLineWidth"))) == NULL) || r; + r = ((glListBase = (PFNGLLISTBASEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glListBase"))) == NULL) || r; + r = ((glLoadIdentity = (PFNGLLOADIDENTITYPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLoadIdentity"))) == NULL) || r; + r = ((glLoadMatrixd = (PFNGLLOADMATRIXDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLoadMatrixd"))) == NULL) || r; + r = ((glLoadMatrixf = (PFNGLLOADMATRIXFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLoadMatrixf"))) == NULL) || r; + r = ((glLoadName = (PFNGLLOADNAMEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLoadName"))) == NULL) || r; + r = ((glLogicOp = (PFNGLLOGICOPPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glLogicOp"))) == NULL) || r; + r = ((glMap1d = (PFNGLMAP1DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMap1d"))) == NULL) || r; + r = ((glMap1f = (PFNGLMAP1FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMap1f"))) == NULL) || r; + r = ((glMap2d = (PFNGLMAP2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMap2d"))) == NULL) || r; + r = ((glMap2f = (PFNGLMAP2FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMap2f"))) == NULL) || r; + r = ((glMapGrid1d = (PFNGLMAPGRID1DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMapGrid1d"))) == NULL) || r; + r = ((glMapGrid1f = (PFNGLMAPGRID1FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMapGrid1f"))) == NULL) || r; + r = ((glMapGrid2d = (PFNGLMAPGRID2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMapGrid2d"))) == NULL) || r; + r = ((glMapGrid2f = (PFNGLMAPGRID2FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMapGrid2f"))) == NULL) || r; + r = ((glMaterialf = (PFNGLMATERIALFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMaterialf"))) == NULL) || r; + r = ((glMaterialfv = (PFNGLMATERIALFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMaterialfv"))) == NULL) || r; + r = ((glMateriali = (PFNGLMATERIALIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMateriali"))) == NULL) || r; + r = ((glMaterialiv = (PFNGLMATERIALIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMaterialiv"))) == NULL) || r; + r = ((glMatrixMode = (PFNGLMATRIXMODEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMatrixMode"))) == NULL) || r; + r = ((glMultMatrixd = (PFNGLMULTMATRIXDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMultMatrixd"))) == NULL) || r; + r = ((glMultMatrixf = (PFNGLMULTMATRIXFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glMultMatrixf"))) == NULL) || r; + r = ((glNewList = (PFNGLNEWLISTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNewList"))) == NULL) || r; + r = ((glNormal3b = (PFNGLNORMAL3BPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3b"))) == NULL) || r; + r = ((glNormal3bv = (PFNGLNORMAL3BVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3bv"))) == NULL) || r; + r = ((glNormal3d = (PFNGLNORMAL3DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3d"))) == NULL) || r; + r = ((glNormal3dv = (PFNGLNORMAL3DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3dv"))) == NULL) || r; + r = ((glNormal3f = (PFNGLNORMAL3FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3f"))) == NULL) || r; + r = ((glNormal3fv = (PFNGLNORMAL3FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3fv"))) == NULL) || r; + r = ((glNormal3i = (PFNGLNORMAL3IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3i"))) == NULL) || r; + r = ((glNormal3iv = (PFNGLNORMAL3IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3iv"))) == NULL) || r; + r = ((glNormal3s = (PFNGLNORMAL3SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3s"))) == NULL) || r; + r = ((glNormal3sv = (PFNGLNORMAL3SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormal3sv"))) == NULL) || r; + r = ((glNormalPointer = (PFNGLNORMALPOINTERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glNormalPointer"))) == NULL) || r; + r = ((glOrtho = (PFNGLORTHOPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glOrtho"))) == NULL) || r; + r = ((glPassThrough = (PFNGLPASSTHROUGHPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPassThrough"))) == NULL) || r; + r = ((glPixelMapfv = (PFNGLPIXELMAPFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPixelMapfv"))) == NULL) || r; + r = ((glPixelMapuiv = (PFNGLPIXELMAPUIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPixelMapuiv"))) == NULL) || r; + r = ((glPixelMapusv = (PFNGLPIXELMAPUSVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPixelMapusv"))) == NULL) || r; + r = ((glPixelStoref = (PFNGLPIXELSTOREFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPixelStoref"))) == NULL) || r; + r = ((glPixelStorei = (PFNGLPIXELSTOREIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPixelStorei"))) == NULL) || r; + r = ((glPixelTransferf = (PFNGLPIXELTRANSFERFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPixelTransferf"))) == NULL) || r; + r = ((glPixelTransferi = (PFNGLPIXELTRANSFERIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPixelTransferi"))) == NULL) || r; + r = ((glPixelZoom = (PFNGLPIXELZOOMPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPixelZoom"))) == NULL) || r; + r = ((glPointSize = (PFNGLPOINTSIZEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPointSize"))) == NULL) || r; + r = ((glPolygonMode = (PFNGLPOLYGONMODEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPolygonMode"))) == NULL) || r; + r = ((glPolygonOffset = (PFNGLPOLYGONOFFSETPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPolygonOffset"))) == NULL) || r; + r = ((glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPolygonStipple"))) == NULL) || r; + r = ((glPopAttrib = (PFNGLPOPATTRIBPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPopAttrib"))) == NULL) || r; + r = ((glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPopClientAttrib"))) == NULL) || r; + r = ((glPopMatrix = (PFNGLPOPMATRIXPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPopMatrix"))) == NULL) || r; + r = ((glPopName = (PFNGLPOPNAMEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPopName"))) == NULL) || r; + r = ((glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPrioritizeTextures"))) == NULL) || r; + r = ((glPushAttrib = (PFNGLPUSHATTRIBPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPushAttrib"))) == NULL) || r; + r = ((glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPushClientAttrib"))) == NULL) || r; + r = ((glPushMatrix = (PFNGLPUSHMATRIXPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPushMatrix"))) == NULL) || r; + r = ((glPushName = (PFNGLPUSHNAMEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glPushName"))) == NULL) || r; + r = ((glRasterPos2d = (PFNGLRASTERPOS2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos2d"))) == NULL) || r; + r = ((glRasterPos2dv = (PFNGLRASTERPOS2DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos2dv"))) == NULL) || r; + r = ((glRasterPos2f = (PFNGLRASTERPOS2FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos2f"))) == NULL) || r; + r = ((glRasterPos2fv = (PFNGLRASTERPOS2FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos2fv"))) == NULL) || r; + r = ((glRasterPos2i = (PFNGLRASTERPOS2IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos2i"))) == NULL) || r; + r = ((glRasterPos2iv = (PFNGLRASTERPOS2IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos2iv"))) == NULL) || r; + r = ((glRasterPos2s = (PFNGLRASTERPOS2SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos2s"))) == NULL) || r; + r = ((glRasterPos2sv = (PFNGLRASTERPOS2SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos2sv"))) == NULL) || r; + r = ((glRasterPos3d = (PFNGLRASTERPOS3DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos3d"))) == NULL) || r; + r = ((glRasterPos3dv = (PFNGLRASTERPOS3DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos3dv"))) == NULL) || r; + r = ((glRasterPos3f = (PFNGLRASTERPOS3FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos3f"))) == NULL) || r; + r = ((glRasterPos3fv = (PFNGLRASTERPOS3FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos3fv"))) == NULL) || r; + r = ((glRasterPos3i = (PFNGLRASTERPOS3IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos3i"))) == NULL) || r; + r = ((glRasterPos3iv = (PFNGLRASTERPOS3IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos3iv"))) == NULL) || r; + r = ((glRasterPos3s = (PFNGLRASTERPOS3SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos3s"))) == NULL) || r; + r = ((glRasterPos3sv = (PFNGLRASTERPOS3SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos3sv"))) == NULL) || r; + r = ((glRasterPos4d = (PFNGLRASTERPOS4DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos4d"))) == NULL) || r; + r = ((glRasterPos4dv = (PFNGLRASTERPOS4DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos4dv"))) == NULL) || r; + r = ((glRasterPos4f = (PFNGLRASTERPOS4FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos4f"))) == NULL) || r; + r = ((glRasterPos4fv = (PFNGLRASTERPOS4FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos4fv"))) == NULL) || r; + r = ((glRasterPos4i = (PFNGLRASTERPOS4IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos4i"))) == NULL) || r; + r = ((glRasterPos4iv = (PFNGLRASTERPOS4IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos4iv"))) == NULL) || r; + r = ((glRasterPos4s = (PFNGLRASTERPOS4SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos4s"))) == NULL) || r; + r = ((glRasterPos4sv = (PFNGLRASTERPOS4SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRasterPos4sv"))) == NULL) || r; + r = ((glReadBuffer = (PFNGLREADBUFFERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glReadBuffer"))) == NULL) || r; + r = ((glReadPixels = (PFNGLREADPIXELSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glReadPixels"))) == NULL) || r; + r = ((glRectd = (PFNGLRECTDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRectd"))) == NULL) || r; + r = ((glRectdv = (PFNGLRECTDVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRectdv"))) == NULL) || r; + r = ((glRectf = (PFNGLRECTFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRectf"))) == NULL) || r; + r = ((glRectfv = (PFNGLRECTFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRectfv"))) == NULL) || r; + r = ((glRecti = (PFNGLRECTIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRecti"))) == NULL) || r; + r = ((glRectiv = (PFNGLRECTIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRectiv"))) == NULL) || r; + r = ((glRects = (PFNGLRECTSPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRects"))) == NULL) || r; + r = ((glRectsv = (PFNGLRECTSVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRectsv"))) == NULL) || r; + r = ((glRenderMode = (PFNGLRENDERMODEPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRenderMode"))) == NULL) || r; + r = ((glRotated = (PFNGLROTATEDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRotated"))) == NULL) || r; + r = ((glRotatef = (PFNGLROTATEFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glRotatef"))) == NULL) || r; + r = ((glScaled = (PFNGLSCALEDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glScaled"))) == NULL) || r; + r = ((glScalef = (PFNGLSCALEFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glScalef"))) == NULL) || r; + r = ((glScissor = (PFNGLSCISSORPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glScissor"))) == NULL) || r; + r = ((glSelectBuffer = (PFNGLSELECTBUFFERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glSelectBuffer"))) == NULL) || r; + r = ((glShadeModel = (PFNGLSHADEMODELPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glShadeModel"))) == NULL) || r; + r = ((glStencilFunc = (PFNGLSTENCILFUNCPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glStencilFunc"))) == NULL) || r; + r = ((glStencilMask = (PFNGLSTENCILMASKPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glStencilMask"))) == NULL) || r; + r = ((glStencilOp = (PFNGLSTENCILOPPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glStencilOp"))) == NULL) || r; + r = ((glTexCoord1d = (PFNGLTEXCOORD1DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord1d"))) == NULL) || r; + r = ((glTexCoord1dv = (PFNGLTEXCOORD1DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord1dv"))) == NULL) || r; + r = ((glTexCoord1f = (PFNGLTEXCOORD1FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord1f"))) == NULL) || r; + r = ((glTexCoord1fv = (PFNGLTEXCOORD1FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord1fv"))) == NULL) || r; + r = ((glTexCoord1i = (PFNGLTEXCOORD1IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord1i"))) == NULL) || r; + r = ((glTexCoord1iv = (PFNGLTEXCOORD1IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord1iv"))) == NULL) || r; + r = ((glTexCoord1s = (PFNGLTEXCOORD1SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord1s"))) == NULL) || r; + r = ((glTexCoord1sv = (PFNGLTEXCOORD1SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord1sv"))) == NULL) || r; + r = ((glTexCoord2d = (PFNGLTEXCOORD2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord2d"))) == NULL) || r; + r = ((glTexCoord2dv = (PFNGLTEXCOORD2DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord2dv"))) == NULL) || r; + r = ((glTexCoord2f = (PFNGLTEXCOORD2FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord2f"))) == NULL) || r; + r = ((glTexCoord2fv = (PFNGLTEXCOORD2FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord2fv"))) == NULL) || r; + r = ((glTexCoord2i = (PFNGLTEXCOORD2IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord2i"))) == NULL) || r; + r = ((glTexCoord2iv = (PFNGLTEXCOORD2IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord2iv"))) == NULL) || r; + r = ((glTexCoord2s = (PFNGLTEXCOORD2SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord2s"))) == NULL) || r; + r = ((glTexCoord2sv = (PFNGLTEXCOORD2SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord2sv"))) == NULL) || r; + r = ((glTexCoord3d = (PFNGLTEXCOORD3DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord3d"))) == NULL) || r; + r = ((glTexCoord3dv = (PFNGLTEXCOORD3DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord3dv"))) == NULL) || r; + r = ((glTexCoord3f = (PFNGLTEXCOORD3FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord3f"))) == NULL) || r; + r = ((glTexCoord3fv = (PFNGLTEXCOORD3FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord3fv"))) == NULL) || r; + r = ((glTexCoord3i = (PFNGLTEXCOORD3IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord3i"))) == NULL) || r; + r = ((glTexCoord3iv = (PFNGLTEXCOORD3IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord3iv"))) == NULL) || r; + r = ((glTexCoord3s = (PFNGLTEXCOORD3SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord3s"))) == NULL) || r; + r = ((glTexCoord3sv = (PFNGLTEXCOORD3SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord3sv"))) == NULL) || r; + r = ((glTexCoord4d = (PFNGLTEXCOORD4DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord4d"))) == NULL) || r; + r = ((glTexCoord4dv = (PFNGLTEXCOORD4DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord4dv"))) == NULL) || r; + r = ((glTexCoord4f = (PFNGLTEXCOORD4FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord4f"))) == NULL) || r; + r = ((glTexCoord4fv = (PFNGLTEXCOORD4FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord4fv"))) == NULL) || r; + r = ((glTexCoord4i = (PFNGLTEXCOORD4IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord4i"))) == NULL) || r; + r = ((glTexCoord4iv = (PFNGLTEXCOORD4IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord4iv"))) == NULL) || r; + r = ((glTexCoord4s = (PFNGLTEXCOORD4SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord4s"))) == NULL) || r; + r = ((glTexCoord4sv = (PFNGLTEXCOORD4SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoord4sv"))) == NULL) || r; + r = ((glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexCoordPointer"))) == NULL) || r; + r = ((glTexEnvf = (PFNGLTEXENVFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexEnvf"))) == NULL) || r; + r = ((glTexEnvfv = (PFNGLTEXENVFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexEnvfv"))) == NULL) || r; + r = ((glTexEnvi = (PFNGLTEXENVIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexEnvi"))) == NULL) || r; + r = ((glTexEnviv = (PFNGLTEXENVIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexEnviv"))) == NULL) || r; + r = ((glTexGend = (PFNGLTEXGENDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexGend"))) == NULL) || r; + r = ((glTexGendv = (PFNGLTEXGENDVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexGendv"))) == NULL) || r; + r = ((glTexGenf = (PFNGLTEXGENFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexGenf"))) == NULL) || r; + r = ((glTexGenfv = (PFNGLTEXGENFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexGenfv"))) == NULL) || r; + r = ((glTexGeni = (PFNGLTEXGENIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexGeni"))) == NULL) || r; + r = ((glTexGeniv = (PFNGLTEXGENIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexGeniv"))) == NULL) || r; + r = ((glTexImage1D = (PFNGLTEXIMAGE1DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexImage1D"))) == NULL) || r; + r = ((glTexImage2D = (PFNGLTEXIMAGE2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexImage2D"))) == NULL) || r; + r = ((glTexParameterf = (PFNGLTEXPARAMETERFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexParameterf"))) == NULL) || r; + r = ((glTexParameterfv = (PFNGLTEXPARAMETERFVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexParameterfv"))) == NULL) || r; + r = ((glTexParameteri = (PFNGLTEXPARAMETERIPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexParameteri"))) == NULL) || r; + r = ((glTexParameteriv = (PFNGLTEXPARAMETERIVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexParameteriv"))) == NULL) || r; + r = ((glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexSubImage1D"))) == NULL) || r; + r = ((glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTexSubImage2D"))) == NULL) || r; + r = ((glTranslated = (PFNGLTRANSLATEDPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTranslated"))) == NULL) || r; + r = ((glTranslatef = (PFNGLTRANSLATEFPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glTranslatef"))) == NULL) || r; + r = ((glVertex2d = (PFNGLVERTEX2DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex2d"))) == NULL) || r; + r = ((glVertex2dv = (PFNGLVERTEX2DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex2dv"))) == NULL) || r; + r = ((glVertex2f = (PFNGLVERTEX2FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex2f"))) == NULL) || r; + r = ((glVertex2fv = (PFNGLVERTEX2FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex2fv"))) == NULL) || r; + r = ((glVertex2i = (PFNGLVERTEX2IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex2i"))) == NULL) || r; + r = ((glVertex2iv = (PFNGLVERTEX2IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex2iv"))) == NULL) || r; + r = ((glVertex2s = (PFNGLVERTEX2SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex2s"))) == NULL) || r; + r = ((glVertex2sv = (PFNGLVERTEX2SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex2sv"))) == NULL) || r; + r = ((glVertex3d = (PFNGLVERTEX3DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex3d"))) == NULL) || r; + r = ((glVertex3dv = (PFNGLVERTEX3DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex3dv"))) == NULL) || r; + r = ((glVertex3f = (PFNGLVERTEX3FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex3f"))) == NULL) || r; + r = ((glVertex3fv = (PFNGLVERTEX3FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex3fv"))) == NULL) || r; + r = ((glVertex3i = (PFNGLVERTEX3IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex3i"))) == NULL) || r; + r = ((glVertex3iv = (PFNGLVERTEX3IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex3iv"))) == NULL) || r; + r = ((glVertex3s = (PFNGLVERTEX3SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex3s"))) == NULL) || r; + r = ((glVertex3sv = (PFNGLVERTEX3SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex3sv"))) == NULL) || r; + r = ((glVertex4d = (PFNGLVERTEX4DPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex4d"))) == NULL) || r; + r = ((glVertex4dv = (PFNGLVERTEX4DVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex4dv"))) == NULL) || r; + r = ((glVertex4f = (PFNGLVERTEX4FPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex4f"))) == NULL) || r; + r = ((glVertex4fv = (PFNGLVERTEX4FVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex4fv"))) == NULL) || r; + r = ((glVertex4i = (PFNGLVERTEX4IPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex4i"))) == NULL) || r; + r = ((glVertex4iv = (PFNGLVERTEX4IVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex4iv"))) == NULL) || r; + r = ((glVertex4s = (PFNGLVERTEX4SPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex4s"))) == NULL) || r; + r = ((glVertex4sv = (PFNGLVERTEX4SVPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertex4sv"))) == NULL) || r; + r = ((glVertexPointer = (PFNGLVERTEXPOINTERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertexPointer"))) == NULL) || r; + r = ((glViewport = (PFNGLVIEWPORTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glViewport"))) == NULL) || r; + + return r; +} +#endif //GLEW_INIT_OPENGL11_FUNCTIONS + + GLenum GLEWAPIENTRY glewInit (void) { GLenum r; From 72ae3b6afb72f4e3b73d608961cdda1fa57344d3 Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Fri, 11 Jul 2014 13:21:00 -0700 Subject: [PATCH 087/116] test commit for travis-ci.org --- readme.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/readme.txt b/readme.txt index d00594291..5dc5f6a6a 100644 --- a/readme.txt +++ b/readme.txt @@ -1,3 +1,4 @@ + Bullet 3.x GPU rigid body pipeline using OpenCL. Note that the Bullet 2.x svn repository from http://bullet.googlecode.com From 433d349369f53cffb5865b9bd01ea26c4caa6e94 Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Fri, 11 Jul 2014 14:25:32 -0700 Subject: [PATCH 088/116] add option for newer Linux demos to dynamically load X11, glX and OpenGL 1 functions (and avoid having to link against X, glx and GL) -DGLEW_INIT_OPENGL11_FUNCTIONS -DGLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS -DDYNAMIC_LOAD_X11_FUNCTIONS and link against libdl (for example usingi -ldl) --- Demos3/BasicDemoCustomOpenGL2/main.cpp | 24 +- btgui/OpenGLWindow/GlewWindows/GL/glew.h | 35 +-- btgui/OpenGLWindow/GlewWindows/GL/glxew.h | 181 +++++++++---- btgui/OpenGLWindow/GlewWindows/glew.c | 127 +++++++-- btgui/OpenGLWindow/OpenGLInclude.h | 14 +- btgui/OpenGLWindow/X11OpenGLWindow.cpp | 311 ++++++++++++++++++---- 6 files changed, 537 insertions(+), 155 deletions(-) diff --git a/Demos3/BasicDemoCustomOpenGL2/main.cpp b/Demos3/BasicDemoCustomOpenGL2/main.cpp index aabb85135..e23b1d250 100644 --- a/Demos3/BasicDemoCustomOpenGL2/main.cpp +++ b/Demos3/BasicDemoCustomOpenGL2/main.cpp @@ -6,8 +6,8 @@ Copyright (c) 2003-2014 Erwin Coumans http://bulletphysics.org This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -133,7 +133,7 @@ int main(int argc, char* argv[]) window->setMouseMoveCallback(MyMouseMoveCallback); window->setKeyboardCallback(MyKeyboardCallback); - //window->setWindowTitle("render test"); +// window->setWindowTitle("render test"); int majorGlVersion, minorGlVersion; @@ -153,7 +153,7 @@ int main(int argc, char* argv[]) #endif // _WIN32 glewInit(); #endif - + //we ned to call glGetError twice, because of some Ubuntu/Intel/OpenGL issue GLuint err = glGetError(); @@ -181,7 +181,7 @@ int main(int argc, char* argv[]) } - + // glClearColor(0.2,0.2,0.2,1); @@ -189,9 +189,9 @@ int main(int argc, char* argv[]) BasicDemoPhysicsSetup physicsSetup; GraphicsPhysicsBridge br; physicsSetup.initPhysics(br); - - struct MyAppie : public DemoApplication + + struct MyAppie : public DemoApplication { virtual void initPhysics() { @@ -210,7 +210,7 @@ int main(int argc, char* argv[]) if (isCtrlPressed) m_modifierKeys |= BT_ACTIVE_CTRL; - + if (isShiftPressed) m_modifierKeys |= BT_ACTIVE_SHIFT; @@ -228,8 +228,8 @@ int main(int argc, char* argv[]) physicsSetup.m_dynamicsWorld->setDebugDrawer(&draw); btClock timer; unsigned long prevTime = timer.getTimeMicroseconds(); - - do + + do { unsigned long curTime = timer.getTimeMicroseconds(); if (!appie.isIdle()) @@ -242,7 +242,7 @@ int main(int argc, char* argv[]) appie.renderme(); physicsSetup.m_dynamicsWorld->debugDrawWorld(); window->endRendering(); - + } while (!window->requestedExit()); } window->closeWindow(); @@ -252,4 +252,4 @@ int main(int argc, char* argv[]) printf("hello\n"); -} \ No newline at end of file +} diff --git a/btgui/OpenGLWindow/GlewWindows/GL/glew.h b/btgui/OpenGLWindow/GlewWindows/GL/glew.h index 2b0c6301a..f33e7d458 100644 --- a/btgui/OpenGLWindow/GlewWindows/GL/glew.h +++ b/btgui/OpenGLWindow/GlewWindows/GL/glew.h @@ -4,24 +4,24 @@ ** Copyright (C) 2002-2008, Marcelo E. Magallon ** Copyright (C) 2002, Lev Povalahev ** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without +** +** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: -** -** * Redistributions of source code must retain the above copyright notice, +** +** * Redistributions of source code must retain the above copyright notice, ** this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation ** and/or other materials provided with the distribution. -** * The name of the author may be used to endorse or promote products +** * The name of the author may be used to endorse or promote products ** derived from this software without specific prior written permission. ** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @@ -31,6 +31,7 @@ #define GLEW_NO_GLU //#define GLEW_INIT_OPENGL11_FUNCTIONS 1 +//#define GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS 1 /* * Mesa 3-D graphics library @@ -58,7 +59,7 @@ /* ** Copyright (c) 2007 The Khronos Group Inc. -** +** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including @@ -66,10 +67,10 @@ ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are 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 Materials. -** +** ** THE MATERIALS ARE 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. @@ -19061,6 +19062,10 @@ GLEWAPI const GLubyte * GLEWAPIENTRY glewGetString (GLenum name); GLEWAPI GLboolean GLEWAPIENTRY glewOpenGL11Init(void); #endif //GLEW_INIT_OPENGL11_FUNCTIONS +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +GLEWAPI GLboolean GLEWAPIENTRY glewXInit(void); +#endif //GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS + #ifdef __cplusplus } #endif diff --git a/btgui/OpenGLWindow/GlewWindows/GL/glxew.h b/btgui/OpenGLWindow/GlewWindows/GL/glxew.h index 76a5f0d82..6115d611e 100644 --- a/btgui/OpenGLWindow/GlewWindows/GL/glxew.h +++ b/btgui/OpenGLWindow/GlewWindows/GL/glxew.h @@ -4,24 +4,24 @@ ** Copyright (C) 2002-2008, Marcelo E. Magallon ** Copyright (C) 2002, Lev Povalahev ** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without +** +** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: -** -** * Redistributions of source code must retain the above copyright notice, +** +** * Redistributions of source code must retain the above copyright notice, ** this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation ** and/or other materials provided with the distribution. -** * The name of the author may be used to endorse or promote products +** * The name of the author may be used to endorse or promote products ** derived from this software without specific prior written permission. ** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @@ -55,7 +55,7 @@ /* ** Copyright (c) 2007 The Khronos Group Inc. -** +** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including @@ -63,10 +63,10 @@ ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are 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 Materials. -** +** ** THE MATERIALS ARE 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. @@ -97,7 +97,7 @@ #include #include #include -#include +#include "glew.h" #ifdef __cplusplus extern "C" { @@ -141,8 +141,50 @@ typedef struct __glXContextRec *GLXContext; typedef struct __GLXcontextRec *GLXContext; #endif -typedef unsigned int GLXVideoDeviceNV; +typedef unsigned int GLXVideoDeviceNV; +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS + +typedef Bool (* PFNGLXQUERYEXTENSION) (Display *dpy, int *errorBase, int *eventBase); +#define glXQueryExtension GLXEW_GET_FUN(__glewXQueryExtension) + +typedef Bool (* PFNGLXQUERYVERSION) (Display *dpy, int *major, int *minor); +#define glXQueryVersion GLXEW_GET_FUN(__glewXQueryVersion) + +typedef int (* PFNGLXGETCONFIG) (Display *dpy, XVisualInfo *vis, int attrib, int *value); +#define glXGetConfig GLXEW_GET_FUN(__glewXGetConfig) + +typedef XVisualInfo* (* PFNGLXCHOOSEVISUAL) (Display *dpy, int screen, int *attribList); +#define glXChooseVisual GLXEW_GET_FUN(__glewXChooseVisual) + +//extern GLXPixmap glXCreateGLXPixmap (Display *dpy, XVisualInfo *vis, Pixmap pixmap); +//extern void glXDestroyGLXPixmap (Display *dpy, GLXPixmap pix); +typedef GLXContext (* PFNGLXCREATECONTEXT) (Display *dpy, XVisualInfo *vis, GLXContext shareList, Bool direct); +#define glXCreateContext GLXEW_GET_FUN(__glewXCreateContext) + + +typedef void (*PFNGLXDESTROYCONTEXT) (Display *dpy, GLXContext ctx); +#define glXDestroyContext GLXEW_GET_FUN(__glewXDestroyContext) + +typedef Bool (* PFNGLXISDIRECT) (Display *dpy, GLXContext ctx); +#define glXIsDirect GLXEW_GET_FUN(__glewXIsDirect) + + +//extern void glXCopyContext (Display *dpy, GLXContext src, GLXContext dst, GLulong mask); +typedef Bool (*PFNGLXMAKECURRENT) (Display *dpy, GLXDrawable drawable, GLXContext ctx); +#define glXMakeCurrent GLXEW_GET_FUN(__glewXMakeCurrent) + +//extern GLXContext glXGetCurrentContext (void); +//extern GLXDrawable glXGetCurrentDrawable (void); +//extern void glXWaitGL (void); +//extern void glXWaitX (void); +typedef void (*PFNGLXSWAPBUFFERS) (Display *dpy, GLXDrawable drawable); +#define glXSwapBuffers GLXEW_GET_FUN(__glewXSwapBuffers) + +//extern void glXUseXFont (Font font, int first, int count, int listBase); + + +#else//GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS extern Bool glXQueryExtension (Display *dpy, int *errorBase, int *eventBase); extern Bool glXQueryVersion (Display *dpy, int *major, int *minor); extern int glXGetConfig (Display *dpy, XVisualInfo *vis, int attrib, int *value); @@ -160,6 +202,7 @@ extern void glXWaitGL (void); extern void glXWaitX (void); extern void glXSwapBuffers (Display *dpy, GLXDrawable drawable); extern void glXUseXFont (Font font, int first, int count, int listBase); +#endif //GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS #define GLXEW_VERSION_1_0 GLXEW_GET_VAR(__GLXEW_VERSION_1_0) @@ -174,9 +217,22 @@ extern void glXUseXFont (Font font, int first, int count, int listBase); #define GLX_VERSION 0x2 #define GLX_EXTENSIONS 0x3 +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS + +typedef const char* (*PFNGLXQUERYEXTENSIONSSTRING) (Display *dpy, int screen); +#define glXQueryExtensionsString GLXEW_GET_FUN(__glewXQueryExtensionsString) + +typedef const char* (*PFNGLXGETCLIENTSTRING) (Display *dpy, int name); +#define glXGetClientString GLXEW_GET_FUN(__glewXGetClientString) + +typedef const char* (*PFNGLXQUERYSERVERSTRING) (Display *dpy, int screen, int name); +#define glXQueryServerString GLXEW_GET_FUN(__glewXQueryServerString) + +#else//GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS extern const char* glXQueryExtensionsString (Display *dpy, int screen); extern const char* glXGetClientString (Display *dpy, int name); extern const char* glXQueryServerString (Display *dpy, int screen, int name); +#endif//GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS #define GLXEW_VERSION_1_1 GLXEW_GET_VAR(__GLXEW_VERSION_1_1) @@ -263,21 +319,21 @@ typedef XID GLXWindow; typedef struct __GLXFBConfigRec *GLXFBConfig; typedef struct { - int event_type; - int draw_type; - unsigned long serial; - Bool send_event; - Display *display; - GLXDrawable drawable; - unsigned int buffer_mask; - unsigned int aux_buffer; - int x, y; - int width, height; - int count; + int event_type; + int draw_type; + unsigned long serial; + Bool send_event; + Display *display; + GLXDrawable drawable; + unsigned int buffer_mask; + unsigned int aux_buffer; + int x, y; + int width, height; + int count; } GLXPbufferClobberEvent; typedef union __GLXEvent { - GLXPbufferClobberEvent glxpbufferclobber; - long pad[24]; + GLXPbufferClobberEvent glxpbufferclobber; + long pad[24]; } GLXEvent; typedef GLXFBConfig* ( * PFNGLXCHOOSEFBCONFIGPROC) (Display *dpy, int screen, const int *attrib_list, int *nelements); @@ -460,7 +516,13 @@ typedef GLXContext ( * PFNGLXCREATECONTEXTATTRIBSARBPROC) (Display* dpy, GLXFBCo #ifndef GLX_ARB_get_proc_address #define GLX_ARB_get_proc_address 1 +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +typedef void* ( * PFNGLXGETPROCADDRESSARBPROC) (const GLubyte *procName); +#define glXGetProcAddressARB GLXEW_GET_FUN(__glewXGetProcAddressARB) + +#else//GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS extern void ( * glXGetProcAddressARB (const GLubyte *procName)) (void); +#endif //GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS #define GLXEW_ARB_get_proc_address GLXEW_GET_VAR(__GLXEW_ARB_get_proc_address) @@ -1161,32 +1223,32 @@ typedef XVisualInfo* ( * PFNGLXGETVISUALFROMFBCONFIGSGIXPROC) (Display *dpy, GLX #define GLX_HYPERPIPE_ID_SGIX 0x8030 typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int networkId; + char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; + int networkId; } GLXHyperpipeNetworkSGIX; typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int XOrigin; - int YOrigin; - int maxHeight; - int maxWidth; + char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; + int XOrigin; + int YOrigin; + int maxHeight; + int maxWidth; } GLXPipeRectLimits; typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int channel; - unsigned int participationType; - int timeSlice; + char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; + int channel; + unsigned int participationType; + int timeSlice; } GLXHyperpipeConfigSGIX; typedef struct { - char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; - int srcXOrigin; - int srcYOrigin; - int srcWidth; - int srcHeight; - int destXOrigin; - int destYOrigin; - int destWidth; - int destHeight; + char pipeName[GLX_HYPERPIPE_PIPE_NAME_LENGTH_SGIX]; + int srcXOrigin; + int srcYOrigin; + int srcWidth; + int srcHeight; + int destXOrigin; + int destYOrigin; + int destWidth; + int destHeight; } GLXPipeRect; typedef int ( * PFNGLXBINDHYPERPIPESGIXPROC) (Display *dpy, int hpId); @@ -1421,6 +1483,24 @@ typedef int ( * PFNGLXVIDEORESIZESUNPROC) (Display* display, GLXDrawable window, #define GLXEW_VAR_EXPORT GLEW_VAR_EXPORT #endif /* GLEW_MX */ +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +GLXEW_FUN_EXPORT PFNGLXGETPROCADDRESSARBPROC __glewXGetProcAddressARB; +GLXEW_FUN_EXPORT PFNGLXQUERYEXTENSION __glewXQueryExtension; +GLXEW_FUN_EXPORT PFNGLXQUERYVERSION __glewXQueryVersion; +GLXEW_FUN_EXPORT PFNGLXGETCONFIG __glewXGetConfig; +GLXEW_FUN_EXPORT PFNGLXCHOOSEVISUAL __glewXChooseVisual; +GLXEW_FUN_EXPORT PFNGLXCREATECONTEXT __glewXCreateContext; +GLXEW_FUN_EXPORT PFNGLXDESTROYCONTEXT __glewXDestroyContext; +GLXEW_FUN_EXPORT PFNGLXISDIRECT __glewXIsDirect; +GLXEW_FUN_EXPORT PFNGLXMAKECURRENT __glewXMakeCurrent; +GLXEW_FUN_EXPORT PFNGLXQUERYEXTENSIONSSTRING __glewXQueryExtensionsString; +GLXEW_FUN_EXPORT PFNGLXGETCLIENTSTRING __glewXGetClientString; +GLXEW_FUN_EXPORT PFNGLXQUERYSERVERSTRING __glewXQueryServerString; +GLXEW_FUN_EXPORT PFNGLXSWAPBUFFERS __glewXSwapBuffers; + + +#endif //GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS + GLXEW_FUN_EXPORT PFNGLXGETCURRENTDISPLAYPROC __glewXGetCurrentDisplay; GLXEW_FUN_EXPORT PFNGLXCHOOSEFBCONFIGPROC __glewXChooseFBConfig; @@ -1453,6 +1533,7 @@ GLXEW_FUN_EXPORT PFNGLXMAKEASSOCIATEDCONTEXTCURRENTAMDPROC __glewXMakeAssociated GLXEW_FUN_EXPORT PFNGLXCREATECONTEXTATTRIBSARBPROC __glewXCreateContextAttribsARB; + GLXEW_FUN_EXPORT PFNGLXBINDTEXIMAGEATIPROC __glewXBindTexImageATI; GLXEW_FUN_EXPORT PFNGLXDRAWABLEATTRIBATIPROC __glewXDrawableAttribATI; GLXEW_FUN_EXPORT PFNGLXRELEASETEXIMAGEATIPROC __glewXReleaseTexImageATI; diff --git a/btgui/OpenGLWindow/GlewWindows/glew.c b/btgui/OpenGLWindow/GlewWindows/glew.c index a21474376..c90af794a 100644 --- a/btgui/OpenGLWindow/GlewWindows/glew.c +++ b/btgui/OpenGLWindow/GlewWindows/glew.c @@ -4,24 +4,24 @@ ** Copyright (C) 2002-2008, Marcelo E. Magallon ** Copyright (C) 2002, Lev Povalahev ** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without +** +** Redistribution and use in source and binary forms, with or without ** modification, are permitted provided that the following conditions are met: -** -** * Redistributions of source code must retain the above copyright notice, +** +** * Redistributions of source code must retain the above copyright notice, ** this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright notice, -** this list of conditions and the following disclaimer in the documentation +** * Redistributions in binary form must reproduce the above copyright notice, +** this list of conditions and the following disclaimer in the documentation ** and/or other materials provided with the distribution. -** * The name of the author may be used to endorse or promote products +** * The name of the author may be used to endorse or promote products ** derived from this software without specific prior written permission. ** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @@ -34,7 +34,38 @@ #if defined(_WIN32) # include #elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) -# include +# include "GL/glxew.h" + +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS + +#include +#include +#include + +void* dlglXGetProcAddressARB(const GLubyte* name) +{ + static void* h = NULL; + static void* gpa; + + if (h == NULL) + { + if ((h = dlopen("libGL.so.1", RTLD_LAZY | RTLD_LOCAL)) == NULL) + { + return NULL; + } + gpa = dlsym(h, "glXGetProcAddressARB"); + } + + if (gpa != NULL) + return ((void*(*)(const GLubyte*))gpa)(name); + else + return dlsym(h, (const char*)name); +} + + + +#endif //GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS + #endif /* @@ -102,7 +133,7 @@ void* NSGLGetProcAddress (const GLubyte *name) { static void* image = NULL; void* addr; - if (NULL == image) + if (NULL == image) { #ifdef GLEW_REGAL image = dlopen("libRegal.dylib", RTLD_LAZY); @@ -169,7 +200,11 @@ void* NSGLGetProcAddress (const GLubyte *name) #elif defined(__native_client__) # define glewGetProcAddress(name) NULL /* TODO */ #else /* __linux */ +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +# define glewGetProcAddress(name) dlglXGetProcAddressARB(name) +#else//GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS # define glewGetProcAddress(name) (*glXGetProcAddressARB)(name) +#endif//GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS #endif /* @@ -9469,7 +9504,7 @@ static GLboolean _glewInit_GL_WIN_swap_hint (GLEW_CONTEXT_ARG_DEF_INIT) /* ------------------------------------------------------------------------- */ GLboolean GLEWAPIENTRY glewGetExtension (const char* name) -{ +{ const GLubyte* start; const GLubyte* end; start = (const GLubyte*)glGetString(GL_EXTENSIONS); @@ -9496,7 +9531,7 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) dot = _glewStrCLen(s, '.'); if (dot == 0) return GLEW_ERROR_NO_GL_VERSION; - + major = s[dot-1]-'0'; minor = s[dot+1]-'0'; @@ -9504,7 +9539,7 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) minor = 0; if (major<0 || major>9) return GLEW_ERROR_NO_GL_VERSION; - + if (major == 1 && minor == 0) { @@ -9521,12 +9556,12 @@ GLenum GLEWAPIENTRY glewContextInit (GLEW_CONTEXT_ARG_DEF_LIST) CONST_CAST(GLEW_VERSION_3_2) = GLEW_VERSION_3_3 == GL_TRUE || ( major == 3 && minor >= 2 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_3_1) = GLEW_VERSION_3_2 == GL_TRUE || ( major == 3 && minor >= 1 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_3_0) = GLEW_VERSION_3_1 == GL_TRUE || ( major == 3 ) ? GL_TRUE : GL_FALSE; - CONST_CAST(GLEW_VERSION_2_1) = GLEW_VERSION_3_0 == GL_TRUE || ( major == 2 && minor >= 1 ) ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_2_1) = GLEW_VERSION_3_0 == GL_TRUE || ( major == 2 && minor >= 1 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_2_0) = GLEW_VERSION_2_1 == GL_TRUE || ( major == 2 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_1_5) = GLEW_VERSION_2_0 == GL_TRUE || ( major == 1 && minor >= 5 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_1_4) = GLEW_VERSION_1_5 == GL_TRUE || ( major == 1 && minor >= 4 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_1_3) = GLEW_VERSION_1_4 == GL_TRUE || ( major == 1 && minor >= 3 ) ? GL_TRUE : GL_FALSE; - CONST_CAST(GLEW_VERSION_1_2_1) = GLEW_VERSION_1_3 == GL_TRUE ? GL_TRUE : GL_FALSE; + CONST_CAST(GLEW_VERSION_1_2_1) = GLEW_VERSION_1_3 == GL_TRUE ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_1_2) = GLEW_VERSION_1_2_1 == GL_TRUE || ( major == 1 && minor >= 2 ) ? GL_TRUE : GL_FALSE; CONST_CAST(GLEW_VERSION_1_1) = GLEW_VERSION_1_2 == GL_TRUE || ( major == 1 && minor >= 1 ) ? GL_TRUE : GL_FALSE; } @@ -12099,7 +12134,7 @@ static PFNWGLGETEXTENSIONSSTRINGARBPROC _wglewGetExtensionsStringARB = NULL; static PFNWGLGETEXTENSIONSSTRINGEXTPROC _wglewGetExtensionsStringEXT = NULL; GLboolean GLEWAPIENTRY wglewGetExtension (const char* name) -{ +{ const GLubyte* start; const GLubyte* end; if (_wglewGetExtensionsStringARB == NULL) @@ -12326,6 +12361,24 @@ GLenum GLEWAPIENTRY wglewContextInit (WGLEW_CONTEXT_ARG_DEF_LIST) #elif !defined(__ANDROID__) && !defined(__native_client__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) + +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +PFNGLXGETPROCADDRESSARBPROC __glewXGetProcAddressARB = NULL; +PFNGLXQUERYEXTENSION __glewXQueryExtension=NULL; +PFNGLXQUERYVERSION __glewXQueryVersion=NULL; +PFNGLXGETCONFIG __glewXGetConfig=NULL; +PFNGLXCHOOSEVISUAL __glewXChooseVisual=NULL; +PFNGLXCREATECONTEXT __glewXCreateContext=NULL; +PFNGLXDESTROYCONTEXT __glewXDestroyContext=NULL; +PFNGLXISDIRECT __glewXIsDirect=NULL; +PFNGLXMAKECURRENT __glewXMakeCurrent=NULL; +PFNGLXQUERYEXTENSIONSSTRING __glewXQueryExtensionsString=NULL; +PFNGLXGETCLIENTSTRING __glewXGetClientString=NULL; +PFNGLXQUERYSERVERSTRING __glewXQueryServerString=NULL; +PFNGLXSWAPBUFFERS __glewXSwapBuffers=NULL; + +#endif//GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS + PFNGLXGETCURRENTDISPLAYPROC __glewXGetCurrentDisplay = NULL; PFNGLXCHOOSEFBCONFIGPROC __glewXChooseFBConfig = NULL; @@ -13164,7 +13217,7 @@ static GLboolean _glewInit_GLX_SUN_video_resize (GLXEW_CONTEXT_ARG_DEF_INIT) /* ------------------------------------------------------------------------ */ GLboolean glxewGetExtension (const char* name) -{ +{ const GLubyte* start; const GLubyte* end; @@ -13476,6 +13529,34 @@ extern GLenum GLEWAPIENTRY wglewContextInit (void); extern GLenum GLEWAPIENTRY glxewContextInit (void); #endif /* _WIN32 */ +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +GLboolean GLEWAPIENTRY glewXInit(void) +{ + GLboolean r = GL_FALSE; + r = ((glXGetProcAddressARB = (PFNGLXGETPROCADDRESSARBPROC)dlglXGetProcAddressARB((const GLubyte*)"glXGetProcAddressARB")) == NULL) || r; + r = ((glXQueryExtension = (PFNGLXQUERYEXTENSION)dlglXGetProcAddressARB((const GLubyte*)"glXQueryExtension")) == NULL) || r; + r = ((glXQueryVersion = (PFNGLXQUERYVERSION)dlglXGetProcAddressARB((const GLubyte*)"glXQueryVersion")) == NULL) || r; + r = ((glXGetConfig = (PFNGLXGETCONFIG)dlglXGetProcAddressARB((const GLubyte*)"glXGetConfig")) == NULL) || r; + r = ((glXChooseVisual = (PFNGLXCHOOSEVISUAL)dlglXGetProcAddressARB((const GLubyte*)"glXChooseVisual")) == NULL) || r; + r = ((glXCreateContext = (PFNGLXCREATECONTEXT)dlglXGetProcAddressARB((const GLubyte*)"glXCreateContext")) == NULL) || r; + r = ((glXDestroyContext = (PFNGLXDESTROYCONTEXT)dlglXGetProcAddressARB((const GLubyte*)"glXDestroyContext")) == NULL) || r; + r = ((glXDestroyContext = (PFNGLXDESTROYCONTEXT)dlglXGetProcAddressARB((const GLubyte*)"glXDestroyContext")) == NULL) || r; + r = ((glXIsDirect = (PFNGLXISDIRECT)dlglXGetProcAddressARB((const GLubyte*)"glXIsDirect")) == NULL) || r; + r = ((glXMakeCurrent = (PFNGLXMAKECURRENT)dlglXGetProcAddressARB((const GLubyte*)"glXMakeCurrent")) == NULL) || r; + r = ((glXQueryExtensionsString = (PFNGLXQUERYEXTENSIONSSTRING)dlglXGetProcAddressARB((const GLubyte*)"glXQueryExtensionsString")) == NULL) || r; + r = ((glXGetClientString = (PFNGLXGETCLIENTSTRING)dlglXGetProcAddressARB((const GLubyte*)"glXGetClientString")) == NULL) || r; + r = ((glXQueryServerString = (PFNGLXQUERYSERVERSTRING)dlglXGetProcAddressARB((const GLubyte*)"glXQueryServerString")) == NULL) || r; + r = ((glXSwapBuffers = (PFNGLXSWAPBUFFERS)dlglXGetProcAddressARB((const GLubyte*)"glXSwapBuffers")) == NULL) || r; + //glxewContextInit(); + _glewInit_GLX_VERSION_1_3(); + + if (r==0) + { + printf("glewXInit dynamically loaded using dlopen/dlsym OK\n"); + } + return r; +} +#endif //GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS #ifdef GLEW_INIT_OPENGL11_FUNCTIONS @@ -14160,6 +14241,10 @@ GLboolean GLEWAPIENTRY glewOpenGL11Init(void) r = ((glVertexPointer = (PFNGLVERTEXPOINTERPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glVertexPointer"))) == NULL) || r; r = ((glViewport = (PFNGLVIEWPORTPROC)glewGetProcAddress(fqn_from_convention(glew_convention, "glViewport"))) == NULL) || r; + if (r==0) + { + printf("glewOpenGL11Init dynamically loaded using dlopen/dlsym OK\n"); + } return r; } #endif //GLEW_INIT_OPENGL11_FUNCTIONS diff --git a/btgui/OpenGLWindow/OpenGLInclude.h b/btgui/OpenGLWindow/OpenGLInclude.h index 665bdd725..e01f20b05 100644 --- a/btgui/OpenGLWindow/OpenGLInclude.h +++ b/btgui/OpenGLWindow/OpenGLInclude.h @@ -1,10 +1,10 @@ /* -Copyright (c) 2012 Advanced Micro Devices, Inc. +Copyright (c) 2012 Advanced Micro Devices, Inc. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. @@ -27,14 +27,14 @@ subject to the following restrictions: #include #else -#include +#include "GlewWindows/GL/glew.h" #ifdef _WINDOWS #include -#include -#include +//#include +//#include #else -#include +//#include //#include #endif //_WINDOWS #endif //APPLE diff --git a/btgui/OpenGLWindow/X11OpenGLWindow.cpp b/btgui/OpenGLWindow/X11OpenGLWindow.cpp index 7d9809f68..78e14c717 100644 --- a/btgui/OpenGLWindow/X11OpenGLWindow.cpp +++ b/btgui/OpenGLWindow/X11OpenGLWindow.cpp @@ -3,12 +3,25 @@ #include #include -#include -#include -#include +#include "GlewWindows/GL/glew.h" +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +#include "GlewWindows/GL/glxew.h" +#else #include -//#include +#endif // GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +#include +//#define DYNAMIC_LOAD_X11_FUNCTIONS +#ifdef DYNAMIC_LOAD_X11_FUNCTIONS +#include +#endif //DYNAMIC_LOAD_X11_FUNCTIONS + +//#include +//#include +//#include + +//defined in GL/glxew.h +//#include #include #include #include @@ -19,6 +32,84 @@ GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; static bool forceOpenGL3 = true; + + +#ifdef DYNAMIC_LOAD_X11_FUNCTIONS + +///our X11 function typedefs +typedef int (*PFNXFREE)(void*); +typedef XErrorHandler (* PFNXSETERRORHANDLER) (XErrorHandler); +typedef int (* PFNXSYNC) (Display* a,Bool b); +typedef Display* (* PFNXOPENDISPLAY) (_Xconst char* a); +typedef Colormap (*PFNXCREATECOLORMAP) (Display* a,Window b,Visual* c,int d); +typedef Window (*PFNXCREATEWINDOW) (Display* a,Window b,int c,int d,unsigned int e,unsigned int f,unsigned int g,int h,unsigned int i,Visual* j,unsigned long k,XSetWindowAttributes* l); +typedef int (*PFNXMAPWINDOW) (Display*, Window); +typedef int (*PFNXSTORENAME) (Display* a,Window b,_Xconst char* c); +typedef int (*PFNXCLOSEDISPLAY) (Display* a); +typedef int (*PFNXDESTROYWINDOW) (Display* a,Window b); +#if NeedWidePrototypes +typedef KeySym (*PFNXKEYCODETOKEYSYM) (Display* a,unsigned int b,int c); +#else +typedef KeySym (*PFNXKEYCODETOKEYSYM) (Display* a,KeyCode b,int c); +#endif +typedef void (*PFNXCONVERTCASE) (KeySym /* sym */,KeySym * /* lower */,KeySym * /* upper */); +typedef int (*PFNXPENDING) (Display* a); +typedef int (*PFNXNEXTEVENT) (Display* a,XEvent* b); +typedef int (*PFNXEVENTSQUEUED) (Display* a,int b); +typedef int (*PFNXPEEKEVENT) (Display* a,XEvent* b); +typedef KeySym (*PFNXLOOKUPKEYSYM) (XKeyEvent* a,int b); +typedef Status (*PFNXGETWINDOWATTRIBUTES) (Display* a,Window b,XWindowAttributes* c); + +#define X11_LIBRARY "libX11.so.6" + +#define MyXSync m_data->m_x11_XSync +#define MyXSetErrorHandler m_data->m_x11_XSetErrorHandler +#define MyXOpenDisplay m_data->m_x11_XOpenDisplay +#define MyXCreateColormap m_data->m_x11_XCreateColormap +#define MyXCreateWindow m_data->m_x11_XCreateWindow +#define MyXMapWindow m_data->m_x11_XMapWindow +#define MyXStoreName m_data->m_x11_XStoreName +#define MyXDestroyWindow m_data->m_x11_XDestroyWindow +#define MyXCloseDisplay m_data->m_x11_XCloseDisplay +#define MyXKeycodeToKeysym m_data->m_x11_XKeycodeToKeysym +#define MyXConvertCase m_data->m_x11_XConvertCase +#define MyXPending m_data->m_x11_XPending +#define MyXNextEvent m_data->m_x11_XNextEvent +#define MyXEventsQueued m_data->m_x11_XEventsQueued +#define MyXPeekEvent m_data->m_x11_XPeekEvent +#define MyXNextEvent m_data->m_x11_XNextEvent +#define MyXGetWindowAttributes m_data->m_x11_XGetWindowAttributes +#define MyXStoreName m_data->m_x11_XStoreName +#define MyXFree m_data->m_x11_XFree +#define MyXMapWindow m_data->m_x11_XMapWindow +#define MyXStoreName m_data->m_x11_XStoreName +#define MyXLookupKeysym m_data->m_x11_XLookupKeysym + +#else +#define MyXSync XSync +#define MyXSetErrorHandler XSetErrorHandler +#define MyXOpenDisplay XOpenDisplay +#define MyXCreateColormap XCreateColormap +#define MyXCreateWindow XCreateWindow +#define MyXMapWindow XMapWindow +#define MyXStoreName XStoreName +#define MyXDestroyWindow XDestroyWindow +#define MyXCloseDisplay XCloseDisplay +#define MyXKeycodeToKeysym XKeycodeToKeysym +#define MyXConvertCase XConvertCase +#define MyXPending XPending +#define MyXNextEvent XNextEvent +#define MyXEventsQueued XEventsQueued +#define MyXPeekEvent XPeekEvent +#define MyXNextEvent XNextEvent +#define MyXGetWindowAttributes XGetWindowAttributes +#define MyXStoreName XStoreName +#define MyXFree XFree +#define MyXMapWindow XMapWindow +#define MyXStoreName XStoreName +#define MyXLookupKeysym XLookupKeysym + +#endif//DYNAMIC_LOAD_X11_FUNCTIONS struct InternalData2 { Display* m_dpy; @@ -32,7 +123,30 @@ struct InternalData2 XEvent m_xev; GLXFBConfig m_bestFbc; - b3WheelCallback m_wheelCallback; +#ifdef DYNAMIC_LOAD_X11_FUNCTIONS + //dynamically load stuff + void* m_x11_library; + PFNXFREE m_x11_XFree; + PFNXSETERRORHANDLER m_x11_XSetErrorHandler; + PFNXSYNC m_x11_XSync; + PFNXOPENDISPLAY m_x11_XOpenDisplay; + PFNXCREATECOLORMAP m_x11_XCreateColormap; + PFNXCREATEWINDOW m_x11_XCreateWindow; + PFNXMAPWINDOW m_x11_XMapWindow; + PFNXSTORENAME m_x11_XStoreName; + PFNXCLOSEDISPLAY m_x11_XCloseDisplay; + PFNXDESTROYWINDOW m_x11_XDestroyWindow; + PFNXKEYCODETOKEYSYM m_x11_XKeycodeToKeysym; + PFNXCONVERTCASE m_x11_XConvertCase; + PFNXPENDING m_x11_XPending; + PFNXNEXTEVENT m_x11_XNextEvent; + PFNXEVENTSQUEUED m_x11_XEventsQueued; + PFNXPEEKEVENT m_x11_XPeekEvent; + PFNXLOOKUPKEYSYM m_x11_XLookupKeysym; + PFNXGETWINDOWATTRIBUTES m_x11_XGetWindowAttributes; +#endif //DYNAMIC_LOAD_X11_FUNCTIONS + + b3WheelCallback m_wheelCallback; b3MouseMoveCallback m_mouseMoveCallback; b3MouseButtonCallback m_mouseButtonCallback; b3ResizeCallback m_resizeCallback; @@ -47,7 +161,68 @@ struct InternalData2 m_resizeCallback(0), m_keyboardCallback(0) { +#ifdef DYNAMIC_LOAD_X11_FUNCTIONS + m_x11_library = dlopen(X11_LIBRARY, RTLD_LOCAL | RTLD_NOW); + if (!m_x11_library) + { + printf("Error opening X11 library %s\n", X11_LIBRARY); + exit(0); + } + bool missingFunc = false; + + missingFunc = ((m_x11_XFree = (PFNXFREE) dlsym(m_x11_library, "XFree"))==NULL) | missingFunc; + assert(!missingFunc); + if (missingFunc) { printf("Error: missing func XFree in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XSetErrorHandler = (PFNXSETERRORHANDLER) dlsym(m_x11_library,"XSetErrorHandler"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XSetErrorHandler in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XSetErrorHandler = (PFNXSETERRORHANDLER) dlsym(m_x11_library,"XSetErrorHandler"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XSetErrorHandler in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XSync = (PFNXSYNC) dlsym(m_x11_library,"XSync"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XSync in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XOpenDisplay = (PFNXOPENDISPLAY) dlsym(m_x11_library,"XOpenDisplay"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XOpenDisplay in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XCreateColormap = (PFNXCREATECOLORMAP) dlsym(m_x11_library,"XCreateColormap"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XCreateColormap in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XCreateWindow = (PFNXCREATEWINDOW) dlsym(m_x11_library,"XCreateWindow"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XCreateWindow in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XMapWindow = (PFNXMAPWINDOW) dlsym(m_x11_library,"XMapWindow"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XMapWindow in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XStoreName = (PFNXSTORENAME) dlsym(m_x11_library,"XStoreName"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XStoreName in %s, exiting!\n", X11_LIBRARY); exit(0);} + + missingFunc = ((m_x11_XCloseDisplay = (PFNXCLOSEDISPLAY) dlsym(m_x11_library,"XCloseDisplay"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XCloseDisplay in %s, exiting!\n", X11_LIBRARY); exit(0);} + + missingFunc = ((m_x11_XDestroyWindow = (PFNXDESTROYWINDOW) dlsym(m_x11_library,"XDestroyWindow"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XMapWindow in %s, exiting!\n", X11_LIBRARY); exit(0);} + + missingFunc = ((m_x11_XKeycodeToKeysym = (PFNXKEYCODETOKEYSYM) dlsym(m_x11_library,"XKeycodeToKeysym"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XKeycodeToKeysym in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XConvertCase = (PFNXCONVERTCASE) dlsym(m_x11_library,"XConvertCase"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XConvertCase in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XPending = (PFNXPENDING) dlsym(m_x11_library,"XPending"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XPending in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XNextEvent = (PFNXNEXTEVENT) dlsym(m_x11_library,"XNextEvent"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XNextEvent in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XEventsQueued = (PFNXEVENTSQUEUED) dlsym(m_x11_library,"XEventsQueued"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XEventsQueued in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XPeekEvent = (PFNXPEEKEVENT) dlsym(m_x11_library,"XPeekEvent"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XPeekEvent in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XLookupKeysym = (PFNXLOOKUPKEYSYM) dlsym(m_x11_library,"XLookupKeysym"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XLookupKeysym in %s, exiting!\n", X11_LIBRARY); exit(0);} + missingFunc = ((m_x11_XGetWindowAttributes = (PFNXGETWINDOWATTRIBUTES) dlsym(m_x11_library,"XGetWindowAttributes"))==NULL) | missingFunc; + if (missingFunc) { printf("Error: missing func XGetWindowAttributes in %s, exiting!\n", X11_LIBRARY); exit(0);} + + if (missingFunc) + { + printf("Error: a missing func in %s, exiting!\n", X11_LIBRARY); + exit(0); + } else + { + printf("X11 functions dynamically loaded using dlopen/dlsym OK!\n"); + } +#endif //DYNAMIC_LOAD_X11_FUNCTIONS } }; @@ -120,6 +295,7 @@ X11OpenGLWindow::~X11OpenGLWindow() void X11OpenGLWindow::enableOpenGL() { + if (forceOpenGL3) { // Get the default screen's GLX extension list @@ -127,7 +303,8 @@ void X11OpenGLWindow::enableOpenGL() DefaultScreen( m_data->m_dpy ) ); // NOTE: It is not necessary to create or make current to a context before - // calling glXGetProcAddressARB + // calling glXGetProcAddressARB, unless we dynamically load OpenGL/GLX/X11 + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); @@ -142,7 +319,7 @@ void X11OpenGLWindow::enableOpenGL() // threads issuing X commands while this code is running. ctxErrorOccurred = false; int (*oldHandler)(Display*, XErrorEvent*) = - XSetErrorHandler(&ctxErrorHandler); + MyXSetErrorHandler(&ctxErrorHandler); // Check for the GLX_ARB_create_context extension string and the function. // If either is not present, use GLX 1.3 context creation method. @@ -178,7 +355,7 @@ void X11OpenGLWindow::enableOpenGL() True, context_attribs ); // Sync to ensure any errors generated are processed. - XSync( m_data->m_dpy, False ); + MyXSync( m_data->m_dpy, False ); if ( !ctxErrorOccurred && ctx ) printf( "Created GL 3.0 context\n" ); else @@ -202,10 +379,10 @@ void X11OpenGLWindow::enableOpenGL() } // Sync to ensure any errors generated are processed. - XSync( m_data->m_dpy, False ); + MyXSync( m_data->m_dpy, False ); // Restore the original error handler - XSetErrorHandler( oldHandler ); + MyXSetErrorHandler( oldHandler ); if ( ctxErrorOccurred || !ctx ) { @@ -231,6 +408,22 @@ void X11OpenGLWindow::enableOpenGL() m_data->m_glc = glXCreateContext(m_data->m_dpy, m_data->m_vi, NULL, GL_TRUE); glXMakeCurrent(m_data->m_dpy, m_data->m_win, m_data->m_glc); } + +#ifdef GLEW_INIT_OPENGL11_FUNCTIONS +{ + GLboolean res = glewOpenGL11Init(); + if (res==0) + { + printf("glewOpenGL11Init OK!\n"); + } else + { + printf("ERROR: glewOpenGL11Init failed, exiting!\n"); + exit(0); + } +} + +#endif //GLEW_INIT_OPENGL11_FUNCTIONS + const GLubyte* ven = glGetString(GL_VENDOR); printf("GL_VENDOR=%s\n", ven); @@ -260,8 +453,8 @@ void X11OpenGLWindow::disableOpenGL() void X11OpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) { -printf("createWindow\n"); - m_data->m_dpy = XOpenDisplay(NULL); + + m_data->m_dpy = MyXOpenDisplay(NULL); if(m_data->m_dpy == NULL) { printf("\n\tcannot connect to X server\n\n"); @@ -270,6 +463,20 @@ printf("createWindow\n"); m_data->m_root = DefaultRootWindow(m_data->m_dpy); + +#ifdef GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS +GLboolean res = glewXInit(); +if (res==0) +{ + printf("glewXInit OK\n"); +} else +{ + printf("glewXInit failed, exit\n"); + exit(0); +} +#endif //GLEW_DYNAMIC_LOAD_ALL_GLX_FUNCTIONS + + if (ci.m_openglVersion < 3) { forceOpenGL3 = false; @@ -312,33 +519,33 @@ printf("createWindow\n"); int i; for (i=0; im_dpy, fbc[i] ); - if ( vi ) - { - int samp_buf, samples; - glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf ); - glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLES , &samples ); + XVisualInfo *vi = glXGetVisualFromFBConfig( m_data->m_dpy, fbc[i] ); + if ( vi ) + { + int samp_buf, samples; + glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf ); + glXGetFBConfigAttrib( m_data->m_dpy, fbc[i], GLX_SAMPLES , &samples ); - //printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," - // " SAMPLES = %d\n", - // i, vi -> visualid, samp_buf, samples ); + //printf( " Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d," + // " SAMPLES = %d\n", + // i, vi -> visualid, samp_buf, samples ); - if ( best_fbc < 0 || samp_buf && samples > best_num_samp ) - best_fbc = i, best_num_samp = samples; - if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) - worst_fbc = i, worst_num_samp = samples; - } - XFree( vi ); + if ( best_fbc < 0 || samp_buf && samples > best_num_samp ) + best_fbc = i, best_num_samp = samples; + if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) + worst_fbc = i, worst_num_samp = samples; + } + MyXFree( vi ); } m_data->m_bestFbc = fbc[ best_fbc ]; // Be sure to free the FBConfig list allocated by glXChooseFBConfig() - XFree( fbc ); + MyXFree( fbc ); m_data->m_vi = glXGetVisualFromFBConfig( m_data->m_dpy, m_data->m_bestFbc ); - m_data->m_swa.colormap = m_data->m_cmap = XCreateColormap( m_data->m_dpy, + m_data->m_swa.colormap = m_data->m_cmap = MyXCreateColormap( m_data->m_dpy, RootWindow( m_data->m_dpy, m_data->m_vi->screen ), m_data->m_vi->visual, AllocNone ); m_data->m_swa.background_pixmap = None ; @@ -347,12 +554,12 @@ printf("createWindow\n"); ; m_data->m_root = RootWindow( m_data->m_dpy, m_data->m_vi->screen ); - m_data->m_win = XCreateWindow( m_data->m_dpy, m_data->m_root, + m_data->m_win = MyXCreateWindow( m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWBorderPixel|CWColormap|CWEventMask, &m_data->m_swa ); - //m_data->m_win = XCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); + //m_data->m_win = m_data->m_x11_XCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); if (!m_data->m_win) @@ -361,14 +568,16 @@ printf("createWindow\n"); exit(0); } - XMapWindow(m_data->m_dpy, m_data->m_win); - XStoreName(m_data->m_dpy, m_data->m_win, "OpenGL3 Window"); + MyXMapWindow(m_data->m_dpy, m_data->m_win); + MyXStoreName(m_data->m_dpy, m_data->m_win, "OpenGL3 Window"); } else { m_data->m_vi = glXChooseVisual(m_data->m_dpy, 0, att); + printf("4\n"); + if(m_data->m_vi == NULL) { printf("\n\tno appropriate visual found\n\n"); exit(0); @@ -378,16 +587,18 @@ printf("createWindow\n"); } - m_data->m_cmap = XCreateColormap(m_data->m_dpy, m_data->m_root, m_data->m_vi->visual, AllocNone); - + m_data->m_cmap = MyXCreateColormap(m_data->m_dpy, m_data->m_root, m_data->m_vi->visual, AllocNone); m_data->m_swa.colormap = m_data->m_cmap; m_data->m_swa.event_mask = ExposureMask | KeyReleaseMask | KeyPressMask |ButtonPressMask | ButtonReleaseMask |PointerMotionMask|StructureNotifyMask; + m_data->m_win = MyXCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); + + MyXMapWindow(m_data->m_dpy, m_data->m_win); + + MyXStoreName(m_data->m_dpy, m_data->m_win, "OpenGL2 Window"); - m_data->m_win = XCreateWindow(m_data->m_dpy, m_data->m_root, 0, 0, ci.m_width, ci.m_height, 0, m_data->m_vi->depth, InputOutput, m_data->m_vi->visual, CWColormap | CWEventMask, &m_data->m_swa); - XMapWindow(m_data->m_dpy, m_data->m_win); - XStoreName(m_data->m_dpy, m_data->m_win, "OpenGL3 Window"); } + enableOpenGL(); } @@ -395,15 +606,15 @@ void X11OpenGLWindow::closeWindow() { disableOpenGL(); - XDestroyWindow(m_data->m_dpy, m_data->m_win); - XCloseDisplay(m_data->m_dpy); + MyXDestroyWindow(m_data->m_dpy, m_data->m_win); + MyXCloseDisplay(m_data->m_dpy); } int X11OpenGLWindow::getAsciiCodeFromVirtualKeycode(int keycode) { KeySym key, key_lc, key_uc; - key = XKeycodeToKeysym( m_data->m_dpy, keycode, 0 ); + key = MyXKeycodeToKeysym( m_data->m_dpy, keycode, 0 ); switch( key ) { case XK_Escape: return B3G_ESCAPE; @@ -442,7 +653,7 @@ int X11OpenGLWindow::getAsciiCodeFromVirtualKeycode(int keycode) case XK_F15: return B3G_F15; default: // Make uppercase - XConvertCase( key, &key_lc, &key_uc ); + MyXConvertCase( key, &key_lc, &key_uc ); key = key_uc; // Valid ISO 8859-1 character? if( (key >= 32 && key <= 126) ||(key >= 160 && key <= 255) ) @@ -460,9 +671,9 @@ void X11OpenGLWindow::pumpMessage() int buttonState = 1; // Process all pending events - while( XPending( m_data->m_dpy ) ) + while( MyXPending( m_data->m_dpy ) ) { - XNextEvent(m_data->m_dpy, &m_data->m_xev); + MyXNextEvent(m_data->m_dpy, &m_data->m_xev); // printf("#"); // fflush(stdout); switch( m_data->m_xev.type ) @@ -491,19 +702,19 @@ void X11OpenGLWindow::pumpMessage() unsigned short is_retriggered = 0; ///filter out keyboard repeat //see http://stackoverflow.com/questions/2100654/ignore-auto-repeat-in-x11-applications - if (XEventsQueued(m_data->m_dpy, QueuedAfterReading)) + if (MyXEventsQueued(m_data->m_dpy, QueuedAfterReading)) { XEvent nev; - XPeekEvent(m_data->m_dpy, &nev); + MyXPeekEvent(m_data->m_dpy, &nev); if (nev.type == KeyPress && nev.xkey.time == m_data->m_xev.xkey.time && nev.xkey.keycode == m_data->m_xev.xkey.keycode) { fprintf (stdout, "key #%ld was retriggered.\n", - (long) XLookupKeysym (&nev.xkey, 0)); + (long) MyXLookupKeysym(&nev.xkey, 0)); // delete retriggered KeyPress event - XNextEvent (m_data->m_dpy, & m_data->m_xev); + MyXNextEvent(m_data->m_dpy, & m_data->m_xev); is_retriggered = 1; } } @@ -620,7 +831,7 @@ void X11OpenGLWindow::startRendering() { pumpMessage(); - XGetWindowAttributes(m_data->m_dpy, m_data->m_win, &m_data->m_gwa); + MyXGetWindowAttributes(m_data->m_dpy, m_data->m_win, &m_data->m_gwa); glViewport(0, 0, m_data->m_gwa.width, m_data->m_gwa.height); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //clear buffers @@ -667,7 +878,7 @@ void X11OpenGLWindow::setRenderCallback( b3RenderCallback renderCallback) void X11OpenGLWindow::setWindowTitle(const char* title) { - XStoreName(m_data->m_dpy, m_data->m_win, title); + MyXStoreName(m_data->m_dpy, m_data->m_win, title); } From 1054fd1992a8c4035d7a276a1d73e85c005cd33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 12 Jul 2014 13:50:12 +0300 Subject: [PATCH 089/116] Fix CMakeLists.txt to not unconditionally add include paths to native system headers in /usr/include and /usr/local/include, which contain include files for the host architecture, and not the target architecture that is being compiled for. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d9b5a4e5..b04f3f290 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -214,7 +214,7 @@ IF (USE_GLUT) ENDIF (GLUT_FOUND) ENDIF (MSVC) - IF(NOT WIN32 AND NOT APPLE) + IF(NOT WIN32 AND NOT APPLE AND NOT CMAKE_CROSSCOMPILING) # This is added for linux. This should always work if everything is installed and working fine. SET(GLUT_INCLUDE_DIR /usr/include /usr/local/include) ENDIF() From d347bca2bad80420869217282535fb4ff919e8b5 Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Sun, 20 Jul 2014 06:22:50 -0700 Subject: [PATCH 090/116] use lower-case input by default under Linux --- btgui/OpenGLWindow/X11OpenGLWindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/btgui/OpenGLWindow/X11OpenGLWindow.cpp b/btgui/OpenGLWindow/X11OpenGLWindow.cpp index 78e14c717..5b5b24bd0 100644 --- a/btgui/OpenGLWindow/X11OpenGLWindow.cpp +++ b/btgui/OpenGLWindow/X11OpenGLWindow.cpp @@ -652,9 +652,9 @@ int X11OpenGLWindow::getAsciiCodeFromVirtualKeycode(int keycode) case XK_F14: return B3G_F14; case XK_F15: return B3G_F15; default: - // Make uppercase + // Make lowercase MyXConvertCase( key, &key_lc, &key_uc ); - key = key_uc; + key = key_lc; // Valid ISO 8859-1 character? if( (key >= 32 && key <= 126) ||(key >= 160 && key <= 255) ) { From 4a43eab4dd9c22a45c2390f03afffa055b30f3ef Mon Sep 17 00:00:00 2001 From: Haydn Trigg Date: Sat, 26 Jul 2014 00:44:15 +0930 Subject: [PATCH 091/116] Update btQuickprof.h --- src/LinearMath/btQuickprof.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/LinearMath/btQuickprof.h b/src/LinearMath/btQuickprof.h index 93f3f4a60..362f62d6d 100644 --- a/src/LinearMath/btQuickprof.h +++ b/src/LinearMath/btQuickprof.h @@ -52,6 +52,11 @@ public: /// Returns the time in us since the last call to reset or since /// the Clock was created. unsigned long int getTimeMicroseconds(); + + /// Returns the time in s since the last call to reset or since + /// the Clock was created. + btScalar getTimeSeconds(); + private: struct btClockData* m_data; }; From 6ff7a6d48b81e4954b4de0aa8170f383d1175676 Mon Sep 17 00:00:00 2001 From: Haydn Trigg Date: Sat, 26 Jul 2014 00:44:16 +0930 Subject: [PATCH 092/116] Update btQuickprof.cpp --- src/LinearMath/btQuickprof.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/LinearMath/btQuickprof.cpp b/src/LinearMath/btQuickprof.cpp index 44e212f31..cbf28faa6 100644 --- a/src/LinearMath/btQuickprof.cpp +++ b/src/LinearMath/btQuickprof.cpp @@ -237,6 +237,14 @@ unsigned long int btClock::getTimeMicroseconds() +/// Returns the time in s since the last call to reset or since +/// the Clock was created. +inline btScalar btClock::getTimeSeconds() +{ + static const btScalar microseconds_to_seconds = btScalar(0.000001); + return btScalar(getTimeMicroseconds()) * microseconds_to_seconds; +} + inline void Profile_Get_Ticks(unsigned long int * ticks) From 5e9102bf0037c0484bcc27317603ce3140b4b01f Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Sun, 27 Jul 2014 10:25:36 -0700 Subject: [PATCH 093/116] fix warnings in OpenGLTrueTypeFont --- btgui/OpenGLTrueTypeFont/fontstash.cpp | 2 +- btgui/OpenGLTrueTypeFont/stb_truetype.h | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/btgui/OpenGLTrueTypeFont/fontstash.cpp b/btgui/OpenGLTrueTypeFont/fontstash.cpp index 803e155e1..8a2bf3de8 100644 --- a/btgui/OpenGLTrueTypeFont/fontstash.cpp +++ b/btgui/OpenGLTrueTypeFont/fontstash.cpp @@ -353,7 +353,7 @@ static struct sth_glyph* get_glyph(struct sth_stash* stash, struct sth_font* fnt float scale; struct sth_texture* texture = NULL; struct sth_glyph* glyph = NULL; - unsigned char* bmp = NULL; + unsigned int h; float size = isize/10.0f; int rh; diff --git a/btgui/OpenGLTrueTypeFont/stb_truetype.h b/btgui/OpenGLTrueTypeFont/stb_truetype.h index c02c578d6..1d1e55d64 100644 --- a/btgui/OpenGLTrueTypeFont/stb_truetype.h +++ b/btgui/OpenGLTrueTypeFont/stb_truetype.h @@ -813,7 +813,7 @@ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - stbtt_uint16 item, offset, start, end; + stbtt_uint16 item, offset, start; // do a binary search of the segments stbtt_uint32 endCount = index_map + 14; @@ -830,11 +830,8 @@ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) // now decrement to bias correctly to find smallest search -= 2; while (entrySelector) { - stbtt_uint16 start, end; + stbtt_uint16 end; searchRange >>= 1; - start = ttUSHORT(data + search + 2 + segcount*2 + 2); - end = ttUSHORT(data + search + 2); - start = ttUSHORT(data + search + searchRange*2 + segcount*2 + 2); end = ttUSHORT(data + search + searchRange*2); if (unicode_codepoint > end) search += searchRange*2; @@ -846,7 +843,7 @@ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - end = ttUSHORT(data + index_map + 14 + 2 + 2*item); + if (unicode_codepoint < start) return 0; @@ -858,7 +855,7 @@ int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) } else if (format == 12 || format == 13) { stbtt_uint32 ngroups = ttULONG(data+index_map+12); stbtt_int32 low,high; - stbtt_uint16 g = 0; + //stbtt_uint16 g = 0; low = 0; high = (stbtt_int32)ngroups; // Binary search the right group. while (low < high) { @@ -966,7 +963,7 @@ int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_verte if (numberOfContours > 0) { stbtt_uint8 flags=0,flagcount; - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0, curve_end=0; + stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0; stbtt_int32 x,y,cx,cy,sx,sy, scx,scy; scx=0; scy=0; From 0b40e1a899307aeec574eff668c42c6fb5823525 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Sun, 27 Jul 2014 10:29:10 -0700 Subject: [PATCH 094/116] add upAxis option for Y or Z up remove some warnings --- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 341 ++++++++---------- btgui/OpenGLWindow/GLInstancingRenderer.h | 2 +- btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h | 10 +- .../Shaders/useShadowMapInstancingVS.glsl | 8 +- .../Shaders/useShadowMapInstancingVS.h | 8 +- btgui/OpenGLWindow/ShapeData.h | 3 +- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 123 +++++-- btgui/OpenGLWindow/SimpleOpenGL3App.h | 2 +- btgui/OpenGLWindow/X11OpenGLWindow.cpp | 11 +- btgui/OpenGLWindow/premake4.lua | 1 - 10 files changed, 255 insertions(+), 254 deletions(-) diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index d8789ff08..8d2e05a4f 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -18,7 +18,7 @@ subject to the following restrictions: bool useShadowMap=true;//false;//true; float shadowMapWidth=8192; float shadowMapHeight=8192; -float shadowMapWorldSize=200; +float shadowMapWorldSize=100; float WHEEL_MULTIPLIER=0.01f; float MOUSE_MOVE_MULTIPLIER = 0.4f; #define MAX_POINTS_IN_BATCH 1024 @@ -68,6 +68,7 @@ float MOUSE_MOVE_MULTIPLIER = 0.4f; static InternalDataRenderer* sData2; GLint lineWidthRange[2]={1,1}; +static b3Vector3 gLightPos=b3MakeVector3(-5,200,-40); struct b3GraphicsInstance { @@ -84,7 +85,16 @@ struct b3GraphicsInstance int m_vertexArrayOffset; int m_primitiveType; - b3GraphicsInstance() :m_cube_vao(-1),m_index_vbo(-1),m_numIndices(-1),m_numVertices(-1),m_numGraphicsInstances(0),m_instanceOffset(0),m_vertexArrayOffset(0),m_primitiveType(B3_GL_TRIANGLES),m_texturehandle(0) + b3GraphicsInstance() + :m_cube_vao(-1), + m_index_vbo(-1), + m_texturehandle(0), + m_numIndices(-1), + m_numVertices(-1), + m_numGraphicsInstances(0), + m_instanceOffset(0), + m_vertexArrayOffset(0), + m_primitiveType(B3_GL_TRIANGLES) { } @@ -98,7 +108,7 @@ bool m_ortho = false; static GLfloat projectionMatrix[16]; static GLfloat modelviewMatrix[16]; -static GLfloat depthLightModelviewMatrix[16]; +//static GLfloat depthLightModelviewMatrix[16]; static void checkError(const char *functionName) { @@ -141,14 +151,15 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData int m_rightMouseButton; - int m_altPressed; - int m_controlPressed; + GLuint m_defaultTexturehandle; b3AlignedObjectArray m_textureHandles; GLRenderToTexture* m_shadowMap; GLuint m_shadowTexture; + int m_altPressed; + int m_controlPressed; InternalDataRenderer() : m_cameraPosition(b3MakeVector3(0,0,0)), @@ -317,7 +328,7 @@ static GLuint instancingShaderPointSprite; // The point spr -static bool done = false; +//static bool done = false; static GLint lines_ModelViewMatrix=0; static GLint lines_ProjectionMatrix=0; @@ -334,6 +345,7 @@ GLuint linesIndexVbo = 0; static GLint useShadow_ModelViewMatrix=0; static GLint useShadow_MVP=0; +static GLint useShadow_lightDirIn=0; static GLint useShadow_ProjectionMatrix=0; static GLint useShadow_DepthBiasModelViewMatrix=0; @@ -344,13 +356,13 @@ static GLint createShadow_depthMVP=0; static GLint ModelViewMatrix=0; static GLint ProjectionMatrix=0; -static GLint DepthModelViewMatrix=0; + static GLint uniform_texture_diffuse = 0; static GLint screenWidthPointSprite=0; static GLint ModelViewMatrixPointSprite=0; static GLint ProjectionMatrixPointSprite=0; -static GLint uniform_texture_diffusePointSprite= 0; +//static GLint uniform_texture_diffusePointSprite= 0; @@ -490,15 +502,15 @@ void GLInstancingRenderer::writeSingleInstanceTransformToGPU(float* position, fl void GLInstancingRenderer::writeTransforms() { - GLint err = glGetError(); - b3Assert(err==GL_NO_ERROR); + + b3Assert(glGetError() ==GL_NO_ERROR); glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo); glFlush(); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); + char* orgBase = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE); if (orgBase) @@ -568,8 +580,7 @@ void GLInstancingRenderer::writeTransforms() { b3Error("ERROR glMapBuffer failed\n"); } - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); glUnmapBuffer( GL_ARRAY_BUFFER); //if this glFinish is removed, the animation is not always working/blocks @@ -577,17 +588,16 @@ void GLInstancingRenderer::writeTransforms() glFlush(); glBindBuffer(GL_ARRAY_BUFFER, 0);//m_data->m_vbo); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); } int GLInstancingRenderer::registerGraphicsInstance(int shapeIndex, const double* pos1, const double* orn1, const double* color1, const double* scaling1) { - float pos[4] = {pos1[0],pos1[1],pos1[2],pos1[3]}; - float orn[4] = {orn1[0],orn1[1],orn1[2],orn1[3]}; - float color[4] = {color1[0],color1[1],color1[2],color1[3]}; - float scaling[4] = {scaling1[0],scaling1[1],scaling1[2],scaling1[3]}; + float pos[4] = {(float)pos1[0],(float)pos1[1],(float)pos1[2],(float)pos1[3]}; + float orn[4] = {(float)orn1[0],(float)orn1[1],(float)orn1[2],(float)orn1[3]}; + float color[4] = {(float)color1[0],(float)color1[1],(float)color1[2],(float)color1[3]}; + float scaling[4] = {(float)scaling1[0],(float)scaling1[1],(float)scaling1[2],(float)scaling1[3]}; return registerGraphicsInstance(shapeIndex,pos,orn,color,scaling); } @@ -635,8 +645,7 @@ int GLInstancingRenderer::registerGraphicsInstance(int shapeIndex, const float* int GLInstancingRenderer::registerTexture(const unsigned char* texels, int width, int height) { - GLint err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); int textureIndex = m_data->m_textureHandles.size(); const GLubyte* image= (const GLubyte*)texels; @@ -644,19 +653,15 @@ int GLInstancingRenderer::registerTexture(const unsigned char* texels, int width glGenTextures(1,(GLuint*)&textureHandle); glBindTexture(GL_TEXTURE_2D,textureHandle); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width,height,0,GL_RGB,GL_UNSIGNED_BYTE,image); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); glGenerateMipmap(GL_TEXTURE_2D); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); m_data->m_textureHandles.push_back(textureHandle); @@ -706,8 +711,10 @@ int GLInstancingRenderer::registerShape(const float* vertices, int numvertices, char* dest= (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_WRITE_ONLY);//GL_WRITE_ONLY int vertexStrideInBytes = 9*sizeof(float); int sz = numvertices*vertexStrideInBytes; +#ifdef B3_DEBUG int totalUsed = vertexStrideInBytes*gfxObj->m_vertexArrayOffset+sz; b3Assert(totalUsedm_maxShapeCapacityInBytes); +#endif//B3_DEBUG memcpy(dest+vertexStrideInBytes*gfxObj->m_vertexArrayOffset,vertices,sz); glUnmapBuffer( GL_ARRAY_BUFFER); @@ -796,7 +803,7 @@ void GLInstancingRenderer::InitShaders() useShadow_DepthBiasModelViewMatrix = glGetUniformLocation(useShadowMapInstancingShader, "DepthBiasModelViewProjectionMatrix"); useShadow_uniform_texture_diffuse = glGetUniformLocation(useShadowMapInstancingShader, "Diffuse"); useShadow_shadowMap = glGetUniformLocation(useShadowMapInstancingShader,"shadowMap"); - + useShadow_lightDirIn = glGetUniformLocation(useShadowMapInstancingShader,"lightDirIn"); createShadowMapInstancingShader = gltLoadShaderPair(createShadowMapInstancingVertexShader,createShadowMapInstancingFragmentShader); glLinkProgram(createShadowMapInstancingShader); @@ -847,26 +854,20 @@ void GLInstancingRenderer::InitShaders() void GLInstancingRenderer::init() { - GLint err = glGetError(); - b3Assert(err==GL_NO_ERROR); - - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); + glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); // glClearColor(float(0.),float(0.),float(0.4),float(0)); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); { B3_PROFILE("texture"); @@ -910,63 +911,32 @@ void GLInstancingRenderer::init() glGenTextures(1,(GLuint*)&m_data->m_defaultTexturehandle); glBindTexture(GL_TEXTURE_2D,m_data->m_defaultTexturehandle); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - #if 0 - - glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - - glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - - - #endif - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256,256,0,GL_RGB,GL_UNSIGNED_BYTE,image); glGenerateMipmap(GL_TEXTURE_2D); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); delete[] image; m_textureinitialized=true; } - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); glBindTexture(GL_TEXTURE_2D,m_data->m_defaultTexturehandle); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); } else { glDisable(GL_TEXTURE_2D); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); } } //glEnable(GL_COLOR_MATERIAL); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); // glEnable(GL_CULL_FACE); // glCullFace(GL_BACK); @@ -1086,14 +1056,28 @@ void GLInstancingRenderer::resize(int width, int height) m_screenHeight = height; } -void GLInstancingRenderer::updateCamera() +void GLInstancingRenderer::updateCamera(int upAxis) { - GLint err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); - - int m_forwardAxis(2); + int m_forwardAxis(-1); + switch (upAxis) + { + case 1: + m_forwardAxis = 2; + m_data->m_cameraUp = b3MakeVector3(0,1,0); + gLightPos = b3MakeVector3(-50.f,100,30); + break; + case 2: + m_forwardAxis = 1; + m_data->m_cameraUp = b3MakeVector3(0,0,1); + gLightPos = b3MakeVector3(-50.f,30,100); + break; + default: + b3Assert(0); + }; + float m_frustumZNear=1; float m_frustumZFar=10000.f; @@ -1106,8 +1090,7 @@ void GLInstancingRenderer::updateCamera() b3Quaternion rot(m_data->m_cameraUp,razi); - - b3Vector3 eyePos = b3MakeVector3(0,0,0); + b3Vector3 eyePos = b3MakeVector3(0,0,0); eyePos[m_forwardAxis] = -m_data->m_cameraDistance; b3Vector3 forward = b3MakeVector3(eyePos[0],eyePos[1],eyePos[2]); @@ -1256,19 +1239,15 @@ void GLInstancingRenderer::getMouseDirection(float* dir, int x, int y) #include "OpenGLTrueTypeFont/stb_image_write.h" void writeTextureToPng(int textureWidth, int textureHeight, const char* fileName, int numComponents) { - GLuint err; - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - + + b3Assert(glGetError() ==GL_NO_ERROR); glPixelStorei(GL_PACK_ALIGNMENT,4); glReadBuffer(GL_NONE); float* orgPixels = (float*)malloc(textureWidth*textureHeight*numComponents*4); char* pixels = (char*)malloc(textureWidth*textureHeight*numComponents*4); glReadPixels(0,0,textureWidth, textureHeight, GL_DEPTH_COMPONENT, GL_FLOAT, orgPixels); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - + b3Assert(glGetError() ==GL_NO_ERROR); for (int j=0;jm_vbo); - GLint err = glGetError(); - b3Assert(err==GL_NO_ERROR); - + b3Assert(glGetError() ==GL_NO_ERROR); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0); - int curOffset = 0; - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - glUseProgram(linesShader); + + b3Assert(glGetError() ==GL_NO_ERROR);glUseProgram(linesShader); glUniformMatrix4fv(lines_ProjectionMatrix, 1, false, &projectionMatrix[0]); glUniformMatrix4fv(lines_ModelViewMatrix, 1, false, &modelviewMatrix[0]); glUniform4f(lines_colour,color[0],color[1],color[2],color[3]); @@ -1412,9 +1385,7 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 // glPointSize(pointDrawSize); glBindVertexArray(linesVertexArrayObject); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - + b3Assert(glGetError() ==GL_NO_ERROR); glBindBuffer(GL_ARRAY_BUFFER, linesVertexBufferObject); { @@ -1422,21 +1393,15 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 glBufferData(GL_ARRAY_BUFFER, numPoints*pointStrideInBytes, 0,GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, numPoints*pointStrideInBytes, positions); - err = glGetError(); - b3Assert(err == GL_NO_ERROR); - + b3Assert(glGetError() ==GL_NO_ERROR); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, linesVertexBufferObject); glEnableVertexAttribArray(0); - err = glGetError(); - b3Assert(err == GL_NO_ERROR); - + b3Assert(glGetError() ==GL_NO_ERROR); int numFloats = pointStrideInBytes / sizeof(float); glVertexAttribPointer(0, numFloats, GL_FLOAT, GL_FALSE, 0, 0); - err = glGetError(); - b3Assert(err == GL_NO_ERROR); - + b3Assert(glGetError() ==GL_NO_ERROR); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, linesIndexVbo); int indexBufferSizeInBytes = numIndices*sizeof(int); @@ -1451,68 +1416,54 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 glBindBuffer(GL_ARRAY_BUFFER, 0); // for (int i=0;i draw only front-facing triangles - GLint err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); } else { glDisable(GL_CULL_FACE); //glCullFace(GL_BACK); } - static b3Vector3 lightPos = b3MakeVector3(-5.f,200,-40);//20,15,10);//-13,6,2);// = b3Vector3(0.5f,2,2); -// lightPos.y+=0.1f; + b3CreateOrtho(-shadowMapWorldSize,shadowMapWorldSize,-shadowMapWorldSize,shadowMapWorldSize,1,300,depthProjectionMatrix);//-14,14,-14,14,1,200, depthProjectionMatrix); float depthViewMatrix[4][4]; b3Vector3 center = b3MakeVector3(0,0,0); b3Vector3 up =b3MakeVector3(0,1,0); - b3CreateLookAt(lightPos,center,up,&depthViewMatrix[0][0]); + b3CreateLookAt(gLightPos,center,up,&depthViewMatrix[0][0]); //b3CreateLookAt(lightPos,m_data->m_cameraTargetPosition,b3Vector3(0,1,0),(float*)depthModelViewMatrix2); GLfloat depthModelMatrix[4][4]; @@ -1669,12 +1625,10 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) { B3_PROFILE("updateCamera"); - updateCamera(); + // updateCamera(); } - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - +b3Assert(glGetError() ==GL_NO_ERROR); // glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -1684,9 +1638,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo); glFlush(); } - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - +b3Assert(glGetError() ==GL_NO_ERROR); int totalNumInstances = 0; @@ -1696,7 +1648,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) } int curOffset = 0; - GLuint lastBindTexture = 0; + //GLuint lastBindTexture = 0; for (int i=0;im_defaultTexturehandle; +//disable lazy evaluation, it just leads to bugs //if (lastBindTexture != curBindTexture) { glBindTexture(GL_TEXTURE_2D,curBindTexture); } - lastBindTexture = curBindTexture; + //lastBindTexture = curBindTexture; - err = glGetError(); - b3Assert(err==GL_NO_ERROR); +b3Assert(glGetError() ==GL_NO_ERROR); // int myOffset = gfxObj->m_instanceOffset*4*sizeof(float); int POSITION_BUFFER_SIZE = (totalNumInstances*sizeof(float)*4); @@ -1731,16 +1683,22 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) int vertexStride = 9*sizeof(float); - int vertexBase = gfxObj->m_vertexArrayOffset*vertexStride; + PointerCaster vertex; + vertex.m_baseIndex = gfxObj->m_vertexArrayOffset*vertexStride; + - glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid*)vertexBase); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), vertex.m_pointer); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+m_maxShapeCapacityInBytes)); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+m_maxShapeCapacityInBytes+POSITION_BUFFER_SIZE)); - int uvoffset = 7*sizeof(float)+vertexBase; - int normaloffset = 4*sizeof(float)+vertexBase; + + PointerCaster uv; + uv.m_baseIndex = 7*sizeof(float)+vertex.m_baseIndex; - glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)uvoffset); - glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), (GLvoid *)normaloffset); + PointerCaster normal; + normal.m_baseIndex = 4*sizeof(float)+vertex.m_baseIndex; + + glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, 9*sizeof(float), uv.m_pointer); + glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 9*sizeof(float), normal.m_pointer); glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+m_maxShapeCapacityInBytes+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE)); glVertexAttribPointer(6, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*3*sizeof(float)+m_maxShapeCapacityInBytes+POSITION_BUFFER_SIZE+ORIENTATION_BUFFER_SIZE+COLOR_BUFFER_SIZE)); @@ -1765,7 +1723,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) int indexCount = gfxObj->m_numIndices; - int indexOffset = 0; + GLvoid* indexOffset = 0; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gfxObj->m_index_vbo); { @@ -1779,9 +1737,8 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) glUniform1f(screenWidthPointSprite,m_screenWidth); //glUniform1i(uniform_texture_diffusePointSprite, 0); - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - glPointSize(20); + b3Assert(glGetError() ==GL_NO_ERROR); + glPointSize(20); #ifndef __APPLE__ glEnable(GL_POINT_SPRITE_ARB); @@ -1789,7 +1746,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) #endif glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - glDrawElementsInstanced(GL_POINTS, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); + glDrawElementsInstanced(GL_POINTS, indexCount, GL_UNSIGNED_INT, indexOffset, gfxObj->m_numGraphicsInstances); } else { switch (renderMode) @@ -1801,7 +1758,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) glUniformMatrix4fv(ProjectionMatrix, 1, false, &projectionMatrix[0]); glUniformMatrix4fv(ModelViewMatrix, 1, false, &modelviewMatrix[0]); glUniform1i(uniform_texture_diffuse, 0); - glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); + glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, indexOffset, gfxObj->m_numGraphicsInstances); break; } case B3_CREATE_SHADOWMAP_RENDERMODE: @@ -1814,7 +1771,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) */ glUseProgram(createShadowMapInstancingShader); glUniformMatrix4fv(createShadow_depthMVP, 1, false, &depthMVP[0][0]); - glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); + glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, indexOffset, gfxObj->m_numGraphicsInstances); break; } @@ -1826,11 +1783,14 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) float MVP[16]; b3Matrix4x4Mul16(projectionMatrix,modelviewMatrix,MVP); glUniformMatrix4fv(useShadow_MVP, 1, false, &MVP[0]); + b3Vector3 gLightDir = gLightPos; + gLightDir.normalize(); + glUniform3f(useShadow_lightDirIn,gLightDir[0],gLightDir[1],gLightDir[2]); glUniformMatrix4fv(useShadow_DepthBiasModelViewMatrix, 1, false, &depthBiasMVP[0][0]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, m_data->m_shadowTexture); glUniform1i(useShadow_shadowMap,1); - glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, (void*)indexOffset, gfxObj->m_numGraphicsInstances); + glDrawElementsInstanced(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, indexOffset, gfxObj->m_numGraphicsInstances); break; } default: @@ -1859,8 +1819,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) } - err = glGetError(); - b3Assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); { B3_PROFILE("glUseProgram(0);"); glUseProgram(0); @@ -1871,9 +1830,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - + b3Assert(glGetError() ==GL_NO_ERROR); } diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.h b/btgui/OpenGLWindow/GLInstancingRenderer.h index f5faeea03..4c8ac49af 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.h +++ b/btgui/OpenGLWindow/GLInstancingRenderer.h @@ -110,7 +110,7 @@ public: void drawLines(const float* positions, const float color[4], int numPoints, int pointStrideInBytes, const unsigned int* indices, int numIndices, float pointDrawSize); void drawPoints(const float* positions, const float color[4], int numPoints, int pointStrideInBytes, float pointDrawSize); void drawPoint(const float* position, const float color[4], float pointSize=1); - void updateCamera(); + void updateCamera(int upAxis=1); void getCameraPosition(float cameraPos[4]); void getCameraPosition(double cameraPos[4]) diff --git a/btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h b/btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h index 4dcb12d12..cb3f06e20 100644 --- a/btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h +++ b/btgui/OpenGLWindow/GwenOpenGL3CoreRenderer.h @@ -208,8 +208,8 @@ public: // //printf("str = %s\n",unicodeText); - int xpos=0; - int ypos=0; + //int xpos=0; + //int ypos=0; float dx; int measureOnly=0; @@ -232,7 +232,7 @@ public: { //float width = 0.f; int pos=0; - float color[]={0.2f,0.2,0.2f,1.f}; + //float color[]={0.2f,0.2,0.2f,1.f}; glBindTexture(GL_TEXTURE_2D,m_fontTextureId); float width = r.x; @@ -299,7 +299,7 @@ public: int pos=0; while (unicodeText[pos]) { - width += m_currentFont->m_CharWidth[unicodeText[pos]]+extraSpacing; + width += m_currentFont->m_CharWidth[(int)unicodeText[pos]]+extraSpacing; pos++; } Gwen::Point pt; @@ -318,4 +318,4 @@ public: }; -#endif //__GWEN_OPENGL3_CORE_RENDERER_H \ No newline at end of file +#endif //__GWEN_OPENGL3_CORE_RENDERER_H diff --git a/btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl b/btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl index 7d175fb57..fe16aaf4c 100644 --- a/btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl +++ b/btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.glsl @@ -15,6 +15,7 @@ uniform mat4 ModelViewMatrix; uniform mat4 ProjectionMatrix; uniform mat4 DepthBiasModelViewProjectionMatrix; uniform mat4 MVP; +uniform vec3 lightDirIn; out vec4 ShadowCoord; @@ -65,13 +66,12 @@ void main(void) { vec4 q = instance_quaternion; ambient = vec3(0.3,.3,0.3); - - + vec4 worldNormal = (quatRotate3( vertexnormal,q)); - vec3 light_pos = vec3(-5.f,100,-40); + normal = normalize(worldNormal).xyz; - lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz)); + lightDir = lightDirIn; vec4 axis = vec4(1,1,1,0); vec4 localcoord = quatRotate3( position.xyz*instance_scale,q); diff --git a/btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.h b/btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.h index f8ed25a2d..8c2ee8765 100644 --- a/btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.h +++ b/btgui/OpenGLWindow/Shaders/useShadowMapInstancingVS.h @@ -13,6 +13,7 @@ static const char* useShadowMapInstancingVertexShader= \ "uniform mat4 ProjectionMatrix;\n" "uniform mat4 DepthBiasModelViewProjectionMatrix;\n" "uniform mat4 MVP;\n" +"uniform vec3 lightDirIn;\n" "out vec4 ShadowCoord;\n" "out Fragment\n" "{\n" @@ -55,12 +56,11 @@ static const char* useShadowMapInstancingVertexShader= \ "{\n" " vec4 q = instance_quaternion;\n" " ambient = vec3(0.3,.3,0.3);\n" -" \n" -" \n" +" \n" " vec4 worldNormal = (quatRotate3( vertexnormal,q));\n" -" vec3 light_pos = vec3(-5.f,100,-40);\n" +" \n" " normal = normalize(worldNormal).xyz;\n" -" lightDir = normalize(light_pos);//gl_LightSource[0].position.xyz));\n" +" lightDir = lightDirIn;\n" " \n" " vec4 axis = vec4(1,1,1,0);\n" " vec4 localcoord = quatRotate3( position.xyz*instance_scale,q);\n" diff --git a/btgui/OpenGLWindow/ShapeData.h b/btgui/OpenGLWindow/ShapeData.h index 1325fbf2b..337345e6b 100644 --- a/btgui/OpenGLWindow/ShapeData.h +++ b/btgui/OpenGLWindow/ShapeData.h @@ -1,6 +1,7 @@ #ifndef SHAPE_DATA_H #define SHAPE_DATA_H +#if USE_BARREL_VERTICES static float barrel_vertices[] = { 0.0f,-0.5f,0.0f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, 0.282362f,-0.5f,-0.205148f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, @@ -125,7 +126,7 @@ static int barrel_indices[] = { 44,47,56, 44,26,47, }; - +#endif //USE_BARREL_VERTICES ///position xyz, unused w, normal, uv static const float cube_vertices[] = diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index 2be04937b..ace8275fb 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -4,7 +4,8 @@ #include "OpenGLWindow/MacOpenGLWindow.h" #else -#include "GL/glew.h" +#include "OpenGLWindow/GlewWindows/GL/glew.h" +//#include "GL/glew.h" #ifdef _WIN32 #include "OpenGLWindow/Win32OpenGLWindow.h" #else @@ -19,8 +20,8 @@ #include "Bullet3Common/b3Vector3.h" #include "Bullet3Common/b3Logging.h" -#include "../btgui/OpenGLTrueTypeFont/fontstash.h" -#include "../btgui/OpenGLWindow/TwFonts.h" +#include "OpenGLTrueTypeFont/fontstash.h" +#include "OpenGLWindow/TwFonts.h" #include "OpenGLTrueTypeFont/opengl_fontstashcallbacks.h" #include @@ -78,13 +79,11 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) m_window->setWindowTitle(title); - GLuint err = glGetError(); - assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); glClearColor(1,1,1,1); m_window->startRendering(); - err = glGetError(); - assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); #ifndef __APPLE__ #ifndef _WIN32 @@ -92,28 +91,26 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) glewExperimental = GL_TRUE; #endif - err = glewInit(); - if (err != GLEW_OK) + + if (glewInit() != GLEW_OK) exit(1); // or handle the error in a nicer way if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API. exit(1); // or handle the error in a nicer way #endif - err = glGetError(); - err = glGetError(); - assert(err==GL_NO_ERROR); + glGetError();//don't remove this call, it is needed for Ubuntu + + b3Assert(glGetError() ==GL_NO_ERROR); m_primRenderer = new GLPrimitiveRenderer(width,height); - err = glGetError(); - assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); m_instancingRenderer = new GLInstancingRenderer(128*1024,4*1024*1024); m_instancingRenderer->init(); m_instancingRenderer->resize(width,height); - err = glGetError(); - assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); m_instancingRenderer->InitShaders(); @@ -128,23 +125,19 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) { - GLint err; + - int datasize; - - float sx,sy,dx,dy,lh; - GLuint texture; + m_data->m_renderCallbacks = new OpenGL2RenderCallbacks(m_primRenderer); m_data->m_fontStash = sth_create(512,512,m_data->m_renderCallbacks);//256,256);//,1024);//512,512); - err = glGetError(); - assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); if (!m_data->m_fontStash) { b3Warning("Could not create stash"); //fprintf(stderr, "Could not create stash.\n"); } - int droidRegular=0; + char* data2 = OpenSansData; unsigned char* data = (unsigned char*) data2; @@ -152,8 +145,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) { b3Warning("error!\n"); } - err = glGetError(); - assert(err==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); } } @@ -176,7 +168,7 @@ void SimpleOpenGL3App::drawText( const char* txt, int posX, int posY) float dx=0; - int measureOnly=0; + //int measureOnly=0; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -196,12 +188,12 @@ void SimpleOpenGL3App::drawText( const char* txt, int posX, int posY) { //float width = 0.f; int pos=0; - float color[]={0.2f,0.2,0.2f,1.f}; + //float color[]={0.2f,0.2,0.2f,1.f}; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,m_data->m_fontTextureId); //float width = r.x; - float extraSpacing = 0.; + //float extraSpacing = 0.; int startX = posX; int startY = posY; @@ -310,24 +302,75 @@ int SimpleOpenGL3App::registerGraphicsSphereShape(float radius, bool usePointSpr return graphicsShapeIndex; } -void SimpleOpenGL3App::drawGrid(int gridSize, float yOffset) +void SimpleOpenGL3App::drawGrid(int gridSize, float upOffset, int upAxis) { - + int sideAxis=-1; + int forwardAxis=-1; + + switch (upAxis) + { + case 1: + forwardAxis=2; + sideAxis=0; + break; + case 2: + forwardAxis=1; + sideAxis=0; + break; + default: + b3Assert(0); + }; b3Vector3 gridColor = b3MakeVector3(0.5,0.5,0.5); + + b3AlignedObjectArray indices; + b3AlignedObjectArray vertices; + int lineIndex=0; for(int i=-gridSize;i<=gridSize;i++) { + { + b3Assert(glGetError() ==GL_NO_ERROR); + b3Vector3 from = b3MakeVector3(0,0,0); + from[sideAxis] = float(i); + from[upAxis] = upOffset; + from[forwardAxis] = float(-gridSize); + b3Vector3 to=b3MakeVector3(0,0,0); + to[sideAxis] = float(i); + to[upAxis] = upOffset; + to[forwardAxis] = float(gridSize); + vertices.push_back(from); + indices.push_back(lineIndex++); + vertices.push_back(to); + indices.push_back(lineIndex++); + m_instancingRenderer->drawLine(from,to,gridColor); + } - GLint err = glGetError(); - b3Assert(err==GL_NO_ERROR); - - m_instancingRenderer->drawLine(b3MakeVector3(float(i),yOffset,float(-gridSize)),b3MakeVector3(float(i),yOffset,float(gridSize)),gridColor); - - err = glGetError(); - b3Assert(err==GL_NO_ERROR); - - m_instancingRenderer->drawLine(b3MakeVector3(float(-gridSize),yOffset,float(i)),b3MakeVector3(float(gridSize),yOffset,float(i)),gridColor); + b3Assert(glGetError() ==GL_NO_ERROR); + { + + b3Assert(glGetError() ==GL_NO_ERROR); + b3Vector3 from=b3MakeVector3(0,0,0); + from[sideAxis] = float(-gridSize); + from[upAxis] = upOffset; + from[forwardAxis] = float(i); + b3Vector3 to=b3MakeVector3(0,0,0); + to[sideAxis] = float(gridSize); + to[upAxis] = upOffset; + to[forwardAxis] = float(i); + vertices.push_back(from); + indices.push_back(lineIndex++); + vertices.push_back(to); + indices.push_back(lineIndex++); + m_instancingRenderer->drawLine(from,to,gridColor); + } + } + + /*m_instancingRenderer->drawLines(&vertices[0].x, + gridColor, + vertices.size(),sizeof(b3Vector3),&indices[0],indices.size(),1); + */ + m_instancingRenderer->drawLine(b3MakeVector3(0,0,0),b3MakeVector3(1,0,0),b3MakeVector3(1,0,0),3); m_instancingRenderer->drawLine(b3MakeVector3(0,0,0),b3MakeVector3(0,1,0),b3MakeVector3(0,1,0),3); m_instancingRenderer->drawLine(b3MakeVector3(0,0,0),b3MakeVector3(0,0,1),b3MakeVector3(0,0,1),3); diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.h b/btgui/OpenGLWindow/SimpleOpenGL3App.h index 7bad61d70..4135dfa38 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.h +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.h @@ -19,7 +19,7 @@ struct SimpleOpenGL3App int registerCubeShape(float halfExtentsX=1.f,float halfExtentsY=1.f, float halfExtentsZ = 1.f); int registerGraphicsSphereShape(float radius, bool usePointSprites=true, int largeSphereThreshold=100, int mediumSphereThreshold=10); - void drawGrid(int gridSize=10, float yOffset=0.001); + void drawGrid(int gridSize=10, float upOffset=0.001, int upAxis=1); void swapBuffer(); void drawText( const char* txt, int posX, int posY); struct sth_stash* getFontStash(); diff --git a/btgui/OpenGLWindow/X11OpenGLWindow.cpp b/btgui/OpenGLWindow/X11OpenGLWindow.cpp index 78e14c717..64211f8de 100644 --- a/btgui/OpenGLWindow/X11OpenGLWindow.cpp +++ b/btgui/OpenGLWindow/X11OpenGLWindow.cpp @@ -530,9 +530,9 @@ if (res==0) // " SAMPLES = %d\n", // i, vi -> visualid, samp_buf, samples ); - if ( best_fbc < 0 || samp_buf && samples > best_num_samp ) + if ( best_fbc < 0 || (samp_buf && (samples > best_num_samp)) ) best_fbc = i, best_num_samp = samples; - if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) + if ( worst_fbc < 0 || (!samp_buf || (samples < worst_num_samp)) ) worst_fbc = i, worst_num_samp = samples; } MyXFree( vi ); @@ -652,9 +652,9 @@ int X11OpenGLWindow::getAsciiCodeFromVirtualKeycode(int keycode) case XK_F14: return B3G_F14; case XK_F15: return B3G_F15; default: - // Make uppercase + // Make lowercase MyXConvertCase( key, &key_lc, &key_uc ); - key = key_uc; + key = key_lc; // Valid ISO 8859-1 character? if( (key >= 32 && key <= 126) ||(key >= 160 && key <= 255) ) { @@ -698,7 +698,7 @@ void X11OpenGLWindow::pumpMessage() if (m_data->m_keyboardCallback) { - +#if 0 unsigned short is_retriggered = 0; ///filter out keyboard repeat //see http://stackoverflow.com/questions/2100654/ignore-auto-repeat-in-x11-applications @@ -718,6 +718,7 @@ void X11OpenGLWindow::pumpMessage() is_retriggered = 1; } } +#endif int keycode = getAsciiCodeFromVirtualKeycode( m_data->m_xev.xkey.keycode); int state = 0; (*m_data->m_keyboardCallback)(keycode,state); diff --git a/btgui/OpenGLWindow/premake4.lua b/btgui/OpenGLWindow/premake4.lua index e98cb5105..100379855 100644 --- a/btgui/OpenGLWindow/premake4.lua +++ b/btgui/OpenGLWindow/premake4.lua @@ -4,7 +4,6 @@ language "C++" kind "StaticLib" - targetdir "../../bin" initOpenGL() initGlew() From c487170196f04c1b1ff3e411f7fd5387a348bc9d Mon Sep 17 00:00:00 2001 From: = <=> Date: Sun, 27 Jul 2014 11:19:11 -0700 Subject: [PATCH 095/116] remove OpenGL/glu.h from gl3 headers (warning), replace some OpenGL definitions ARB/non-ARB --- Demos3/GpuDemos/softbody/GpuSoftBodyDemo.cpp | 4 +++- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 25 +++++++++++++------- btgui/OpenGLWindow/OpenGLInclude.h | 2 +- btgui/OpenGLWindow/ShapeData.h | 2 +- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 4 ++-- src/Bullet3Common/premake4.lua | 4 +--- 6 files changed, 24 insertions(+), 17 deletions(-) diff --git a/Demos3/GpuDemos/softbody/GpuSoftBodyDemo.cpp b/Demos3/GpuDemos/softbody/GpuSoftBodyDemo.cpp index cd15924fc..3eb54ceaf 100644 --- a/Demos3/GpuDemos/softbody/GpuSoftBodyDemo.cpp +++ b/Demos3/GpuDemos/softbody/GpuSoftBodyDemo.cpp @@ -1,4 +1,6 @@ + #include "GpuSoftBodyDemo.h" +#define USE_BARREL_VERTICES #include "OpenGLWindow/ShapeData.h" #include "OpenGLWindow/GLInstancingRenderer.h" #include "Bullet3Common/b3Quaternion.h" @@ -414,4 +416,4 @@ void GpuSoftClothDemo::setupScene(const ConstructionInfo& ci) err = glGetError(); assert(err==GL_NO_ERROR); -} \ No newline at end of file +} diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index 8d2e05a4f..270747198 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -29,10 +29,17 @@ float MOUSE_MOVE_MULTIPLIER = 0.4f; #include "b3gWindowInterface.h" #include "Bullet3Common/b3MinMax.h" +#ifndef __APPLE__ +#ifndef glVertexAttribDivisor +#define glVertexAttribDivisor glVertexAttribDivisorARB +#endif //glVertexAttribDivisor +#ifndef GL_COMPARE_REF_TO_TEXTURE +#define GL_COMPARE_REF_TO_TEXTURE GL_COMPARE_R_TO_TEXTURE +#endif //GL_COMPARE_REF_TO_TEXTURE #ifndef glDrawElementsInstanced #define glDrawElementsInstanced glDrawElementsInstancedARB #endif - +#endif //__APPLE__ #include "GLInstancingRenderer.h" #include @@ -1563,7 +1570,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); m_data->m_shadowMap=new GLRenderToTexture(); m_data->m_shadowMap->init(shadowMapWidth, shadowMapHeight,m_data->m_shadowTexture,RENDERTEXTURE_DEPTH); @@ -1709,13 +1716,13 @@ b3Assert(glGetError() ==GL_NO_ERROR); glEnableVertexAttribArray(4); glEnableVertexAttribArray(5); glEnableVertexAttribArray(6); - glVertexAttribDivisorARB(0, 0); - glVertexAttribDivisorARB(1, 1); - glVertexAttribDivisorARB(2, 1); - glVertexAttribDivisorARB(3, 0); - glVertexAttribDivisorARB(4, 0); - glVertexAttribDivisorARB(5, 1); - glVertexAttribDivisorARB(6, 1); + glVertexAttribDivisor(0, 0); + glVertexAttribDivisor(1, 1); + glVertexAttribDivisor(2, 1); + glVertexAttribDivisor(3, 0); + glVertexAttribDivisor(4, 0); + glVertexAttribDivisor(5, 1); + glVertexAttribDivisor(6, 1); diff --git a/btgui/OpenGLWindow/OpenGLInclude.h b/btgui/OpenGLWindow/OpenGLInclude.h index e01f20b05..19d4f3725 100644 --- a/btgui/OpenGLWindow/OpenGLInclude.h +++ b/btgui/OpenGLWindow/OpenGLInclude.h @@ -22,7 +22,7 @@ subject to the following restrictions: #if defined(__APPLE__) && !defined (VMDMESA) #include //#include -#include +//#include //#import #include #else diff --git a/btgui/OpenGLWindow/ShapeData.h b/btgui/OpenGLWindow/ShapeData.h index 337345e6b..f538f1e5f 100644 --- a/btgui/OpenGLWindow/ShapeData.h +++ b/btgui/OpenGLWindow/ShapeData.h @@ -1,7 +1,7 @@ #ifndef SHAPE_DATA_H #define SHAPE_DATA_H -#if USE_BARREL_VERTICES +#ifdef USE_BARREL_VERTICES static float barrel_vertices[] = { 0.0f,-0.5f,0.0f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, 0.282362f,-0.5f,-0.205148f, 1.0f, 0.0f,-1.0f,0.0f, 0.5f, 0.5f, diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index ace8275fb..d6a414430 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -20,8 +20,8 @@ #include "Bullet3Common/b3Vector3.h" #include "Bullet3Common/b3Logging.h" -#include "OpenGLTrueTypeFont/fontstash.h" -#include "OpenGLWindow/TwFonts.h" +#include "../btgui/OpenGLTrueTypeFont/fontstash.h" +#include "../btgui/OpenGLWindow/TwFonts.h" #include "OpenGLTrueTypeFont/opengl_fontstashcallbacks.h" #include diff --git a/src/Bullet3Common/premake4.lua b/src/Bullet3Common/premake4.lua index e5fbb5280..0430cdc2a 100644 --- a/src/Bullet3Common/premake4.lua +++ b/src/Bullet3Common/premake4.lua @@ -4,11 +4,9 @@ kind "StaticLib" - targetdir "../../bin" - includedirs {".."} files { "**.cpp", "**.h" - } \ No newline at end of file + } From cac50c1a8ef7fbd4c1184dbc3f4ddfae11006feb Mon Sep 17 00:00:00 2001 From: = <=> Date: Tue, 29 Jul 2014 11:08:09 -0700 Subject: [PATCH 096/116] remove a few warnings, fix GLInstancingRenderer::drawLines --- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 44 +++++++++---------- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 41 ++++++++++------- btgui/OpenGLWindow/SimpleOpenGL3App.h | 23 +++++++++- .../Featherstone/btMultiBody.cpp | 14 ++++++ .../Featherstone/btMultiBodyLink.h | 5 +++ 5 files changed, 87 insertions(+), 40 deletions(-) diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index 270747198..23a142f78 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -92,7 +92,7 @@ struct b3GraphicsInstance int m_vertexArrayOffset; int m_primitiveType; - b3GraphicsInstance() + b3GraphicsInstance() :m_cube_vao(-1), m_index_vbo(-1), m_texturehandle(0), @@ -158,7 +158,7 @@ struct InternalDataRenderer : public GLInstanceRendererInternalData int m_rightMouseButton; - + GLuint m_defaultTexturehandle; b3AlignedObjectArray m_textureHandles; @@ -509,7 +509,7 @@ void GLInstancingRenderer::writeSingleInstanceTransformToGPU(float* position, fl void GLInstancingRenderer::writeTransforms() { - + b3Assert(glGetError() ==GL_NO_ERROR); @@ -517,7 +517,7 @@ void GLInstancingRenderer::writeTransforms() glFlush(); b3Assert(glGetError() ==GL_NO_ERROR); - + char* orgBase = (char*)glMapBuffer( GL_ARRAY_BUFFER,GL_READ_WRITE); if (orgBase) @@ -661,7 +661,7 @@ int GLInstancingRenderer::registerTexture(const unsigned char* texels, int width glBindTexture(GL_TEXTURE_2D,textureHandle); b3Assert(glGetError() ==GL_NO_ERROR); - + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width,height,0,GL_RGB,GL_UNSIGNED_BYTE,image); @@ -863,7 +863,7 @@ void GLInstancingRenderer::init() { b3Assert(glGetError() ==GL_NO_ERROR); - + glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); @@ -919,7 +919,7 @@ void GLInstancingRenderer::init() glGenTextures(1,(GLuint*)&m_data->m_defaultTexturehandle); glBindTexture(GL_TEXTURE_2D,m_data->m_defaultTexturehandle); b3Assert(glGetError() ==GL_NO_ERROR); - + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256,256,0,GL_RGB,GL_UNSIGNED_BYTE,image); glGenerateMipmap(GL_TEXTURE_2D); @@ -1084,7 +1084,7 @@ void GLInstancingRenderer::updateCamera(int upAxis) default: b3Assert(0); }; - + float m_frustumZNear=1; float m_frustumZFar=10000.f; @@ -1246,7 +1246,7 @@ void GLInstancingRenderer::getMouseDirection(float* dir, int x, int y) #include "OpenGLTrueTypeFont/stb_image_write.h" void writeTextureToPng(int textureWidth, int textureHeight, const char* fileName, int numComponents) { - + b3Assert(glGetError() ==GL_NO_ERROR); glPixelStorei(GL_PACK_ALIGNMENT,4); @@ -1314,7 +1314,7 @@ void GLInstancingRenderer::renderScene() if (useShadowMap) { - + renderSceneInternal(B3_CREATE_SHADOWMAP_RENDERMODE); // glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); renderSceneInternal(B3_USE_SHADOWMAP_RENDERMODE); @@ -1335,7 +1335,7 @@ void GLInstancingRenderer::drawPoints(const float* positions, const float color[ glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0); - + b3Assert(glGetError() ==GL_NO_ERROR);glUseProgram(linesShader); glUniformMatrix4fv(lines_ProjectionMatrix, 1, false, &projectionMatrix[0]); glUniformMatrix4fv(lines_ModelViewMatrix, 1, false, &modelviewMatrix[0]); @@ -1383,7 +1383,7 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D,0); - + b3Assert(glGetError() ==GL_NO_ERROR);glUseProgram(linesShader); glUniformMatrix4fv(lines_ProjectionMatrix, 1, false, &projectionMatrix[0]); glUniformMatrix4fv(lines_ModelViewMatrix, 1, false, &modelviewMatrix[0]); @@ -1406,8 +1406,8 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 glEnableVertexAttribArray(0); b3Assert(glGetError() ==GL_NO_ERROR); - int numFloats = pointStrideInBytes / sizeof(float); - glVertexAttribPointer(0, numFloats, GL_FLOAT, GL_FALSE, 0, 0); + int numFloats = 3; + glVertexAttribPointer(0, numFloats, GL_FLOAT, GL_FALSE, pointStrideInBytes, 0); b3Assert(glGetError() ==GL_NO_ERROR); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, linesIndexVbo); @@ -1427,7 +1427,7 @@ void GLInstancingRenderer::drawLines(const float* positions, const float color[4 glBindVertexArray(0); b3Assert(glGetError() ==GL_NO_ERROR); glPointSize(1); -b3Assert(glGetError() ==GL_NO_ERROR); + b3Assert(glGetError() ==GL_NO_ERROR); } @@ -1439,7 +1439,7 @@ void GLInstancingRenderer::drawLine(const float from[4], const float to[4], cons glBindTexture(GL_TEXTURE_2D,0); b3Assert(glGetError() ==GL_NO_ERROR); - + glUseProgram(linesShader); @@ -1505,13 +1505,13 @@ struct PointerCaster int m_baseIndex; GLvoid* m_pointer; }; - + PointerCaster() :m_pointer(0) { } - - + + }; void GLInstancingRenderer::renderSceneInternal(int renderMode) { @@ -1593,7 +1593,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode) //glCullFace(GL_BACK); } - + b3CreateOrtho(-shadowMapWorldSize,shadowMapWorldSize,-shadowMapWorldSize,shadowMapWorldSize,1,300,depthProjectionMatrix);//-14,14,-14,14,1,200, depthProjectionMatrix); float depthViewMatrix[4][4]; b3Vector3 center = b3MakeVector3(0,0,0); @@ -1692,12 +1692,12 @@ b3Assert(glGetError() ==GL_NO_ERROR); int vertexStride = 9*sizeof(float); PointerCaster vertex; vertex.m_baseIndex = gfxObj->m_vertexArrayOffset*vertexStride; - + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 9*sizeof(float), vertex.m_pointer); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+m_maxShapeCapacityInBytes)); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, 0, (GLvoid *)(curOffset*4*sizeof(float)+m_maxShapeCapacityInBytes+POSITION_BUFFER_SIZE)); - + PointerCaster uv; uv.m_baseIndex = 7*sizeof(float)+vertex.m_baseIndex; diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index d6a414430..0033419e6 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -20,8 +20,8 @@ #include "Bullet3Common/b3Vector3.h" #include "Bullet3Common/b3Logging.h" -#include "../btgui/OpenGLTrueTypeFont/fontstash.h" -#include "../btgui/OpenGLWindow/TwFonts.h" +#include "OpenGLTrueTypeFont/fontstash.h" +#include "OpenGLWindow/TwFonts.h" #include "OpenGLTrueTypeFont/opengl_fontstashcallbacks.h" #include @@ -81,7 +81,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) b3Assert(glGetError() ==GL_NO_ERROR); - glClearColor(1,1,1,1); + glClearColor(0.9,0.9,1,1); m_window->startRendering(); b3Assert(glGetError() ==GL_NO_ERROR); @@ -91,7 +91,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) glewExperimental = GL_TRUE; #endif - + if (glewInit() != GLEW_OK) exit(1); // or handle the error in a nicer way if (!GLEW_VERSION_2_1) // check that the machine supports the 2.1 API. @@ -99,7 +99,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) #endif glGetError();//don't remove this call, it is needed for Ubuntu - + b3Assert(glGetError() ==GL_NO_ERROR); m_primRenderer = new GLPrimitiveRenderer(width,height); @@ -125,9 +125,9 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) { - - + + m_data->m_renderCallbacks = new OpenGL2RenderCallbacks(m_primRenderer); m_data->m_fontStash = sth_create(512,512,m_data->m_renderCallbacks);//256,256);//,1024);//512,512); b3Assert(glGetError() ==GL_NO_ERROR); @@ -137,7 +137,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) b3Warning("Could not create stash"); //fprintf(stderr, "Could not create stash.\n"); } - + char* data2 = OpenSansData; unsigned char* data = (unsigned char*) data2; @@ -302,11 +302,20 @@ int SimpleOpenGL3App::registerGraphicsSphereShape(float radius, bool usePointSpr return graphicsShapeIndex; } -void SimpleOpenGL3App::drawGrid(int gridSize, float upOffset, int upAxis) +void SimpleOpenGL3App::drawGrid(DrawGridData data) { + int gridSize = data.gridSize; + float upOffset = data.upOffset; + int upAxis = data.upAxis; + float gridColor[4]; + gridColor[0] = data.gridColor[0]; + gridColor[1] = data.gridColor[1]; + gridColor[2] = data.gridColor[2]; + gridColor[3] = data.gridColor[3]; + int sideAxis=-1; int forwardAxis=-1; - + switch (upAxis) { case 1: @@ -320,8 +329,8 @@ void SimpleOpenGL3App::drawGrid(int gridSize, float upOffset, int upAxis) default: b3Assert(0); }; - b3Vector3 gridColor = b3MakeVector3(0.5,0.5,0.5); - + //b3Vector3 gridColor = b3MakeVector3(0.5,0.5,0.5); + b3AlignedObjectArray indices; b3AlignedObjectArray vertices; int lineIndex=0; @@ -346,7 +355,7 @@ void SimpleOpenGL3App::drawGrid(int gridSize, float upOffset, int upAxis) b3Assert(glGetError() ==GL_NO_ERROR); { - + b3Assert(glGetError() ==GL_NO_ERROR); b3Vector3 from=b3MakeVector3(0,0,0); from[sideAxis] = float(-gridSize); @@ -360,12 +369,12 @@ void SimpleOpenGL3App::drawGrid(int gridSize, float upOffset, int upAxis) indices.push_back(lineIndex++); vertices.push_back(to); indices.push_back(lineIndex++); - m_instancingRenderer->drawLine(from,to,gridColor); + m_instancingRenderer->drawLine(from,to,gridColor); } - + } - + /*m_instancingRenderer->drawLines(&vertices[0].x, gridColor, vertices.size(),sizeof(b3Vector3),&indices[0],indices.size(),1); diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.h b/btgui/OpenGLWindow/SimpleOpenGL3App.h index 4135dfa38..0ebf8ed4b 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.h +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.h @@ -5,6 +5,25 @@ #include "OpenGLWindow/GLPrimitiveRenderer.h" #include "OpenGLWindow/b3gWindowInterface.h" +struct DrawGridData +{ + int gridSize; + float upOffset; + int upAxis; + float gridColor[4]; + + DrawGridData() + :gridSize(10), + upOffset(0.001f), + upAxis(1) + { + gridColor[0] = 0.6f; + gridColor[1] = 0.6f; + gridColor[2] = 0.6f; + gridColor[3] = 1.f; + } +}; + struct SimpleOpenGL3App { struct SimpleInternalData* m_data; @@ -15,11 +34,11 @@ struct SimpleOpenGL3App SimpleOpenGL3App(const char* title, int width,int height); virtual ~SimpleOpenGL3App(); - + int registerCubeShape(float halfExtentsX=1.f,float halfExtentsY=1.f, float halfExtentsZ = 1.f); int registerGraphicsSphereShape(float radius, bool usePointSprites=true, int largeSphereThreshold=100, int mediumSphereThreshold=10); - void drawGrid(int gridSize=10, float upOffset=0.001, int upAxis=1); + void drawGrid(DrawGridData data=DrawGridData()); void swapBuffer(); void drawText( const char* txt, int posX, int posY); struct sth_stash* getFontStash(); diff --git a/src/BulletDynamics/Featherstone/btMultiBody.cpp b/src/BulletDynamics/Featherstone/btMultiBody.cpp index c8812af44..fc12bfd6b 100644 --- a/src/BulletDynamics/Featherstone/btMultiBody.cpp +++ b/src/BulletDynamics/Featherstone/btMultiBody.cpp @@ -819,6 +819,9 @@ void btMultiBody::stepVelocitiesMultiDof(btScalar dt, break; } + default: + { + } } @@ -1329,6 +1332,10 @@ void btMultiBody::stepVelocitiesMultiDof(btScalar dt, break; } + default: + { + + } } //determine h*D^{-1} @@ -2589,6 +2596,10 @@ void btMultiBody::stepPositionsMultiDof(btScalar dt, btScalar *pq, btScalar *pqd break; } #endif + default: + { + } + } m_links[i].updateCacheMultiDof(pq); @@ -2709,6 +2720,9 @@ void btMultiBody::filConstraintJacobianMultiDof(int link, break; } #endif + default: + { + } } } diff --git a/src/BulletDynamics/Featherstone/btMultiBodyLink.h b/src/BulletDynamics/Featherstone/btMultiBodyLink.h index df96b3c41..9e90c6f48 100644 --- a/src/BulletDynamics/Featherstone/btMultiBodyLink.h +++ b/src/BulletDynamics/Featherstone/btMultiBodyLink.h @@ -507,6 +507,11 @@ struct btMultibodyLink break; } #endif + default: + { + //invalid type + btAssert(0); + } } } }; From fb01827aee5cc30720389998636f66a0b6b7616a Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 29 Jul 2014 14:03:15 -0700 Subject: [PATCH 097/116] expose debugDraw in gl3 --- Demos/CommonPhysicsSetup.h | 15 ++-- Demos/CommonRigidBodySetup.h | 58 ++++++++------- Demos3/AllBullet2Demos/BulletDemoInterface.h | 6 +- Demos3/AllBullet2Demos/main.cpp | 1 + .../BasicDemo/Bullet2RigidBodyDemo.cpp | 70 +++++++++++++------ .../bullet2/BasicDemo/Bullet2RigidBodyDemo.h | 5 +- Demos3/bullet2/BasicDemo/MyDebugDrawer.h | 68 ++++++++++++++++-- .../BulletMultiBodyDemos.cpp | 7 ++ .../BulletMultiBodyDemos.h | 2 + 9 files changed, 170 insertions(+), 62 deletions(-) diff --git a/Demos/CommonPhysicsSetup.h b/Demos/CommonPhysicsSetup.h index 6be944e2c..5b2828d76 100644 --- a/Demos/CommonPhysicsSetup.h +++ b/Demos/CommonPhysicsSetup.h @@ -21,6 +21,9 @@ struct GraphicsPhysicsBridge virtual void syncPhysicsToGraphics(const btDiscreteDynamicsWorld* rbWorld) { } + virtual void createPhysicsDebugDrawer( btDiscreteDynamicsWorld* rbWorld) + { + } }; struct CommonPhysicsSetup @@ -28,13 +31,15 @@ struct CommonPhysicsSetup public: virtual ~CommonPhysicsSetup() {} - + virtual void initPhysics(GraphicsPhysicsBridge& gfxBridge) = 0; - + virtual void exitPhysics()=0; - + virtual void stepSimulation(float deltaTime)=0; - + + virtual void debugDraw()=0; + virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) = 0; virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld)=0; virtual void removePickingConstraint() = 0; @@ -42,7 +47,7 @@ public: virtual void syncPhysicsToGraphics(GraphicsPhysicsBridge& gfxBridge) = 0; virtual btRigidBody* createRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape, const btVector4& color=btVector4(1,0,0,1))=0; - + virtual btBoxShape* createBoxShape(const btVector3& halfExtents)=0; }; diff --git a/Demos/CommonRigidBodySetup.h b/Demos/CommonRigidBodySetup.h index 3ba22cb6a..4d118162a 100644 --- a/Demos/CommonRigidBodySetup.h +++ b/Demos/CommonRigidBodySetup.h @@ -15,14 +15,14 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup btConstraintSolver* m_solver; btDefaultCollisionConfiguration* m_collisionConfiguration; btDiscreteDynamicsWorld* m_dynamicsWorld; - + //data for picking objects class btRigidBody* m_pickedBody; class btTypedConstraint* m_pickedConstraint; btVector3 m_oldPickingPos; btVector3 m_hitPos; btScalar m_oldPickingDist; - + CommonRigidBodySetup() :m_broadphase(0), m_dispatcher(0), @@ -33,35 +33,35 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup m_pickedConstraint(0) { } - + virtual void createEmptyDynamicsWorld() { ///collision configuration contains default setup for memory, collision setup m_collisionConfiguration = new btDefaultCollisionConfiguration(); //m_collisionConfiguration->setConvexConvexMultipointIterations(); - + ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); - + m_broadphase = new btDbvtBroadphase(); - + ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; m_solver = sol; - + m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration); - + m_dynamicsWorld->setGravity(btVector3(0, -10, 0)); } - - + + virtual void stepSimulation(float deltaTime) { if (m_dynamicsWorld) { m_dynamicsWorld->stepSimulation(deltaTime); } - } + } virtual void exitPhysics() @@ -97,18 +97,18 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup delete shape; } m_collisionShapes.clear(); - + delete m_dynamicsWorld; - + delete m_solver; - + delete m_broadphase; - + delete m_dispatcher; - + delete m_collisionConfiguration; } - + virtual void syncPhysicsToGraphics(GraphicsPhysicsBridge& gfxBridge) { if (m_dynamicsWorld) @@ -117,6 +117,15 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup } } + virtual void debugDraw() + { + if (m_dynamicsWorld) + { + m_dynamicsWorld->debugDrawWorld(); + } + + } + virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld) { if (m_dynamicsWorld==0) @@ -127,7 +136,7 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup m_dynamicsWorld->rayTest(rayFromWorld, rayToWorld, rayCallback); if (rayCallback.hasHit()) { - + btVector3 pickPos = rayCallback.m_hitPointWorld; btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject); if (body) @@ -148,8 +157,8 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup p2p->m_setting.m_tau = 0.001f; } } - - + + // pickObject(pickPos, rayCallback.m_collisionObject); m_oldPickingPos = rayToWorld; m_hitPos = pickPos; @@ -167,13 +176,13 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup if (pickCon) { //keep it at the same picking distance - + btVector3 newPivotB; - + btVector3 dir = rayToWorld - rayFromWorld; dir.normalize(); dir *= m_oldPickingDist; - + newPivotB = rayFromWorld + dir; pickCon->setPivotB(newPivotB); return true; @@ -191,12 +200,13 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup m_pickedBody = 0; } } - + btBoxShape* createBoxShape(const btVector3& halfExtents) { btBoxShape* box = new btBoxShape(halfExtents); + m_collisionShapes.push_back(box); return box; } diff --git a/Demos3/AllBullet2Demos/BulletDemoInterface.h b/Demos3/AllBullet2Demos/BulletDemoInterface.h index 8e69b05bd..188e8e437 100644 --- a/Demos3/AllBullet2Demos/BulletDemoInterface.h +++ b/Demos3/AllBullet2Demos/BulletDemoInterface.h @@ -12,11 +12,12 @@ public: virtual ~BulletDemoInterface() { } - + virtual void initPhysics()=0; virtual void exitPhysics()=0; virtual void stepSimulation(float deltaTime)=0; virtual void renderScene()=0; + virtual void physicsDebugDraw()=0; virtual bool mouseMoveCallback(float x,float y)=0; virtual bool mouseButtonCallback(int button, int state, float x, float y)=0; virtual bool keyboardCallback(int key, int state)=0; @@ -43,6 +44,9 @@ public: virtual void renderScene() { } + virtual void physicsDebugDraw() + { + } virtual bool mouseMoveCallback(float x,float y) { return false; diff --git a/Demos3/AllBullet2Demos/main.cpp b/Demos3/AllBullet2Demos/main.cpp index 41dc09498..9d9d0ca0a 100644 --- a/Demos3/AllBullet2Demos/main.cpp +++ b/Demos3/AllBullet2Demos/main.cpp @@ -429,6 +429,7 @@ int main(int argc, char* argv[]) prevTimeInMicroseconds = curTimeInMicroseconds; } sCurrentDemo->renderScene(); + sCurrentDemo->physicsDebugDraw(); } static int toggle = 1; diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp index fad0a877a..8c721a023 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp @@ -2,6 +2,7 @@ #include "btBulletDynamicsCommon.h" #include "OpenGLWindow/SimpleOpenGL3App.h" #include "BulletCollision/CollisionShapes/btShapeHull.h"//to create a tesselation of a generic btConvexShape +#include "MyDebugDrawer.h" struct GraphicsVertex { float pos[4]; @@ -13,9 +14,10 @@ struct GraphicsVertex struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge { SimpleOpenGL3App* m_glApp; + MyDebugDrawer* m_debugDraw; MyGraphicsPhysicsBridge(SimpleOpenGL3App* glApp) - :m_glApp(glApp) + :m_glApp(glApp), m_debugDraw(0) { } virtual void createRigidBodyGraphicsObject(btRigidBody* body, const btVector3& color) @@ -41,7 +43,7 @@ struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge box->setUserIndex(cubeShapeId); break; } - + default: { if (collisionShape->isConvex()) @@ -50,18 +52,18 @@ struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge { btShapeHull* hull = new btShapeHull(convex); hull->buildHull(0.0); - + { - int strideInBytes = 9*sizeof(float); - int numVertices = hull->numVertices(); - int numIndices =hull->numIndices(); - + //int strideInBytes = 9*sizeof(float); + //int numVertices = hull->numVertices(); + //int numIndices =hull->numIndices(); + btAlignedObjectArray gvertices; btAlignedObjectArray indices; for (int t=0;tnumTriangles();t++) { - + btVector3 triNormal; int index0 = hull->getIndexPointer()[t*3+0]; @@ -82,20 +84,20 @@ struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge vtx.pos[1] = pos.y(); vtx.pos[2] = pos.z(); vtx.pos[3] = 0.f; - + vtx.normal[0] =triNormal.x(); vtx.normal[1] =triNormal.y(); vtx.normal[2] =triNormal.z(); - vtx.normal[3] =0; + vtx.texcoord[0] = 0.5f; vtx.texcoord[1] = 0.5f; - + indices.push_back(gvertices.size()); gvertices.push_back(vtx); } } - - + + int shapeId = m_glApp->m_instancingRenderer->registerShape(&gvertices[0].pos[0],gvertices.size(),&indices[0],indices.size()); convex->setUserIndex(shapeId); } @@ -123,15 +125,30 @@ struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge } m_glApp->m_instancingRenderer->writeTransforms(); } + + virtual void createPhysicsDebugDrawer(btDiscreteDynamicsWorld* rbWorld) + { + btAssert(rbWorld); + m_debugDraw = new MyDebugDrawer(m_glApp); + rbWorld->setDebugDrawer(m_debugDraw ); + + + m_debugDraw->setDebugMode( + btIDebugDraw::DBG_DrawWireframe + +btIDebugDraw::DBG_DrawAabb + //btIDebugDraw::DBG_DrawContactPoints + ); + + } }; Bullet2RigidBodyDemo::Bullet2RigidBodyDemo(SimpleOpenGL3App* app, CommonPhysicsSetup* physicsSetup) - :m_glApp(app), - m_physicsSetup(physicsSetup), + : m_physicsSetup(physicsSetup), m_controlPressed(false), - m_altPressed(false) + m_altPressed(false), + m_glApp(app) { - + } void Bullet2RigidBodyDemo::initPhysics() { @@ -143,7 +160,7 @@ void Bullet2RigidBodyDemo::initPhysics() void Bullet2RigidBodyDemo::exitPhysics() { - + m_physicsSetup->exitPhysics(); } @@ -164,6 +181,12 @@ void Bullet2RigidBodyDemo::renderScene() m_glApp->m_instancingRenderer->renderScene(); } + +void Bullet2RigidBodyDemo::physicsDebugDraw() +{ + m_physicsSetup->debugDraw(); +} + Bullet2RigidBodyDemo::~Bullet2RigidBodyDemo() { } @@ -213,7 +236,7 @@ btVector3 Bullet2RigidBodyDemo::getRayTo(int x,int y) float height = m_glApp->m_instancingRenderer->getScreenHeight(); aspect = width / height; - + hor*=aspect; @@ -228,14 +251,14 @@ btVector3 Bullet2RigidBodyDemo::getRayTo(int x,int y) return rayTo; } - + bool Bullet2RigidBodyDemo::mouseMoveCallback(float x,float y) { btVector3 rayTo = getRayTo(x, y); btVector3 rayFrom; m_glApp->m_instancingRenderer->getCameraPosition(rayFrom); m_physicsSetup->movePickedBody(rayFrom,rayTo); - + return false; } bool Bullet2RigidBodyDemo::mouseButtonCallback(int button, int state, float x, float y) @@ -251,9 +274,10 @@ bool Bullet2RigidBodyDemo::mouseButtonCallback(int button, int state, float x, f btVector3 rayFrom = camPos; btVector3 rayTo = getRayTo(x,y); - bool hasPicked = m_physicsSetup->pickBody(rayFrom, rayTo); - + m_physicsSetup->pickBody(rayFrom, rayTo); + + } } else { diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h index 07e3f41e8..9a2d56f99 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h @@ -3,10 +3,10 @@ #include "LinearMath/btVector3.h" -#include "../../AllBullet2Demos/BulletDemoInterface.h" +#include "BulletDemoInterface.h" #include "OpenGLWindow/b3gWindowInterface.h" -#include "../../../Demos/CommonPhysicsSetup.h" +#include "../../Demos/CommonPhysicsSetup.h" class Bullet2RigidBodyDemo : public BulletDemoInterface @@ -26,6 +26,7 @@ public: virtual void initPhysics(); virtual void exitPhysics(); virtual void renderScene(); + virtual void physicsDebugDraw(); virtual void stepSimulation(float dt); diff --git a/Demos3/bullet2/BasicDemo/MyDebugDrawer.h b/Demos3/bullet2/BasicDemo/MyDebugDrawer.h index 81f9a536c..27340470c 100644 --- a/Demos3/bullet2/BasicDemo/MyDebugDrawer.h +++ b/Demos3/bullet2/BasicDemo/MyDebugDrawer.h @@ -2,25 +2,60 @@ #define MY_DEBUG_DRAWER_H #include "LinearMath/btIDebugDraw.h" +#include "LinearMath/btAlignedObjectArray.h" +#define BT_LINE_BATCH_SIZE 512 +struct MyDebugVec3 +{ + MyDebugVec3(const btVector3 org) + :x(org.x()), + y(org.y()), + z(org.z()) + { + } + + float x; + float y; + float z; +}; class MyDebugDrawer : public btIDebugDraw { SimpleOpenGL3App* m_glApp; int m_debugMode; + + btAlignedObjectArray m_linePoints; + btAlignedObjectArray m_lineIndices; + btVector3 m_currentLineColor; + public: MyDebugDrawer(SimpleOpenGL3App* app) : m_glApp(app) - ,m_debugMode(btIDebugDraw::DBG_DrawWireframe|btIDebugDraw::DBG_DrawAabb) + ,m_debugMode(btIDebugDraw::DBG_DrawWireframe|btIDebugDraw::DBG_DrawAabb), + m_currentLineColor(-1,-1,-1) { } virtual void drawLine(const btVector3& from1,const btVector3& to1,const btVector3& color1) { - float from[4] = {from1[0],from1[1],from1[2],from1[3]}; - float to[4] = {to1[0],to1[1],to1[2],to1[3]}; - float color[4] = {color1[0],color1[1],color1[2],color1[3]}; - m_glApp->m_instancingRenderer->drawLine(from,to,color); + //float from[4] = {from1[0],from1[1],from1[2],from1[3]}; + //float to[4] = {to1[0],to1[1],to1[2],to1[3]}; + //float color[4] = {color1[0],color1[1],color1[2],color1[3]}; + //m_glApp->m_instancingRenderer->drawLine(from,to,color); + if (m_currentLineColor!=color1 || m_linePoints.size() >= BT_LINE_BATCH_SIZE) + { + flushLines(); + m_currentLineColor = color1; + } + MyDebugVec3 from(from1); + MyDebugVec3 to(to1); + + m_linePoints.push_back(from); + m_linePoints.push_back(to); + + m_lineIndices.push_back(m_lineIndices.size()); + m_lineIndices.push_back(m_lineIndices.size()); + } virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) @@ -34,17 +69,36 @@ public: virtual void draw3dText(const btVector3& location,const char* textString) { } - + virtual void setDebugMode(int debugMode) { m_debugMode = debugMode; } - + virtual int getDebugMode() const { return m_debugMode; } + virtual void flushLines() + { + int sz = m_linePoints.size(); + if (sz) + { + float debugColor[4]; + debugColor[0] = m_currentLineColor.x(); + debugColor[1] = m_currentLineColor.y(); + debugColor[2] = m_currentLineColor.z(); + debugColor[3] = 1.f; + m_glApp->m_instancingRenderer->drawLines(&m_linePoints[0].x,debugColor, + m_linePoints.size(),sizeof(MyDebugVec3), + &m_lineIndices[0], + m_lineIndices.size(), + 1); + m_linePoints.clear(); + m_lineIndices.clear(); + } + } }; diff --git a/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp b/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp index 80dced6bb..81b1dc718 100644 --- a/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp +++ b/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp @@ -607,6 +607,13 @@ void FeatherstoneDemo1::renderScene() m_glApp->m_instancingRenderer->renderScene(); } +void FeatherstoneDemo1::physicsDebugDraw() +{ + if (m_dynamicsWorld) + { + m_dynamicsWorld->debugDrawWorld(); + } +} void FeatherstoneDemo1::stepSimulation(float deltaTime) { diff --git a/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h b/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h index 76c0b62c7..928691fd1 100644 --- a/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h +++ b/Demos3/bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h @@ -89,6 +89,8 @@ public: virtual void initPhysics(); virtual void exitPhysics(); virtual void renderScene(); + virtual void physicsDebugDraw(); + virtual void stepSimulation(float deltaTime); }; From 0c39cda57b4124ba185b3bd18b1b84dd4776684d Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 29 Jul 2014 16:58:22 -0700 Subject: [PATCH 098/116] enable png and mp4 output in SimpleOpenGL3App, see Demos3/SimpleOpenGL3 use commandline parameter --png_file="pngname" or --mp4_file="video.mp4" Thanks to http://blog.mmacklin.com/2013/06/11/real-time-video-capture-with-ffmpeg/ --- Demos3/SimpleOpenGL3/main.cpp | 38 ++++-- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 149 ++++++++++++++++++++++++ btgui/OpenGLWindow/SimpleOpenGL3App.h | 3 + build3/premake4.lua | 2 +- 4 files changed, 182 insertions(+), 10 deletions(-) diff --git a/Demos3/SimpleOpenGL3/main.cpp b/Demos3/SimpleOpenGL3/main.cpp index 91faf454a..530d2b9a5 100644 --- a/Demos3/SimpleOpenGL3/main.cpp +++ b/Demos3/SimpleOpenGL3/main.cpp @@ -1,13 +1,18 @@ -#include "../../btgui/OpenGLWindow/SimpleOpenGL3App.h" +#include "OpenGLWindow/SimpleOpenGL3App.h" #include "Bullet3Common/b3Vector3.h" +#include "Bullet3Common/b3CommandLineArgs.h" #include "assert.h" #include +char* gVideoFileName = 0; +char* gPngFileName = 0; + int main(int argc, char* argv[]) { - + b3CommandLineArgs myArgs(argc,argv); + float dt = 1./120.f; - + SimpleOpenGL3App* app = new SimpleOpenGL3App("SimpleOpenGL3App",1024,768); app->m_instancingRenderer->setCameraDistance(13); app->m_instancingRenderer->setCameraPitch(0); @@ -15,25 +20,40 @@ int main(int argc, char* argv[]) GLint err = glGetError(); assert(err==GL_NO_ERROR); - + + myArgs.GetCmdLineArgument("mp4_file",gVideoFileName); + if (gVideoFileName) + app->dumpFramesToVideo(gVideoFileName); + + myArgs.GetCmdLineArgument("png_file",gPngFileName); + char fileName[1024]; + do { + static int frameCount = 0; + frameCount++; + if (gPngFileName) + { + printf("gPngFileName=%s\n",gPngFileName); + + sprintf(fileName,"%s%d.png",gPngFileName,frameCount++); + app->dumpNextFrameToPng(fileName); + } + GLint err = glGetError(); assert(err==GL_NO_ERROR); app->m_instancingRenderer->init(); app->m_instancingRenderer->updateCamera(); - + app->drawGrid(); char bla[1024]; - static int frameCount = 0; - frameCount++; sprintf(bla,"Simple test frame %d", frameCount); - + app->drawText(bla,10,10); app->swapBuffer(); } while (!app->m_window->requestedExit()); - + delete app; return 0; } diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index 0033419e6..265b9958b 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -13,6 +13,7 @@ #include "OpenGLWindow/X11OpenGLWindow.h" #endif //_WIN32 #endif//__APPLE__ +#include #include "OpenGLWindow/GLPrimitiveRenderer.h" #include "OpenGLWindow/GLInstancingRenderer.h" @@ -24,6 +25,12 @@ #include "OpenGLWindow/TwFonts.h" #include "OpenGLTrueTypeFont/opengl_fontstashcallbacks.h" #include +#include "GLRenderToTexture.h" + +#ifdef _WIN32 + #define popen _popen + #define pclose _pclose +#endif // _WIN32 struct SimpleInternalData { @@ -31,6 +38,9 @@ struct SimpleInternalData struct sth_stash* m_fontStash; OpenGL2RenderCallbacks* m_renderCallbacks; int m_droidRegular; + const char* m_frameDumpPngFileName; + FILE* m_ffmpegFile; + GLRenderToTexture* m_renderTexture; }; @@ -70,6 +80,10 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) { gApp = this; m_data = new SimpleInternalData; + m_data->m_frameDumpPngFileName = 0; + m_data->m_renderTexture = 0; + m_data->m_ffmpegFile = 0; + m_window = new b3gDefaultOpenGLWindow(); b3gWindowConstructionInfo ci; ci.m_title = title; @@ -404,8 +418,143 @@ SimpleOpenGL3App::~SimpleOpenGL3App() delete m_data ; } +//#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "OpenGLTrueTypeFont/stb_image_write.h" +static void writeTextureToFile(int textureWidth, int textureHeight, const char* fileName, FILE* ffmpegVideo) +{ + int numComponents = 4; + //glPixelStorei(GL_PACK_ALIGNMENT,1); + GLuint err=glGetError(); + assert(err==GL_NO_ERROR); + //glReadBuffer(GL_BACK);//COLOR_ATTACHMENT0); + err=glGetError(); + assert(err==GL_NO_ERROR); + float* orgPixels = (float*)malloc(textureWidth*textureHeight*numComponents*4); + glReadPixels(0,0,textureWidth, textureHeight, GL_RGBA, GL_FLOAT, orgPixels); + //it is useful to have the actual float values for debugging purposes + + //convert float->char + char* pixels = (char*)malloc(textureWidth*textureHeight*numComponents); + err=glGetError(); + assert(err==GL_NO_ERROR); + + for (int j=0;jendRendering(); + if (m_data->m_frameDumpPngFileName) + { + writeTextureToFile(m_instancingRenderer->getScreenWidth(), + this->m_instancingRenderer->getScreenHeight(),m_data->m_frameDumpPngFileName, + m_data->m_ffmpegFile); + //m_data->m_renderTexture->disable(); + //if (m_data->m_ffmpegFile==0) + //{ + // m_data->m_frameDumpPngFileName = 0; + //} + } m_window->startRendering(); } +// see also http://blog.mmacklin.com/2013/06/11/real-time-video-capture-with-ffmpeg/ +void SimpleOpenGL3App::dumpFramesToVideo(const char* mp4FileName) +{ + int width = m_instancingRenderer->getScreenWidth(); + int height = m_instancingRenderer->getScreenHeight(); + char cmd[8192]; + + sprintf(cmd,"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - " + "-threads 0 -y -crf 0 -b 50000k -vf vflip %s",width,height,mp4FileName); + + // sprintf(cmd,"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - " + // "-threads 0 -preset fast -y -crf 21 -vf vflip %s",width,height,mp4FileName); + + if (m_data->m_ffmpegFile) + { + pclose(m_data->m_ffmpegFile); + } + m_data->m_ffmpegFile = popen(cmd, "w"); + + m_data->m_frameDumpPngFileName = mp4FileName; +} +void SimpleOpenGL3App::dumpNextFrameToPng(const char* filename) +{ + + // open pipe to ffmpeg's stdin in binary write mode + + m_data->m_frameDumpPngFileName = filename; + +//you could use m_renderTexture to allow to render at higher resolutions, such as 4k or so + /*if (!m_data->m_renderTexture) + { + m_data->m_renderTexture = new GLRenderToTexture(); + GLuint renderTextureId; + glGenTextures(1, &renderTextureId); + + // "Bind" the newly created texture : all future texture functions will modify this texture + glBindTexture(GL_TEXTURE_2D, renderTextureId); + + // Give an empty image to OpenGL ( the last "0" ) + //glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, g_OpenGLWidth,g_OpenGLHeight, 0,GL_RGBA, GL_UNSIGNED_BYTE, 0); + //glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F, g_OpenGLWidth,g_OpenGLHeight, 0,GL_RGBA, GL_FLOAT, 0); + glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA32F, + m_instancingRenderer->getScreenWidth(),m_instancingRenderer->getScreenHeight() + , 0,GL_RGBA, GL_FLOAT, 0); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + m_data->m_renderTexture->init(m_instancingRenderer->getScreenWidth(),this->m_instancingRenderer->getScreenHeight(),renderTextureId, RENDERTEXTURE_COLOR); + } + + bool result = m_data->m_renderTexture->enable(); +*/ +} diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.h b/btgui/OpenGLWindow/SimpleOpenGL3App.h index 0ebf8ed4b..9bfa64e2c 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.h +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.h @@ -38,6 +38,9 @@ struct SimpleOpenGL3App int registerCubeShape(float halfExtentsX=1.f,float halfExtentsY=1.f, float halfExtentsZ = 1.f); int registerGraphicsSphereShape(float radius, bool usePointSprites=true, int largeSphereThreshold=100, int mediumSphereThreshold=10); + void dumpNextFrameToPng(const char* pngFilename); + void dumpFramesToVideo(const char* mp4Filename); + void drawGrid(DrawGridData data=DrawGridData()); void swapBuffer(); void drawText( const char* txt, int posX, int posY); diff --git a/build3/premake4.lua b/build3/premake4.lua index 9d17c5e3c..4f5d5be50 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -116,7 +116,7 @@ if findOpenGL() then include "../btgui/OpenGLWindow" -- include "../Demos3/ImplicitCloth" --- include "../Demos3/SimpleOpenGL3" + include "../Demos3/SimpleOpenGL3" include "../btgui/lua-5.2.3" include "../test/lua" From a817b0bb24176e8e83f82ded7f564bd3a331d5e8 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Tue, 29 Jul 2014 23:06:36 -0700 Subject: [PATCH 099/116] support Retina for movie generation in SimpleOpenGL3App --- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index 265b9958b..9b0a85b34 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -491,8 +491,8 @@ void SimpleOpenGL3App::swapBuffer() m_window->endRendering(); if (m_data->m_frameDumpPngFileName) { - writeTextureToFile(m_instancingRenderer->getScreenWidth(), - this->m_instancingRenderer->getScreenHeight(),m_data->m_frameDumpPngFileName, + writeTextureToFile(m_window->getRetinaScale()*m_instancingRenderer->getScreenWidth(), + m_window->getRetinaScale()*this->m_instancingRenderer->getScreenHeight(),m_data->m_frameDumpPngFileName, m_data->m_ffmpegFile); //m_data->m_renderTexture->disable(); //if (m_data->m_ffmpegFile==0) @@ -505,8 +505,8 @@ void SimpleOpenGL3App::swapBuffer() // see also http://blog.mmacklin.com/2013/06/11/real-time-video-capture-with-ffmpeg/ void SimpleOpenGL3App::dumpFramesToVideo(const char* mp4FileName) { - int width = m_instancingRenderer->getScreenWidth(); - int height = m_instancingRenderer->getScreenHeight(); + int width = m_window->getRetinaScale()*m_instancingRenderer->getScreenWidth(); + int height = m_window->getRetinaScale()*m_instancingRenderer->getScreenHeight(); char cmd[8192]; sprintf(cmd,"ffmpeg -r 60 -f rawvideo -pix_fmt rgba -s %dx%d -i - " From e1abb8ba8900993782fe9fef6a641aa82e3eae4c Mon Sep 17 00:00:00 2001 From: "Erwin Coumans (Google)" Date: Wed, 30 Jul 2014 08:27:17 -0700 Subject: [PATCH 100/116] fix #include path and compile error --- Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h index 9a2d56f99..a7475323b 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h @@ -3,10 +3,10 @@ #include "LinearMath/btVector3.h" -#include "BulletDemoInterface.h" +#include "../../AllBullet2Demos/BulletDemoInterface.h" #include "OpenGLWindow/b3gWindowInterface.h" -#include "../../Demos/CommonPhysicsSetup.h" +#include "../../../Demos/CommonPhysicsSetup.h" class Bullet2RigidBodyDemo : public BulletDemoInterface From 97fc144134584e4c2cfe212d9aef7725cacdd951 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Wed, 30 Jul 2014 09:48:18 -0700 Subject: [PATCH 101/116] fix Windows compile error, SIMD data needs to be passed by reference --- Demos3/bullet2/BasicDemo/MyDebugDrawer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Demos3/bullet2/BasicDemo/MyDebugDrawer.h b/Demos3/bullet2/BasicDemo/MyDebugDrawer.h index 27340470c..54c4387e8 100644 --- a/Demos3/bullet2/BasicDemo/MyDebugDrawer.h +++ b/Demos3/bullet2/BasicDemo/MyDebugDrawer.h @@ -7,7 +7,7 @@ struct MyDebugVec3 { - MyDebugVec3(const btVector3 org) + MyDebugVec3(const btVector3& org) :x(org.x()), y(org.y()), z(org.z()) From 1d00d91707c88cd5d48902001d6973c125052929 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Wed, 30 Jul 2014 16:13:34 -0700 Subject: [PATCH 102/116] add btHingeAccumulatedAngleConstraint derived from btHingeConstraint, that exposes a new method getAccumulatedHingeAngle See also https://github.com/bulletphysics/bullet3/issues/42 --- .../ConstraintSolver/btHingeConstraint.cpp | 53 +++++++++++++++++++ .../ConstraintSolver/btHingeConstraint.h | 38 +++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp b/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp index c18974130..6e2cd66b8 100644 --- a/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp +++ b/src/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp @@ -285,8 +285,59 @@ void btHingeConstraint::buildJacobian() #endif //__SPU__ +static inline btScalar btNormalizeAnglePositive(btScalar angle) +{ + return btFmod(btFmod(angle, 2.0*SIMD_PI) + 2.0*SIMD_PI, 2.0*SIMD_PI); +} + + + +static btScalar btShortestAngularDistance(btScalar accAngle, btScalar curAngle) +{ + btScalar result = btNormalizeAngle(btNormalizeAnglePositive(btNormalizeAnglePositive(curAngle) - + btNormalizeAnglePositive(accAngle))); + return result; +} + +static btScalar btShortestAngleUpdate(btScalar accAngle, btScalar curAngle) +{ + btScalar tol(0.3); + btScalar result = btShortestAngularDistance(accAngle, curAngle); + + if (btFabs(result) > tol) + return curAngle; + else + return accAngle + result; + + return curAngle; +} + + +btScalar btHingeAccumulatedAngleConstraint::getAccumulatedHingeAngle() +{ + btScalar hingeAngle = getHingeAngle(); + m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,hingeAngle); + return m_accumulatedAngle; +} +void btHingeAccumulatedAngleConstraint::setAccumulatedHingeAngle(btScalar accAngle) +{ + m_accumulatedAngle = accAngle; +} + +void btHingeAccumulatedAngleConstraint::getInfo1(btConstraintInfo1* info) +{ + //update m_accumulatedAngle + btScalar curHingeAngle = getHingeAngle(); + m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,curHingeAngle); + + btHingeConstraint::getInfo1(info); +} + + void btHingeConstraint::getInfo1(btConstraintInfo1* info) { + + if (m_useSolveConstraintObsolete) { info->m_numConstraintRows = 0; @@ -606,6 +657,8 @@ void btHingeConstraint::updateRHS(btScalar timeStep) } + + btScalar btHingeConstraint::getHingeAngle() { return getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); diff --git a/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h b/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h index 7c33ac24e..30d506c6e 100644 --- a/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h +++ b/src/BulletDynamics/ConstraintSolver/btHingeConstraint.h @@ -236,6 +236,7 @@ public: } + ///The getHingeAngle gives the hinge angle in range [-PI,PI] btScalar getHingeAngle(); btScalar getHingeAngle(const btTransform& transA,const btTransform& transB); @@ -326,6 +327,43 @@ struct btHingeConstraintDoubleData }; #endif //BT_BACKWARDS_COMPATIBLE_SERIALIZATION +///The getAccumulatedHingeAngle returns the accumulated hinge angle, taking rotation across the -PI/PI boundary into account +ATTRIBUTE_ALIGNED16(class) btHingeAccumulatedAngleConstraint : public btHingeConstraint +{ +protected: + btScalar m_accumulatedAngle; +public: + + BT_DECLARE_ALIGNED_ALLOCATOR(); + + btHingeAccumulatedAngleConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB, const btVector3& axisInA,const btVector3& axisInB, bool useReferenceFrameA = false) + :btHingeConstraint(rbA,rbB,pivotInA,pivotInB, axisInA,axisInB, useReferenceFrameA ) + { + m_accumulatedAngle=getHingeAngle(); + } + + btHingeAccumulatedAngleConstraint(btRigidBody& rbA,const btVector3& pivotInA,const btVector3& axisInA, bool useReferenceFrameA = false) + :btHingeConstraint(rbA,pivotInA,axisInA, useReferenceFrameA) + { + m_accumulatedAngle=getHingeAngle(); + } + + btHingeAccumulatedAngleConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA = false) + :btHingeConstraint(rbA,rbB, rbAFrame, rbBFrame, useReferenceFrameA ) + { + m_accumulatedAngle=getHingeAngle(); + } + + btHingeAccumulatedAngleConstraint(btRigidBody& rbA,const btTransform& rbAFrame, bool useReferenceFrameA = false) + :btHingeConstraint(rbA,rbAFrame, useReferenceFrameA ) + { + m_accumulatedAngle=getHingeAngle(); + } + btScalar getAccumulatedHingeAngle(); + void setAccumulatedHingeAngle(btScalar accAngle); + virtual void getInfo1 (btConstraintInfo1* info); + +}; struct btHingeConstraintFloatData { From d79814416718c998483f1b2b4833d6cbefbb99fb Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Wed, 30 Jul 2014 22:28:38 -0700 Subject: [PATCH 103/116] don't add collision shapes to the list twice --- Demos/CommonRigidBodySetup.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Demos/CommonRigidBodySetup.h b/Demos/CommonRigidBodySetup.h index 4d118162a..0520b038d 100644 --- a/Demos/CommonRigidBodySetup.h +++ b/Demos/CommonRigidBodySetup.h @@ -206,7 +206,6 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup btBoxShape* createBoxShape(const btVector3& halfExtents) { btBoxShape* box = new btBoxShape(halfExtents); - m_collisionShapes.push_back(box); return box; } From 4b8c8e7910a44abafeeebcf0e8be2891afad7f47 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 11:47:04 -0700 Subject: [PATCH 104/116] expose basic parameters in SimpleOpenGL3App, test with accumulated hinge angle, GUI is still preliminary --- Demos/CommonPhysicsSetup.h | 9 ++ .../ConstraintDemo/ConstraintPhysicsSetup.cpp | 70 +++++++++ Demos/ConstraintDemo/ConstraintPhysicsSetup.h | 16 ++ Demos3/AllBullet2Demos/BulletDemoEntries.h | 12 ++ .../GwenParameterInterface.cpp | 142 ++++++++++++++++++ .../AllBullet2Demos/GwenParameterInterface.h | 20 +++ Demos3/AllBullet2Demos/main.cpp | 88 ++--------- Demos3/AllBullet2Demos/premake4.lua | 2 + Demos3/GpuDemos/gwenUserInterface.cpp | 17 ++- .../BasicDemo/Bullet2RigidBodyDemo.cpp | 5 + .../bullet2/BasicDemo/Bullet2RigidBodyDemo.h | 5 +- btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 3 + btgui/OpenGLWindow/SimpleOpenGL3App.h | 2 + 13 files changed, 310 insertions(+), 81 deletions(-) create mode 100644 Demos/ConstraintDemo/ConstraintPhysicsSetup.cpp create mode 100644 Demos/ConstraintDemo/ConstraintPhysicsSetup.h create mode 100644 Demos3/AllBullet2Demos/GwenParameterInterface.cpp create mode 100644 Demos3/AllBullet2Demos/GwenParameterInterface.h diff --git a/Demos/CommonPhysicsSetup.h b/Demos/CommonPhysicsSetup.h index 5b2828d76..2f18d1382 100644 --- a/Demos/CommonPhysicsSetup.h +++ b/Demos/CommonPhysicsSetup.h @@ -7,11 +7,14 @@ class btBoxShape; class btTransform; class btCollisionShape; #include "LinearMath/btVector3.h" +#include "CommonParameterInterface.h" + class btDiscreteDynamicsWorld; ///The GraphicsPhysicsBridge let's the graphics engine create graphics representation and synchronize struct GraphicsPhysicsBridge { + virtual void createRigidBodyGraphicsObject(btRigidBody* body,const btVector3& color) { } @@ -24,6 +27,12 @@ struct GraphicsPhysicsBridge virtual void createPhysicsDebugDrawer( btDiscreteDynamicsWorld* rbWorld) { } + + virtual CommonParameterInterface* getParameterInterface() + { + return 0; + } + }; struct CommonPhysicsSetup diff --git a/Demos/ConstraintDemo/ConstraintPhysicsSetup.cpp b/Demos/ConstraintDemo/ConstraintPhysicsSetup.cpp new file mode 100644 index 000000000..4b2de0f43 --- /dev/null +++ b/Demos/ConstraintDemo/ConstraintPhysicsSetup.cpp @@ -0,0 +1,70 @@ +#include "ConstraintPhysicsSetup.h" + +ConstraintPhysicsSetup::ConstraintPhysicsSetup() +{ +} +ConstraintPhysicsSetup::~ConstraintPhysicsSetup() +{ +} + +btScalar val; +btHingeAccumulatedAngleConstraint* spDoorHinge=0; +void ConstraintPhysicsSetup::stepSimulation(float deltaTime) +{ + val=spDoorHinge->getAccumulatedHingeAngle()*SIMD_DEGS_PER_RAD;// spDoorHinge->getHingeAngle()*SIMD_DEGS_PER_RAD; + if (m_dynamicsWorld) + { + m_dynamicsWorld->stepSimulation(deltaTime); + } +} + + + +void ConstraintPhysicsSetup::initPhysics(GraphicsPhysicsBridge& gfxBridge) +{ + createEmptyDynamicsWorld(); + + gfxBridge.createPhysicsDebugDrawer(m_dynamicsWorld); +int mode = btIDebugDraw::DBG_DrawWireframe + +btIDebugDraw::DBG_DrawConstraints + +btIDebugDraw::DBG_DrawConstraintLimits; + m_dynamicsWorld->getDebugDrawer()->setDebugMode(mode); + +val=1.f; + SliderParams slider("hinge angle",&val); +slider.m_minVal=-720; +slider.m_maxVal=720; + gfxBridge.getParameterInterface()->registerSliderFloatParameter(slider); + + + { // create a door using hinge constraint attached to the world + btCollisionShape* pDoorShape = new btBoxShape(btVector3(2.0f, 5.0f, 0.2f)); + m_collisionShapes.push_back(pDoorShape); + btTransform doorTrans; + doorTrans.setIdentity(); + doorTrans.setOrigin(btVector3(-5.0f, -2.0f, 0.0f)); + btRigidBody* pDoorBody = createRigidBody( 1.0, doorTrans, pDoorShape); + pDoorBody->setActivationState(DISABLE_DEACTIVATION); + const btVector3 btPivotA(10.f + 2.1f, -2.0f, 0.0f ); // right next to the door slightly outside + btVector3 btAxisA( 0.0f, 1.0f, 0.0f ); // pointing upwards, aka Y-axis + + spDoorHinge = new btHingeAccumulatedAngleConstraint( *pDoorBody, btPivotA, btAxisA ); + +// spDoorHinge->setLimit( 0.0f, SIMD_PI_2 ); + // test problem values +// spDoorHinge->setLimit( -SIMD_PI, SIMD_PI*0.8f); + +// spDoorHinge->setLimit( 1.f, -1.f); +// spDoorHinge->setLimit( -SIMD_PI*0.8f, SIMD_PI); +// spDoorHinge->setLimit( -SIMD_PI*0.8f, SIMD_PI, 0.9f, 0.3f, 0.0f); +// spDoorHinge->setLimit( -SIMD_PI*0.8f, SIMD_PI, 0.9f, 0.01f, 0.0f); // "sticky limits" + // spDoorHinge->setLimit( -SIMD_PI * 0.25f, SIMD_PI * 0.25f ); +// spDoorHinge->setLimit( 0.0f, 0.0f ); + m_dynamicsWorld->addConstraint(spDoorHinge); + spDoorHinge->setDbgDrawSize(btScalar(5.f)); + + //doorTrans.setOrigin(btVector3(-5.0f, 2.0f, 0.0f)); + //btRigidBody* pDropBody = localCreateRigidBody( 10.0, doorTrans, shape); + } + +} \ No newline at end of file diff --git a/Demos/ConstraintDemo/ConstraintPhysicsSetup.h b/Demos/ConstraintDemo/ConstraintPhysicsSetup.h new file mode 100644 index 000000000..e85853cb8 --- /dev/null +++ b/Demos/ConstraintDemo/ConstraintPhysicsSetup.h @@ -0,0 +1,16 @@ +#ifndef CONSTAINT_PHYSICS_SETUP_H +#define CONSTAINT_PHYSICS_SETUP_H + +#include "../CommonRigidBodySetup.h" + +struct ConstraintPhysicsSetup : public CommonRigidBodySetup +{ + ConstraintPhysicsSetup(); + virtual ~ConstraintPhysicsSetup(); + virtual void initPhysics(GraphicsPhysicsBridge& gfxBridge); + + virtual void stepSimulation(float deltaTime); + +}; + +#endif //CONSTAINT_PHYSICS_SETUP_H diff --git a/Demos3/AllBullet2Demos/BulletDemoEntries.h b/Demos3/AllBullet2Demos/BulletDemoEntries.h index 84334b0c3..b03fe08fe 100644 --- a/Demos3/AllBullet2Demos/BulletDemoEntries.h +++ b/Demos3/AllBullet2Demos/BulletDemoEntries.h @@ -5,6 +5,8 @@ #include "BulletDemoInterface.h" #include "../bullet2/BasicDemo/BasicDemo.h" #include "../bullet2/BasicDemo/HingeDemo.h" +#include "../bullet2/BasicDemo/HingeDemo.h" + #include "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h" #include "../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.h" @@ -12,6 +14,8 @@ #include "../bullet2/LuaDemo/LuaDemo.h" #include "../bullet2/ChainDemo/ChainDemo.h" #include "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h" +#include "../../Demos/ConstraintDemo/ConstraintPhysicsSetup.h" + static BulletDemoInterface* MyCcdPhysicsDemoCreateFunc(SimpleOpenGL3App* app) { @@ -25,6 +29,13 @@ static BulletDemoInterface* MyKinematicObjectCreateFunc(SimpleOpenGL3App* app) return new BasicDemo(app, physicsSetup); } +static BulletDemoInterface* MyConstraintCreateFunc(SimpleOpenGL3App* app) +{ + CommonPhysicsSetup* physicsSetup = new ConstraintPhysicsSetup(); + return new BasicDemo(app, physicsSetup); +} + + struct BulletDemoEntry { int m_menuLevel; @@ -42,6 +53,7 @@ static BulletDemoEntry allDemos[]= {1,"BasicDemo",BasicDemo::MyCreateFunc}, { 1, "CcdDemo", MyCcdPhysicsDemoCreateFunc }, { 1, "Kinematic", MyKinematicObjectCreateFunc }, + { 1, "Constraints", MyConstraintCreateFunc }, /* {1,"ChainDemo",ChainDemo::MyCreateFunc}, // {0, "Stress tests", 0 }, diff --git a/Demos3/AllBullet2Demos/GwenParameterInterface.cpp b/Demos3/AllBullet2Demos/GwenParameterInterface.cpp new file mode 100644 index 000000000..6df0a26d3 --- /dev/null +++ b/Demos3/AllBullet2Demos/GwenParameterInterface.cpp @@ -0,0 +1,142 @@ +#include "GwenParameterInterface.h" +#include "../GpuDemos/gwenInternalData.h" + + +template +struct MySliderEventHandler : public Gwen::Event::Handler +{ + Gwen::Controls::TextBox* m_label; + Gwen::Controls::Slider* m_pSlider; + char m_variableName[1024]; + T* m_targetValue; + + MySliderEventHandler(const char* varName, Gwen::Controls::TextBox* label, Gwen::Controls::Slider* pSlider,T* target) + :m_label(label), + m_pSlider(pSlider), + m_targetValue(target) + { + memcpy(m_variableName,varName,strlen(varName)+1); + } + + + void SliderMoved( Gwen::Controls::Base* pControl ) + { + Gwen::Controls::Slider* pSlider = (Gwen::Controls::Slider*)pControl; + //printf("value = %f\n", pSlider->GetValue());//UnitPrint( Utility::Format( L"Slider Value: %.2f", pSlider->GetValue() ) ); + float bla = pSlider->GetValue(); + T v = T(bla); + SetValue(v); + + } + + void SetValue(T v) + { + if (v < m_pSlider->GetRangeMin()) + { + printf("?\n"); + } + + if (v > m_pSlider->GetRangeMax()) + { + printf("?\n"); + + } + m_pSlider->SetValue(v,true); + (*m_targetValue) = v; + float val = float(v);//todo: specialize on template type + char txt[1024]; + sprintf(txt,"%s : %.3f", m_variableName,val); + m_label->SetText(txt); + + } +}; + + +struct GwenParameters +{ + b3AlignedObjectArray*> m_sliderEventHandlers; + b3AlignedObjectArray m_sliders; + b3AlignedObjectArray m_textLabels; + int m_savedYposition; +}; + +GwenParameterInterface::GwenParameterInterface(GwenInternalData* gwenInternalData) +:m_gwenInternalData(gwenInternalData) +{ + m_paramInternalData = new GwenParameters; + m_paramInternalData->m_savedYposition = m_gwenInternalData->m_curYposition; + +} + +GwenParameterInterface::~GwenParameterInterface() +{ + + removeAllParameters(); + delete m_paramInternalData; +} + + + +#include +void GwenParameterInterface::registerSliderFloatParameter(SliderParams& params) +{ + Gwen::Controls::TextBox* label = new Gwen::Controls::TextBox(m_gwenInternalData->m_demoPage->GetPage()); + m_paramInternalData->m_textLabels.push_back(label); + //m_data->m_myControls.push_back(label); + label->SetText( params.m_name); + label->SetPos( 10, 10 + 25 ); + label->SetWidth(110); + label->SetPos(10,m_gwenInternalData->m_curYposition); + m_gwenInternalData->m_curYposition+=22; + + Gwen::Controls::HorizontalSlider* pSlider = new Gwen::Controls::HorizontalSlider( m_gwenInternalData->m_demoPage->GetPage()); + m_paramInternalData->m_sliders.push_back(pSlider); + //m_data->m_myControls.push_back(pSlider); + pSlider->SetPos( 10, m_gwenInternalData->m_curYposition ); + pSlider->SetSize( 100, 20 ); + pSlider->SetRange( params.m_minVal, params.m_maxVal); + pSlider->SetNotchCount(20);//float(params.m_maxVal-params.m_minVal)/100.f); + pSlider->SetClampToNotches( params.m_clampToNotches ); + pSlider->SetValue( *params.m_paramValuePointer);//dimensions[i] ); + char labelName[1024]; + sprintf(labelName,"%s",params.m_name);//axisNames[0]); + MySliderEventHandler* handler = new MySliderEventHandler(labelName,label,pSlider,params.m_paramValuePointer); + m_paramInternalData->m_sliderEventHandlers.push_back(handler); + + pSlider->onValueChanged.Add( handler, &MySliderEventHandler::SliderMoved ); + handler->SliderMoved(pSlider); + float v = pSlider->GetValue(); + m_gwenInternalData->m_curYposition+=22; +} + +void GwenParameterInterface::syncParameters() +{ + for (int i=0;im_sliderEventHandlers.size();i++) + { + MySliderEventHandler* handler = m_paramInternalData->m_sliderEventHandlers[i]; + handler->m_pSlider->SetValue(*handler->m_targetValue,true); + } +} + +void GwenParameterInterface::removeAllParameters() +{ + for (int i=0;im_sliders.size();i++) + { + delete m_paramInternalData->m_sliders[i]; + } + m_paramInternalData->m_sliders.clear(); + + for (int i=0;im_sliderEventHandlers.size();i++) + { + delete m_paramInternalData->m_sliderEventHandlers[i]; + } + m_paramInternalData->m_sliderEventHandlers.clear(); + + for (int i=0;im_textLabels.size();i++) + { + delete m_paramInternalData->m_textLabels[i]; + } + m_paramInternalData->m_textLabels.clear(); + + m_gwenInternalData->m_curYposition = this->m_paramInternalData->m_savedYposition; +} \ No newline at end of file diff --git a/Demos3/AllBullet2Demos/GwenParameterInterface.h b/Demos3/AllBullet2Demos/GwenParameterInterface.h new file mode 100644 index 000000000..a36741dd9 --- /dev/null +++ b/Demos3/AllBullet2Demos/GwenParameterInterface.h @@ -0,0 +1,20 @@ +#ifndef GWEN_PARAMETER_INTERFACE_H +#define GWEN_PARAMETER_INTERFACE_H + +#include "../../Demos/CommonParameterInterface.h" + +struct GwenParameterInterface : public CommonParameterInterface +{ + struct GwenInternalData* m_gwenInternalData; + + struct GwenParameters* m_paramInternalData; + + GwenParameterInterface(struct GwenInternalData* gwenInternalData); + virtual ~GwenParameterInterface(); + virtual void registerSliderFloatParameter(SliderParams& params); + virtual void syncParameters(); + virtual void removeAllParameters(); + +}; + +#endif//GWEN_PARAMETER_INTERFACE_H diff --git a/Demos3/AllBullet2Demos/main.cpp b/Demos3/AllBullet2Demos/main.cpp index 9d9d0ca0a..230ceaf63 100644 --- a/Demos3/AllBullet2Demos/main.cpp +++ b/Demos3/AllBullet2Demos/main.cpp @@ -6,6 +6,8 @@ #include "../GpuDemos/gwenUserInterface.h" #include "BulletDemoEntries.h" #include "../../btgui/Timing/b3Clock.h" +#include "GwenParameterInterface.h" + #define DEMO_SELECTION_COMBOBOX 13 const char* startFileName = "bulletDemo.txt"; static SimpleOpenGL3App* app=0; @@ -114,6 +116,7 @@ void selectDemo(int demoIndex) } if (allDemos[demoIndex].m_createFunc && app) { + app->m_parameterInterface->removeAllParameters(); sCurrentDemo = (*allDemos[demoIndex].m_createFunc)(app); if (sCurrentDemo) { @@ -225,81 +228,6 @@ struct MyMenuItemHander :public Gwen::Event::Handler -template -struct MySliderEventHandler : public Gwen::Event::Handler -{ - Gwen::Controls::TextBox* m_label; - Gwen::Controls::Slider* m_pSlider; - char m_variableName[1024]; - T* m_targetValue; - - MySliderEventHandler(const char* varName, Gwen::Controls::TextBox* label, Gwen::Controls::Slider* pSlider,T* target) - :m_label(label), - m_pSlider(pSlider), - m_targetValue(target) - { - memcpy(m_variableName,varName,strlen(varName)+1); - } - - - void SliderMoved( Gwen::Controls::Base* pControl ) - { - Gwen::Controls::Slider* pSlider = (Gwen::Controls::Slider*)pControl; - //printf("value = %f\n", pSlider->GetValue());//UnitPrint( Utility::Format( L"Slider Value: %.2f", pSlider->GetValue() ) ); - float bla = pSlider->GetValue(); - T v = T(bla); - SetValue(v); - - } - - void SetValue(T v) - { - if (v < m_pSlider->GetRangeMin()) - { - printf("?\n"); - } - - if (v > m_pSlider->GetRangeMax()) - { - printf("?\n"); - - } - m_pSlider->SetValue(v,true); - (*m_targetValue) = v; - int val = int(v);//todo: specialize on template type - char txt[1024]; - sprintf(txt,"%s : %d", m_variableName,val); - m_label->SetText(txt); - - } -}; -void MyParameter(const char* name, GwenInternalData* data, double* param) -{ - Gwen::Controls::TextBox* label = new Gwen::Controls::TextBox(data->m_demoPage->GetPage()); - //m_data->m_myControls.push_back(label); - label->SetText( name); - label->SetPos( 10, 10 + 25 ); - label->SetWidth(110); - label->SetPos(10,data->m_curYposition); - data->m_curYposition+=22; - - Gwen::Controls::HorizontalSlider* pSlider = new Gwen::Controls::HorizontalSlider( data->m_demoPage->GetPage()); - //m_data->m_myControls.push_back(pSlider); - pSlider->SetPos( 10, data->m_curYposition ); - pSlider->SetSize( 100, 20 ); - pSlider->SetRange( -10, 10 ); - pSlider->SetNotchCount(10); - pSlider->SetClampToNotches( true ); - pSlider->SetValue( *param);//dimensions[i] ); - char labelName[1024]; - sprintf(labelName,"%s",name);//axisNames[0]); - MySliderEventHandler* handler = new MySliderEventHandler(labelName,label,pSlider,param); - pSlider->onValueChanged.Add( handler, &MySliderEventHandler::SliderMoved ); - handler->SliderMoved(pSlider); - float v = pSlider->GetValue(); - data->m_curYposition+=22; -} - extern float shadowMapWorldSize; int main(int argc, char* argv[]) { @@ -318,6 +246,7 @@ int main(int argc, char* argv[]) app->m_window->setMouseMoveCallback(MyMouseMoveCallback); app->m_window->setMouseButtonCallback(MyMouseButtonCallback); app->m_window->setKeyboardCallback(MyKeyboardCallback); + GLint err = glGetError(); assert(err==GL_NO_ERROR); @@ -328,6 +257,10 @@ int main(int argc, char* argv[]) // gui->getInternalData()->m_explorerPage Gwen::Controls::TreeControl* tree = gui->getInternalData()->m_explorerTreeCtrl; + + + app->m_parameterInterface = new GwenParameterInterface(gui->getInternalData()); + //gui->getInternalData()->m_demoPage; int numDemos = sizeof(allDemos)/sizeof(BulletDemoEntry); @@ -390,9 +323,7 @@ int main(int argc, char* argv[]) */ unsigned long int prevTimeInMicroseconds = clock.getTimeMicroseconds(); - MyParameter("Motor A",gui->getInternalData(),&motorA); - MyParameter("Motor B",gui->getInternalData(),&motorB); - + do { @@ -438,6 +369,7 @@ int main(int argc, char* argv[]) gui->draw(app->m_instancingRenderer->getScreenWidth(),app->m_instancingRenderer->getScreenHeight()); } toggle=1-toggle; + app->m_parameterInterface->syncParameters(); app->swapBuffer(); } while (!app->m_window->requestedExit()); diff --git a/Demos3/AllBullet2Demos/premake4.lua b/Demos3/AllBullet2Demos/premake4.lua index e9a3a3d59..93a648b63 100644 --- a/Demos3/AllBullet2Demos/premake4.lua +++ b/Demos3/AllBullet2Demos/premake4.lua @@ -27,6 +27,8 @@ "../../Demos/BasicDemo/BasicDemoPhysicsSetup.h", "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp", "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h", + "../../Demos/ConstraintDemo/ConstraintPhysicsSetup.cpp", + "../../Demos/ConstraintDemo/ConstraintPhysicsSetup.h", "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp", "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h", "../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.cpp", diff --git a/Demos3/GpuDemos/gwenUserInterface.cpp b/Demos3/GpuDemos/gwenUserInterface.cpp index dc306994a..bd45630ee 100644 --- a/Demos3/GpuDemos/gwenUserInterface.cpp +++ b/Demos3/GpuDemos/gwenUserInterface.cpp @@ -31,12 +31,25 @@ GwenUserInterface::~GwenUserInterface() delete coreRend; } - + +class MyMenuItems : public Gwen::Controls::Base +{ +public: + + MyMenuItems() :Gwen::Controls::Base(0) + { + } + void myQuitApp( Gwen::Controls::Base* pControl ) + { + exit(0); + } +}; struct MyTestMenuBar : public Gwen::Controls::MenuStrip { +MyMenuItems* menuItems = new MyMenuItems; MyTestMenuBar(Gwen::Controls::Base* pParent) :Gwen::Controls::MenuStrip(pParent) @@ -44,7 +57,7 @@ struct MyTestMenuBar : public Gwen::Controls::MenuStrip // Gwen::Controls::MenuStrip* menu = new Gwen::Controls::MenuStrip( pParent ); { Gwen::Controls::MenuItem* pRoot = AddItem( L"File" ); - + pRoot->GetMenu()->AddItem(L"Quit",menuItems,(Gwen::Event::Handler::Function)&MyMenuItems::myQuitApp); pRoot = AddItem( L"View" ); // Gwen::Event::Handler* handler = GWEN_MCALL(&MyTestMenuBar::MenuItemSelect ); pRoot->GetMenu()->AddItem( L"Profiler");//,,m_profileWindow,(Gwen::Event::Handler::Function)&MyProfileWindow::MenuItemSelect); diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp index 8c721a023..4ef48ddc0 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp @@ -140,6 +140,11 @@ struct MyGraphicsPhysicsBridge : public GraphicsPhysicsBridge ); } + + virtual CommonParameterInterface* getParameterInterface() + { + return m_glApp->m_parameterInterface; + } }; Bullet2RigidBodyDemo::Bullet2RigidBodyDemo(SimpleOpenGL3App* app, CommonPhysicsSetup* physicsSetup) diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h index a7475323b..7cf7a85a4 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h @@ -28,7 +28,10 @@ public: virtual void renderScene(); virtual void physicsDebugDraw(); virtual void stepSimulation(float dt); - + virtual CommonPhysicsSetup* getPhysicsSetup() + { + return m_physicsSetup; + } virtual ~Bullet2RigidBodyDemo(); btVector3 getRayTo(int x,int y); diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index 9b0a85b34..b3a739194 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -41,6 +41,7 @@ struct SimpleInternalData const char* m_frameDumpPngFileName; FILE* m_ffmpegFile; GLRenderToTexture* m_renderTexture; + void* m_userPointer; }; @@ -83,6 +84,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) m_data->m_frameDumpPngFileName = 0; m_data->m_renderTexture = 0; m_data->m_ffmpegFile = 0; + m_data->m_userPointer = 0; m_window = new b3gDefaultOpenGLWindow(); b3gWindowConstructionInfo ci; @@ -117,6 +119,7 @@ SimpleOpenGL3App::SimpleOpenGL3App( const char* title, int width,int height) b3Assert(glGetError() ==GL_NO_ERROR); m_primRenderer = new GLPrimitiveRenderer(width,height); + m_parameterInterface = 0; b3Assert(glGetError() ==GL_NO_ERROR); diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.h b/btgui/OpenGLWindow/SimpleOpenGL3App.h index 9bfa64e2c..eb4be1f6d 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.h +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.h @@ -31,6 +31,7 @@ struct SimpleOpenGL3App class b3gWindowInterface* m_window; class GLPrimitiveRenderer* m_primRenderer; class GLInstancingRenderer* m_instancingRenderer; + struct CommonParameterInterface* m_parameterInterface; SimpleOpenGL3App(const char* title, int width,int height); virtual ~SimpleOpenGL3App(); @@ -46,6 +47,7 @@ struct SimpleOpenGL3App void drawText( const char* txt, int posX, int posY); struct sth_stash* getFontStash(); + }; #endif //SIMPLE_OPENGL3_APP_H From 04632538ec3b496ff5e0e74555959c364ecc7a3c Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 13:38:31 -0700 Subject: [PATCH 105/116] add tinyxml, urdfdom and urdfdom_headers from https://github.com/ros/urdfdom (removed BOOST dependency and make it compile on Windows) --- btgui/tinyxml/tinystr.cpp | 111 + btgui/tinyxml/tinystr.h | 305 +++ btgui/tinyxml/tinyxml.cpp | 1886 +++++++++++++++++ btgui/tinyxml/tinyxml.h | 1805 ++++++++++++++++ btgui/tinyxml/tinyxmlerror.cpp | 52 + btgui/tinyxml/tinyxmlparser.cpp | 1638 ++++++++++++++ btgui/urdf/boost_replacement/lexical_cast.h | 27 + .../urdf/boost_replacement/printf_console.cpp | 28 + btgui/urdf/boost_replacement/printf_console.h | 13 + btgui/urdf/boost_replacement/shared_ptr.h | 213 ++ btgui/urdf/boost_replacement/string_split.cpp | 253 +++ btgui/urdf/boost_replacement/string_split.h | 31 + btgui/urdf/premake4.lua | 50 + btgui/urdf/urdfdom/LICENSE | 15 + btgui/urdf/urdfdom/README.txt | 7 + .../include/urdf_parser/urdf_parser.h | 63 + .../urdfdom/urdf_parser/src/check_urdf.cpp | 137 ++ btgui/urdf/urdfdom/urdf_parser/src/joint.cpp | 579 +++++ btgui/urdf/urdfdom/urdf_parser/src/link.cpp | 505 +++++ btgui/urdf/urdfdom/urdf_parser/src/model.cpp | 238 +++ btgui/urdf/urdfdom/urdf_parser/src/pose.cpp | 91 + btgui/urdf/urdfdom/urdf_parser/src/twist.cpp | 85 + .../urdf_parser/src/urdf_model_state.cpp | 154 ++ .../urdfdom/urdf_parser/src/urdf_sensor.cpp | 364 ++++ btgui/urdf/urdfdom/urdf_parser/src/world.cpp | 71 + .../urdf/urdfdom/urdf_parser/test/memtest.cpp | 20 + btgui/urdf/urdfdom_headers/LICENSE | 15 + btgui/urdf/urdfdom_headers/README.txt | 6 + .../include/urdf_exception/exception.h | 53 + .../urdf_model/include/urdf_model/color.h | 102 + .../urdf_model/include/urdf_model/joint.h | 234 ++ .../urdf_model/include/urdf_model/link.h | 258 +++ .../urdf_model/include/urdf_model/model.h | 215 ++ .../urdf_model/include/urdf_model/pose.h | 265 +++ .../urdf_model/include/urdf_model/twist.h | 68 + .../include/urdf_model_state/model_state.h | 141 ++ .../include/urdf_model_state/twist.h | 42 + .../urdf_sensor/include/urdf_sensor/sensor.h | 176 ++ .../urdf_world/include/urdf_world/world.h | 114 + build3/premake4.lua | 7 +- 40 files changed, 10434 insertions(+), 3 deletions(-) create mode 100755 btgui/tinyxml/tinystr.cpp create mode 100755 btgui/tinyxml/tinystr.h create mode 100755 btgui/tinyxml/tinyxml.cpp create mode 100755 btgui/tinyxml/tinyxml.h create mode 100755 btgui/tinyxml/tinyxmlerror.cpp create mode 100755 btgui/tinyxml/tinyxmlparser.cpp create mode 100644 btgui/urdf/boost_replacement/lexical_cast.h create mode 100644 btgui/urdf/boost_replacement/printf_console.cpp create mode 100644 btgui/urdf/boost_replacement/printf_console.h create mode 100644 btgui/urdf/boost_replacement/shared_ptr.h create mode 100644 btgui/urdf/boost_replacement/string_split.cpp create mode 100644 btgui/urdf/boost_replacement/string_split.h create mode 100644 btgui/urdf/premake4.lua create mode 100644 btgui/urdf/urdfdom/LICENSE create mode 100644 btgui/urdf/urdfdom/README.txt create mode 100644 btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/joint.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/link.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/model.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/pose.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/twist.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/urdf_model_state.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/urdf_sensor.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/src/world.cpp create mode 100644 btgui/urdf/urdfdom/urdf_parser/test/memtest.cpp create mode 100644 btgui/urdf/urdfdom_headers/LICENSE create mode 100644 btgui/urdf/urdfdom_headers/README.txt create mode 100644 btgui/urdf/urdfdom_headers/urdf_exception/include/urdf_exception/exception.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/color.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/twist.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_model_state/include/urdf_model_state/model_state.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_model_state/include/urdf_model_state/twist.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_sensor/include/urdf_sensor/sensor.h create mode 100644 btgui/urdf/urdfdom_headers/urdf_world/include/urdf_world/world.h diff --git a/btgui/tinyxml/tinystr.cpp b/btgui/tinyxml/tinystr.cpp new file mode 100755 index 000000000..066576820 --- /dev/null +++ b/btgui/tinyxml/tinystr.cpp @@ -0,0 +1,111 @@ +/* +www.sourceforge.net/projects/tinyxml + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TIXML_USE_STL + +#include "tinystr.h" + +// Error value for find primitive +const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); + + +// Null rep. +TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; + + +void TiXmlString::reserve (size_type cap) +{ + if (cap > capacity()) + { + TiXmlString tmp; + tmp.init(length(), cap); + memcpy(tmp.start(), data(), length()); + swap(tmp); + } +} + + +TiXmlString& TiXmlString::assign(const char* str, size_type len) +{ + size_type cap = capacity(); + if (len > cap || cap > 3*(len + 8)) + { + TiXmlString tmp; + tmp.init(len); + memcpy(tmp.start(), str, len); + swap(tmp); + } + else + { + memmove(start(), str, len); + set_size(len); + } + return *this; +} + + +TiXmlString& TiXmlString::append(const char* str, size_type len) +{ + size_type newsize = length() + len; + if (newsize > capacity()) + { + reserve (newsize + capacity()); + } + memmove(finish(), str, len); + set_size(newsize); + return *this; +} + + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) +{ + TiXmlString tmp; + tmp.reserve(a.length() + b.length()); + tmp += a; + tmp += b; + return tmp; +} + +TiXmlString operator + (const TiXmlString & a, const char* b) +{ + TiXmlString tmp; + TiXmlString::size_type b_len = static_cast( strlen(b) ); + tmp.reserve(a.length() + b_len); + tmp += a; + tmp.append(b, b_len); + return tmp; +} + +TiXmlString operator + (const char* a, const TiXmlString & b) +{ + TiXmlString tmp; + TiXmlString::size_type a_len = static_cast( strlen(a) ); + tmp.reserve(a_len + b.length()); + tmp.append(a, a_len); + tmp += b; + return tmp; +} + + +#endif // TIXML_USE_STL diff --git a/btgui/tinyxml/tinystr.h b/btgui/tinyxml/tinystr.h new file mode 100755 index 000000000..89cca3341 --- /dev/null +++ b/btgui/tinyxml/tinystr.h @@ -0,0 +1,305 @@ +/* +www.sourceforge.net/projects/tinyxml + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TIXML_USE_STL + +#ifndef TIXML_STRING_INCLUDED +#define TIXML_STRING_INCLUDED + +#include +#include + +/* The support for explicit isn't that universal, and it isn't really + required - it is used to check that the TiXmlString class isn't incorrectly + used. Be nice to old compilers and macro it here: +*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + #define TIXML_EXPLICIT explicit +#elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + #define TIXML_EXPLICIT explicit +#else + #define TIXML_EXPLICIT +#endif + + +/* + TiXmlString is an emulation of a subset of the std::string template. + Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. + Only the member functions relevant to the TinyXML project have been implemented. + The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase + a string and there's no more room, we allocate a buffer twice as big as we need. +*/ +class TiXmlString +{ + public : + // The size type used + typedef size_t size_type; + + // Error value for find primitive + static const size_type npos; // = -1; + + + // TiXmlString empty constructor + TiXmlString () : rep_(&nullrep_) + { + } + + // TiXmlString copy constructor + TiXmlString ( const TiXmlString & copy) : rep_(0) + { + init(copy.length()); + memcpy(start(), copy.data(), length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) + { + init( static_cast( strlen(copy) )); + memcpy(start(), copy, length()); + } + + // TiXmlString constructor, based on a string + TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) + { + init(len); + memcpy(start(), str, len); + } + + // TiXmlString destructor + ~TiXmlString () + { + quit(); + } + + TiXmlString& operator = (const char * copy) + { + return assign( copy, (size_type)strlen(copy)); + } + + TiXmlString& operator = (const TiXmlString & copy) + { + return assign(copy.start(), copy.length()); + } + + + // += operator. Maps to append + TiXmlString& operator += (const char * suffix) + { + return append(suffix, static_cast( strlen(suffix) )); + } + + // += operator. Maps to append + TiXmlString& operator += (char single) + { + return append(&single, 1); + } + + // += operator. Maps to append + TiXmlString& operator += (const TiXmlString & suffix) + { + return append(suffix.data(), suffix.length()); + } + + + // Convert a TiXmlString into a null-terminated char * + const char * c_str () const { return rep_->str; } + + // Convert a TiXmlString into a char * (need not be null terminated). + const char * data () const { return rep_->str; } + + // Return the length of a TiXmlString + size_type length () const { return rep_->size; } + + // Alias for length() + size_type size () const { return rep_->size; } + + // Checks if a TiXmlString is empty + bool empty () const { return rep_->size == 0; } + + // Return capacity of string + size_type capacity () const { return rep_->capacity; } + + + // single char extraction + const char& at (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // [] operator + char& operator [] (size_type index) const + { + assert( index < length() ); + return rep_->str[ index ]; + } + + // find a char in a string. Return TiXmlString::npos if not found + size_type find (char lookup) const + { + return find(lookup, 0); + } + + // find a char in a string from an offset. Return TiXmlString::npos if not found + size_type find (char tofind, size_type offset) const + { + if (offset >= length()) return npos; + + for (const char* p = c_str() + offset; *p != '\0'; ++p) + { + if (*p == tofind) return static_cast< size_type >( p - c_str() ); + } + return npos; + } + + void clear () + { + //Lee: + //The original was just too strange, though correct: + // TiXmlString().swap(*this); + //Instead use the quit & re-init: + quit(); + init(0,0); + } + + /* Function to reserve a big amount of data when we know we'll need it. Be aware that this + function DOES NOT clear the content of the TiXmlString if any exists. + */ + void reserve (size_type cap); + + TiXmlString& assign (const char* str, size_type len); + + TiXmlString& append (const char* str, size_type len); + + void swap (TiXmlString& other) + { + Rep* r = rep_; + rep_ = other.rep_; + other.rep_ = r; + } + + private: + + void init(size_type sz) { init(sz, sz); } + void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } + char* start() const { return rep_->str; } + char* finish() const { return rep_->str + rep_->size; } + + struct Rep + { + size_type size, capacity; + char str[1]; + }; + + void init(size_type sz, size_type cap) + { + if (cap) + { + // Lee: the original form: + // rep_ = static_cast(operator new(sizeof(Rep) + cap)); + // doesn't work in some cases of new being overloaded. Switching + // to the normal allocation, although use an 'int' for systems + // that are overly picky about structure alignment. + const size_type bytesNeeded = sizeof(Rep) + cap; + const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); + rep_ = reinterpret_cast( new int[ intsNeeded ] ); + + rep_->str[ rep_->size = sz ] = '\0'; + rep_->capacity = cap; + } + else + { + rep_ = &nullrep_; + } + } + + void quit() + { + if (rep_ != &nullrep_) + { + // The rep_ is really an array of ints. (see the allocator, above). + // Cast it back before delete, so the compiler won't incorrectly call destructors. + delete [] ( reinterpret_cast( rep_ ) ); + } + } + + Rep * rep_; + static Rep nullrep_; + +} ; + + +inline bool operator == (const TiXmlString & a, const TiXmlString & b) +{ + return ( a.length() == b.length() ) // optimization on some platforms + && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare +} +inline bool operator < (const TiXmlString & a, const TiXmlString & b) +{ + return strcmp(a.c_str(), b.c_str()) < 0; +} + +inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } +inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } +inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } +inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } + +inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } +inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } +inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } +inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } + +TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); +TiXmlString operator + (const TiXmlString & a, const char* b); +TiXmlString operator + (const char* a, const TiXmlString & b); + + +/* + TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. + Only the operators that we need for TinyXML have been developped. +*/ +class TiXmlOutStream : public TiXmlString +{ +public : + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const TiXmlString & in) + { + *this += in; + return *this; + } + + // TiXmlOutStream << operator. + TiXmlOutStream & operator << (const char * in) + { + *this += in; + return *this; + } + +} ; + +#endif // TIXML_STRING_INCLUDED +#endif // TIXML_USE_STL diff --git a/btgui/tinyxml/tinyxml.cpp b/btgui/tinyxml/tinyxml.cpp new file mode 100755 index 000000000..9c161dfcb --- /dev/null +++ b/btgui/tinyxml/tinyxml.cpp @@ -0,0 +1,1886 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#include + +#ifdef TIXML_USE_STL +#include +#include +#endif + +#include "tinyxml.h" + +FILE* TiXmlFOpen( const char* filename, const char* mode ); + +bool TiXmlBase::condenseWhiteSpace = true; + +// Microsoft compiler security +FILE* TiXmlFOpen( const char* filename, const char* mode ) +{ + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + FILE* fp = 0; + errno_t err = fopen_s( &fp, filename, mode ); + if ( !err && fp ) + return fp; + return 0; + #else + return fopen( filename, mode ); + #endif +} + +void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) +{ + int i=0; + + while( i<(int)str.length() ) + { + unsigned char c = (unsigned char) str[i]; + + if ( c == '&' + && i < ( (int)str.length() - 2 ) + && str[i+1] == '#' + && str[i+2] == 'x' ) + { + // Hexadecimal character reference. + // Pass through unchanged. + // © -- copyright symbol, for example. + // + // The -1 is a bug fix from Rob Laveaux. It keeps + // an overflow from happening if there is no ';'. + // There are actually 2 ways to exit this loop - + // while fails (error case) and break (semicolon found). + // However, there is no mechanism (currently) for + // this function to return an error. + while ( i<(int)str.length()-1 ) + { + outString->append( str.c_str() + i, 1 ); + ++i; + if ( str[i] == ';' ) + break; + } + } + else if ( c == '&' ) + { + outString->append( entity[0].str, entity[0].strLength ); + ++i; + } + else if ( c == '<' ) + { + outString->append( entity[1].str, entity[1].strLength ); + ++i; + } + else if ( c == '>' ) + { + outString->append( entity[2].str, entity[2].strLength ); + ++i; + } + else if ( c == '\"' ) + { + outString->append( entity[3].str, entity[3].strLength ); + ++i; + } + else if ( c == '\'' ) + { + outString->append( entity[4].str, entity[4].strLength ); + ++i; + } + else if ( c < 32 ) + { + // Easy pass at non-alpha/numeric/symbol + // Below 32 is symbolic. + char buf[ 32 ]; + + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); + #else + sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); + #endif + + //*ME: warning C4267: convert 'size_t' to 'int' + //*ME: Int-Cast to make compiler happy ... + outString->append( buf, (int)strlen( buf ) ); + ++i; + } + else + { + //char realc = (char) c; + //outString->append( &realc, 1 ); + *outString += (char) c; // somewhat more efficient function call. + ++i; + } + } +} + + +TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() +{ + parent = 0; + type = _type; + firstChild = 0; + lastChild = 0; + prev = 0; + next = 0; +} + + +TiXmlNode::~TiXmlNode() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } +} + + +void TiXmlNode::CopyTo( TiXmlNode* target ) const +{ + target->SetValue (value.c_str() ); + target->userData = userData; + target->location = location; +} + + +void TiXmlNode::Clear() +{ + TiXmlNode* node = firstChild; + TiXmlNode* temp = 0; + + while ( node ) + { + temp = node; + node = node->next; + delete temp; + } + + firstChild = 0; + lastChild = 0; +} + + +TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) +{ + assert( node->parent == 0 || node->parent == this ); + assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); + + if ( node->Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + delete node; + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + node->parent = this; + + node->prev = lastChild; + node->next = 0; + + if ( lastChild ) + lastChild->next = node; + else + firstChild = node; // it was an empty list. + + lastChild = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) +{ + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + + return LinkEndChild( node ); +} + + +TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) +{ + if ( !beforeThis || beforeThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->next = beforeThis; + node->prev = beforeThis->prev; + if ( beforeThis->prev ) + { + beforeThis->prev->next = node; + } + else + { + assert( firstChild == beforeThis ); + firstChild = node; + } + beforeThis->prev = node; + return node; +} + + +TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) +{ + if ( !afterThis || afterThis->parent != this ) { + return 0; + } + if ( addThis.Type() == TiXmlNode::TINYXML_DOCUMENT ) + { + if ( GetDocument() ) + GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = addThis.Clone(); + if ( !node ) + return 0; + node->parent = this; + + node->prev = afterThis; + node->next = afterThis->next; + if ( afterThis->next ) + { + afterThis->next->prev = node; + } + else + { + assert( lastChild == afterThis ); + lastChild = node; + } + afterThis->next = node; + return node; +} + + +TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) +{ + if ( !replaceThis ) + return 0; + + if ( replaceThis->parent != this ) + return 0; + + if ( withThis.ToDocument() ) { + // A document can never be a child. Thanks to Noam. + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + TiXmlNode* node = withThis.Clone(); + if ( !node ) + return 0; + + node->next = replaceThis->next; + node->prev = replaceThis->prev; + + if ( replaceThis->next ) + replaceThis->next->prev = node; + else + lastChild = node; + + if ( replaceThis->prev ) + replaceThis->prev->next = node; + else + firstChild = node; + + delete replaceThis; + node->parent = this; + return node; +} + + +bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) +{ + if ( !removeThis ) { + return false; + } + + if ( removeThis->parent != this ) + { + assert( 0 ); + return false; + } + + if ( removeThis->next ) + removeThis->next->prev = removeThis->prev; + else + lastChild = removeThis->prev; + + if ( removeThis->prev ) + removeThis->prev->next = removeThis->next; + else + firstChild = removeThis->next; + + delete removeThis; + return true; +} + +const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = firstChild; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = lastChild; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild(); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling(); + } +} + + +const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const +{ + if ( !previous ) + { + return FirstChild( val ); + } + else + { + assert( previous->parent == this ); + return previous->NextSibling( val ); + } +} + + +const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = next; node; node = node->next ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const +{ + const TiXmlNode* node; + for ( node = prev; node; node = node->prev ) + { + if ( strcmp( node->Value(), _value ) == 0 ) + return node; + } + return 0; +} + + +void TiXmlElement::RemoveAttribute( const char * name ) +{ + #ifdef TIXML_USE_STL + TIXML_STRING str( name ); + TiXmlAttribute* node = attributeSet.Find( str ); + #else + TiXmlAttribute* node = attributeSet.Find( name ); + #endif + if ( node ) + { + attributeSet.Remove( node ); + delete node; + } +} + +const TiXmlElement* TiXmlNode::FirstChildElement() const +{ + const TiXmlNode* node; + + for ( node = FirstChild(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = FirstChild( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement() const +{ + const TiXmlNode* node; + + for ( node = NextSibling(); + node; + node = node->NextSibling() ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const +{ + const TiXmlNode* node; + + for ( node = NextSibling( _value ); + node; + node = node->NextSibling( _value ) ) + { + if ( node->ToElement() ) + return node->ToElement(); + } + return 0; +} + + +const TiXmlDocument* TiXmlNode::GetDocument() const +{ + const TiXmlNode* node; + + for( node = this; node; node = node->parent ) + { + if ( node->ToDocument() ) + return node->ToDocument(); + } + return 0; +} + + +TiXmlElement::TiXmlElement (const char * _value) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} + + +#ifdef TIXML_USE_STL +TiXmlElement::TiXmlElement( const std::string& _value ) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) +{ + firstChild = lastChild = 0; + value = _value; +} +#endif + + +TiXmlElement::TiXmlElement( const TiXmlElement& copy) + : TiXmlNode( TiXmlNode::TINYXML_ELEMENT ) +{ + firstChild = lastChild = 0; + copy.CopyTo( this ); +} + + +TiXmlElement& TiXmlElement::operator=( const TiXmlElement& base ) +{ + ClearThis(); + base.CopyTo( this ); + return *this; +} + + +TiXmlElement::~TiXmlElement() +{ + ClearThis(); +} + + +void TiXmlElement::ClearThis() +{ + Clear(); + while( attributeSet.First() ) + { + TiXmlAttribute* node = attributeSet.First(); + attributeSet.Remove( node ); + delete node; + } +} + + +const char* TiXmlElement::Attribute( const char* name ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( node ) + return node->Value(); + return 0; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( attrib ) + return &attrib->ValueStr(); + return 0; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, int* i ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; + + if ( attrib ) { + result = attrib->Value(); + if ( i ) { + attrib->QueryIntValue( i ); + } + } + return result; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; + + if ( attrib ) { + result = &attrib->ValueStr(); + if ( i ) { + attrib->QueryIntValue( i ); + } + } + return result; +} +#endif + + +const char* TiXmlElement::Attribute( const char* name, double* d ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const char* result = 0; + + if ( attrib ) { + result = attrib->Value(); + if ( d ) { + attrib->QueryDoubleValue( d ); + } + } + return result; +} + + +#ifdef TIXML_USE_STL +const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + const std::string* result = 0; + + if ( attrib ) { + result = &attrib->ValueStr(); + if ( d ) { + attrib->QueryDoubleValue( d ); + } + } + return result; +} +#endif + + +int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); +} + + +int TiXmlElement::QueryUnsignedAttribute( const char* name, unsigned* value ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + int ival = 0; + int result = node->QueryIntValue( &ival ); + *value = (unsigned)ival; + return result; +} + + +int TiXmlElement::QueryBoolAttribute( const char* name, bool* bval ) const +{ + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + int result = TIXML_WRONG_TYPE; + if ( StringEqual( node->Value(), "true", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "yes", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "1", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = true; + result = TIXML_SUCCESS; + } + else if ( StringEqual( node->Value(), "false", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "no", true, TIXML_ENCODING_UNKNOWN ) + || StringEqual( node->Value(), "0", true, TIXML_ENCODING_UNKNOWN ) ) + { + *bval = false; + result = TIXML_SUCCESS; + } + return result; +} + + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryIntValue( ival ); +} +#endif + + +int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryDoubleValue( dval ); +} + + +#ifdef TIXML_USE_STL +int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const +{ + const TiXmlAttribute* attrib = attributeSet.Find( name ); + if ( !attrib ) + return TIXML_NO_ATTRIBUTE; + return attrib->QueryDoubleValue( dval ); +} +#endif + + +void TiXmlElement::SetAttribute( const char * name, int val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& name, int val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetIntValue( val ); + } +} +#endif + + +void TiXmlElement::SetDoubleAttribute( const char * name, double val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetDoubleAttribute( const std::string& name, double val ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( name ); + if ( attrib ) { + attrib->SetDoubleValue( val ); + } +} +#endif + + +void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( cname ); + if ( attrib ) { + attrib->SetValue( cvalue ); + } +} + + +#ifdef TIXML_USE_STL +void TiXmlElement::SetAttribute( const std::string& _name, const std::string& _value ) +{ + TiXmlAttribute* attrib = attributeSet.FindOrCreate( _name ); + if ( attrib ) { + attrib->SetValue( _value ); + } +} +#endif + + +void TiXmlElement::Print( FILE* cfile, int depth ) const +{ + int i; + assert( cfile ); + for ( i=0; iNext() ) + { + fprintf( cfile, " " ); + attrib->Print( cfile, depth ); + } + + // There are 3 different formatting approaches: + // 1) An element without children is printed as a node + // 2) An element with only a text child is printed as text + // 3) An element with children is printed on multiple lines. + TiXmlNode* node; + if ( !firstChild ) + { + fprintf( cfile, " />" ); + } + else if ( firstChild == lastChild && firstChild->ToText() ) + { + fprintf( cfile, ">" ); + firstChild->Print( cfile, depth + 1 ); + fprintf( cfile, "", value.c_str() ); + } + else + { + fprintf( cfile, ">" ); + + for ( node = firstChild; node; node=node->NextSibling() ) + { + if ( !node->ToText() ) + { + fprintf( cfile, "\n" ); + } + node->Print( cfile, depth+1 ); + } + fprintf( cfile, "\n" ); + for( i=0; i", value.c_str() ); + } +} + + +void TiXmlElement::CopyTo( TiXmlElement* target ) const +{ + // superclass: + TiXmlNode::CopyTo( target ); + + // Element class: + // Clone the attributes, then clone the children. + const TiXmlAttribute* attribute = 0; + for( attribute = attributeSet.First(); + attribute; + attribute = attribute->Next() ) + { + target->SetAttribute( attribute->Name(), attribute->Value() ); + } + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + +bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this, attributeSet.First() ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +TiXmlNode* TiXmlElement::Clone() const +{ + TiXmlElement* clone = new TiXmlElement( Value() ); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +const char* TiXmlElement::GetText() const +{ + const TiXmlNode* child = this->FirstChild(); + if ( child ) { + const TiXmlText* childText = child->ToText(); + if ( childText ) { + return childText->Value(); + } + } + return 0; +} + + +TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + ClearError(); +} + +TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} + + +#ifdef TIXML_USE_STL +TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) +{ + tabsize = 4; + useMicrosoftBOM = false; + value = documentName; + ClearError(); +} +#endif + + +TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::TINYXML_DOCUMENT ) +{ + copy.CopyTo( this ); +} + + +TiXmlDocument& TiXmlDocument::operator=( const TiXmlDocument& copy ) +{ + Clear(); + copy.CopyTo( this ); + return *this; +} + + +bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) +{ + return LoadFile( Value(), encoding ); +} + + +bool TiXmlDocument::SaveFile() const +{ + return SaveFile( Value() ); +} + +bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) +{ + TIXML_STRING filename( _filename ); + value = filename; + + // reading in binary mode so that tinyxml can normalize the EOL + FILE* file = TiXmlFOpen( value.c_str (), "rb" ); + + if ( file ) + { + bool result = LoadFile( file, encoding ); + fclose( file ); + return result; + } + else + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } +} + +bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) +{ + if ( !file ) + { + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Delete the existing data: + Clear(); + location.Clear(); + + // Get the file size, so we can pre-allocate the string. HUGE speed impact. + long length = 0; + fseek( file, 0, SEEK_END ); + length = ftell( file ); + fseek( file, 0, SEEK_SET ); + + // Strange case, but good to handle up front. + if ( length <= 0 ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Subtle bug here. TinyXml did use fgets. But from the XML spec: + // 2.11 End-of-Line Handling + // + // + // ...the XML processor MUST behave as if it normalized all line breaks in external + // parsed entities (including the document entity) on input, before parsing, by translating + // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to + // a single #xA character. + // + // + // It is not clear fgets does that, and certainly isn't clear it works cross platform. + // Generally, you expect fgets to translate from the convention of the OS to the c/unix + // convention, and not work generally. + + /* + while( fgets( buf, sizeof(buf), file ) ) + { + data += buf; + } + */ + + char* buf = new char[ length+1 ]; + buf[0] = 0; + + if ( fread( buf, length, 1, file ) != 1 ) { + delete [] buf; + SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); + return false; + } + + // Process the buffer in place to normalize new lines. (See comment above.) + // Copies from the 'p' to 'q' pointer, where p can advance faster if + // a newline-carriage return is hit. + // + // Wikipedia: + // Systems based on ASCII or a compatible character set use either LF (Line feed, '\n', 0x0A, 10 in decimal) or + // CR (Carriage return, '\r', 0x0D, 13 in decimal) individually, or CR followed by LF (CR+LF, 0x0D 0x0A)... + // * LF: Multics, Unix and Unix-like systems (GNU/Linux, AIX, Xenix, Mac OS X, FreeBSD, etc.), BeOS, Amiga, RISC OS, and others + // * CR+LF: DEC RT-11 and most other early non-Unix, non-IBM OSes, CP/M, MP/M, DOS, OS/2, Microsoft Windows, Symbian OS + // * CR: Commodore 8-bit machines, Apple II family, Mac OS up to version 9 and OS-9 + + const char* p = buf; // the read head + char* q = buf; // the write head + const char CR = 0x0d; + const char LF = 0x0a; + + buf[length] = 0; + while( *p ) { + assert( p < (buf+length) ); + assert( q <= (buf+length) ); + assert( q <= p ); + + if ( *p == CR ) { + *q++ = LF; + p++; + if ( *p == LF ) { // check for CR+LF (and skip LF) + p++; + } + } + else { + *q++ = *p++; + } + } + assert( q <= (buf+length) ); + *q = 0; + + Parse( buf, 0, encoding ); + + delete [] buf; + return !Error(); +} + + +bool TiXmlDocument::SaveFile( const char * filename ) const +{ + // The old c stuff lives on... + FILE* fp = TiXmlFOpen( filename, "w" ); + if ( fp ) + { + bool result = SaveFile( fp ); + fclose( fp ); + return result; + } + return false; +} + + +bool TiXmlDocument::SaveFile( FILE* fp ) const +{ + if ( useMicrosoftBOM ) + { + const unsigned char TIXML_UTF_LEAD_0 = 0xefU; + const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; + const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + + fputc( TIXML_UTF_LEAD_0, fp ); + fputc( TIXML_UTF_LEAD_1, fp ); + fputc( TIXML_UTF_LEAD_2, fp ); + } + Print( fp, 0 ); + return (ferror(fp) == 0); +} + + +void TiXmlDocument::CopyTo( TiXmlDocument* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->error = error; + target->errorId = errorId; + target->errorDesc = errorDesc; + target->tabsize = tabsize; + target->errorLocation = errorLocation; + target->useMicrosoftBOM = useMicrosoftBOM; + + TiXmlNode* node = 0; + for ( node = firstChild; node; node = node->NextSibling() ) + { + target->LinkEndChild( node->Clone() ); + } +} + + +TiXmlNode* TiXmlDocument::Clone() const +{ + TiXmlDocument* clone = new TiXmlDocument(); + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlDocument::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + node->Print( cfile, depth ); + fprintf( cfile, "\n" ); + } +} + + +bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const +{ + if ( visitor->VisitEnter( *this ) ) + { + for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) + { + if ( !node->Accept( visitor ) ) + break; + } + } + return visitor->VisitExit( *this ); +} + + +const TiXmlAttribute* TiXmlAttribute::Next() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} + +/* +TiXmlAttribute* TiXmlAttribute::Next() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( next->value.empty() && next->name.empty() ) + return 0; + return next; +} +*/ + +const TiXmlAttribute* TiXmlAttribute::Previous() const +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} + +/* +TiXmlAttribute* TiXmlAttribute::Previous() +{ + // We are using knowledge of the sentinel. The sentinel + // have a value or name. + if ( prev->value.empty() && prev->name.empty() ) + return 0; + return prev; +} +*/ + +void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + TIXML_STRING n, v; + + EncodeString( name, &n ); + EncodeString( value, &v ); + + if (value.find ('\"') == TIXML_STRING::npos) { + if ( cfile ) { + fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; + } + } + else { + if ( cfile ) { + fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); + } + if ( str ) { + (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; + } + } +} + + +int TiXmlAttribute::QueryIntValue( int* ival ) const +{ + if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +int TiXmlAttribute::QueryDoubleValue( double* dval ) const +{ + if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; +} + +void TiXmlAttribute::SetIntValue( int _value ) +{ + char buf [64]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); + #else + sprintf (buf, "%d", _value); + #endif + SetValue (buf); +} + +void TiXmlAttribute::SetDoubleValue( double _value ) +{ + char buf [256]; + #if defined(TIXML_SNPRINTF) + TIXML_SNPRINTF( buf, sizeof(buf), "%g", _value); + #else + sprintf (buf, "%g", _value); + #endif + SetValue (buf); +} + +int TiXmlAttribute::IntValue() const +{ + return atoi (value.c_str ()); +} + +double TiXmlAttribute::DoubleValue() const +{ + return atof (value.c_str ()); +} + + +TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) +{ + copy.CopyTo( this ); +} + + +TiXmlComment& TiXmlComment::operator=( const TiXmlComment& base ) +{ + Clear(); + base.CopyTo( this ); + return *this; +} + + +void TiXmlComment::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlComment::CopyTo( TiXmlComment* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlComment::Clone() const +{ + TiXmlComment* clone = new TiXmlComment(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlText::Print( FILE* cfile, int depth ) const +{ + assert( cfile ); + if ( cdata ) + { + int i; + fprintf( cfile, "\n" ); + for ( i=0; i\n", value.c_str() ); // unformatted output + } + else + { + TIXML_STRING buffer; + EncodeString( value, &buffer ); + fprintf( cfile, "%s", buffer.c_str() ); + } +} + + +void TiXmlText::CopyTo( TiXmlText* target ) const +{ + TiXmlNode::CopyTo( target ); + target->cdata = cdata; +} + + +bool TiXmlText::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlText::Clone() const +{ + TiXmlText* clone = 0; + clone = new TiXmlText( "" ); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlDeclaration::TiXmlDeclaration( const char * _version, + const char * _encoding, + const char * _standalone ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} + + +#ifdef TIXML_USE_STL +TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) +{ + version = _version; + encoding = _encoding; + standalone = _standalone; +} +#endif + + +TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) + : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) +{ + copy.CopyTo( this ); +} + + +TiXmlDeclaration& TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) +{ + Clear(); + copy.CopyTo( this ); + return *this; +} + + +void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const +{ + if ( cfile ) fprintf( cfile, "" ); + if ( str ) (*str) += "?>"; +} + + +void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const +{ + TiXmlNode::CopyTo( target ); + + target->version = version; + target->encoding = encoding; + target->standalone = standalone; +} + + +bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlDeclaration::Clone() const +{ + TiXmlDeclaration* clone = new TiXmlDeclaration(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +void TiXmlUnknown::Print( FILE* cfile, int depth ) const +{ + for ( int i=0; i", value.c_str() ); +} + + +void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const +{ + TiXmlNode::CopyTo( target ); +} + + +bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const +{ + return visitor->Visit( *this ); +} + + +TiXmlNode* TiXmlUnknown::Clone() const +{ + TiXmlUnknown* clone = new TiXmlUnknown(); + + if ( !clone ) + return 0; + + CopyTo( clone ); + return clone; +} + + +TiXmlAttributeSet::TiXmlAttributeSet() +{ + sentinel.next = &sentinel; + sentinel.prev = &sentinel; +} + + +TiXmlAttributeSet::~TiXmlAttributeSet() +{ + assert( sentinel.next == &sentinel ); + assert( sentinel.prev == &sentinel ); +} + + +void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) +{ + #ifdef TIXML_USE_STL + assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. + #else + assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. + #endif + + addMe->next = &sentinel; + addMe->prev = sentinel.prev; + + sentinel.prev->next = addMe; + sentinel.prev = addMe; +} + +void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) +{ + TiXmlAttribute* node; + + for( node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node == removeMe ) + { + node->prev->next = node->next; + node->next->prev = node->prev; + node->next = 0; + node->prev = 0; + return; + } + } + assert( 0 ); // we tried to remove a non-linked attribute. +} + + +#ifdef TIXML_USE_STL +TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( node->name == name ) + return node; + } + return 0; +} + +TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const std::string& _name ) +{ + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); + } + return attrib; +} +#endif + + +TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const +{ + for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) + { + if ( strcmp( node->name.c_str(), name ) == 0 ) + return node; + } + return 0; +} + + +TiXmlAttribute* TiXmlAttributeSet::FindOrCreate( const char* _name ) +{ + TiXmlAttribute* attrib = Find( _name ); + if ( !attrib ) { + attrib = new TiXmlAttribute(); + Add( attrib ); + attrib->SetName( _name ); + } + return attrib; +} + + +#ifdef TIXML_USE_STL +std::istream& operator>> (std::istream & in, TiXmlNode & base) +{ + TIXML_STRING tag; + tag.reserve( 8 * 1000 ); + base.StreamIn( &in, &tag ); + + base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); + return in; +} +#endif + + +#ifdef TIXML_USE_STL +std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out << printer.Str(); + + return out; +} + + +std::string& operator<< (std::string& out, const TiXmlNode& base ) +{ + TiXmlPrinter printer; + printer.SetStreamPrinting(); + base.Accept( &printer ); + out.append( printer.Str() ); + + return out; +} +#endif + + +TiXmlHandle TiXmlHandle::FirstChild() const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const +{ + if ( node ) + { + TiXmlNode* child = node->FirstChild( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement() const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement(); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const +{ + if ( node ) + { + TiXmlElement* child = node->FirstChildElement( value ); + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild(); + for ( i=0; + child && iNextSibling(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlNode* child = node->FirstChild( value ); + for ( i=0; + child && iNextSibling( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement(); + for ( i=0; + child && iNextSiblingElement(), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const +{ + if ( node ) + { + int i; + TiXmlElement* child = node->FirstChildElement( value ); + for ( i=0; + child && iNextSiblingElement( value ), ++i ) + { + // nothing + } + if ( child ) + return TiXmlHandle( child ); + } + return TiXmlHandle( 0 ); +} + + +bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) +{ + return true; +} + +bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) +{ + DoIndent(); + buffer += "<"; + buffer += element.Value(); + + for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) + { + buffer += " "; + attrib->Print( 0, 0, &buffer ); + } + + if ( !element.FirstChild() ) + { + buffer += " />"; + DoLineBreak(); + } + else + { + buffer += ">"; + if ( element.FirstChild()->ToText() + && element.LastChild() == element.FirstChild() + && element.FirstChild()->ToText()->CDATA() == false ) + { + simpleTextPrint = true; + // no DoLineBreak()! + } + else + { + DoLineBreak(); + } + } + ++depth; + return true; +} + + +bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) +{ + --depth; + if ( !element.FirstChild() ) + { + // nothing. + } + else + { + if ( simpleTextPrint ) + { + simpleTextPrint = false; + } + else + { + DoIndent(); + } + buffer += ""; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlText& text ) +{ + if ( text.CDATA() ) + { + DoIndent(); + buffer += ""; + DoLineBreak(); + } + else if ( simpleTextPrint ) + { + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + } + else + { + DoIndent(); + TIXML_STRING str; + TiXmlBase::EncodeString( text.ValueTStr(), &str ); + buffer += str; + DoLineBreak(); + } + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) +{ + DoIndent(); + declaration.Print( 0, 0, &buffer ); + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlComment& comment ) +{ + DoIndent(); + buffer += ""; + DoLineBreak(); + return true; +} + + +bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) +{ + DoIndent(); + buffer += "<"; + buffer += unknown.Value(); + buffer += ">"; + DoLineBreak(); + return true; +} + diff --git a/btgui/tinyxml/tinyxml.h b/btgui/tinyxml/tinyxml.h new file mode 100755 index 000000000..a3589e5b2 --- /dev/null +++ b/btgui/tinyxml/tinyxml.h @@ -0,0 +1,1805 @@ +/* +www.sourceforge.net/projects/tinyxml +Original code by Lee Thomason (www.grinninglizard.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#ifndef TINYXML_INCLUDED +#define TINYXML_INCLUDED + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4530 ) +#pragma warning( disable : 4786 ) +#endif + +#include +#include +#include +#include +#include + +// Help out windows: +#if defined( _DEBUG ) && !defined( DEBUG ) +#define DEBUG +#endif + +#ifdef TIXML_USE_STL + #include + #include + #include + #define TIXML_STRING std::string +#else + #include "tinystr.h" + #define TIXML_STRING TiXmlString +#endif + +// Deprecated library function hell. Compilers want to use the +// new safe versions. This probably doesn't fully address the problem, +// but it gets closer. There are too many compilers for me to fully +// test. If you get compilation troubles, undefine TIXML_SAFE +#define TIXML_SAFE + +#ifdef TIXML_SAFE + #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) + // Microsoft visual studio, version 2005 and higher. + #define TIXML_SNPRINTF _snprintf_s + #define TIXML_SSCANF sscanf_s + #elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) + // Microsoft visual studio, version 6 and higher. + //#pragma message( "Using _sn* functions." ) + #define TIXML_SNPRINTF _snprintf + #define TIXML_SSCANF sscanf + #elif defined(__GNUC__) && (__GNUC__ >= 3 ) + // GCC version 3 and higher.s + //#warning( "Using sn* functions." ) + #define TIXML_SNPRINTF snprintf + #define TIXML_SSCANF sscanf + #else + #define TIXML_SNPRINTF snprintf + #define TIXML_SSCANF sscanf + #endif +#endif + +class TiXmlDocument; +class TiXmlElement; +class TiXmlComment; +class TiXmlUnknown; +class TiXmlAttribute; +class TiXmlText; +class TiXmlDeclaration; +class TiXmlParsingData; + +const int TIXML_MAJOR_VERSION = 2; +const int TIXML_MINOR_VERSION = 6; +const int TIXML_PATCH_VERSION = 2; + +/* Internal structure for tracking location of items + in the XML file. +*/ +struct TiXmlCursor +{ + TiXmlCursor() { Clear(); } + void Clear() { row = col = -1; } + + int row; // 0 based. + int col; // 0 based. +}; + + +/** + Implements the interface to the "Visitor pattern" (see the Accept() method.) + If you call the Accept() method, it requires being passed a TiXmlVisitor + class to handle callbacks. For nodes that contain other nodes (Document, Element) + you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves + are simply called with Visit(). + + If you return 'true' from a Visit method, recursive parsing will continue. If you return + false, no children of this node or its sibilings will be Visited. + + All flavors of Visit methods have a default implementation that returns 'true' (continue + visiting). You need to only override methods that are interesting to you. + + Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. + + You should never change the document from a callback. + + @sa TiXmlNode::Accept() +*/ +class TiXmlVisitor +{ +public: + virtual ~TiXmlVisitor() {} + + /// Visit a document. + virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } + /// Visit a document. + virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } + + /// Visit an element. + virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } + /// Visit an element. + virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } + + /// Visit a declaration + virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } + /// Visit a text node + virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } + /// Visit a comment node + virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } + /// Visit an unknown node + virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } +}; + +// Only used by Attribute::Query functions +enum +{ + TIXML_SUCCESS, + TIXML_NO_ATTRIBUTE, + TIXML_WRONG_TYPE +}; + + +// Used by the parsing routines. +enum TiXmlEncoding +{ + TIXML_ENCODING_UNKNOWN, + TIXML_ENCODING_UTF8, + TIXML_ENCODING_LEGACY +}; + +const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; + +/** TiXmlBase is a base class for every class in TinyXml. + It does little except to establish that TinyXml classes + can be printed and provide some utility functions. + + In XML, the document and elements can contain + other elements and other types of nodes. + + @verbatim + A Document can contain: Element (container or leaf) + Comment (leaf) + Unknown (leaf) + Declaration( leaf ) + + An Element can contain: Element (container or leaf) + Text (leaf) + Attributes (not on tree) + Comment (leaf) + Unknown (leaf) + + A Decleration contains: Attributes (not on tree) + @endverbatim +*/ +class TiXmlBase +{ + friend class TiXmlNode; + friend class TiXmlElement; + friend class TiXmlDocument; + +public: + TiXmlBase() : userData(0) {} + virtual ~TiXmlBase() {} + + /** All TinyXml classes can print themselves to a filestream + or the string class (TiXmlString in non-STL mode, std::string + in STL mode.) Either or both cfile and str can be null. + + This is a formatted print, and will insert + tabs and newlines. + + (For an unformatted stream, use the << operator.) + */ + virtual void Print( FILE* cfile, int depth ) const = 0; + + /** The world does not agree on whether white space should be kept or + not. In order to make everyone happy, these global, static functions + are provided to set whether or not TinyXml will condense all white space + into a single space or not. The default is to condense. Note changing this + value is not thread safe. + */ + static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } + + /// Return the current white space setting. + static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } + + /** Return the position, in the original source file, of this node or attribute. + The row and column are 1-based. (That is the first row and first column is + 1,1). If the returns values are 0 or less, then the parser does not have + a row and column value. + + Generally, the row and column value will be set when the TiXmlDocument::Load(), + TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set + when the DOM was created from operator>>. + + The values reflect the initial load. Once the DOM is modified programmatically + (by adding or changing nodes and attributes) the new values will NOT update to + reflect changes in the document. + + There is a minor performance cost to computing the row and column. Computation + can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. + + @sa TiXmlDocument::SetTabSize() + */ + int Row() const { return location.row + 1; } + int Column() const { return location.col + 1; } ///< See Row() + + void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. + void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. + const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. + + // Table that returs, for a given lead byte, the total number of bytes + // in the UTF-8 sequence. + static const int utf8ByteTable[256]; + + virtual const char* Parse( const char* p, + TiXmlParsingData* data, + TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; + + /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, + or they will be transformed into entities! + */ + static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); + + enum + { + TIXML_NO_ERROR = 0, + TIXML_ERROR, + TIXML_ERROR_OPENING_FILE, + TIXML_ERROR_PARSING_ELEMENT, + TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, + TIXML_ERROR_READING_ELEMENT_VALUE, + TIXML_ERROR_READING_ATTRIBUTES, + TIXML_ERROR_PARSING_EMPTY, + TIXML_ERROR_READING_END_TAG, + TIXML_ERROR_PARSING_UNKNOWN, + TIXML_ERROR_PARSING_COMMENT, + TIXML_ERROR_PARSING_DECLARATION, + TIXML_ERROR_DOCUMENT_EMPTY, + TIXML_ERROR_EMBEDDED_NULL, + TIXML_ERROR_PARSING_CDATA, + TIXML_ERROR_DOCUMENT_TOP_ONLY, + + TIXML_ERROR_STRING_COUNT + }; + +protected: + + static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); + + inline static bool IsWhiteSpace( char c ) + { + return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); + } + inline static bool IsWhiteSpace( int c ) + { + if ( c < 256 ) + return IsWhiteSpace( (char) c ); + return false; // Again, only truly correct for English/Latin...but usually works. + } + + #ifdef TIXML_USE_STL + static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); + static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); + #endif + + /* Reads an XML name into the string provided. Returns + a pointer just past the last character of the name, + or 0 if the function has an error. + */ + static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); + + /* Reads text. Returns a pointer past the given end tag. + Wickedly complex options, but it keeps the (sensitive) code in one place. + */ + static const char* ReadText( const char* in, // where to start + TIXML_STRING* text, // the string read + bool ignoreWhiteSpace, // whether to keep the white space + const char* endTag, // what ends this text + bool ignoreCase, // whether to ignore case in the end tag + TiXmlEncoding encoding ); // the current encoding + + // If an entity has been found, transform it into a character. + static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); + + // Get a character, while interpreting entities. + // The length can be from 0 to 4 bytes. + inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) + { + assert( p ); + if ( encoding == TIXML_ENCODING_UTF8 ) + { + *length = utf8ByteTable[ *((const unsigned char*)p) ]; + assert( *length >= 0 && *length < 5 ); + } + else + { + *length = 1; + } + + if ( *length == 1 ) + { + if ( *p == '&' ) + return GetEntity( p, _value, length, encoding ); + *_value = *p; + return p+1; + } + else if ( *length ) + { + //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), + // and the null terminator isn't needed + for( int i=0; p[i] && i<*length; ++i ) { + _value[i] = p[i]; + } + return p + (*length); + } + else + { + // Not valid text. + return 0; + } + } + + // Return true if the next characters in the stream are any of the endTag sequences. + // Ignore case only works for english, and should only be relied on when comparing + // to English words: StringEqual( p, "version", true ) is fine. + static bool StringEqual( const char* p, + const char* endTag, + bool ignoreCase, + TiXmlEncoding encoding ); + + static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; + + TiXmlCursor location; + + /// Field containing a generic user pointer + void* userData; + + // None of these methods are reliable for any language except English. + // Good for approximation, not great for accuracy. + static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); + static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); + inline static int ToLower( int v, TiXmlEncoding encoding ) + { + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( v < 128 ) return tolower( v ); + return v; + } + else + { + return tolower( v ); + } + } + static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); + +private: + TiXmlBase( const TiXmlBase& ); // not implemented. + void operator=( const TiXmlBase& base ); // not allowed. + + struct Entity + { + const char* str; + unsigned int strLength; + char chr; + }; + enum + { + NUM_ENTITY = 5, + MAX_ENTITY_LENGTH = 6 + + }; + static Entity entity[ NUM_ENTITY ]; + static bool condenseWhiteSpace; +}; + + +/** The parent class for everything in the Document Object Model. + (Except for attributes). + Nodes have siblings, a parent, and children. A node can be + in a document, or stand on its own. The type of a TiXmlNode + can be queried, and it can be cast to its more defined type. +*/ +class TiXmlNode : public TiXmlBase +{ + friend class TiXmlDocument; + friend class TiXmlElement; + +public: + #ifdef TIXML_USE_STL + + /** An input stream operator, for every class. Tolerant of newlines and + formatting, but doesn't expect them. + */ + friend std::istream& operator >> (std::istream& in, TiXmlNode& base); + + /** An output stream operator, for every class. Note that this outputs + without any newlines or formatting, as opposed to Print(), which + includes tabs and new lines. + + The operator<< and operator>> are not completely symmetric. Writing + a node to a stream is very well defined. You'll get a nice stream + of output, without any extra whitespace or newlines. + + But reading is not as well defined. (As it always is.) If you create + a TiXmlElement (for example) and read that from an input stream, + the text needs to define an element or junk will result. This is + true of all input streams, but it's worth keeping in mind. + + A TiXmlDocument will read nodes until it reads a root element, and + all the children of that root element. + */ + friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); + + /// Appends the XML node or attribute to a std::string. + friend std::string& operator<< (std::string& out, const TiXmlNode& base ); + + #endif + + /** The types of XML nodes supported by TinyXml. (All the + unsupported types are picked up by UNKNOWN.) + */ + enum NodeType + { + TINYXML_DOCUMENT, + TINYXML_ELEMENT, + TINYXML_COMMENT, + TINYXML_UNKNOWN, + TINYXML_TEXT, + TINYXML_DECLARATION, + TINYXML_TYPECOUNT + }; + + virtual ~TiXmlNode(); + + /** The meaning of 'value' changes for the specific type of + TiXmlNode. + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + + The subclasses will wrap this function. + */ + const char *Value() const { return value.c_str (); } + + #ifdef TIXML_USE_STL + /** Return Value() as a std::string. If you only use STL, + this is more efficient than calling Value(). + Only available in STL mode. + */ + const std::string& ValueStr() const { return value; } + #endif + + const TIXML_STRING& ValueTStr() const { return value; } + + /** Changes the value of the node. Defined as: + @verbatim + Document: filename of the xml file + Element: name of the element + Comment: the comment text + Unknown: the tag contents + Text: the text string + @endverbatim + */ + void SetValue(const char * _value) { value = _value;} + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Delete all the children of this node. Does not affect 'this'. + void Clear(); + + /// One step up the DOM. + TiXmlNode* Parent() { return parent; } + const TiXmlNode* Parent() const { return parent; } + + const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. + TiXmlNode* FirstChild() { return firstChild; } + const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. + /// The first child of this node with the matching 'value'. Will be null if none found. + TiXmlNode* FirstChild( const char * _value ) { + // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) + // call the method, cast the return back to non-const. + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); + } + const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. + TiXmlNode* LastChild() { return lastChild; } + + const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. + TiXmlNode* LastChild( const char * _value ) { + return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. + #endif + + /** An alternate way to walk the children of a node. + One way to iterate over nodes is: + @verbatim + for( child = parent->FirstChild(); child; child = child->NextSibling() ) + @endverbatim + + IterateChildren does the same thing with the syntax: + @verbatim + child = 0; + while( child = parent->IterateChildren( child ) ) + @endverbatim + + IterateChildren takes the previous child as input and finds + the next one. If the previous child is null, it returns the + first. IterateChildren will return null when done. + */ + const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); + } + + /// This flavor of IterateChildren searches for children with a particular 'value' + const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; + TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. + #endif + + /** Add a new node related to this. Adds a child past the LastChild. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); + + + /** Add a new node related to this. Adds a child past the LastChild. + + NOTE: the node to be added is passed by pointer, and will be + henceforth owned (and deleted) by tinyXml. This method is efficient + and avoids an extra copy, but should be used with care as it + uses a different memory model than the other insert functions. + + @sa InsertEndChild + */ + TiXmlNode* LinkEndChild( TiXmlNode* addThis ); + + /** Add a new node related to this. Adds a child before the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); + + /** Add a new node related to this. Adds a child after the specified child. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); + + /** Replace a child of this node. + Returns a pointer to the new object or NULL if an error occured. + */ + TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); + + /// Delete a child of this node. + bool RemoveChild( TiXmlNode* removeThis ); + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling() const { return prev; } + TiXmlNode* PreviousSibling() { return prev; } + + /// Navigate to a sibling node. + const TiXmlNode* PreviousSibling( const char * ) const; + TiXmlNode* PreviousSibling( const char *_prev ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. + const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. + TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Navigate to a sibling node. + const TiXmlNode* NextSibling() const { return next; } + TiXmlNode* NextSibling() { return next; } + + /// Navigate to a sibling node with the given 'value'. + const TiXmlNode* NextSibling( const char * ) const; + TiXmlNode* NextSibling( const char* _next ) { + return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement() const; + TiXmlElement* NextSiblingElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); + } + + /** Convenience function to get through elements. + Calls NextSibling and ToElement. Will skip all non-Element + nodes. Returns 0 if there is not another element. + */ + const TiXmlElement* NextSiblingElement( const char * ) const; + TiXmlElement* NextSiblingElement( const char *_next ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement() const; + TiXmlElement* FirstChildElement() { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); + } + + /// Convenience function to get through elements. + const TiXmlElement* FirstChildElement( const char * _value ) const; + TiXmlElement* FirstChildElement( const char * _value ) { + return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); + } + + #ifdef TIXML_USE_STL + const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. + #endif + + /** Query the type (as an enumerated value, above) of this node. + The possible types are: TINYXML_DOCUMENT, TINYXML_ELEMENT, TINYXML_COMMENT, + TINYXML_UNKNOWN, TINYXML_TEXT, and TINYXML_DECLARATION. + */ + int Type() const { return type; } + + /** Return a pointer to the Document this node lives in. + Returns null if not in a document. + */ + const TiXmlDocument* GetDocument() const; + TiXmlDocument* GetDocument() { + return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); + } + + /// Returns true if this node has no children. + bool NoChildren() const { return !firstChild; } + + virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. + + /** Create an exact duplicate of this node and return it. The memory must be deleted + by the caller. + */ + virtual TiXmlNode* Clone() const = 0; + + /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the + XML tree will be conditionally visited and the host will be called back + via the TiXmlVisitor interface. + + This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse + the XML for the callbacks, so the performance of TinyXML is unchanged by using this + interface versus any other.) + + The interface has been based on ideas from: + + - http://www.saxproject.org/ + - http://c2.com/cgi/wiki?HierarchicalVisitorPattern + + Which are both good references for "visiting". + + An example of using Accept(): + @verbatim + TiXmlPrinter printer; + tinyxmlDoc.Accept( &printer ); + const char* xmlcstr = printer.CStr(); + @endverbatim + */ + virtual bool Accept( TiXmlVisitor* visitor ) const = 0; + +protected: + TiXmlNode( NodeType _type ); + + // Copy to the allocated object. Shared functionality between Clone, Copy constructor, + // and the assignment operator. + void CopyTo( TiXmlNode* target ) const; + + #ifdef TIXML_USE_STL + // The real work of the input operator. + virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; + #endif + + // Figure out what is at *p, and parse it. Returns null if it is not an xml node. + TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); + + TiXmlNode* parent; + NodeType type; + + TiXmlNode* firstChild; + TiXmlNode* lastChild; + + TIXML_STRING value; + + TiXmlNode* prev; + TiXmlNode* next; + +private: + TiXmlNode( const TiXmlNode& ); // not implemented. + void operator=( const TiXmlNode& base ); // not allowed. +}; + + +/** An attribute is a name-value pair. Elements have an arbitrary + number of attributes, each with a unique name. + + @note The attributes are not TiXmlNodes, since they are not + part of the tinyXML document object model. There are other + suggested ways to look at this problem. +*/ +class TiXmlAttribute : public TiXmlBase +{ + friend class TiXmlAttributeSet; + +public: + /// Construct an empty attribute. + TiXmlAttribute() : TiXmlBase() + { + document = 0; + prev = next = 0; + } + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlAttribute( const std::string& _name, const std::string& _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + #endif + + /// Construct an attribute with a name and value. + TiXmlAttribute( const char * _name, const char * _value ) + { + name = _name; + value = _value; + document = 0; + prev = next = 0; + } + + const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. + const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. + #ifdef TIXML_USE_STL + const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. + #endif + int IntValue() const; ///< Return the value of this attribute, converted to an integer. + double DoubleValue() const; ///< Return the value of this attribute, converted to a double. + + // Get the tinyxml string representation + const TIXML_STRING& NameTStr() const { return name; } + + /** QueryIntValue examines the value string. It is an alternative to the + IntValue() method with richer error checking. + If the value is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. + + A specialized but useful call. Note that for success it returns 0, + which is the opposite of almost all other TinyXml calls. + */ + int QueryIntValue( int* _value ) const; + /// QueryDoubleValue examines the value string. See QueryIntValue(). + int QueryDoubleValue( double* _value ) const; + + void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. + void SetValue( const char* _value ) { value = _value; } ///< Set the value. + + void SetIntValue( int _value ); ///< Set the value from an integer. + void SetDoubleValue( double _value ); ///< Set the value from a double. + + #ifdef TIXML_USE_STL + /// STL std::string form. + void SetName( const std::string& _name ) { name = _name; } + /// STL std::string form. + void SetValue( const std::string& _value ) { value = _value; } + #endif + + /// Get the next sibling attribute in the DOM. Returns null at end. + const TiXmlAttribute* Next() const; + TiXmlAttribute* Next() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); + } + + /// Get the previous sibling attribute in the DOM. Returns null at beginning. + const TiXmlAttribute* Previous() const; + TiXmlAttribute* Previous() { + return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); + } + + bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } + bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } + bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } + + /* Attribute parsing starts: first letter of the name + returns: the next char after the value end quote + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + // Prints this Attribute to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + + // [internal use] + // Set the document pointer so the attribute can report errors. + void SetDocument( TiXmlDocument* doc ) { document = doc; } + +private: + TiXmlAttribute( const TiXmlAttribute& ); // not implemented. + void operator=( const TiXmlAttribute& base ); // not allowed. + + TiXmlDocument* document; // A pointer back to a document, for error reporting. + TIXML_STRING name; + TIXML_STRING value; + TiXmlAttribute* prev; + TiXmlAttribute* next; +}; + + +/* A class used to manage a group of attributes. + It is only used internally, both by the ELEMENT and the DECLARATION. + + The set can be changed transparent to the Element and Declaration + classes that use it, but NOT transparent to the Attribute + which has to implement a next() and previous() method. Which makes + it a bit problematic and prevents the use of STL. + + This version is implemented with circular lists because: + - I like circular lists + - it demonstrates some independence from the (typical) doubly linked list. +*/ +class TiXmlAttributeSet +{ +public: + TiXmlAttributeSet(); + ~TiXmlAttributeSet(); + + void Add( TiXmlAttribute* attribute ); + void Remove( TiXmlAttribute* attribute ); + + const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } + const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } + + TiXmlAttribute* Find( const char* _name ) const; + TiXmlAttribute* FindOrCreate( const char* _name ); + +# ifdef TIXML_USE_STL + TiXmlAttribute* Find( const std::string& _name ) const; + TiXmlAttribute* FindOrCreate( const std::string& _name ); +# endif + + +private: + //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), + //*ME: this class must be also use a hidden/disabled copy-constructor !!! + TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed + void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) + + TiXmlAttribute sentinel; +}; + + +/** The element is a container class. It has a value, the element name, + and can contain other elements, text, comments, and unknowns. + Elements also contain an arbitrary number of attributes. +*/ +class TiXmlElement : public TiXmlNode +{ +public: + /// Construct an element. + TiXmlElement (const char * in_value); + + #ifdef TIXML_USE_STL + /// std::string constructor. + TiXmlElement( const std::string& _value ); + #endif + + TiXmlElement( const TiXmlElement& ); + + TiXmlElement& operator=( const TiXmlElement& base ); + + virtual ~TiXmlElement(); + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + */ + const char* Attribute( const char* name ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an integer, + the integer value will be put in the return 'i', if 'i' + is non-null. + */ + const char* Attribute( const char* name, int* i ) const; + + /** Given an attribute name, Attribute() returns the value + for the attribute of that name, or null if none exists. + If the attribute exists and can be converted to an double, + the double value will be put in the return 'd', if 'd' + is non-null. + */ + const char* Attribute( const char* name, double* d ) const; + + /** QueryIntAttribute examines the attribute - it is an alternative to the + Attribute() method with richer error checking. + If the attribute is an integer, it is stored in 'value' and + the call returns TIXML_SUCCESS. If it is not + an integer, it returns TIXML_WRONG_TYPE. If the attribute + does not exist, then TIXML_NO_ATTRIBUTE is returned. + */ + int QueryIntAttribute( const char* name, int* _value ) const; + /// QueryUnsignedAttribute examines the attribute - see QueryIntAttribute(). + int QueryUnsignedAttribute( const char* name, unsigned* _value ) const; + /** QueryBoolAttribute examines the attribute - see QueryIntAttribute(). + Note that '1', 'true', or 'yes' are considered true, while '0', 'false' + and 'no' are considered false. + */ + int QueryBoolAttribute( const char* name, bool* _value ) const; + /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). + int QueryDoubleAttribute( const char* name, double* _value ) const; + /// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). + int QueryFloatAttribute( const char* name, float* _value ) const { + double d; + int result = QueryDoubleAttribute( name, &d ); + if ( result == TIXML_SUCCESS ) { + *_value = (float)d; + } + return result; + } + + #ifdef TIXML_USE_STL + /// QueryStringAttribute examines the attribute - see QueryIntAttribute(). + int QueryStringAttribute( const char* name, std::string* _value ) const { + const char* cstr = Attribute( name ); + if ( cstr ) { + *_value = std::string( cstr ); + return TIXML_SUCCESS; + } + return TIXML_NO_ATTRIBUTE; + } + + /** Template form of the attribute query which will try to read the + attribute into the specified type. Very easy, very powerful, but + be careful to make sure to call this with the correct type. + + NOTE: This method doesn't work correctly for 'string' types that contain spaces. + + @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE + */ + template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + + std::stringstream sstream( node->ValueStr() ); + sstream >> *outValue; + if ( !sstream.fail() ) + return TIXML_SUCCESS; + return TIXML_WRONG_TYPE; + } + + int QueryValueAttribute( const std::string& name, std::string* outValue ) const + { + const TiXmlAttribute* node = attributeSet.Find( name ); + if ( !node ) + return TIXML_NO_ATTRIBUTE; + *outValue = node->ValueStr(); + return TIXML_SUCCESS; + } + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char* name, const char * _value ); + + #ifdef TIXML_USE_STL + const std::string* Attribute( const std::string& name ) const; + const std::string* Attribute( const std::string& name, int* i ) const; + const std::string* Attribute( const std::string& name, double* d ) const; + int QueryIntAttribute( const std::string& name, int* _value ) const; + int QueryDoubleAttribute( const std::string& name, double* _value ) const; + + /// STL std::string form. + void SetAttribute( const std::string& name, const std::string& _value ); + ///< STL std::string form. + void SetAttribute( const std::string& name, int _value ); + ///< STL std::string form. + void SetDoubleAttribute( const std::string& name, double value ); + #endif + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetAttribute( const char * name, int value ); + + /** Sets an attribute of name to a given value. The attribute + will be created if it does not exist, or changed if it does. + */ + void SetDoubleAttribute( const char * name, double value ); + + /** Deletes an attribute with the given name. + */ + void RemoveAttribute( const char * name ); + #ifdef TIXML_USE_STL + void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. + #endif + + const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. + TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } + const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. + TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } + + /** Convenience function for easy access to the text inside an element. Although easy + and concise, GetText() is limited compared to getting the TiXmlText child + and accessing it directly. + + If the first child of 'this' is a TiXmlText, the GetText() + returns the character string of the Text node, else null is returned. + + This is a convenient method for getting the text of simple contained text: + @verbatim + This is text + const char* str = fooElement->GetText(); + @endverbatim + + 'str' will be a pointer to "This is text". + + Note that this function can be misleading. If the element foo was created from + this XML: + @verbatim + This is text + @endverbatim + + then the value of str would be null. The first child node isn't a text node, it is + another element. From this XML: + @verbatim + This is text + @endverbatim + GetText() will return "This is ". + + WARNING: GetText() accesses a child node - don't become confused with the + similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are + safe type casts on the referenced node. + */ + const char* GetText() const; + + /// Creates a new Element and returns it - the returned element is a copy. + virtual TiXmlNode* Clone() const; + // Print the Element to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: next char past '<' + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + + void CopyTo( TiXmlElement* target ) const; + void ClearThis(); // like clear, but initializes 'this' object as well + + // Used to be public [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + /* [internal use] + Reads the "value" of the element -- another element, or text. + This should terminate with the current end tag. + */ + const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + +private: + TiXmlAttributeSet attributeSet; +}; + + +/** An XML comment. +*/ +class TiXmlComment : public TiXmlNode +{ +public: + /// Constructs an empty comment. + TiXmlComment() : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) {} + /// Construct a comment from text. + TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::TINYXML_COMMENT ) { + SetValue( _value ); + } + TiXmlComment( const TiXmlComment& ); + TiXmlComment& operator=( const TiXmlComment& base ); + + virtual ~TiXmlComment() {} + + /// Returns a copy of this Comment. + virtual TiXmlNode* Clone() const; + // Write this Comment to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /* Attribtue parsing starts: at the ! of the !-- + returns: next char past '>' + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlComment* target ) const; + + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif +// virtual void StreamOut( TIXML_OSTREAM * out ) const; + +private: + +}; + + +/** XML text. A text node can have 2 ways to output the next. "normal" output + and CDATA. It will default to the mode it was parsed from the XML file and + you generally want to leave it alone, but you can change the output mode with + SetCDATA() and query it with CDATA(). +*/ +class TiXmlText : public TiXmlNode +{ + friend class TiXmlElement; +public: + /** Constructor for text element. By default, it is treated as + normal, encoded text. If you want it be output as a CDATA text + element, set the parameter _cdata to 'true' + */ + TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) + { + SetValue( initValue ); + cdata = false; + } + virtual ~TiXmlText() {} + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TINYXML_TEXT) + { + SetValue( initValue ); + cdata = false; + } + #endif + + TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TINYXML_TEXT ) { copy.CopyTo( this ); } + TiXmlText& operator=( const TiXmlText& base ) { base.CopyTo( this ); return *this; } + + // Write this text object to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + /// Queries whether this represents text using a CDATA section. + bool CDATA() const { return cdata; } + /// Turns on or off a CDATA representation of text. + void SetCDATA( bool _cdata ) { cdata = _cdata; } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + /// [internal use] Creates a new Element and returns it. + virtual TiXmlNode* Clone() const; + void CopyTo( TiXmlText* target ) const; + + bool Blank() const; // returns true if all white space and new lines + // [internal use] + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + bool cdata; // true if this should be input and output as a CDATA style text element +}; + + +/** In correct XML the declaration is the first entry in the file. + @verbatim + + @endverbatim + + TinyXml will happily read or write files without a declaration, + however. There are 3 possible attributes to the declaration: + version, encoding, and standalone. + + Note: In this version of the code, the attributes are + handled as special cases, not generic attributes, simply + because there can only be at most 3 and they are always the same. +*/ +class TiXmlDeclaration : public TiXmlNode +{ +public: + /// Construct an empty declaration. + TiXmlDeclaration() : TiXmlNode( TiXmlNode::TINYXML_DECLARATION ) {} + +#ifdef TIXML_USE_STL + /// Constructor. + TiXmlDeclaration( const std::string& _version, + const std::string& _encoding, + const std::string& _standalone ); +#endif + + /// Construct. + TiXmlDeclaration( const char* _version, + const char* _encoding, + const char* _standalone ); + + TiXmlDeclaration( const TiXmlDeclaration& copy ); + TiXmlDeclaration& operator=( const TiXmlDeclaration& copy ); + + virtual ~TiXmlDeclaration() {} + + /// Version. Will return an empty string if none was found. + const char *Version() const { return version.c_str (); } + /// Encoding. Will return an empty string if none was found. + const char *Encoding() const { return encoding.c_str (); } + /// Is this a standalone document? + const char *Standalone() const { return standalone.c_str (); } + + /// Creates a copy of this Declaration and returns it. + virtual TiXmlNode* Clone() const; + // Print this declaration to a FILE stream. + virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; + virtual void Print( FILE* cfile, int depth ) const { + Print( cfile, depth, 0 ); + } + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* visitor ) const; + +protected: + void CopyTo( TiXmlDeclaration* target ) const; + // used to be public + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + + TIXML_STRING version; + TIXML_STRING encoding; + TIXML_STRING standalone; +}; + + +/** Any tag that tinyXml doesn't recognize is saved as an + unknown. It is a tag of text, but should not be modified. + It will be written back to the XML, unchanged, when the file + is saved. + + DTD tags get thrown into TiXmlUnknowns. +*/ +class TiXmlUnknown : public TiXmlNode +{ +public: + TiXmlUnknown() : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) {} + virtual ~TiXmlUnknown() {} + + TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::TINYXML_UNKNOWN ) { copy.CopyTo( this ); } + TiXmlUnknown& operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); return *this; } + + /// Creates a copy of this Unknown and returns it. + virtual TiXmlNode* Clone() const; + // Print this Unknown to a FILE stream. + virtual void Print( FILE* cfile, int depth ) const; + + virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); + + virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected: + void CopyTo( TiXmlUnknown* target ) const; + + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + +}; + + +/** Always the top level node. A document binds together all the + XML pieces. It can be saved, loaded, and printed to the screen. + The 'value' of a document node is the xml file name. +*/ +class TiXmlDocument : public TiXmlNode +{ +public: + /// Create an empty document, that has no name. + TiXmlDocument(); + /// Create a document with a name. The name of the document is also the filename of the xml. + TiXmlDocument( const char * documentName ); + + #ifdef TIXML_USE_STL + /// Constructor. + TiXmlDocument( const std::string& documentName ); + #endif + + TiXmlDocument( const TiXmlDocument& copy ); + TiXmlDocument& operator=( const TiXmlDocument& copy ); + + virtual ~TiXmlDocument() {} + + /** Load a file using the current document value. + Returns true if successful. Will delete any existing + document data before loading. + */ + bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the current document value. Returns true if successful. + bool SaveFile() const; + /// Load a file using the given filename. Returns true if successful. + bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given filename. Returns true if successful. + bool SaveFile( const char * filename ) const; + /** Load a file using the given FILE*. Returns true if successful. Note that this method + doesn't stream - the entire object pointed at by the FILE* + will be interpreted as an XML file. TinyXML doesn't stream in XML from the current + file location. Streaming may be added in the future. + */ + bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + /// Save a file using the given FILE*. Returns true if successful. + bool SaveFile( FILE* ) const; + + #ifdef TIXML_USE_STL + bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. + { + return LoadFile( filename.c_str(), encoding ); + } + bool SaveFile( const std::string& filename ) const ///< STL std::string version. + { + return SaveFile( filename.c_str() ); + } + #endif + + /** Parse the given null terminated block of xml data. Passing in an encoding to this + method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml + to use that encoding, regardless of what TinyXml might otherwise try to detect. + */ + virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); + + /** Get the root element -- the only top level element -- of the document. + In well formed XML, there should only be one. TinyXml is tolerant of + multiple elements at the document level. + */ + const TiXmlElement* RootElement() const { return FirstChildElement(); } + TiXmlElement* RootElement() { return FirstChildElement(); } + + /** If an error occurs, Error will be set to true. Also, + - The ErrorId() will contain the integer identifier of the error (not generally useful) + - The ErrorDesc() method will return the name of the error. (very useful) + - The ErrorRow() and ErrorCol() will return the location of the error (if known) + */ + bool Error() const { return error; } + + /// Contains a textual (english) description of the error if one occurs. + const char * ErrorDesc() const { return errorDesc.c_str (); } + + /** Generally, you probably want the error string ( ErrorDesc() ). But if you + prefer the ErrorId, this function will fetch it. + */ + int ErrorId() const { return errorId; } + + /** Returns the location (if known) of the error. The first column is column 1, + and the first row is row 1. A value of 0 means the row and column wasn't applicable + (memory errors, for example, have no row/column) or the parser lost the error. (An + error in the error reporting, in that case.) + + @sa SetTabSize, Row, Column + */ + int ErrorRow() const { return errorLocation.row+1; } + int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() + + /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) + to report the correct values for row and column. It does not change the output + or input in any way. + + By calling this method, with a tab size + greater than 0, the row and column of each node and attribute is stored + when the file is loaded. Very useful for tracking the DOM back in to + the source file. + + The tab size is required for calculating the location of nodes. If not + set, the default of 4 is used. The tabsize is set per document. Setting + the tabsize to 0 disables row/column tracking. + + Note that row and column tracking is not supported when using operator>>. + + The tab size needs to be enabled before the parse or load. Correct usage: + @verbatim + TiXmlDocument doc; + doc.SetTabSize( 8 ); + doc.Load( "myfile.xml" ); + @endverbatim + + @sa Row, Column + */ + void SetTabSize( int _tabsize ) { tabsize = _tabsize; } + + int TabSize() const { return tabsize; } + + /** If you have handled the error, it can be reset with this call. The error + state is automatically cleared if you Parse a new XML block. + */ + void ClearError() { error = false; + errorId = 0; + errorDesc = ""; + errorLocation.row = errorLocation.col = 0; + //errorLocation.last = 0; + } + + /** Write the document to standard out using formatted printing ("pretty print"). */ + void Print() const { Print( stdout, 0 ); } + + /* Write the document to a string using formatted printing ("pretty print"). This + will allocate a character array (new char[]) and return it as a pointer. The + calling code pust call delete[] on the return char* to avoid a memory leak. + */ + //char* PrintToMemory() const; + + /// Print this Document to a FILE stream. + virtual void Print( FILE* cfile, int depth = 0 ) const; + // [internal use] + void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); + + virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. + + /** Walk the XML tree visiting this node and all of its children. + */ + virtual bool Accept( TiXmlVisitor* content ) const; + +protected : + // [internal use] + virtual TiXmlNode* Clone() const; + #ifdef TIXML_USE_STL + virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); + #endif + +private: + void CopyTo( TiXmlDocument* target ) const; + + bool error; + int errorId; + TIXML_STRING errorDesc; + int tabsize; + TiXmlCursor errorLocation; + bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. +}; + + +/** + A TiXmlHandle is a class that wraps a node pointer with null checks; this is + an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml + DOM structure. It is a separate utility class. + + Take an example: + @verbatim + + + + + + + @endverbatim + + Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very + easy to write a *lot* of code that looks like: + + @verbatim + TiXmlElement* root = document.FirstChildElement( "Document" ); + if ( root ) + { + TiXmlElement* element = root->FirstChildElement( "Element" ); + if ( element ) + { + TiXmlElement* child = element->FirstChildElement( "Child" ); + if ( child ) + { + TiXmlElement* child2 = child->NextSiblingElement( "Child" ); + if ( child2 ) + { + // Finally do something useful. + @endverbatim + + And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity + of such code. A TiXmlHandle checks for null pointers so it is perfectly safe + and correct to use: + + @verbatim + TiXmlHandle docHandle( &document ); + TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); + if ( child2 ) + { + // do something useful + @endverbatim + + Which is MUCH more concise and useful. + + It is also safe to copy handles - internally they are nothing more than node pointers. + @verbatim + TiXmlHandle handleCopy = handle; + @endverbatim + + What they should not be used for is iteration: + + @verbatim + int i=0; + while ( true ) + { + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); + if ( !child ) + break; + // do something + ++i; + } + @endverbatim + + It seems reasonable, but it is in fact two embedded while loops. The Child method is + a linear walk to find the element, so this code would iterate much more than it needs + to. Instead, prefer: + + @verbatim + TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); + + for( child; child; child=child->NextSiblingElement() ) + { + // do something + } + @endverbatim +*/ +class TiXmlHandle +{ +public: + /// Create a handle from any node (at any depth of the tree.) This can be a null pointer. + TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } + /// Copy constructor + TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } + TiXmlHandle operator=( const TiXmlHandle& ref ) { if ( &ref != this ) this->node = ref.node; return *this; } + + /// Return a handle to the first child node. + TiXmlHandle FirstChild() const; + /// Return a handle to the first child node with the given name. + TiXmlHandle FirstChild( const char * value ) const; + /// Return a handle to the first child element. + TiXmlHandle FirstChildElement() const; + /// Return a handle to the first child element with the given name. + TiXmlHandle FirstChildElement( const char * value ) const; + + /** Return a handle to the "index" child with the given name. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( const char* value, int index ) const; + /** Return a handle to the "index" child. + The first child is 0, the second 1, etc. + */ + TiXmlHandle Child( int index ) const; + /** Return a handle to the "index" child element with the given name. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( const char* value, int index ) const; + /** Return a handle to the "index" child element. + The first child element is 0, the second 1, etc. Note that only TiXmlElements + are indexed: other types are not counted. + */ + TiXmlHandle ChildElement( int index ) const; + + #ifdef TIXML_USE_STL + TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } + TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } + + TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } + TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } + #endif + + /** Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* ToNode() const { return node; } + /** Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } + /** Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } + /** Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } + + /** @deprecated use ToNode. + Return the handle as a TiXmlNode. This may return null. + */ + TiXmlNode* Node() const { return ToNode(); } + /** @deprecated use ToElement. + Return the handle as a TiXmlElement. This may return null. + */ + TiXmlElement* Element() const { return ToElement(); } + /** @deprecated use ToText() + Return the handle as a TiXmlText. This may return null. + */ + TiXmlText* Text() const { return ToText(); } + /** @deprecated use ToUnknown() + Return the handle as a TiXmlUnknown. This may return null. + */ + TiXmlUnknown* Unknown() const { return ToUnknown(); } + +private: + TiXmlNode* node; +}; + + +/** Print to memory functionality. The TiXmlPrinter is useful when you need to: + + -# Print to memory (especially in non-STL mode) + -# Control formatting (line endings, etc.) + + When constructed, the TiXmlPrinter is in its default "pretty printing" mode. + Before calling Accept() you can call methods to control the printing + of the XML document. After TiXmlNode::Accept() is called, the printed document can + be accessed via the CStr(), Str(), and Size() methods. + + TiXmlPrinter uses the Visitor API. + @verbatim + TiXmlPrinter printer; + printer.SetIndent( "\t" ); + + doc.Accept( &printer ); + fprintf( stdout, "%s", printer.CStr() ); + @endverbatim +*/ +class TiXmlPrinter : public TiXmlVisitor +{ +public: + TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), + buffer(), indent( " " ), lineBreak( "\n" ) {} + + virtual bool VisitEnter( const TiXmlDocument& doc ); + virtual bool VisitExit( const TiXmlDocument& doc ); + + virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); + virtual bool VisitExit( const TiXmlElement& element ); + + virtual bool Visit( const TiXmlDeclaration& declaration ); + virtual bool Visit( const TiXmlText& text ); + virtual bool Visit( const TiXmlComment& comment ); + virtual bool Visit( const TiXmlUnknown& unknown ); + + /** Set the indent characters for printing. By default 4 spaces + but tab (\t) is also useful, or null/empty string for no indentation. + */ + void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } + /// Query the indention string. + const char* Indent() { return indent.c_str(); } + /** Set the line breaking string. By default set to newline (\n). + Some operating systems prefer other characters, or can be + set to the null/empty string for no indenation. + */ + void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } + /// Query the current line breaking string. + const char* LineBreak() { return lineBreak.c_str(); } + + /** Switch over to "stream printing" which is the most dense formatting without + linebreaks. Common when the XML is needed for network transmission. + */ + void SetStreamPrinting() { indent = ""; + lineBreak = ""; + } + /// Return the result. + const char* CStr() { return buffer.c_str(); } + /// Return the length of the result string. + size_t Size() { return buffer.size(); } + + #ifdef TIXML_USE_STL + /// Return the result. + const std::string& Str() { return buffer; } + #endif + +private: + void DoIndent() { + for( int i=0; i +#include + +#include "tinyxml.h" + +//#define DEBUG_PARSER +#if defined( DEBUG_PARSER ) +# if defined( DEBUG ) && defined( _MSC_VER ) +# include +# define TIXML_LOG OutputDebugString +# else +# define TIXML_LOG printf +# endif +#endif + +// Note tha "PutString" hardcodes the same list. This +// is less flexible than it appears. Changing the entries +// or order will break putstring. +TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] = +{ + { "&", 5, '&' }, + { "<", 4, '<' }, + { ">", 4, '>' }, + { """, 6, '\"' }, + { "'", 6, '\'' } +}; + +// Bunch of unicode info at: +// http://www.unicode.org/faq/utf_bom.html +// Including the basic of this table, which determines the #bytes in the +// sequence from the lead byte. 1 placed for invalid sequences -- +// although the result will be junk, pass it through as much as possible. +// Beware of the non-characters in UTF-8: +// ef bb bf (Microsoft "lead bytes") +// ef bf be +// ef bf bf + +const unsigned char TIXML_UTF_LEAD_0 = 0xefU; +const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; +const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; + +const int TiXmlBase::utf8ByteTable[256] = +{ + // 0 1 2 3 4 5 6 7 8 9 a b c d e f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 + 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte + 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid +}; + + +void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) +{ + const unsigned long BYTE_MASK = 0xBF; + const unsigned long BYTE_MARK = 0x80; + const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + + if (input < 0x80) + *length = 1; + else if ( input < 0x800 ) + *length = 2; + else if ( input < 0x10000 ) + *length = 3; + else if ( input < 0x200000 ) + *length = 4; + else + { *length = 0; return; } // This code won't covert this correctly anyway. + + output += *length; + + // Scary scary fall throughs. + switch (*length) + { + case 4: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 3: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 2: + --output; + *output = (char)((input | BYTE_MARK) & BYTE_MASK); + input >>= 6; + case 1: + --output; + *output = (char)(input | FIRST_BYTE_MARK[*length]); + } +} + + +/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalpha( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalpha( anyByte ); +// } +} + + +/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) +{ + // This will only work for low-ascii, everything else is assumed to be a valid + // letter. I'm not sure this is the best approach, but it is quite tricky trying + // to figure out alhabetical vs. not across encoding. So take a very + // conservative approach. + +// if ( encoding == TIXML_ENCODING_UTF8 ) +// { + if ( anyByte < 127 ) + return isalnum( anyByte ); + else + return 1; // What else to do? The unicode set is huge...get the english ones right. +// } +// else +// { +// return isalnum( anyByte ); +// } +} + + +class TiXmlParsingData +{ + friend class TiXmlDocument; + public: + void Stamp( const char* now, TiXmlEncoding encoding ); + + const TiXmlCursor& Cursor() const { return cursor; } + + private: + // Only used by the document! + TiXmlParsingData( const char* start, int _tabsize, int row, int col ) + { + assert( start ); + stamp = start; + tabsize = _tabsize; + cursor.row = row; + cursor.col = col; + } + + TiXmlCursor cursor; + const char* stamp; + int tabsize; +}; + + +void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) +{ + assert( now ); + + // Do nothing if the tabsize is 0. + if ( tabsize < 1 ) + { + return; + } + + // Get the current row, column. + int row = cursor.row; + int col = cursor.col; + const char* p = stamp; + assert( p ); + + while ( p < now ) + { + // Treat p as unsigned, so we have a happy compiler. + const unsigned char* pU = (const unsigned char*)p; + + // Code contributed by Fletcher Dunn: (modified by lee) + switch (*pU) { + case 0: + // We *should* never get here, but in case we do, don't + // advance past the terminating null character, ever + return; + + case '\r': + // bump down to the next line + ++row; + col = 0; + // Eat the character + ++p; + + // Check for \r\n sequence, and treat this as a single character + if (*p == '\n') { + ++p; + } + break; + + case '\n': + // bump down to the next line + ++row; + col = 0; + + // Eat the character + ++p; + + // Check for \n\r sequence, and treat this as a single + // character. (Yes, this bizarre thing does occur still + // on some arcane platforms...) + if (*p == '\r') { + ++p; + } + break; + + case '\t': + // Eat the character + ++p; + + // Skip to next tab stop + col = (col / tabsize + 1) * tabsize; + break; + + case TIXML_UTF_LEAD_0: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + if ( *(p+1) && *(p+2) ) + { + // In these cases, don't advance the column. These are + // 0-width spaces. + if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) + p += 3; + else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) + p += 3; + else + { p +=3; ++col; } // A normal character. + } + } + else + { + ++p; + ++col; + } + break; + + default: + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // Eat the 1 to 4 byte utf8 character. + int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; + if ( step == 0 ) + step = 1; // Error case from bad encoding, but handle gracefully. + p += step; + + // Just advance one column, of course. + ++col; + } + else + { + ++p; + ++col; + } + break; + } + } + cursor.row = row; + cursor.col = col; + assert( cursor.row >= -1 ); + assert( cursor.col >= -1 ); + stamp = p; + assert( stamp ); +} + + +const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) +{ + if ( !p || !*p ) + { + return 0; + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + while ( *p ) + { + const unsigned char* pU = (const unsigned char*)p; + + // Skip the stupid Microsoft UTF-8 Byte order marks + if ( *(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==TIXML_UTF_LEAD_1 + && *(pU+2)==TIXML_UTF_LEAD_2 ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbeU ) + { + p += 3; + continue; + } + else if(*(pU+0)==TIXML_UTF_LEAD_0 + && *(pU+1)==0xbfU + && *(pU+2)==0xbfU ) + { + p += 3; + continue; + } + + if ( IsWhiteSpace( *p ) ) // Still using old rules for white space. + ++p; + else + break; + } + } + else + { + while ( *p && IsWhiteSpace( *p ) ) + ++p; + } + + return p; +} + +#ifdef TIXML_USE_STL +/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) +{ + for( ;; ) + { + if ( !in->good() ) return false; + + int c = in->peek(); + // At this scope, we can't get to a document. So fail silently. + if ( !IsWhiteSpace( c ) || c <= 0 ) + return true; + + *tag += (char) in->get(); + } +} + +/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) +{ + //assert( character > 0 && character < 128 ); // else it won't work in utf-8 + while ( in->good() ) + { + int c = in->peek(); + if ( c == character ) + return true; + if ( c <= 0 ) // Silent failure: can't get document at this scope + return false; + + in->get(); + *tag += (char) c; + } + return false; +} +#endif + +// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The +// "assign" optimization removes over 10% of the execution time. +// +const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) +{ + // Oddly, not supported on some comilers, + //name->clear(); + // So use this: + *name = ""; + assert( p ); + + // Names start with letters or underscores. + // Of course, in unicode, tinyxml has no idea what a letter *is*. The + // algorithm is generous. + // + // After that, they can be letters, underscores, numbers, + // hyphens, or colons. (Colons are valid ony for namespaces, + // but tinyxml can't tell namespaces from names.) + if ( p && *p + && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) + { + const char* start = p; + while( p && *p + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) + { + //(*name) += *p; // expensive + ++p; + } + if ( p-start > 0 ) { + name->assign( start, p-start ); + } + return p; + } + return 0; +} + +const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) +{ + // Presume an entity, and pull it out. + TIXML_STRING ent; + int i; + *length = 0; + + if ( *(p+1) && *(p+1) == '#' && *(p+2) ) + { + unsigned long ucs = 0; + ptrdiff_t delta = 0; + unsigned mult = 1; + + if ( *(p+2) == 'x' ) + { + // Hexadecimal. + if ( !*(p+3) ) return 0; + + const char* q = p+3; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != 'x' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else if ( *q >= 'a' && *q <= 'f' ) + ucs += mult * (*q - 'a' + 10); + else if ( *q >= 'A' && *q <= 'F' ) + ucs += mult * (*q - 'A' + 10 ); + else + return 0; + mult *= 16; + --q; + } + } + else + { + // Decimal. + if ( !*(p+2) ) return 0; + + const char* q = p+2; + q = strchr( q, ';' ); + + if ( !q || !*q ) return 0; + + delta = q-p; + --q; + + while ( *q != '#' ) + { + if ( *q >= '0' && *q <= '9' ) + ucs += mult * (*q - '0'); + else + return 0; + mult *= 10; + --q; + } + } + if ( encoding == TIXML_ENCODING_UTF8 ) + { + // convert the UCS to UTF-8 + ConvertUTF32ToUTF8( ucs, value, length ); + } + else + { + *value = (char)ucs; + *length = 1; + } + return p + delta + 1; + } + + // Now try to match it. + for( i=0; iappend( cArr, len ); + } + } + else + { + bool whitespace = false; + + // Remove leading white space: + p = SkipWhiteSpace( p, encoding ); + while ( p && *p + && !StringEqual( p, endTag, caseInsensitive, encoding ) ) + { + if ( *p == '\r' || *p == '\n' ) + { + whitespace = true; + ++p; + } + else if ( IsWhiteSpace( *p ) ) + { + whitespace = true; + ++p; + } + else + { + // If we've found whitespace, add it before the + // new character. Any whitespace just becomes a space. + if ( whitespace ) + { + (*text) += ' '; + whitespace = false; + } + int len; + char cArr[4] = { 0, 0, 0, 0 }; + p = GetChar( p, cArr, &len, encoding ); + if ( len == 1 ) + (*text) += cArr[0]; // more efficient + else + text->append( cArr, len ); + } + } + } + if ( p && *p ) + p += strlen( endTag ); + return ( p && *p ) ? p : 0; +} + +#ifdef TIXML_USE_STL + +void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + // The basic issue with a document is that we don't know what we're + // streaming. Read something presumed to be a tag (and hope), then + // identify it, and call the appropriate stream method on the tag. + // + // This "pre-streaming" will never read the closing ">" so the + // sub-tag can orient itself. + + if ( !StreamTo( in, '<', tag ) ) + { + SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + while ( in->good() ) + { + int tagIndex = (int) tag->length(); + while ( in->good() && in->peek() != '>' ) + { + int c = in->get(); + if ( c <= 0 ) + { + SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + break; + } + (*tag) += (char) c; + } + + if ( in->good() ) + { + // We now have something we presume to be a node of + // some sort. Identify it, and call the node to + // continue streaming. + TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); + + if ( node ) + { + node->StreamIn( in, tag ); + bool isElement = node->ToElement() != 0; + delete node; + node = 0; + + // If this is the root element, we're done. Parsing will be + // done by the >> operator. + if ( isElement ) + { + return; + } + } + else + { + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + } + } + // We should have returned sooner. + SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); +} + +#endif + +const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) +{ + ClearError(); + + // Parse away, at the document level. Since a document + // contains nothing but other tags, most of what happens + // here is skipping white space. + if ( !p || !*p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + // Note that, for a document, this needs to come + // before the while space skip, so that parsing + // starts from the pointer we are given. + location.Clear(); + if ( prevData ) + { + location.row = prevData->cursor.row; + location.col = prevData->cursor.col; + } + else + { + location.row = 0; + location.col = 0; + } + TiXmlParsingData data( p, TabSize(), location.row, location.col ); + location = data.Cursor(); + + if ( encoding == TIXML_ENCODING_UNKNOWN ) + { + // Check for the Microsoft UTF-8 lead bytes. + const unsigned char* pU = (const unsigned char*)p; + if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 + && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 + && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) + { + encoding = TIXML_ENCODING_UTF8; + useMicrosoftBOM = true; + } + } + + p = SkipWhiteSpace( p, encoding ); + if ( !p ) + { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); + return 0; + } + + while ( p && *p ) + { + TiXmlNode* node = Identify( p, encoding ); + if ( node ) + { + p = node->Parse( p, &data, encoding ); + LinkEndChild( node ); + } + else + { + break; + } + + // Did we get encoding info? + if ( encoding == TIXML_ENCODING_UNKNOWN + && node->ToDeclaration() ) + { + TiXmlDeclaration* dec = node->ToDeclaration(); + const char* enc = dec->Encoding(); + assert( enc ); + + if ( *enc == 0 ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; + else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) + encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice + else + encoding = TIXML_ENCODING_LEGACY; + } + + p = SkipWhiteSpace( p, encoding ); + } + + // Was this empty? + if ( !firstChild ) { + SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); + return 0; + } + + // All is well. + return p; +} + +void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + // The first error in a chain is more accurate - don't set again! + if ( error ) + return; + + assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); + error = true; + errorId = err; + errorDesc = errorString[ errorId ]; + + errorLocation.Clear(); + if ( pError && data ) + { + data->Stamp( pError, encoding ); + errorLocation = data->Cursor(); + } +} + + +TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) +{ + TiXmlNode* returnNode = 0; + + p = SkipWhiteSpace( p, encoding ); + if( !p || !*p || *p != '<' ) + { + return 0; + } + + p = SkipWhiteSpace( p, encoding ); + + if ( !p || !*p ) + { + return 0; + } + + // What is this thing? + // - Elements start with a letter or underscore, but xml is reserved. + // - Comments: "; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + if ( document ) + document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // [ 1475201 ] TinyXML parses entities in comments + // Oops - ReadText doesn't work, because we don't want to parse the entities. + // p = ReadText( p, &value, false, endTag, false, encoding ); + // + // from the XML spec: + /* + [Definition: Comments may appear anywhere in a document outside other markup; in addition, + they may appear within the document type declaration at places allowed by the grammar. + They are not part of the document's character data; an XML processor MAY, but need not, + make it possible for an application to retrieve the text of comments. For compatibility, + the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity + references MUST NOT be recognized within comments. + + An example of a comment: + + + */ + + value = ""; + // Keep all the white space. + while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) + { + value.append( p, 1 ); + ++p; + } + if ( p && *p ) + p += strlen( endTag ); + + return p; +} + + +const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) return 0; + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + // Read the name, the '=' and the value. + const char* pErr = p; + p = ReadName( p, &name, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); + return 0; + } + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p || *p != '=' ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + ++p; // skip '=' + p = SkipWhiteSpace( p, encoding ); + if ( !p || !*p ) + { + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + + const char* end; + const char SINGLE_QUOTE = '\''; + const char DOUBLE_QUOTE = '\"'; + + if ( *p == SINGLE_QUOTE ) + { + ++p; + end = "\'"; // single quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else if ( *p == DOUBLE_QUOTE ) + { + ++p; + end = "\""; // double quote in string + p = ReadText( p, &value, false, end, false, encoding ); + } + else + { + // All attribute values should be in single or double quotes. + // But this is such a common error that the parser will try + // its best, even without them. + value = ""; + while ( p && *p // existence + && !IsWhiteSpace( *p ) // whitespace + && *p != '/' && *p != '>' ) // tag end + { + if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { + // [ 1451649 ] Attribute values with trailing quotes not handled correctly + // We did not have an opening quote but seem to have a + // closing one. Give up and throw an error. + if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); + return 0; + } + value += *p; + ++p; + } + } + return p; +} + +#ifdef TIXML_USE_STL +void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->peek(); + if ( !cdata && (c == '<' ) ) + { + return; + } + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + + (*tag) += (char) c; + in->get(); // "commits" the peek made above + + if ( cdata && c == '>' && tag->size() >= 3 ) { + size_t len = tag->size(); + if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { + // terminator of cdata. + return; + } + } + } +} +#endif + +const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) +{ + value = ""; + TiXmlDocument* document = GetDocument(); + + if ( data ) + { + data->Stamp( p, encoding ); + location = data->Cursor(); + } + + const char* const startTag = ""; + + if ( cdata || StringEqual( p, startTag, false, encoding ) ) + { + cdata = true; + + if ( !StringEqual( p, startTag, false, encoding ) ) + { + if ( document ) + document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); + return 0; + } + p += strlen( startTag ); + + // Keep all the white space, ignore the encoding, etc. + while ( p && *p + && !StringEqual( p, endTag, false, encoding ) + ) + { + value += *p; + ++p; + } + + TIXML_STRING dummy; + p = ReadText( p, &dummy, false, endTag, false, encoding ); + return p; + } + else + { + bool ignoreWhite = true; + + const char* end = "<"; + p = ReadText( p, &value, ignoreWhite, end, false, encoding ); + if ( p && *p ) + return p-1; // don't truncate the '<' + return 0; + } +} + +#ifdef TIXML_USE_STL +void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) +{ + while ( in->good() ) + { + int c = in->get(); + if ( c <= 0 ) + { + TiXmlDocument* document = GetDocument(); + if ( document ) + document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); + return; + } + (*tag) += (char) c; + + if ( c == '>' ) + { + // All is well. + return; + } + } +} +#endif + +const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) +{ + p = SkipWhiteSpace( p, _encoding ); + // Find the beginning, find the end, and look for + // the stuff in-between. + TiXmlDocument* document = GetDocument(); + if ( !p || !*p || !StringEqual( p, "SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); + return 0; + } + if ( data ) + { + data->Stamp( p, _encoding ); + location = data->Cursor(); + } + p += 5; + + version = ""; + encoding = ""; + standalone = ""; + + while ( p && *p ) + { + if ( *p == '>' ) + { + ++p; + return p; + } + + p = SkipWhiteSpace( p, _encoding ); + if ( StringEqual( p, "version", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + version = attrib.Value(); + } + else if ( StringEqual( p, "encoding", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + encoding = attrib.Value(); + } + else if ( StringEqual( p, "standalone", true, _encoding ) ) + { + TiXmlAttribute attrib; + p = attrib.Parse( p, data, _encoding ); + standalone = attrib.Value(); + } + else + { + // Read over whatever it is. + while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) + ++p; + } + } + return 0; +} + +bool TiXmlText::Blank() const +{ + for ( unsigned i=0; i + +namespace boost +{ + + template T lexical_cast(const char* txt) + { + double result = atof(txt); + return result; + }; + + struct bad_lexical_cast + { + const char* what() + { + return ("bad lexical cast\n"); + } + + }; + +} //namespace boost + +#endif + diff --git a/btgui/urdf/boost_replacement/printf_console.cpp b/btgui/urdf/boost_replacement/printf_console.cpp new file mode 100644 index 000000000..9c9014ac6 --- /dev/null +++ b/btgui/urdf/boost_replacement/printf_console.cpp @@ -0,0 +1,28 @@ +#include "printf_console.h" +#include + + +void logError(const char* msg, const char* arg0, const char* arg1, const char* arg2) +{ + printf("%s %s %s %s\n", msg,arg0,arg1,arg2); + +} + +void logDebug(const char* msg, float v0, float v1) +{ + printf("%s %f %f\n", msg, v0, v1); +}; +void logDebug(const char* msg, const char* msg1, const char* arg1) +{ + printf("%s %s %s\n", msg, msg1, arg1); + +} + +void logInform(const char* msg, const char* arg0) +{ + printf("%s %s\n", msg, arg0); +} +void logWarn(const char* msg,int id, const char* arg0) +{ + printf("%s %d %s\n", msg,id,arg0); +} diff --git a/btgui/urdf/boost_replacement/printf_console.h b/btgui/urdf/boost_replacement/printf_console.h new file mode 100644 index 000000000..247aab2c5 --- /dev/null +++ b/btgui/urdf/boost_replacement/printf_console.h @@ -0,0 +1,13 @@ +#ifndef PRINTF_CONSOLE_H +#define PRINTF_CONSOLE_H + + +void logError(const char* msg="", const char* arg0="", const char* arg1="", const char* arg2=""); +void logDebug(const char* msg, float v0, float v1); +void logDebug(const char* msg, const char* msg1="", const char* arg1=""); +void logInform(const char* msg, const char* arg0=""); +void logWarn(const char* msg,int id, const char* arg0=""); + +#endif + + diff --git a/btgui/urdf/boost_replacement/shared_ptr.h b/btgui/urdf/boost_replacement/shared_ptr.h new file mode 100644 index 000000000..e1a6b349c --- /dev/null +++ b/btgui/urdf/boost_replacement/shared_ptr.h @@ -0,0 +1,213 @@ +/* +Bullet Continuous Collision Detection and Physics Library Maya Plugin +Copyright (c) 2008 Walt Disney Studios + +This software is provided 'as-is', without any express or implied warranty. +In no event will the authors be held liable for any damages arising +from the use of this software. +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, +subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must +not be misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Written by: Nicola Candussi + +Modified by Francisco Gochez +Dec 2011 - Added deferencing operator +*/ + +//my_shared_ptr + +#ifndef DYN_SHARED_PTR_H +#define DYN_SHARED_PTR_H + +#define DYN_SHARED_PTR_THREAD_SAFE + + +#include + +#ifdef _WIN32 +#include + +namespace boost +{ +class my_shared_count { +public: + my_shared_count(): m_count(1) { } + ~my_shared_count() { } + + long increment() + { +#ifdef DYN_SHARED_PTR_THREAD_SAFE + return InterlockedIncrement(&m_count); +#else + return ++m_count; +#endif + } + + long decrement() { +#ifdef DYN_SHARED_PTR_THREAD_SAFE + return InterlockedDecrement(&m_count); +#else + return ++m_count; +#endif + } + + long use_count() { return m_count; } + +private: + long m_count; +}; +}; +#else //ifdef WIN32 + + +#include + +class my_shared_count { +public: + my_shared_count(): m_count(1) { +#ifdef DYN_SHARED_PTR_THREAD_SAFE + pthread_mutex_init(&m_mutex, 0); +#endif + } + ~my_shared_count() { +#ifdef DYN_SHARED_PTR_THREAD_SAFE + pthread_mutex_destroy(&m_mutex); +#endif + } + + long increment() + { +#ifdef DYN_SHARED_PTR_THREAD_SAFE + pthread_mutex_lock(&m_mutex); +#endif + long c = ++m_count; +#ifdef DYN_SHARED_PTR_THREAD_SAFE + pthread_mutex_unlock(&m_mutex); +#endif + return c; + } + + long decrement() { +#ifdef DYN_SHARED_PTR_THREAD_SAFE + pthread_mutex_lock(&m_mutex); +#endif + long c = --m_count; +#ifdef DYN_SHARED_PTR_THREAD_SAFE + pthread_mutex_unlock(&m_mutex); +#endif + return c; + } + + long use_count() { return m_count; } + +private: + long m_count; + mutable pthread_mutex_t m_mutex; +}; + +#endif + + +template +class my_shared_ptr +{ +public: + my_shared_ptr(): m_ptr(NULL), m_count(NULL) { } + my_shared_ptr(my_shared_ptr const& other): + m_ptr(other.m_ptr), + m_count(other.m_count) + { + if(other.m_count != NULL) other.m_count->increment(); + } + + template + my_shared_ptr(my_shared_ptr const& other): + m_ptr(other.m_ptr), + m_count(other.m_count) + { + if(other.m_count != NULL) other.m_count->increment(); + } + + my_shared_ptr(T const* other): m_ptr(const_cast(other)), m_count(NULL) + { + if(other != NULL) m_count = new my_shared_count; + } + + ~my_shared_ptr() + { + giveup_ownership(); + } + + void reset(T const* other) + { + if(m_ptr == other) return; + giveup_ownership(); + m_ptr = const_cast(other); + if(other != NULL) m_count = new my_shared_count; + else m_count = NULL; + } + + T* get() { return m_ptr; } + T const* get() const { return m_ptr; } + T* operator->() { return m_ptr; } + T const* operator->() const { return m_ptr; } + operator bool() const { return m_ptr != NULL; } + T& operator*() const + { + assert(m_ptr != 0); + return *m_ptr; + } + + bool operator<(my_shared_ptr const& rhs) const { return m_ptr < rhs.m_ptr; } + + my_shared_ptr& operator=(my_shared_ptr const& other) { + if(m_ptr == other.m_ptr) return *this; + giveup_ownership(); + m_ptr = other.m_ptr; + m_count = other.m_count; + if(other.m_count != NULL) m_count->increment(); + return *this; + } + + template + my_shared_ptr& operator=(my_shared_ptr& other) { + if(m_ptr == other.m_ptr) return *this; + giveup_ownership(); + m_ptr = other.m_ptr; + m_count = other.m_count; + if(other.m_count != NULL) m_count->increment(); + return *this; + } + +protected: + + template friend class my_shared_ptr; + void giveup_ownership() + { + if(m_count != NULL) { + if( m_count->decrement() == 0) { + delete m_ptr; + m_ptr = NULL; + delete m_count; + m_count = NULL; + } + } + } + +protected: + T *m_ptr; + my_shared_count *m_count; + +}; + + +#endif diff --git a/btgui/urdf/boost_replacement/string_split.cpp b/btgui/urdf/boost_replacement/string_split.cpp new file mode 100644 index 000000000..bbe8146f4 --- /dev/null +++ b/btgui/urdf/boost_replacement/string_split.cpp @@ -0,0 +1,253 @@ + + +#include +#include +#include +#include +#include + +#include "string_split.h" + +namespace boost +{ + void split( std::vector&pieces, const std::string& vector_str, std::vector separators) + { + assert(separators.size()==1); + if (separators.size()==1) + { + char** strArray = str_split(vector_str.c_str(),separators[0].c_str()); + int numSubStr = str_array_len(strArray); + for (int i=0;i is_any_of(const char* seps) + { + std::vector strArray; + + int numSeps = strlen(seps); + for (int i=0;i +#include +#include + +namespace boost +{ + void split( std::vector&pieces, const std::string& vector_str, std::vector separators); + std::vector is_any_of(const char* seps); +}; + +///The string split C code is by Lars Wirzenius +///See http://stackoverflow.com/questions/2531605/how-to-split-a-string-with-a-delimiter-larger-than-one-single-char + + +/* Split a string into substrings. Return dynamic array of dynamically + allocated substrings, or NULL if there was an error. Caller is + expected to free the memory, for example with str_array_free. */ +char** str_split(const char* input, const char* sep); + +/* Free a dynamic array of dynamic strings. */ +void str_array_free(char** array); + +/* Return length of a NULL-delimited array of strings. */ +size_t str_array_len(char** array); + +#endif //STRING_SPLIT_H + diff --git a/btgui/urdf/premake4.lua b/btgui/urdf/premake4.lua new file mode 100644 index 000000000..65abdb218 --- /dev/null +++ b/btgui/urdf/premake4.lua @@ -0,0 +1,50 @@ + + + project "urdf_test" + + flags {"FloatStrict"} + + language "C++" + + kind "ConsoleApp" + targetdir "../../bin" + +-- links { +-- } + + includedirs { + ".", + "boost_replacement", + "../tinyxml", + "urdfdom/urdf_parser/include", + "urdfdom_headers/urdf_exception/include", + "urdfdom_headers/urdf_model/include", + + } + + + files { + "urdfdom/urdf_parser/src/check_urdf.cpp", + "urdfdom/urdf_parser/src/pose.cpp", + "urdfdom/urdf_parser/src/model.cpp", + "urdfdom/urdf_parser/src/link.cpp", + "urdfdom/urdf_parser/src/joint.cpp", + "urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h", + "urdfdom_headers/urdf_exception/include/urdf_exception/exception.h", + "urdfdom_headers/urdf_model/include/urdf_model/pose.h", + "urdfdom_headers/urdf_model/include/urdf_model/model.h", + "urdfdom_headers/urdf_model/include/urdf_model/link.h", + "urdfdom_headers/urdf_model/include/urdf_model/joint.h", + "../tinyxml/tinystr.cpp", + "../tinyxml/tinyxml.cpp", + "../tinyxml/tinyxmlerror.cpp", + "../tinyxml/tinyxmlparser.cpp", + "boost_replacement/lexical_cast.h", + "boost_replacement/shared_ptr.h", + "boost_replacement/printf_console.cpp", + "boost_replacement/printf_console.h", + "boost_replacement/string_split.cpp", + "boost_replacement/string_split.h", + + + } diff --git a/btgui/urdf/urdfdom/LICENSE b/btgui/urdf/urdfdom/LICENSE new file mode 100644 index 000000000..e80920e25 --- /dev/null +++ b/btgui/urdf/urdfdom/LICENSE @@ -0,0 +1,15 @@ +Software License Agreement (Apache License) + +Copyright 2011 John Hsu + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/btgui/urdf/urdfdom/README.txt b/btgui/urdf/urdfdom/README.txt new file mode 100644 index 000000000..4e3bff6d8 --- /dev/null +++ b/btgui/urdf/urdfdom/README.txt @@ -0,0 +1,7 @@ +The URDF (U-Robot Description Format) library + provides core data structures and a simple XML parsers + for populating the class data structures from an URDF file. + +For now, the details of the URDF specifications reside on + http://ros.org/wiki/urdf + diff --git a/btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h b/btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h new file mode 100644 index 000000000..b4bf6082a --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h @@ -0,0 +1,63 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ + +#ifndef URDF_PARSER_URDF_PARSER_H +#define URDF_PARSER_URDF_PARSER_H + +#include + +#include +#include + +//#include + +#ifndef M_PI +#define M_PI 3.1415925438 +#endif //M_PI + + +#include + + + + +namespace urdf{ + + my_shared_ptr parseURDF(const std::string &xml_string); + +} + +#endif diff --git a/btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp b/btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp new file mode 100644 index 000000000..530d64286 --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp @@ -0,0 +1,137 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ + +#include "urdf_parser/urdf_parser.h" +#include +#include + +using namespace urdf; + +void printTree(my_shared_ptr link,int level = 0) +{ + level+=2; + int count = 0; + for (std::vector >::const_iterator child = link->child_links.begin(); child != link->child_links.end(); child++) + { + if (*child) + { + for(int j=0;jname << std::endl; + // first grandchild + printTree(*child,level); + } + else + { + for(int j=0;jname << " has a null child!" << *child << std::endl; + } + } + +} + + +#define MSTRINGIFY(A) #A + + +const char* urdf_char = MSTRINGIFY( + + + + + + + + + + + + + + + + + + + + +); + + +int main(int argc, char** argv) +{ + + std::string xml_string; + + if (argc < 2){ + std::cerr << "No URDF file name provided, using a dummy test URDF" << std::endl; + + xml_string = std::string(urdf_char); + + } else + { + + + std::fstream xml_file(argv[1], std::fstream::in); + while ( xml_file.good() ) + { + std::string line; + std::getline( xml_file, line); + xml_string += (line + "\n"); + } + xml_file.close(); + } + + my_shared_ptr robot = parseURDF(xml_string); + if (!robot){ + std::cerr << "ERROR: Model Parsing the xml failed" << std::endl; + return -1; + } + std::cout << "robot name is: " << robot->getName() << std::endl; + + // get info from parser + std::cout << "---------- Successfully Parsed XML ---------------" << std::endl; + // get root link + my_shared_ptr root_link=robot->getRoot(); + if (!root_link) return -1; + + std::cout << "root Link: " << root_link->name << " has " << root_link->child_links.size() << " child(ren)" << std::endl; + + + // print entire tree + printTree(root_link); + return 0; +} + diff --git a/btgui/urdf/urdfdom/urdf_parser/src/joint.cpp b/btgui/urdf/urdfdom/urdf_parser/src/joint.cpp new file mode 100644 index 000000000..3852fe08f --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/joint.cpp @@ -0,0 +1,579 @@ +/********************************************************************* +* Software Ligcense Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: John Hsu */ + +#include +#include +#ifdef URDF_USE_BOOST +#include +#else +#include +#endif +#include + +#ifdef URDF_USE_CONSOLE_BRIDGE + #include +#else + #include "printf_console.h" +#endif + +#include +#include + +namespace urdf{ + +bool parsePose(Pose &pose, TiXmlElement* xml); + +bool parseJointDynamics(JointDynamics &jd, TiXmlElement* config) +{ + jd.clear(); + + // Get joint damping + const char* damping_str = config->Attribute("damping"); + if (damping_str == NULL){ + logDebug("urdfdom.joint_dynamics: no damping, defaults to 0"); + jd.damping = 0; + } + else + { + try + { + jd.damping = boost::lexical_cast(damping_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("damping value (%s) is not a float: %s",damping_str, e.what()); + return false; + } + } + + // Get joint friction + const char* friction_str = config->Attribute("friction"); + if (friction_str == NULL){ + logDebug("urdfdom.joint_dynamics: no friction, defaults to 0"); + jd.friction = 0; + } + else + { + try + { + jd.friction = boost::lexical_cast(friction_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("friction value (%s) is not a float: %s",friction_str, e.what()); + return false; + } + } + + if (damping_str == NULL && friction_str == NULL) + { + logError("joint dynamics element specified with no damping and no friction"); + return false; + } + else{ + logDebug("urdfdom.joint_dynamics: damping %f and friction %f", jd.damping, jd.friction); + return true; + } +} + +bool parseJointLimits(JointLimits &jl, TiXmlElement* config) +{ + jl.clear(); + + // Get lower joint limit + const char* lower_str = config->Attribute("lower"); + if (lower_str == NULL){ + logDebug("urdfdom.joint_limit: no lower, defaults to 0"); + jl.lower = 0; + } + else + { + try + { + jl.lower = boost::lexical_cast(lower_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("lower value (%s) is not a float: %s", lower_str, e.what()); + return false; + } + } + + // Get upper joint limit + const char* upper_str = config->Attribute("upper"); + if (upper_str == NULL){ + logDebug("urdfdom.joint_limit: no upper, , defaults to 0"); + jl.upper = 0; + } + else + { + try + { + jl.upper = boost::lexical_cast(upper_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("upper value (%s) is not a float: %s",upper_str, e.what()); + return false; + } + } + + // Get joint effort limit + const char* effort_str = config->Attribute("effort"); + if (effort_str == NULL){ + logError("joint limit: no effort"); + return false; + } + else + { + try + { + jl.effort = boost::lexical_cast(effort_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("effort value (%s) is not a float: %s",effort_str, e.what()); + return false; + } + } + + // Get joint velocity limit + const char* velocity_str = config->Attribute("velocity"); + if (velocity_str == NULL){ + logError("joint limit: no velocity"); + return false; + } + else + { + try + { + jl.velocity = boost::lexical_cast(velocity_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("velocity value (%s) is not a float: %s",velocity_str, e.what()); + return false; + } + } + + return true; +} + +bool parseJointSafety(JointSafety &js, TiXmlElement* config) +{ + js.clear(); + + // Get soft_lower_limit joint limit + const char* soft_lower_limit_str = config->Attribute("soft_lower_limit"); + if (soft_lower_limit_str == NULL) + { + logDebug("urdfdom.joint_safety: no soft_lower_limit, using default value"); + js.soft_lower_limit = 0; + } + else + { + try + { + js.soft_lower_limit = boost::lexical_cast(soft_lower_limit_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("soft_lower_limit value (%s) is not a float: %s",soft_lower_limit_str, e.what()); + return false; + } + } + + // Get soft_upper_limit joint limit + const char* soft_upper_limit_str = config->Attribute("soft_upper_limit"); + if (soft_upper_limit_str == NULL) + { + logDebug("urdfdom.joint_safety: no soft_upper_limit, using default value"); + js.soft_upper_limit = 0; + } + else + { + try + { + js.soft_upper_limit = boost::lexical_cast(soft_upper_limit_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("soft_upper_limit value (%s) is not a float: %s",soft_upper_limit_str, e.what()); + return false; + } + } + + // Get k_position_ safety "position" gain - not exactly position gain + const char* k_position_str = config->Attribute("k_position"); + if (k_position_str == NULL) + { + logDebug("urdfdom.joint_safety: no k_position, using default value"); + js.k_position = 0; + } + else + { + try + { + js.k_position = boost::lexical_cast(k_position_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("k_position value (%s) is not a float: %s",k_position_str, e.what()); + return false; + } + } + // Get k_velocity_ safety velocity gain + const char* k_velocity_str = config->Attribute("k_velocity"); + if (k_velocity_str == NULL) + { + logError("joint safety: no k_velocity"); + return false; + } + else + { + try + { + js.k_velocity = boost::lexical_cast(k_velocity_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("k_velocity value (%s) is not a float: %s",k_velocity_str, e.what()); + return false; + } + } + + return true; +} + +bool parseJointCalibration(JointCalibration &jc, TiXmlElement* config) +{ + jc.clear(); + + // Get rising edge position + const char* rising_position_str = config->Attribute("rising"); + if (rising_position_str == NULL) + { + logDebug("urdfdom.joint_calibration: no rising, using default value"); + jc.rising.reset(0); + } + else + { + try + { + jc.rising.reset(new double(boost::lexical_cast(rising_position_str))); + } + catch (boost::bad_lexical_cast &e) + { + logError("risingvalue (%s) is not a float: %s",rising_position_str, e.what()); + return false; + } + } + + // Get falling edge position + const char* falling_position_str = config->Attribute("falling"); + if (falling_position_str == NULL) + { + logDebug("urdfdom.joint_calibration: no falling, using default value"); + jc.falling.reset(0); + } + else + { + try + { + jc.falling.reset(new double(boost::lexical_cast(falling_position_str))); + } + catch (boost::bad_lexical_cast &e) + { + logError("fallingvalue (%s) is not a float: %s",falling_position_str, e.what()); + return false; + } + } + + return true; +} + +bool parseJointMimic(JointMimic &jm, TiXmlElement* config) +{ + jm.clear(); + + // Get name of joint to mimic + const char* joint_name_str = config->Attribute("joint"); + + if (joint_name_str == NULL) + { + logError("joint mimic: no mimic joint specified"); + return false; + } + else + jm.joint_name = joint_name_str; + + // Get mimic multiplier + const char* multiplier_str = config->Attribute("multiplier"); + + if (multiplier_str == NULL) + { + logDebug("urdfdom.joint_mimic: no multiplier, using default value of 1"); + jm.multiplier = 1; + } + else + { + try + { + jm.multiplier = boost::lexical_cast(multiplier_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("multiplier value (%s) is not a float: %s",multiplier_str, e.what()); + return false; + } + } + + + // Get mimic offset + const char* offset_str = config->Attribute("offset"); + if (offset_str == NULL) + { + logDebug("urdfdom.joint_mimic: no offset, using default value of 0"); + jm.offset = 0; + } + else + { + try + { + jm.offset = boost::lexical_cast(offset_str); + } + catch (boost::bad_lexical_cast &e) + { + logError("offset value (%s) is not a float: %s",offset_str, e.what()); + return false; + } + } + + return true; +} + +bool parseJoint(Joint &joint, TiXmlElement* config) +{ + joint.clear(); + + // Get Joint Name + const char *name = config->Attribute("name"); + if (!name) + { + logError("unnamed joint found"); + return false; + } + joint.name = name; + + // Get transform from Parent Link to Joint Frame + TiXmlElement *origin_xml = config->FirstChildElement("origin"); + if (!origin_xml) + { + logDebug("urdfdom: Joint [%s] missing origin tag under parent describing transform from Parent Link to Joint Frame, (using Identity transform).", joint.name.c_str()); + joint.parent_to_joint_origin_transform.clear(); + } + else + { + if (!parsePose(joint.parent_to_joint_origin_transform, origin_xml)) + { + joint.parent_to_joint_origin_transform.clear(); + logError("Malformed parent origin element for joint [%s]", joint.name.c_str()); + return false; + } + } + + // Get Parent Link + TiXmlElement *parent_xml = config->FirstChildElement("parent"); + if (parent_xml) + { + const char *pname = parent_xml->Attribute("link"); + if (!pname) + { + logInform("no parent link name specified for Joint link [%s]. this might be the root?", joint.name.c_str()); + } + else + { + joint.parent_link_name = std::string(pname); + } + } + + // Get Child Link + TiXmlElement *child_xml = config->FirstChildElement("child"); + if (child_xml) + { + const char *pname = child_xml->Attribute("link"); + if (!pname) + { + logInform("no child link name specified for Joint link [%s].", joint.name.c_str()); + } + else + { + joint.child_link_name = std::string(pname); + } + } + + // Get Joint type + const char* type_char = config->Attribute("type"); + if (!type_char) + { + logError("joint [%s] has no type, check to see if it's a reference.", joint.name.c_str()); + return false; + } + + std::string type_str = type_char; + if (type_str == "planar") + joint.type = Joint::PLANAR; + else if (type_str == "floating") + joint.type = Joint::FLOATING; + else if (type_str == "revolute") + joint.type = Joint::REVOLUTE; + else if (type_str == "continuous") + joint.type = Joint::CONTINUOUS; + else if (type_str == "prismatic") + joint.type = Joint::PRISMATIC; + else if (type_str == "fixed") + joint.type = Joint::FIXED; + else + { + logError("Joint [%s] has no known type [%s]", joint.name.c_str(), type_str.c_str()); + return false; + } + + // Get Joint Axis + if (joint.type != Joint::FLOATING && joint.type != Joint::FIXED) + { + // axis + TiXmlElement *axis_xml = config->FirstChildElement("axis"); + if (!axis_xml){ + logDebug("urdfdom: no axis elemement for Joint link [%s], defaulting to (1,0,0) axis", joint.name.c_str()); + joint.axis = Vector3(1.0, 0.0, 0.0); + } + else{ + if (axis_xml->Attribute("xyz")){ + try { + joint.axis.init(axis_xml->Attribute("xyz")); + } + catch (ParseError &e) { + joint.axis.clear(); + logError("Malformed axis element for joint [%s]: %s", joint.name.c_str(), e.what()); + return false; + } + } + } + } + + // Get limit + TiXmlElement *limit_xml = config->FirstChildElement("limit"); + if (limit_xml) + { + joint.limits.reset(new JointLimits()); + if (!parseJointLimits(*joint.limits, limit_xml)) + { + logError("Could not parse limit element for joint [%s]", joint.name.c_str()); + joint.limits.reset(0); + return false; + } + } + else if (joint.type == Joint::REVOLUTE) + { + logError("Joint [%s] is of type REVOLUTE but it does not specify limits", joint.name.c_str()); + return false; + } + else if (joint.type == Joint::PRISMATIC) + { + logError("Joint [%s] is of type PRISMATIC without limits", joint.name.c_str()); + return false; + } + + // Get safety + TiXmlElement *safety_xml = config->FirstChildElement("safety_controller"); + if (safety_xml) + { + joint.safety.reset(new JointSafety()); + if (!parseJointSafety(*joint.safety, safety_xml)) + { + logError("Could not parse safety element for joint [%s]", joint.name.c_str()); + joint.safety.reset(0); + return false; + } + } + + // Get calibration + TiXmlElement *calibration_xml = config->FirstChildElement("calibration"); + if (calibration_xml) + { + joint.calibration.reset(new JointCalibration()); + if (!parseJointCalibration(*joint.calibration, calibration_xml)) + { + logError("Could not parse calibration element for joint [%s]", joint.name.c_str()); + joint.calibration.reset(0); + return false; + } + } + + // Get Joint Mimic + TiXmlElement *mimic_xml = config->FirstChildElement("mimic"); + if (mimic_xml) + { + joint.mimic.reset(new JointMimic()); + if (!parseJointMimic(*joint.mimic, mimic_xml)) + { + logError("Could not parse mimic element for joint [%s]", joint.name.c_str()); + joint.mimic.reset(0); + return false; + } + } + + // Get Dynamics + TiXmlElement *prop_xml = config->FirstChildElement("dynamics"); + if (prop_xml) + { + joint.dynamics.reset(new JointDynamics()); + if (!parseJointDynamics(*joint.dynamics, prop_xml)) + { + logError("Could not parse joint_dynamics element for joint [%s]", joint.name.c_str()); + joint.dynamics.reset(0); + return false; + } + } + + return true; +} + + + + +} diff --git a/btgui/urdf/urdfdom/urdf_parser/src/link.cpp b/btgui/urdf/urdfdom/urdf_parser/src/link.cpp new file mode 100644 index 000000000..e28906c3c --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/link.cpp @@ -0,0 +1,505 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ + + +#include +#include +//#include +//#include +#ifdef URDF_USE_BOOST +#include +#else +#include +#endif + +#include +#include +#ifdef URDF_USE_CONSOLE_BRIDGE +#include +#else +#include "printf_console.h" +#endif + + + +namespace urdf{ + +bool parsePose(Pose &pose, TiXmlElement* xml); + +bool parseMaterial(Material &material, TiXmlElement *config, bool only_name_is_ok) +{ + bool has_rgb = false; + bool has_filename = false; + + material.clear(); + + if (!config->Attribute("name")) + { + logError("Material must contain a name attribute"); + return false; + } + + material.name = config->Attribute("name"); + + // texture + TiXmlElement *t = config->FirstChildElement("texture"); + if (t) + { + if (t->Attribute("filename")) + { + material.texture_filename = t->Attribute("filename"); + has_filename = true; + } + } + + // color + TiXmlElement *c = config->FirstChildElement("color"); + if (c) + { + if (c->Attribute("rgba")) { + + try { + material.color.init(c->Attribute("rgba")); + has_rgb = true; + } + catch (ParseError &e) { + material.color.clear(); + logError(std::string("Material [" + material.name + "] has malformed color rgba values: " + e.what()).c_str()); + } + } + } + + if (!has_rgb && !has_filename) { + if (!only_name_is_ok) // no need for an error if only name is ok + { + if (!has_rgb) logError(std::string("Material ["+material.name+"] color has no rgba").c_str()); + if (!has_filename) logError(std::string("Material ["+material.name+"] not defined in file").c_str()); + } + return false; + } + return true; +} + + +bool parseSphere(Sphere &s, TiXmlElement *c) +{ + s.clear(); + + s.type = Geometry::SPHERE; + if (!c->Attribute("radius")) + { + logError("Sphere shape must have a radius attribute"); + return false; + } + + try + { + s.radius = boost::lexical_cast(c->Attribute("radius")); + } + catch (boost::bad_lexical_cast &e) + { + // std::stringstream stm; + // stm << "radius [" << c->Attribute("radius") << "] is not a valid float: " << e.what(); + // logError(stm.str().c_str()); + logError("radius issue"); + return false; + } + + return true; +} + +bool parseBox(Box &b, TiXmlElement *c) +{ + b.clear(); + + b.type = Geometry::BOX; + if (!c->Attribute("size")) + { + logError("Box shape has no size attribute"); + return false; + } + try + { + b.dim.init(c->Attribute("size")); + } + catch (ParseError &e) + { + b.dim.clear(); + logError(e.what()); + return false; + } + return true; +} + +bool parseCylinder(Cylinder &y, TiXmlElement *c) +{ + y.clear(); + + y.type = Geometry::CYLINDER; + if (!c->Attribute("length") || + !c->Attribute("radius")) + { + logError("Cylinder shape must have both length and radius attributes"); + return false; + } + + try + { + y.length = boost::lexical_cast(c->Attribute("length")); + } + catch (boost::bad_lexical_cast &e) + { + // std::stringstream stm; + // stm << "length [" << c->Attribute("length") << "] is not a valid float"; + //logError(stm.str().c_str()); + logError("length"); + return false; + } + + try + { + y.radius = boost::lexical_cast(c->Attribute("radius")); + } + catch (boost::bad_lexical_cast &e) + { + // std::stringstream stm; + // stm << "radius [" << c->Attribute("radius") << "] is not a valid float"; + //logError(stm.str().c_str()); + logError("radius"); + return false; + } + return true; +} + + +bool parseMesh(Mesh &m, TiXmlElement *c) +{ + m.clear(); + + m.type = Geometry::MESH; + if (!c->Attribute("filename")) { + logError("Mesh must contain a filename attribute"); + return false; + } + + m.filename = c->Attribute("filename"); + + if (c->Attribute("scale")) { + try { + m.scale.init(c->Attribute("scale")); + } + catch (ParseError &e) { + m.scale.clear(); + logError("Mesh scale was specified, but could not be parsed: %s", e.what()); + return false; + } + } + else + { + m.scale.x = m.scale.y = m.scale.z = 1; + } + return true; +} + +my_shared_ptr parseGeometry(TiXmlElement *g) +{ + my_shared_ptr geom; + if (!g) return geom; + + TiXmlElement *shape = g->FirstChildElement(); + if (!shape) + { + logError("Geometry tag contains no child element."); + return geom; + } + + const std::string type_name = shape->ValueTStr().c_str(); + if (type_name == "sphere") + { + Sphere *s = new Sphere(); + geom.reset(s); + if (parseSphere(*s, shape)) + return geom; + } + else if (type_name == "box") + { + Box *b = new Box(); + geom.reset(b); + if (parseBox(*b, shape)) + return geom; + } + else if (type_name == "cylinder") + { + Cylinder *c = new Cylinder(); + geom.reset(c); + if (parseCylinder(*c, shape)) + return geom; + } + else if (type_name == "mesh") + { + Mesh *m = new Mesh(); + geom.reset(m); + if (parseMesh(*m, shape)) + return geom; + } + else + { + logError("Unknown geometry type '%s'", type_name.c_str()); + return geom; + } + + return my_shared_ptr(); +} + +bool parseInertial(Inertial &i, TiXmlElement *config) +{ + i.clear(); + + // Origin + TiXmlElement *o = config->FirstChildElement("origin"); + if (o) + { + if (!parsePose(i.origin, o)) + return false; + } + + TiXmlElement *mass_xml = config->FirstChildElement("mass"); + if (!mass_xml) + { + logError("Inertial element must have a mass element"); + return false; + } + if (!mass_xml->Attribute("value")) + { + logError("Inertial: mass element must have value attribute"); + return false; + } + + try + { + i.mass = boost::lexical_cast(mass_xml->Attribute("value")); + } + catch (boost::bad_lexical_cast &e) + { + // std::stringstream stm; + // stm << "Inertial: mass [" << mass_xml->Attribute("value") + // << "] is not a float"; + //logError(stm.str().c_str()); + logError("Inertial mass issue"); + return false; + } + + TiXmlElement *inertia_xml = config->FirstChildElement("inertia"); + if (!inertia_xml) + { + logError("Inertial element must have inertia element"); + return false; + } + if (!(inertia_xml->Attribute("ixx") && inertia_xml->Attribute("ixy") && inertia_xml->Attribute("ixz") && + inertia_xml->Attribute("iyy") && inertia_xml->Attribute("iyz") && + inertia_xml->Attribute("izz"))) + { + logError("Inertial: inertia element must have ixx,ixy,ixz,iyy,iyz,izz attributes"); + return false; + } + try + { + i.ixx = boost::lexical_cast(inertia_xml->Attribute("ixx")); + i.ixy = boost::lexical_cast(inertia_xml->Attribute("ixy")); + i.ixz = boost::lexical_cast(inertia_xml->Attribute("ixz")); + i.iyy = boost::lexical_cast(inertia_xml->Attribute("iyy")); + i.iyz = boost::lexical_cast(inertia_xml->Attribute("iyz")); + i.izz = boost::lexical_cast(inertia_xml->Attribute("izz")); + } + catch (boost::bad_lexical_cast &e) + { + /* std::stringstream stm; + stm << "Inertial: one of the inertia elements is not a valid double:" + << " ixx [" << inertia_xml->Attribute("ixx") << "]" + << " ixy [" << inertia_xml->Attribute("ixy") << "]" + << " ixz [" << inertia_xml->Attribute("ixz") << "]" + << " iyy [" << inertia_xml->Attribute("iyy") << "]" + << " iyz [" << inertia_xml->Attribute("iyz") << "]" + << " izz [" << inertia_xml->Attribute("izz") << "]"; + logError(stm.str().c_str()); + */ + logError("Inertia error"); + + return false; + } + return true; +} + +bool parseVisual(Visual &vis, TiXmlElement *config) +{ + vis.clear(); + + // Origin + TiXmlElement *o = config->FirstChildElement("origin"); + if (o) { + if (!parsePose(vis.origin, o)) + return false; + } + + // Geometry + TiXmlElement *geom = config->FirstChildElement("geometry"); + vis.geometry = parseGeometry(geom); + if (!vis.geometry) + return false; + + const char *name_char = config->Attribute("name"); + if (name_char) + vis.name = name_char; + + // Material + TiXmlElement *mat = config->FirstChildElement("material"); + if (mat) { + // get material name + if (!mat->Attribute("name")) { + logError("Visual material must contain a name attribute"); + return false; + } + vis.material_name = mat->Attribute("name"); + + // try to parse material element in place + vis.material.reset(new Material()); + if (!parseMaterial(*vis.material, mat, true)) + { + logDebug("urdfdom: material has only name, actual material definition may be in the model"); + } + } + + return true; +} + +bool parseCollision(Collision &col, TiXmlElement* config) +{ + col.clear(); + + // Origin + TiXmlElement *o = config->FirstChildElement("origin"); + if (o) { + if (!parsePose(col.origin, o)) + return false; + } + + // Geometry + TiXmlElement *geom = config->FirstChildElement("geometry"); + col.geometry = parseGeometry(geom); + if (!col.geometry) + return false; + + const char *name_char = config->Attribute("name"); + if (name_char) + col.name = name_char; + + return true; +} + +bool parseLink(Link &link, TiXmlElement* config) +{ + + link.clear(); + + const char *name_char = config->Attribute("name"); + if (!name_char) + { + logError("No name given for the link."); + return false; + } + link.name = std::string(name_char); + + // Inertial (optional) + TiXmlElement *i = config->FirstChildElement("inertial"); + if (i) + { + link.inertial.reset(new Inertial()); + if (!parseInertial(*link.inertial, i)) + { + logError("Could not parse inertial element for Link [%s]", link.name.c_str()); + return false; + } + } + + // Multiple Visuals (optional) + for (TiXmlElement* vis_xml = config->FirstChildElement("visual"); vis_xml; vis_xml = vis_xml->NextSiblingElement("visual")) + { + + my_shared_ptr vis; + vis.reset(new Visual()); + if (parseVisual(*vis, vis_xml)) + { + link.visual_array.push_back(vis); + } + else + { + vis.reset(0); + logError("Could not parse visual element for Link [%s]", link.name.c_str()); + return false; + } + } + + // Visual (optional) + // Assign the first visual to the .visual ptr, if it exists + if (!link.visual_array.empty()) + link.visual = link.visual_array[0]; + + // Multiple Collisions (optional) + for (TiXmlElement* col_xml = config->FirstChildElement("collision"); col_xml; col_xml = col_xml->NextSiblingElement("collision")) + { + my_shared_ptr col; + col.reset(new Collision()); + if (parseCollision(*col, col_xml)) + { + link.collision_array.push_back(col); + } + else + { + col.reset(0); + logError("Could not parse collision element for Link [%s]", link.name.c_str()); + return false; + } + } + + // Collision (optional) + // Assign the first collision to the .collision ptr, if it exists + if (!link.collision_array.empty()) + link.collision = link.collision_array[0]; + return true; + +} + +} diff --git a/btgui/urdf/urdfdom/urdf_parser/src/model.cpp b/btgui/urdf/urdfdom/urdf_parser/src/model.cpp new file mode 100644 index 000000000..8819c739e --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/model.cpp @@ -0,0 +1,238 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ +//#include +#include +#include "urdf_parser/urdf_parser.h" +#ifdef URDF_USE_CONSOLE_BRIDGE + #include +#else + #include "printf_console.h" +#endif + +namespace urdf{ + +bool parseMaterial(Material &material, TiXmlElement *config, bool only_name_is_ok); +bool parseLink(Link &link, TiXmlElement *config); +bool parseJoint(Joint &joint, TiXmlElement *config); + + +my_shared_ptr parseURDF(const std::string &xml_string) +{ + my_shared_ptr model(new ModelInterface); + model->clear(); + + TiXmlDocument xml_doc; + xml_doc.Parse(xml_string.c_str()); + if (xml_doc.Error()) + { + logError(xml_doc.ErrorDesc()); + xml_doc.ClearError(); + model.reset(0); + return model; + } + + TiXmlElement *robot_xml = xml_doc.FirstChildElement("robot"); + if (!robot_xml) + { + logError("Could not find the 'robot' element in the xml file"); + model.reset(0); + return model; + } + + // Get robot name + const char *name = robot_xml->Attribute("name"); + if (!name) + { + logError("No name given for the robot."); + model.reset(0); + return model; + } + model->name_ = std::string(name); + + // Get all Material elements + for (TiXmlElement* material_xml = robot_xml->FirstChildElement("material"); material_xml; material_xml = material_xml->NextSiblingElement("material")) + { + my_shared_ptr material; + material.reset(new Material); + + try { + parseMaterial(*material, material_xml, false); // material needs to be fully defined here + if (model->getMaterial(material->name)) + { + logError("material '%s' is not unique.", material->name.c_str()); + material.reset(0); + model.reset(0); + return model; + } + else + { + model->materials_.insert(make_pair(material->name,material)); + logDebug("urdfdom: successfully added a new material '%s'", material->name.c_str()); + } + } + catch (ParseError &e) { + logError("material xml is not initialized correctly"); + material.reset(0); + model.reset(0); + return model; + } + } + + // Get all Link elements + for (TiXmlElement* link_xml = robot_xml->FirstChildElement("link"); link_xml; link_xml = link_xml->NextSiblingElement("link")) + { + my_shared_ptr link; + link.reset(new Link); + + try { + parseLink(*link, link_xml); + if (model->getLink(link->name)) + { + logError("link '%s' is not unique.", link->name.c_str()); + model.reset(0); + return model; + } + else + { + // set link visual material + logDebug("urdfdom: setting link '%s' material", link->name.c_str()); + if (link->visual) + { + if (!link->visual->material_name.empty()) + { + if (model->getMaterial(link->visual->material_name)) + { + logDebug("urdfdom: setting link '%s' material to '%s'", link->name.c_str(),link->visual->material_name.c_str()); + link->visual->material = model->getMaterial( link->visual->material_name.c_str() ); + } + else + { + if (link->visual->material) + { + logDebug("urdfdom: link '%s' material '%s' defined in Visual.", link->name.c_str(),link->visual->material_name.c_str()); + model->materials_.insert(make_pair(link->visual->material->name,link->visual->material)); + } + else + { + logError("link '%s' material '%s' undefined.", link->name.c_str(),link->visual->material_name.c_str()); + model.reset(0); + return model; + } + } + } + } + + model->links_.insert(make_pair(link->name,link)); + logDebug("urdfdom: successfully added a new link '%s'", link->name.c_str()); + } + } + catch (ParseError &e) { + logError("link xml is not initialized correctly"); + model.reset(0); + return model; + } + } + if (model->links_.empty()){ + logError("No link elements found in urdf file"); + model.reset(0); + return model; + } + + // Get all Joint elements + for (TiXmlElement* joint_xml = robot_xml->FirstChildElement("joint"); joint_xml; joint_xml = joint_xml->NextSiblingElement("joint")) + { + my_shared_ptr joint; + joint.reset(new Joint); + + if (parseJoint(*joint, joint_xml)) + { + if (model->getJoint(joint->name)) + { + logError("joint '%s' is not unique.", joint->name.c_str()); + model.reset(0); + return model; + } + else + { + model->joints_.insert(make_pair(joint->name,joint)); + logDebug("urdfdom: successfully added a new joint '%s'", joint->name.c_str()); + } + } + else + { + logError("joint xml is not initialized correctly"); + model.reset(0); + return model; + } + } + + + // every link has children links and joints, but no parents, so we create a + // local convenience data structure for keeping child->parent relations + std::map parent_link_tree; + parent_link_tree.clear(); + + // building tree: name mapping + try + { + model->initTree(parent_link_tree); + } + catch(ParseError &e) + { + logError("Failed to build tree: %s", e.what()); + model.reset(0); + return model; + } + + // find the root link + try + { + model->initRoot(parent_link_tree); + } + catch(ParseError &e) + { + logError("Failed to find root link: %s", e.what()); + model.reset(0); + return model; + } + + return model; +} + + + +} + diff --git a/btgui/urdf/urdfdom/urdf_parser/src/pose.cpp b/btgui/urdf/urdfdom/urdf_parser/src/pose.cpp new file mode 100644 index 000000000..6b78e1da9 --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/pose.cpp @@ -0,0 +1,91 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen, John Hsu */ + + +#include +#include +#include +//#include +#include + +#ifdef URDF_USE_CONSOLE_BRIDGE +#include +#else +#include "printf_console.h" +#endif + +#include +#include + + +namespace urdf{ + +bool parsePose(Pose &pose, TiXmlElement* xml) +{ + pose.clear(); + if (xml) + { + const char* xyz_str = xml->Attribute("xyz"); + if (xyz_str != NULL) + { + try { + pose.position.init(xyz_str); + } + catch (ParseError &e) { + logError(e.what()); + return false; + } + } + + const char* rpy_str = xml->Attribute("rpy"); + if (rpy_str != NULL) + { + try { + pose.rotation.init(rpy_str); + } + catch (ParseError &e) { + logError(e.what()); + return false; + } + } + } + return true; +} + + +} + + diff --git a/btgui/urdf/urdfdom/urdf_parser/src/twist.cpp b/btgui/urdf/urdfdom/urdf_parser/src/twist.cpp new file mode 100644 index 000000000..211782564 --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/twist.cpp @@ -0,0 +1,85 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: John Hsu */ + + +#include +#include +#include +#include +#include +#include +#include + +namespace urdf{ + +bool parseTwist(Twist &twist, TiXmlElement* xml) +{ + twist.clear(); + if (xml) + { + const char* linear_char = xml->Attribute("linear"); + if (linear_char != NULL) + { + try { + twist.linear.init(linear_char); + } + catch (ParseError &e) { + twist.linear.clear(); + logError("Malformed linear string [%s]: %s", linear_char, e.what()); + return false; + } + } + + const char* angular_char = xml->Attribute("angular"); + if (angular_char != NULL) + { + try { + twist.angular.init(angular_char); + } + catch (ParseError &e) { + twist.angular.clear(); + logError("Malformed angular [%s]: %s", angular_char, e.what()); + return false; + } + } + } + return true; +} + +} + + + diff --git a/btgui/urdf/urdfdom/urdf_parser/src/urdf_model_state.cpp b/btgui/urdf/urdfdom/urdf_parser/src/urdf_model_state.cpp new file mode 100644 index 000000000..4cb60f892 --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/urdf_model_state.cpp @@ -0,0 +1,154 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: John Hsu */ + + +#include +#include +#include +#include +#include +#include +#include + +namespace urdf{ + +bool parseModelState(ModelState &ms, TiXmlElement* config) +{ + ms.clear(); + + const char *name_char = config->Attribute("name"); + if (!name_char) + { + logError("No name given for the model_state."); + return false; + } + ms.name = std::string(name_char); + + const char *time_stamp_char = config->Attribute("time_stamp"); + if (time_stamp_char) + { + try { + double sec = boost::lexical_cast(time_stamp_char); + ms.time_stamp.set(sec); + } + catch (boost::bad_lexical_cast &e) { + logError("Parsing time stamp [%s] failed: %s", time_stamp_char, e.what()); + return false; + } + } + + TiXmlElement *joint_state_elem = config->FirstChildElement("joint_state"); + if (joint_state_elem) + { + boost::shared_ptr joint_state; + joint_state.reset(new JointState()); + + const char *joint_char = joint_state_elem->Attribute("joint"); + if (joint_char) + joint_state->joint = std::string(joint_char); + else + { + logError("No joint name given for the model_state."); + return false; + } + + // parse position + const char *position_char = joint_state_elem->Attribute("position"); + if (position_char) + { + + std::vector pieces; + boost::split( pieces, position_char, boost::is_any_of(" ")); + for (unsigned int i = 0; i < pieces.size(); ++i){ + if (pieces[i] != ""){ + try { + joint_state->position.push_back(boost::lexical_cast(pieces[i].c_str())); + } + catch (boost::bad_lexical_cast &e) { + throw ParseError("position element ("+ pieces[i] +") is not a valid float"); + } + } + } + } + + // parse velocity + const char *velocity_char = joint_state_elem->Attribute("velocity"); + if (velocity_char) + { + + std::vector pieces; + boost::split( pieces, velocity_char, boost::is_any_of(" ")); + for (unsigned int i = 0; i < pieces.size(); ++i){ + if (pieces[i] != ""){ + try { + joint_state->velocity.push_back(boost::lexical_cast(pieces[i].c_str())); + } + catch (boost::bad_lexical_cast &e) { + throw ParseError("velocity element ("+ pieces[i] +") is not a valid float"); + } + } + } + } + + // parse effort + const char *effort_char = joint_state_elem->Attribute("effort"); + if (effort_char) + { + + std::vector pieces; + boost::split( pieces, effort_char, boost::is_any_of(" ")); + for (unsigned int i = 0; i < pieces.size(); ++i){ + if (pieces[i] != ""){ + try { + joint_state->effort.push_back(boost::lexical_cast(pieces[i].c_str())); + } + catch (boost::bad_lexical_cast &e) { + throw ParseError("effort element ("+ pieces[i] +") is not a valid float"); + } + } + } + } + + // add to vector + ms.joint_states.push_back(joint_state); + } +}; + + + +} + + diff --git a/btgui/urdf/urdfdom/urdf_parser/src/urdf_sensor.cpp b/btgui/urdf/urdfdom/urdf_parser/src/urdf_sensor.cpp new file mode 100644 index 000000000..58db5cdbe --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/urdf_sensor.cpp @@ -0,0 +1,364 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: John Hsu */ + + +#include +#include +#include +#include +#include +#include +#include + +namespace urdf{ + +bool parsePose(Pose &pose, TiXmlElement* xml); + +bool parseCamera(Camera &camera, TiXmlElement* config) +{ + camera.clear(); + camera.type = VisualSensor::CAMERA; + + TiXmlElement *image = config->FirstChildElement("image"); + if (image) + { + const char* width_char = image->Attribute("width"); + if (width_char) + { + try + { + camera.width = boost::lexical_cast(width_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Camera image width [%s] is not a valid int: %s", width_char, e.what()); + return false; + } + } + else + { + logError("Camera sensor needs an image width attribute"); + return false; + } + + const char* height_char = image->Attribute("height"); + if (height_char) + { + try + { + camera.height = boost::lexical_cast(height_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Camera image height [%s] is not a valid int: %s", height_char, e.what()); + return false; + } + } + else + { + logError("Camera sensor needs an image height attribute"); + return false; + } + + const char* format_char = image->Attribute("format"); + if (format_char) + camera.format = std::string(format_char); + else + { + logError("Camera sensor needs an image format attribute"); + return false; + } + + const char* hfov_char = image->Attribute("hfov"); + if (hfov_char) + { + try + { + camera.hfov = boost::lexical_cast(hfov_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Camera image hfov [%s] is not a valid float: %s", hfov_char, e.what()); + return false; + } + } + else + { + logError("Camera sensor needs an image hfov attribute"); + return false; + } + + const char* near_char = image->Attribute("near"); + if (near_char) + { + try + { + camera.near = boost::lexical_cast(near_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Camera image near [%s] is not a valid float: %s", near_char, e.what()); + return false; + } + } + else + { + logError("Camera sensor needs an image near attribute"); + return false; + } + + const char* far_char = image->Attribute("far"); + if (far_char) + { + try + { + camera.far = boost::lexical_cast(far_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Camera image far [%s] is not a valid float: %s", far_char, e.what()); + return false; + } + } + else + { + logError("Camera sensor needs an image far attribute"); + return false; + } + + } + else + { + logError("Camera sensor has no element"); + return false; + } + return true; +} + +bool parseRay(Ray &ray, TiXmlElement* config) +{ + ray.clear(); + ray.type = VisualSensor::RAY; + + TiXmlElement *horizontal = config->FirstChildElement("horizontal"); + if (horizontal) + { + const char* samples_char = horizontal->Attribute("samples"); + if (samples_char) + { + try + { + ray.horizontal_samples = boost::lexical_cast(samples_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Ray horizontal samples [%s] is not a valid float: %s", samples_char, e.what()); + return false; + } + } + + const char* resolution_char = horizontal->Attribute("resolution"); + if (resolution_char) + { + try + { + ray.horizontal_resolution = boost::lexical_cast(resolution_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Ray horizontal resolution [%s] is not a valid float: %s", resolution_char, e.what()); + return false; + } + } + + const char* min_angle_char = horizontal->Attribute("min_angle"); + if (min_angle_char) + { + try + { + ray.horizontal_min_angle = boost::lexical_cast(min_angle_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Ray horizontal min_angle [%s] is not a valid float: %s", min_angle_char, e.what()); + return false; + } + } + + const char* max_angle_char = horizontal->Attribute("max_angle"); + if (max_angle_char) + { + try + { + ray.horizontal_max_angle = boost::lexical_cast(max_angle_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Ray horizontal max_angle [%s] is not a valid float: %s", max_angle_char, e.what()); + return false; + } + } + } + + TiXmlElement *vertical = config->FirstChildElement("vertical"); + if (vertical) + { + const char* samples_char = vertical->Attribute("samples"); + if (samples_char) + { + try + { + ray.vertical_samples = boost::lexical_cast(samples_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Ray vertical samples [%s] is not a valid float: %s", samples_char, e.what()); + return false; + } + } + + const char* resolution_char = vertical->Attribute("resolution"); + if (resolution_char) + { + try + { + ray.vertical_resolution = boost::lexical_cast(resolution_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Ray vertical resolution [%s] is not a valid float: %s", resolution_char, e.what()); + return false; + } + } + + const char* min_angle_char = vertical->Attribute("min_angle"); + if (min_angle_char) + { + try + { + ray.vertical_min_angle = boost::lexical_cast(min_angle_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Ray vertical min_angle [%s] is not a valid float: %s", min_angle_char, e.what()); + return false; + } + } + + const char* max_angle_char = vertical->Attribute("max_angle"); + if (max_angle_char) + { + try + { + ray.vertical_max_angle = boost::lexical_cast(max_angle_char); + } + catch (boost::bad_lexical_cast &e) + { + logError("Ray vertical max_angle [%s] is not a valid float: %s", max_angle_char, e.what()); + return false; + } + } + } +} + +boost::shared_ptr parseVisualSensor(TiXmlElement *g) +{ + boost::shared_ptr visual_sensor; + + // get sensor type + TiXmlElement *sensor_xml; + if (g->FirstChildElement("camera")) + { + Camera *camera = new Camera(); + visual_sensor.reset(camera); + sensor_xml = g->FirstChildElement("camera"); + if (!parseCamera(*camera, sensor_xml)) + visual_sensor.reset(); + } + else if (g->FirstChildElement("ray")) + { + Ray *ray = new Ray(); + visual_sensor.reset(ray); + sensor_xml = g->FirstChildElement("ray"); + if (!parseRay(*ray, sensor_xml)) + visual_sensor.reset(); + } + else + { + logError("No know sensor types [camera|ray] defined in block"); + } + return visual_sensor; +} + + +bool parseSensor(Sensor &sensor, TiXmlElement* config) +{ + sensor.clear(); + + const char *name_char = config->Attribute("name"); + if (!name_char) + { + logError("No name given for the sensor."); + return false; + } + sensor.name = std::string(name_char); + + // parse parent_link_name + const char *parent_link_name_char = config->Attribute("parent_link_name"); + if (!parent_link_name_char) + { + logError("No parent_link_name given for the sensor."); + return false; + } + sensor.parent_link_name = std::string(parent_link_name_char); + + // parse origin + TiXmlElement *o = config->FirstChildElement("origin"); + if (o) + { + if (!parsePose(sensor.origin, o)) + return false; + } + + // parse sensor + sensor.sensor = parseVisualSensor(config); + return true; +} + + +} + + diff --git a/btgui/urdf/urdfdom/urdf_parser/src/world.cpp b/btgui/urdf/urdfdom/urdf_parser/src/world.cpp new file mode 100644 index 000000000..f858b259d --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/src/world.cpp @@ -0,0 +1,71 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace urdf{ + +bool parseWorld(World &world, TiXmlElement* config) +{ + + // to be implemented + + return true; +} + +bool exportWorld(World &world, TiXmlElement* xml) +{ + TiXmlElement * world_xml = new TiXmlElement("world"); + world_xml->SetAttribute("name", world.name); + + // to be implemented + // exportModels(*world.models, world_xml); + + xml->LinkEndChild(world_xml); + + return true; +} + +} diff --git a/btgui/urdf/urdfdom/urdf_parser/test/memtest.cpp b/btgui/urdf/urdfdom/urdf_parser/test/memtest.cpp new file mode 100644 index 000000000..d835eb3db --- /dev/null +++ b/btgui/urdf/urdfdom/urdf_parser/test/memtest.cpp @@ -0,0 +1,20 @@ +#include "urdf_parser/urdf_parser.h" +#include +#include + +int main(int argc, char** argv){ + while (true){ + std::string xml_string; + std::fstream xml_file(argv[1], std::fstream::in); + while ( xml_file.good() ) + { + std::string line; + std::getline( xml_file, line); + xml_string += (line + "\n"); + } + xml_file.close(); + + + urdf::parseURDF(xml_string); + } +} diff --git a/btgui/urdf/urdfdom_headers/LICENSE b/btgui/urdf/urdfdom_headers/LICENSE new file mode 100644 index 000000000..e80920e25 --- /dev/null +++ b/btgui/urdf/urdfdom_headers/LICENSE @@ -0,0 +1,15 @@ +Software License Agreement (Apache License) + +Copyright 2011 John Hsu + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/btgui/urdf/urdfdom_headers/README.txt b/btgui/urdf/urdfdom_headers/README.txt new file mode 100644 index 000000000..6a841d52e --- /dev/null +++ b/btgui/urdf/urdfdom_headers/README.txt @@ -0,0 +1,6 @@ +The URDF (U-Robot Description Format) headers + provides core data structure headers for URDF. + +For now, the details of the URDF specifications reside on + http://ros.org/wiki/urdf + diff --git a/btgui/urdf/urdfdom_headers/urdf_exception/include/urdf_exception/exception.h b/btgui/urdf/urdfdom_headers/urdf_exception/include/urdf_exception/exception.h new file mode 100644 index 000000000..24222f1ff --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_exception/include/urdf_exception/exception.h @@ -0,0 +1,53 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +// URDF exceptions +#ifndef URDF_INTERFACE_EXCEPTION_H_ +#define URDF_INTERFACE_EXCEPTION_H_ + +#include +#include + +namespace urdf +{ + +class ParseError: public std::runtime_error +{ +public: + ParseError(const std::string &error_msg) : std::runtime_error(error_msg) {}; +}; + +} + +#endif diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/color.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/color.h new file mode 100644 index 000000000..ffb70c922 --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/color.h @@ -0,0 +1,102 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Josh Faust */ + +#ifndef URDF_INTERFACE_COLOR_H +#define URDF_INTERFACE_COLOR_H + +#include +#include +#include +//#include +//#include + +namespace urdf +{ + +class Color +{ +public: + Color() {this->clear();}; + float r; + float g; + float b; + float a; + + void clear() + { + r = g = b = 0.0f; + a = 1.0f; + } + bool init(const std::string &vector_str) + { + this->clear(); + std::vector pieces; + std::vector rgba; +#if 0 + boost::split( pieces, vector_str, boost::is_any_of(" ")); + for (unsigned int i = 0; i < pieces.size(); ++i) + { + if (!pieces[i].empty()) + { + try + { + rgba.push_back(boost::lexical_cast(pieces[i].c_str())); + } + catch (boost::bad_lexical_cast &e) + { + return false; + } + } + } + + if (rgba.size() != 4) + { + return false; + } +#endif + this->r = rgba[0]; + this->g = rgba[1]; + this->b = rgba[2]; + this->a = rgba[3]; + + return true; + }; +}; + +} + +#endif + diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h new file mode 100644 index 000000000..0cfb80fc7 --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h @@ -0,0 +1,234 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ + +#ifndef URDF_INTERFACE_JOINT_H +#define URDF_INTERFACE_JOINT_H + +#include +#include +#ifdef URDF_USE_BOOST +#include +#define my_shared_ptr my_shared_ptr +#else +#include +#endif + +#include "urdf_model/pose.h" + + +namespace urdf{ + +class Link; + +class JointDynamics +{ +public: + JointDynamics() { this->clear(); }; + double damping; + double friction; + + void clear() + { + damping = 0; + friction = 0; + }; +}; + +class JointLimits +{ +public: + JointLimits() { this->clear(); }; + double lower; + double upper; + double effort; + double velocity; + + void clear() + { + lower = 0; + upper = 0; + effort = 0; + velocity = 0; + }; +}; + +/// \brief Parameters for Joint Safety Controllers +class JointSafety +{ +public: + /// clear variables on construction + JointSafety() { this->clear(); }; + + /// + /// IMPORTANT: The safety controller support is very much PR2 specific, not intended for generic usage. + /// + /// Basic safety controller operation is as follows + /// + /// current safety controllers will take effect on joints outside the position range below: + /// + /// position range: [JointSafety::soft_lower_limit + JointLimits::velocity / JointSafety::k_position, + /// JointSafety::soft_uppper_limit - JointLimits::velocity / JointSafety::k_position] + /// + /// if (joint_position is outside of the position range above) + /// velocity_limit_min = -JointLimits::velocity + JointSafety::k_position * (joint_position - JointSafety::soft_lower_limit) + /// velocity_limit_max = JointLimits::velocity + JointSafety::k_position * (joint_position - JointSafety::soft_upper_limit) + /// else + /// velocity_limit_min = -JointLimits::velocity + /// velocity_limit_max = JointLimits::velocity + /// + /// velocity range: [velocity_limit_min + JointLimits::effort / JointSafety::k_velocity, + /// velocity_limit_max - JointLimits::effort / JointSafety::k_velocity] + /// + /// if (joint_velocity is outside of the velocity range above) + /// effort_limit_min = -JointLimits::effort + JointSafety::k_velocity * (joint_velocity - velocity_limit_min) + /// effort_limit_max = JointLimits::effort + JointSafety::k_velocity * (joint_velocity - velocity_limit_max) + /// else + /// effort_limit_min = -JointLimits::effort + /// effort_limit_max = JointLimits::effort + /// + /// Final effort command sent to the joint is saturated by [effort_limit_min,effort_limit_max] + /// + /// Please see wiki for more details: http://www.ros.org/wiki/pr2_controller_manager/safety_limits + /// + double soft_upper_limit; + double soft_lower_limit; + double k_position; + double k_velocity; + + void clear() + { + soft_upper_limit = 0; + soft_lower_limit = 0; + k_position = 0; + k_velocity = 0; + }; +}; + + +class JointCalibration +{ +public: + JointCalibration() { this->clear(); }; + double reference_position; + my_shared_ptr rising, falling; + + void clear() + { + reference_position = 0; + }; +}; + +class JointMimic +{ +public: + JointMimic() { this->clear(); }; + double offset; + double multiplier; + std::string joint_name; + + void clear() + { + offset = 0.0; + multiplier = 0.0; + joint_name.clear(); + }; +}; + + +class Joint +{ +public: + + Joint() { this->clear(); }; + + std::string name; + enum + { + UNKNOWN, REVOLUTE, CONTINUOUS, PRISMATIC, FLOATING, PLANAR, FIXED + } type; + + /// \brief type_ meaning of axis_ + /// ------------------------------------------------------ + /// UNKNOWN unknown type + /// REVOLUTE rotation axis + /// PRISMATIC translation axis + /// FLOATING N/A + /// PLANAR plane normal axis + /// FIXED N/A + Vector3 axis; + + /// child Link element + /// child link frame is the same as the Joint frame + std::string child_link_name; + + /// parent Link element + /// origin specifies the transform from Parent Link to Joint Frame + std::string parent_link_name; + /// transform from Parent Link frame to Joint frame + Pose parent_to_joint_origin_transform; + + /// Joint Dynamics + my_shared_ptr dynamics; + + /// Joint Limits + my_shared_ptr limits; + + /// Unsupported Hidden Feature + my_shared_ptr safety; + + /// Unsupported Hidden Feature + my_shared_ptr calibration; + + /// Option to Mimic another Joint + my_shared_ptr mimic; + + void clear() + { + this->axis.clear(); + this->child_link_name.clear(); + this->parent_link_name.clear(); + this->parent_to_joint_origin_transform.clear(); + this->dynamics.reset(0); + this->limits.reset(0); + this->safety.reset(0); + this->calibration.reset(0); + this->type = UNKNOWN; + }; +}; + +} + +#endif diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h new file mode 100644 index 000000000..649516469 --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h @@ -0,0 +1,258 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ + +#ifndef URDF_INTERFACE_LINK_H +#define URDF_INTERFACE_LINK_H + +#include +#include +#include + + +#ifdef URDF_USE_BOOST + #include + #include +#else + #include +#endif + +#include "joint.h" +#include "color.h" +#include "pose.h" + +namespace urdf{ + +class Geometry +{ +public: + enum {SPHERE, BOX, CYLINDER, MESH} type; + + virtual ~Geometry(void) + { + } +}; + +class Sphere : public Geometry +{ +public: + Sphere() { this->clear(); type = SPHERE; }; + double radius; + + void clear() + { + radius = 0; + }; +}; + +class Box : public Geometry +{ +public: + Box() { this->clear(); type = BOX; } + Vector3 dim; + + void clear() + { + this->dim.clear(); + }; +}; + +class Cylinder : public Geometry +{ +public: + Cylinder() { this->clear(); type = CYLINDER; }; + double length; + double radius; + + void clear() + { + length = 0; + radius = 0; + }; +}; + +class Mesh : public Geometry +{ +public: + Mesh() { this->clear(); type = MESH; }; + std::string filename; + Vector3 scale; + + void clear() + { + filename.clear(); + // default scale + scale.x = 1; + scale.y = 1; + scale.z = 1; + }; +}; + +class Material +{ +public: + Material() { this->clear(); }; + std::string name; + std::string texture_filename; + Color color; + + void clear() + { + color.clear(); + texture_filename.clear(); + name.clear(); + }; +}; + +class Inertial +{ +public: + Inertial() { this->clear(); }; + Pose origin; + double mass; + double ixx,ixy,ixz,iyy,iyz,izz; + + void clear() + { + origin.clear(); + mass = 0; + ixx = ixy = ixz = iyy = iyz = izz = 0; + }; +}; + +class Visual +{ +public: + Visual() { this->clear(); }; + Pose origin; + my_shared_ptr geometry; + + std::string material_name; + my_shared_ptr material; + + void clear() + { + origin.clear(); + material_name.clear(); + material.reset(0); + geometry.reset(0); + name.clear(); + }; + + std::string name; +}; + +class Collision +{ +public: + Collision() { this->clear(); }; + Pose origin; + my_shared_ptr geometry; + + void clear() + { + origin.clear(); + geometry.reset(0); + name.clear(); + }; + + std::string name; + +}; + + +class Link +{ +public: + Link() { this->clear(); }; + + std::string name; + + /// inertial element + my_shared_ptr inertial; + + /// visual element + my_shared_ptr visual; + + /// collision element + my_shared_ptr collision; + + /// if more than one collision element is specified, all collision elements are placed in this array (the collision member points to the first element of the array) + std::vector > collision_array; + + /// if more than one visual element is specified, all visual elements are placed in this array (the visual member points to the first element of the array) + std::vector > visual_array; + + /// Parent Joint element + /// explicitly stating "parent" because we want directional-ness for tree structure + /// every link can have one parent + my_shared_ptr parent_joint; + + std::vector > child_joints; + std::vector > child_links; + + const Link* getParent() const + {return parent_link_;} + + void setParent(const my_shared_ptr &parent) + { + parent_link_ = parent.get(); + } + + void clear() + { + this->name.clear(); + this->inertial.reset(0); + this->visual.reset(0); + this->collision.reset(0); + this->parent_joint.reset(0); + this->child_joints.clear(); + this->child_links.clear(); + this->collision_array.clear(); + this->visual_array.clear(); + }; + +private: +// boost::weak_ptr parent_link_; + const Link* parent_link_; + +}; + + + + +} + +#endif diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h new file mode 100644 index 000000000..b40fdb53d --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h @@ -0,0 +1,215 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ + +#ifndef URDF_INTERFACE_MODEL_H +#define URDF_INTERFACE_MODEL_H + +#include +#include +//#include +#include + +#include + +namespace urdf { + +class ModelInterface +{ +public: + my_shared_ptr getRoot(void) const{return this->root_link_;}; + my_shared_ptr getLink(const std::string& name) const + { + my_shared_ptr ptr; + if (this->links_.find(name) == this->links_.end()) + ptr.reset(0); + else + ptr = this->links_.find(name)->second; + return ptr; + }; + + my_shared_ptr getJoint(const std::string& name) const + { + my_shared_ptr ptr; + if (this->joints_.find(name) == this->joints_.end()) + ptr.reset(0); + else + ptr = this->joints_.find(name)->second; + return ptr; + }; + + + const std::string& getName() const {return name_;}; + void getLinks(std::vector >& links) const + { + for (std::map >::const_iterator link = this->links_.begin();link != this->links_.end(); link++) + { + links.push_back(link->second); + } + }; + + void clear() + { + name_.clear(); + this->links_.clear(); + this->joints_.clear(); + this->materials_.clear(); + this->root_link_.reset(0); + }; + + /// non-const getLink() + void getLink(const std::string& name,my_shared_ptr &link) const + { + my_shared_ptr ptr; + if (this->links_.find(name) == this->links_.end()) + ptr.reset(0); + else + ptr = this->links_.find(name)->second; + link = ptr; + }; + + /// non-const getMaterial() + my_shared_ptr getMaterial(const std::string& name) const + { + my_shared_ptr ptr; + if (this->materials_.find(name) == this->materials_.end()) + ptr.reset(0); + else + ptr = this->materials_.find(name)->second; + return ptr; + }; + + void initTree(std::map &parent_link_tree) + { + // loop through all joints, for every link, assign children links and children joints + for (std::map >::iterator joint = this->joints_.begin();joint != this->joints_.end(); joint++) + { + std::string parent_link_name = joint->second->parent_link_name; + std::string child_link_name = joint->second->child_link_name; + + if (parent_link_name.empty() || child_link_name.empty()) + { + assert(0); + + // throw ParseError("Joint [" + joint->second->name + "] is missing a parent and/or child link specification."); + } + else + { + // find child and parent links + my_shared_ptr child_link, parent_link; + this->getLink(child_link_name, child_link); + if (!child_link) + { + assert(0); +// throw ParseError("child link [" + child_link_name + "] of joint [" + joint->first + "] not found"); + } + this->getLink(parent_link_name, parent_link); + if (!parent_link) + { + assert(0); + +/* throw ParseError("parent link [" + parent_link_name + "] of joint [" + joint->first + "] not found. This is not valid according to the URDF spec. Every link you refer to from a joint needs to be explicitly defined in the robot description. To fix this problem you can either remove this joint [" + joint->first + "] from your urdf file, or add \"\" to your urdf file."); + + */} + + //set parent link for child link + child_link->setParent(parent_link); + + //set parent joint for child link + child_link->parent_joint = joint->second; + + //set child joint for parent link + parent_link->child_joints.push_back(joint->second); + + //set child link for parent link + parent_link->child_links.push_back(child_link); + + // fill in child/parent string map + parent_link_tree[child_link->name] = parent_link_name; + } + } + } + + void initRoot(const std::map &parent_link_tree) + { + this->root_link_.reset(0); + + // find the links that have no parent in the tree + for (std::map >::const_iterator l=this->links_.begin(); l!=this->links_.end(); l++) + { + std::map::const_iterator parent = parent_link_tree.find(l->first); + if (parent == parent_link_tree.end()) + { + // store root link + if (!this->root_link_) + { + getLink(l->first, this->root_link_); + } + // we already found a root link + else + { + assert(0); + // throw ParseError("Two root links found: [" + this->root_link_->name + "] and [" + l->first + "]"); + } + } + } + if (!this->root_link_) + { + assert(0); + //throw ParseError("No root link found. The robot xml is not a valid tree."); + } + } + + + /// \brief complete list of Links + std::map > links_; + /// \brief complete list of Joints + std::map > joints_; + /// \brief complete list of Materials + std::map > materials_; + + /// \brief The name of the robot model + std::string name_; + + /// \brief The root is always a link (the parent of the tree describing the robot) + my_shared_ptr root_link_; + + + +}; + +} + +#endif diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h new file mode 100644 index 000000000..1f99efb3c --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h @@ -0,0 +1,265 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: Wim Meeussen */ + +#ifndef URDF_INTERFACE_POSE_H +#define URDF_INTERFACE_POSE_H + +#include +//#include +#include +#include +#ifndef M_PI +#define M_PI 3.141592538 +#endif //M_PI + +#ifdef URDF_USE_BOOST + #include + #include +#else + #include + #include +#endif //URDF_USE_BOOST + +#include +#include + +namespace urdf{ + +class Vector3 +{ +public: + Vector3(double _x,double _y, double _z) {this->x=_x;this->y=_y;this->z=_z;}; + Vector3() {this->clear();}; + double x; + double y; + double z; + + void clear() {this->x=this->y=this->z=0.0;}; + void init(const std::string &vector_str) + { + this->clear(); + std::vector pieces; + std::vector xyz; + boost::split( pieces, vector_str, boost::is_any_of(" ")); + for (unsigned int i = 0; i < pieces.size(); ++i){ + if (pieces[i] != ""){ + try { + xyz.push_back(boost::lexical_cast(pieces[i].c_str())); + } + catch (boost::bad_lexical_cast &e) + { + assert(0); + // throw ParseError("Unable to parse component [" + pieces[i] + "] to a double (while parsing a vector value)"); + } + } + } + + + + if (xyz.size() != 3) + { + assert(0); + // throw ParseError("Parser found " + boost::lexical_cast(xyz.size()) + " elements but 3 expected while parsing vector [" + vector_str + "]"); + } + this->x = xyz[0]; + this->y = xyz[1]; + this->z = xyz[2]; + } + + Vector3 operator+(Vector3 vec) + { + return Vector3(this->x+vec.x,this->y+vec.y,this->z+vec.z); + }; +}; + +class Rotation +{ +public: + Rotation(double _x,double _y, double _z, double _w) {this->x=_x;this->y=_y;this->z=_z;this->w=_w;}; + Rotation() {this->clear();}; + void getQuaternion(double &quat_x,double &quat_y,double &quat_z, double &quat_w) const + { + quat_x = this->x; + quat_y = this->y; + quat_z = this->z; + quat_w = this->w; + }; + void getRPY(double &roll,double &pitch,double &yaw) const + { + double sqw; + double sqx; + double sqy; + double sqz; + + sqx = this->x * this->x; + sqy = this->y * this->y; + sqz = this->z * this->z; + sqw = this->w * this->w; + + roll = atan2(2 * (this->y*this->z + this->w*this->x), sqw - sqx - sqy + sqz); + double sarg = -2 * (this->x*this->z - this->w*this->y); + pitch = sarg <= -1.0 ? -0.5*M_PI : (sarg >= 1.0 ? 0.5*M_PI : asin(sarg)); + yaw = atan2(2 * (this->x*this->y + this->w*this->z), sqw + sqx - sqy - sqz); + + }; + void setFromQuaternion(double quat_x,double quat_y,double quat_z,double quat_w) + { + this->x = quat_x; + this->y = quat_y; + this->z = quat_z; + this->w = quat_w; + this->normalize(); + }; + void setFromRPY(double roll, double pitch, double yaw) + { + double phi, the, psi; + + phi = roll / 2.0; + the = pitch / 2.0; + psi = yaw / 2.0; + + this->x = sin(phi) * cos(the) * cos(psi) - cos(phi) * sin(the) * sin(psi); + this->y = cos(phi) * sin(the) * cos(psi) + sin(phi) * cos(the) * sin(psi); + this->z = cos(phi) * cos(the) * sin(psi) - sin(phi) * sin(the) * cos(psi); + this->w = cos(phi) * cos(the) * cos(psi) + sin(phi) * sin(the) * sin(psi); + + this->normalize(); + }; + + double x,y,z,w; + + void init(const std::string &rotation_str) + { + this->clear(); + Vector3 rpy; + rpy.init(rotation_str); + setFromRPY(rpy.x, rpy.y, rpy.z); + } + + void clear() { this->x=this->y=this->z=0.0;this->w=1.0; } + + void normalize() + { + double s = sqrt(this->x * this->x + + this->y * this->y + + this->z * this->z + + this->w * this->w); + if (s == 0.0) + { + this->x = 0.0; + this->y = 0.0; + this->z = 0.0; + this->w = 1.0; + } + else + { + this->x /= s; + this->y /= s; + this->z /= s; + this->w /= s; + } + }; + + // Multiplication operator (copied from gazebo) + Rotation operator*( const Rotation &qt ) const + { + Rotation c; + + c.x = this->w * qt.x + this->x * qt.w + this->y * qt.z - this->z * qt.y; + c.y = this->w * qt.y - this->x * qt.z + this->y * qt.w + this->z * qt.x; + c.z = this->w * qt.z + this->x * qt.y - this->y * qt.x + this->z * qt.w; + c.w = this->w * qt.w - this->x * qt.x - this->y * qt.y - this->z * qt.z; + + return c; + }; + /// Rotate a vector using the quaternion + Vector3 operator*(Vector3 vec) const + { + Rotation tmp; + Vector3 result; + + tmp.w = 0.0; + tmp.x = vec.x; + tmp.y = vec.y; + tmp.z = vec.z; + + tmp = (*this) * (tmp * this->GetInverse()); + + result.x = tmp.x; + result.y = tmp.y; + result.z = tmp.z; + + return result; + }; + // Get the inverse of this quaternion + Rotation GetInverse() const + { + Rotation q; + + double norm = this->w*this->w+this->x*this->x+this->y*this->y+this->z*this->z; + + if (norm > 0.0) + { + q.w = this->w / norm; + q.x = -this->x / norm; + q.y = -this->y / norm; + q.z = -this->z / norm; + } + + return q; + }; + + +}; + +class Pose +{ +public: + Pose() { this->clear(); }; + + Vector3 position; + Rotation rotation; + + void clear() + { + this->position.clear(); + this->rotation.clear(); + }; +}; + +} + +#endif diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/twist.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/twist.h new file mode 100644 index 000000000..ba57e4c0c --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/twist.h @@ -0,0 +1,68 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: John Hsu */ + +#ifndef URDF_TWIST_H +#define URDF_TWIST_H + +#include +#include +#include +#include +#include + +namespace urdf{ + + +class Twist +{ +public: + Twist() { this->clear(); }; + + Vector3 linear; + // Angular velocity represented by Euler angles + Vector3 angular; + + void clear() + { + this->linear.clear(); + this->angular.clear(); + }; +}; + +} + +#endif + diff --git a/btgui/urdf/urdfdom_headers/urdf_model_state/include/urdf_model_state/model_state.h b/btgui/urdf/urdfdom_headers/urdf_model_state/include/urdf_model_state/model_state.h new file mode 100644 index 000000000..b1327191a --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_model_state/include/urdf_model_state/model_state.h @@ -0,0 +1,141 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: John Hsu */ + +#ifndef URDF_MODEL_STATE_H +#define URDF_MODEL_STATE_H + +#include +#include +#include +#include +#include + +#include "urdf_model/pose.h" +#include + + +namespace urdf{ + +class Time +{ +public: + Time() { this->clear(); }; + + void set(double _seconds) + { + this->sec = (int32_t)(floor(_seconds)); + this->nsec = (int32_t)(round((_seconds - this->sec) * 1e9)); + this->Correct(); + }; + + operator double () + { + return (static_cast(this->sec) + + static_cast(this->nsec)*1e-9); + }; + + int32_t sec; + int32_t nsec; + + void clear() + { + this->sec = 0; + this->nsec = 0; + }; +private: + void Correct() + { + // Make any corrections + if (this->nsec >= 1e9) + { + this->sec++; + this->nsec = (int32_t)(this->nsec - 1e9); + } + else if (this->nsec < 0) + { + this->sec--; + this->nsec = (int32_t)(this->nsec + 1e9); + } + }; +}; + + +class JointState +{ +public: + JointState() { this->clear(); }; + + /// joint name + std::string joint; + + std::vector position; + std::vector velocity; + std::vector effort; + + void clear() + { + this->joint.clear(); + this->position.clear(); + this->velocity.clear(); + this->effort.clear(); + } +}; + +class ModelState +{ +public: + ModelState() { this->clear(); }; + + /// state name must be unique + std::string name; + + Time time_stamp; + + void clear() + { + this->name.clear(); + this->time_stamp.set(0); + this->joint_states.clear(); + }; + + std::vector > joint_states; + +}; + +} + +#endif + diff --git a/btgui/urdf/urdfdom_headers/urdf_model_state/include/urdf_model_state/twist.h b/btgui/urdf/urdfdom_headers/urdf_model_state/include/urdf_model_state/twist.h new file mode 100644 index 000000000..05f1917b9 --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_model_state/include/urdf_model_state/twist.h @@ -0,0 +1,42 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +#ifndef URDF_MODEL_STATE_TWIST_ +#define URDF_MODEL_STATE_TWIST_ + +#warning "Please Use #include " + +#include + +#endif diff --git a/btgui/urdf/urdfdom_headers/urdf_sensor/include/urdf_sensor/sensor.h b/btgui/urdf/urdfdom_headers/urdf_sensor/include/urdf_sensor/sensor.h new file mode 100644 index 000000000..3b996957b --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_sensor/include/urdf_sensor/sensor.h @@ -0,0 +1,176 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: John Hsu */ + +/* example + + + + + 1.5708 + + + + + + + + + + + + + + +*/ + + + +#ifndef URDF_SENSOR_H +#define URDF_SENSOR_H + +#include +#include +#include +#include +#include +#include "urdf_model/pose.h" +#include "urdf_model/joint.h" +#include "urdf_model/link.h" + +namespace urdf{ + +class VisualSensor +{ +public: + enum {CAMERA, RAY} type; + virtual ~VisualSensor(void) + { + } +}; + +class Camera : public VisualSensor +{ +public: + Camera() { this->clear(); }; + unsigned int width, height; + /// format is optional: defaults to R8G8B8), but can be + /// (L8|R8G8B8|B8G8R8|BAYER_RGGB8|BAYER_BGGR8|BAYER_GBRG8|BAYER_GRBG8) + std::string format; + double hfov; + double near; + double far; + + void clear() + { + hfov = 0; + width = 0; + height = 0; + format.clear(); + near = 0; + far = 0; + }; +}; + +class Ray : public VisualSensor +{ +public: + Ray() { this->clear(); }; + unsigned int horizontal_samples; + double horizontal_resolution; + double horizontal_min_angle; + double horizontal_max_angle; + unsigned int vertical_samples; + double vertical_resolution; + double vertical_min_angle; + double vertical_max_angle; + + void clear() + { + // set defaults + horizontal_samples = 1; + horizontal_resolution = 1; + horizontal_min_angle = 0; + horizontal_max_angle = 0; + vertical_samples = 1; + vertical_resolution = 1; + vertical_min_angle = 0; + vertical_max_angle = 0; + }; +}; + + +class Sensor +{ +public: + Sensor() { this->clear(); }; + + /// sensor name must be unique + std::string name; + + /// update rate in Hz + double update_rate; + + /// transform from parent frame to optical center + /// with z-forward and x-right, y-down + Pose origin; + + /// sensor + boost::shared_ptr sensor; + + + /// Parent link element name. A pointer is stored in parent_link_. + std::string parent_link_name; + + boost::shared_ptr getParent() const + {return parent_link_.lock();}; + + void setParent(boost::shared_ptr parent) + { this->parent_link_ = parent; } + + void clear() + { + this->name.clear(); + this->sensor.reset(); + this->parent_link_name.clear(); + this->parent_link_.reset(); + }; + +private: + boost::weak_ptr parent_link_; + +}; +} +#endif diff --git a/btgui/urdf/urdfdom_headers/urdf_world/include/urdf_world/world.h b/btgui/urdf/urdfdom_headers/urdf_world/include/urdf_world/world.h new file mode 100644 index 000000000..eb13fc4b1 --- /dev/null +++ b/btgui/urdf/urdfdom_headers/urdf_world/include/urdf_world/world.h @@ -0,0 +1,114 @@ +/********************************************************************* +* Software License Agreement (BSD License) +* +* Copyright (c) 2008, Willow Garage, Inc. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above +* copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided +* with the distribution. +* * Neither the name of the Willow Garage nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +* POSSIBILITY OF SUCH DAMAGE. +*********************************************************************/ + +/* Author: John Hsu */ + +/* encapsulates components in a world + see http://ros.org/wiki/usdf/XML/urdf_world and + for details +*/ +/* example world XML + + + + + ... + + + + + + + + + + + + + + + + + + + +*/ + +#ifndef USDF_STATE_H +#define USDF_STATE_H + +#include +#include +#include +#include +#include +#include + +#include "urdf_model/model.h" +#include "urdf_model/pose.h" +#include "urdf_model/twist.h" + +namespace urdf{ + +class Entity +{ +public: + boost::shared_ptr model; + Pose origin; + Twist twist; +}; + +class World +{ +public: + World() { this->clear(); }; + + /// world name must be unique + std::string name; + + std::vector models; + + void initXml(TiXmlElement* config); + + void clear() + { + this->name.clear(); + }; +}; +} + +#endif + diff --git a/build3/premake4.lua b/build3/premake4.lua index 4f5d5be50..bcc6ddeb4 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -79,9 +79,9 @@ } end - - flags { "NoRTTI", "NoExceptions"} - defines { "_HAS_EXCEPTIONS=0" } +-- comment-out for now, URDF reader needs exceptions +-- flags { "NoRTTI", "NoExceptions"} +-- defines { "_HAS_EXCEPTIONS=0" } targetdir "../bin" location("./" .. act .. postfix) @@ -117,6 +117,7 @@ if findOpenGL() then -- include "../Demos3/ImplicitCloth" include "../Demos3/SimpleOpenGL3" + include "../btgui/urdf" include "../btgui/lua-5.2.3" include "../test/lua" From e4f64d91f17dfa7b4a2b2eea80861fda6496e4f3 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 14:04:09 -0700 Subject: [PATCH 106/116] add CommonParameterInterface.h --- Demos/CommonParameterInterface.h | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Demos/CommonParameterInterface.h diff --git a/Demos/CommonParameterInterface.h b/Demos/CommonParameterInterface.h new file mode 100644 index 000000000..afb78114b --- /dev/null +++ b/Demos/CommonParameterInterface.h @@ -0,0 +1,41 @@ + +#ifndef PARAM_INTERFACE_H +#define PARAM_INTERFACE_H + +#pragma once + +typedef void (*SliderParamChangedCallback) (float newVal); +#include "LinearMath/btScalar.h" + +struct SliderParams +{ + const char* m_name; + float m_minVal; + float m_maxVal; + SliderParamChangedCallback m_callback; + btScalar* m_paramValuePointer; + void* m_userPointer; + bool m_clampToNotches; + + SliderParams(const char* name, btScalar* targetValuePointer) + :m_name(name), + m_minVal(-100), + m_maxVal(100), + m_callback(0), + m_paramValuePointer(targetValuePointer), + m_userPointer(0), + m_clampToNotches(false) + { + } + +}; + + +struct CommonParameterInterface +{ + virtual void registerSliderFloatParameter(SliderParams& params)=0; + virtual void syncParameters()=0; + virtual void removeAllParameters()=0; +}; + +#endif //PARAM_INTERFACE_H From 8e1fbb482b7d1d40a3b417cf67d6b341ddfc25d8 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 14:06:53 -0700 Subject: [PATCH 107/116] add GwenParameterInterface.cpp and ConstraintPhysicsSetup.cpp to CMakeLists.txt should fix the build --- Demos3/AllBullet2Demos/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Demos3/AllBullet2Demos/CMakeLists.txt b/Demos3/AllBullet2Demos/CMakeLists.txt index f4153f67d..850ef5ba4 100644 --- a/Demos3/AllBullet2Demos/CMakeLists.txt +++ b/Demos3/AllBullet2Demos/CMakeLists.txt @@ -10,12 +10,16 @@ SET(App_AllBullet2Demos_SRCS main.cpp BulletDemoInterface.h BulletDemoEntries.h + GwenParameterInterface.cpp + GwenParameterInterface.h ../bullet2/BasicDemo/Bullet2RigidBodyDemo.cpp ../bullet2/BasicDemo/Bullet2RigidBodyDemo.h ../../Demos/BasicDemo/BasicDemoPhysicsSetup.cpp ../../Demos/BasicDemo/BasicDemoPhysicsSetup.h ../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.cpp ../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h + ../../Demos/ConstraintDemo/ConstraintPhysicsSetup.cpp + ../../Demos/ConstraintDemo/ConstraintPhysicsSetup.h ../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp ../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h ../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.cpp From 793bcb1cded338a9a90f90ba593246034c0b78e6 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 14:20:24 -0700 Subject: [PATCH 108/116] move menuItems into constructor (was a typo) --- Demos3/GpuDemos/gwenUserInterface.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Demos3/GpuDemos/gwenUserInterface.cpp b/Demos3/GpuDemos/gwenUserInterface.cpp index bd45630ee..0646b59e6 100644 --- a/Demos3/GpuDemos/gwenUserInterface.cpp +++ b/Demos3/GpuDemos/gwenUserInterface.cpp @@ -49,13 +49,14 @@ struct MyTestMenuBar : public Gwen::Controls::MenuStrip { -MyMenuItems* menuItems = new MyMenuItems; MyTestMenuBar(Gwen::Controls::Base* pParent) :Gwen::Controls::MenuStrip(pParent) { // Gwen::Controls::MenuStrip* menu = new Gwen::Controls::MenuStrip( pParent ); { +MyMenuItems* menuItems = new MyMenuItems; + Gwen::Controls::MenuItem* pRoot = AddItem( L"File" ); pRoot->GetMenu()->AddItem(L"Quit",menuItems,(Gwen::Event::Handler::Function)&MyMenuItems::myQuitApp); pRoot = AddItem( L"View" ); From f9691957c1423d60d97eb4fbf1ab39a0c738eb4e Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 14:42:33 -0700 Subject: [PATCH 109/116] fix Windows version of urdf parser --- btgui/urdf/boost_replacement/shared_ptr.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/btgui/urdf/boost_replacement/shared_ptr.h b/btgui/urdf/boost_replacement/shared_ptr.h index e1a6b349c..5d29732b6 100644 --- a/btgui/urdf/boost_replacement/shared_ptr.h +++ b/btgui/urdf/boost_replacement/shared_ptr.h @@ -36,8 +36,6 @@ Dec 2011 - Added deferencing operator #ifdef _WIN32 #include -namespace boost -{ class my_shared_count { public: my_shared_count(): m_count(1) { } @@ -65,7 +63,6 @@ public: private: long m_count; }; -}; #else //ifdef WIN32 From 3d944782e9a53857c355bf09d042eac67770062d Mon Sep 17 00:00:00 2001 From: Haydn Trigg Date: Fri, 1 Aug 2014 07:25:31 +0930 Subject: [PATCH 110/116] Update btQuickprof.cpp removed inline declaration from get time seconds function definition --- src/LinearMath/btQuickprof.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LinearMath/btQuickprof.cpp b/src/LinearMath/btQuickprof.cpp index cbf28faa6..4a2e58aef 100644 --- a/src/LinearMath/btQuickprof.cpp +++ b/src/LinearMath/btQuickprof.cpp @@ -239,7 +239,7 @@ unsigned long int btClock::getTimeMicroseconds() /// Returns the time in s since the last call to reset or since /// the Clock was created. -inline btScalar btClock::getTimeSeconds() +btScalar btClock::getTimeSeconds() { static const btScalar microseconds_to_seconds = btScalar(0.000001); return btScalar(getTimeMicroseconds()) * microseconds_to_seconds; From a08d4a94e30b35238d6ab42107ad93d8c8935dd0 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 16:54:28 -0700 Subject: [PATCH 111/116] create URDF skeleton for a demo (only loading data, not converting it yet) --- Demos/CommonRigidBodySetup.h | 11 +- Demos3/AllBullet2Demos/BulletDemoEntries.h | 9 +- Demos3/AllBullet2Demos/CMakeLists.txt | 25 +++- Demos3/ImportURDFDemo/ImportURDFSetup.cpp | 133 ++++++++++++++++++ Demos3/ImportURDFDemo/ImportURDFSetup.h | 16 +++ .../include/urdf_parser/urdf_parser.h | 4 +- btgui/urdf/urdfdom/urdf_parser/src/joint.cpp | 12 +- btgui/urdf/urdfdom/urdf_parser/src/link.cpp | 10 +- btgui/urdf/urdfdom/urdf_parser/src/model.cpp | 4 +- btgui/urdf/urdfdom/urdf_parser/src/pose.cpp | 8 +- btgui/urdf/urdfdom/urdf_parser/src/twist.cpp | 2 +- .../urdf_parser/src/urdf_model_state.cpp | 2 +- .../urdfdom/urdf_parser/src/urdf_sensor.cpp | 2 +- btgui/urdf/urdfdom/urdf_parser/src/world.cpp | 4 +- .../urdf_model/include/urdf_model/joint.h | 4 +- .../urdf_model/include/urdf_model/link.h | 2 +- .../urdf_model/include/urdf_model/model.h | 4 +- .../urdf_model/include/urdf_model/pose.h | 6 +- .../urdf_model/include/urdf_model/twist.h | 2 +- 19 files changed, 219 insertions(+), 41 deletions(-) create mode 100644 Demos3/ImportURDFDemo/ImportURDFSetup.cpp create mode 100644 Demos3/ImportURDFDemo/ImportURDFSetup.h diff --git a/Demos/CommonRigidBodySetup.h b/Demos/CommonRigidBodySetup.h index 0520b038d..41507db05 100644 --- a/Demos/CommonRigidBodySetup.h +++ b/Demos/CommonRigidBodySetup.h @@ -70,14 +70,15 @@ struct CommonRigidBodySetup : public CommonPhysicsSetup //cleanup in the reverse order of creation/initialization //remove the rigidbodies from the dynamics world and delete them - int i; - for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--) - { - m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i)); - } + if (m_dynamicsWorld) { + int i; + for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--) + { + m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i)); + } for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) { btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; diff --git a/Demos3/AllBullet2Demos/BulletDemoEntries.h b/Demos3/AllBullet2Demos/BulletDemoEntries.h index b03fe08fe..9f1ae4450 100644 --- a/Demos3/AllBullet2Demos/BulletDemoEntries.h +++ b/Demos3/AllBullet2Demos/BulletDemoEntries.h @@ -15,6 +15,7 @@ #include "../bullet2/ChainDemo/ChainDemo.h" #include "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h" #include "../../Demos/ConstraintDemo/ConstraintPhysicsSetup.h" +#include "../ImportURDFDemo/ImportUrdfSetup.h" static BulletDemoInterface* MyCcdPhysicsDemoCreateFunc(SimpleOpenGL3App* app) @@ -35,6 +36,11 @@ static BulletDemoInterface* MyConstraintCreateFunc(SimpleOpenGL3App* app) return new BasicDemo(app, physicsSetup); } +static BulletDemoInterface* MyImportUrdfCreateFunc(SimpleOpenGL3App* app) +{ + CommonPhysicsSetup* physicsSetup = new ImportUrdfDemo(); + return new BasicDemo(app, physicsSetup); +} struct BulletDemoEntry { @@ -54,7 +60,8 @@ static BulletDemoEntry allDemos[]= { 1, "CcdDemo", MyCcdPhysicsDemoCreateFunc }, { 1, "Kinematic", MyKinematicObjectCreateFunc }, { 1, "Constraints", MyConstraintCreateFunc }, - + { 1, "URDF", MyImportUrdfCreateFunc }, + /* {1,"ChainDemo",ChainDemo::MyCreateFunc}, // {0, "Stress tests", 0 }, diff --git a/Demos3/AllBullet2Demos/CMakeLists.txt b/Demos3/AllBullet2Demos/CMakeLists.txt index 850ef5ba4..965e634ea 100644 --- a/Demos3/AllBullet2Demos/CMakeLists.txt +++ b/Demos3/AllBullet2Demos/CMakeLists.txt @@ -27,7 +27,7 @@ SET(App_AllBullet2Demos_SRCS ../bullet2/BasicDemo/BasicDemo.cpp ../bullet2/BasicDemo/BasicDemo.h # the next few demos are not converted to 'newer' structure yet -# target is to convert all Bullet 2 demos in new structure, but need to settle down on features +# target is to convert all Bullet 2 demos in new structure but need to settle down on features # ../bullet2/BasicDemo/HingeDemo.cpp # ../bullet2/BasicDemo/HingeDemo.h # ../bullet2/ChainDemo/ChainDemo.cpp @@ -38,9 +38,30 @@ SET(App_AllBullet2Demos_SRCS # ../bullet2/LuaDemo/LuaDemo.h ../GpuDemos/gwenUserInterface.cpp ../GpuDemos/gwenUserInterface.h + ../ImportURDFDemo/ImportURDFSetup.cpp + ../ImportURDFDemo/ImportURDFSetup.h ../../btgui/Timing/b3Clock.cpp ../../btgui/Timing/b3Clock.h - + ../../btgui/urdf/urdfdom/urdf_parser/src/pose.cpp + ../../btgui/urdf/urdfdom/urdf_parser/src/model.cpp + ../../btgui/urdf/urdfdom/urdf_parser/src/link.cpp + ../../btgui/urdf/urdfdom/urdf_parser/src/joint.cpp + ../../btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h + ../../btgui/urdf/urdfdom_headers/urdf_exception/include/urdf_exception/exception.h + ../../btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h + ../../btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h + ../../btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h + ../../btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h + ../../btgui/tinyxml/tinystr.cpp + ../../btgui/tinyxml/tinyxml.cpp + ../../btgui/tinyxml/tinyxmlerror.cpp + ../../btgui/tinyxml/tinyxmlparser.cpp + ../../btgui/urdf/boost_replacement/lexical_cast.h + ../../btgui/urdf/boost_replacement/shared_ptr.h + ../../btgui/urdf/boost_replacement/printf_console.cpp + ../../btgui/urdf/boost_replacement/printf_console.h + ../../btgui/urdf/boost_replacement/string_split.cpp + ../../btgui/urdf/boost_replacement/string_split.h ${BULLET_PHYSICS_SOURCE_DIR}/build3/bullet.rc ) diff --git a/Demos3/ImportURDFDemo/ImportURDFSetup.cpp b/Demos3/ImportURDFDemo/ImportURDFSetup.cpp new file mode 100644 index 000000000..e20b8d5f6 --- /dev/null +++ b/Demos3/ImportURDFDemo/ImportURDFSetup.cpp @@ -0,0 +1,133 @@ +#include "ImportURDFSetup.h" + +ImportUrdfDemo::ImportUrdfDemo() +{ + +} + +ImportUrdfDemo::~ImportUrdfDemo() +{ + +} + + + + +#include "urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h" +#include +#include + +using namespace urdf; + +void printTree(my_shared_ptr link,int level = 0) +{ + level+=2; + int count = 0; + for (std::vector >::const_iterator child = link->child_links.begin(); child != link->child_links.end(); child++) + { + if (*child) + { + for(int j=0;jname << std::endl; + // first grandchild + printTree(*child,level); + } + else + { + for(int j=0;jname << " has a null child!" << *child << std::endl; + } + } + +} + + +#define MSTRINGIFY(A) #A + + +const char* urdf_char = MSTRINGIFY( + + + + + + + + + + + + + + + + + + + + + ); + +const char* urdf_char2 = MSTRINGIFY( + + + + + + + + + + + ); + +int main2(int argc, char** argv) +{ + + std::string xml_string; + + if (argc < 2){ + std::cerr << "No URDF file name provided, using a dummy test URDF" << std::endl; + + xml_string = std::string(urdf_char); + + } else + { + + + std::fstream xml_file(argv[1], std::fstream::in); + while ( xml_file.good() ) + { + std::string line; + std::getline( xml_file, line); + xml_string += (line + "\n"); + } + xml_file.close(); + } + + my_shared_ptr robot = parseURDF(xml_string); + if (!robot){ + std::cerr << "ERROR: Model Parsing the xml failed" << std::endl; + return -1; + } + std::cout << "robot name is: " << robot->getName() << std::endl; + + // get info from parser + std::cout << "---------- Successfully Parsed XML ---------------" << std::endl; + // get root link + my_shared_ptr root_link=robot->getRoot(); + if (!root_link) return -1; + + std::cout << "root Link: " << root_link->name << " has " << root_link->child_links.size() << " child(ren)" << std::endl; + + + // print entire tree + printTree(root_link); + return 0; +} + + +void ImportUrdfDemo::initPhysics(GraphicsPhysicsBridge& gfxBridge) +{ + main2(0,0); +} \ No newline at end of file diff --git a/Demos3/ImportURDFDemo/ImportURDFSetup.h b/Demos3/ImportURDFDemo/ImportURDFSetup.h new file mode 100644 index 000000000..043c6f438 --- /dev/null +++ b/Demos3/ImportURDFDemo/ImportURDFSetup.h @@ -0,0 +1,16 @@ +#ifndef IMPORT_URDF_SETUP_H +#define IMPORT_URDF_SETUP_H + + +#include "../../Demos/CommonRigidBodySetup.h" + +class ImportUrdfDemo : public CommonRigidBodySetup +{ +public: + ImportUrdfDemo(); + virtual ~ImportUrdfDemo(); + + virtual void initPhysics(GraphicsPhysicsBridge& gfxBridge); +}; + +#endif //IMPORT_URDF_SETUP_H diff --git a/btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h b/btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h index b4bf6082a..336af0fa3 100644 --- a/btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h +++ b/btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h @@ -40,7 +40,7 @@ #include #include -#include +#include "tinyxml/tinyxml.h" //#include @@ -49,7 +49,7 @@ #endif //M_PI -#include +#include diff --git a/btgui/urdf/urdfdom/urdf_parser/src/joint.cpp b/btgui/urdf/urdfdom/urdf_parser/src/joint.cpp index 3852fe08f..bde0c5f73 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/joint.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/joint.cpp @@ -35,22 +35,22 @@ /* Author: John Hsu */ #include -#include +#include #ifdef URDF_USE_BOOST #include #else -#include +#include #endif -#include +#include #ifdef URDF_USE_CONSOLE_BRIDGE #include #else - #include "printf_console.h" + #include "urdf/boost_replacement/printf_console.h" #endif -#include -#include +#include +#include namespace urdf{ diff --git a/btgui/urdf/urdfdom/urdf_parser/src/link.cpp b/btgui/urdf/urdfdom/urdf_parser/src/link.cpp index e28906c3c..a224146b3 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/link.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/link.cpp @@ -35,22 +35,22 @@ /* Author: Wim Meeussen */ -#include -#include +#include +#include //#include //#include #ifdef URDF_USE_BOOST #include #else -#include +#include #endif #include -#include +#include #ifdef URDF_USE_CONSOLE_BRIDGE #include #else -#include "printf_console.h" +#include "urdf/boost_replacement/printf_console.h" #endif diff --git a/btgui/urdf/urdfdom/urdf_parser/src/model.cpp b/btgui/urdf/urdfdom/urdf_parser/src/model.cpp index 8819c739e..7c9d7e9c7 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/model.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/model.cpp @@ -35,11 +35,11 @@ /* Author: Wim Meeussen */ //#include #include -#include "urdf_parser/urdf_parser.h" +#include "urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h" #ifdef URDF_USE_CONSOLE_BRIDGE #include #else - #include "printf_console.h" + #include "urdf/boost_replacement/printf_console.h" #endif namespace urdf{ diff --git a/btgui/urdf/urdfdom/urdf_parser/src/pose.cpp b/btgui/urdf/urdfdom/urdf_parser/src/pose.cpp index 6b78e1da9..e90247c0e 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/pose.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/pose.cpp @@ -35,7 +35,7 @@ /* Author: Wim Meeussen, John Hsu */ -#include +#include #include #include //#include @@ -44,11 +44,11 @@ #ifdef URDF_USE_CONSOLE_BRIDGE #include #else -#include "printf_console.h" +#include "urdf/boost_replacement/printf_console.h" #endif -#include -#include +#include +#include namespace urdf{ diff --git a/btgui/urdf/urdfdom/urdf_parser/src/twist.cpp b/btgui/urdf/urdfdom/urdf_parser/src/twist.cpp index 211782564..4980e17de 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/twist.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/twist.cpp @@ -35,7 +35,7 @@ /* Author: John Hsu */ -#include +#include #include #include #include diff --git a/btgui/urdf/urdfdom/urdf_parser/src/urdf_model_state.cpp b/btgui/urdf/urdfdom/urdf_parser/src/urdf_model_state.cpp index 4cb60f892..f30b8456e 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/urdf_model_state.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/urdf_model_state.cpp @@ -35,7 +35,7 @@ /* Author: John Hsu */ -#include +#include #include #include #include diff --git a/btgui/urdf/urdfdom/urdf_parser/src/urdf_sensor.cpp b/btgui/urdf/urdfdom/urdf_parser/src/urdf_sensor.cpp index 58db5cdbe..85a886d3f 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/urdf_sensor.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/urdf_sensor.cpp @@ -35,7 +35,7 @@ /* Author: John Hsu */ -#include +#include #include #include #include diff --git a/btgui/urdf/urdfdom/urdf_parser/src/world.cpp b/btgui/urdf/urdfdom/urdf_parser/src/world.cpp index f858b259d..ddc27c5f3 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/world.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/world.cpp @@ -35,8 +35,8 @@ /* Author: Wim Meeussen */ -#include -#include +#include +#include #include #include #include diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h index 0cfb80fc7..cd889dcec 100644 --- a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h @@ -43,10 +43,10 @@ #include #define my_shared_ptr my_shared_ptr #else -#include +#include #endif -#include "urdf_model/pose.h" +#include namespace urdf{ diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h index 649516469..67a1647ec 100644 --- a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h @@ -46,7 +46,7 @@ #include #include #else - #include + #include #endif #include "joint.h" diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h index b40fdb53d..5bd11a6d6 100644 --- a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h @@ -40,9 +40,9 @@ #include #include //#include -#include +#include -#include +#include namespace urdf { diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h index 1f99efb3c..93183c8f8 100644 --- a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h @@ -49,11 +49,11 @@ #include #include #else - #include - #include + #include + #include #endif //URDF_USE_BOOST -#include +#include #include namespace urdf{ diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/twist.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/twist.h index ba57e4c0c..5560de34a 100644 --- a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/twist.h +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/twist.h @@ -41,7 +41,7 @@ #include #include #include -#include +#include namespace urdf{ From fa3d01e6af0bf24f3ed7435523bfd1107358fb91 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 18:10:50 -0700 Subject: [PATCH 112/116] fix build --- Demos3/AllBullet2Demos/BulletDemoEntries.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Demos3/AllBullet2Demos/BulletDemoEntries.h b/Demos3/AllBullet2Demos/BulletDemoEntries.h index 9f1ae4450..75a7945d1 100644 --- a/Demos3/AllBullet2Demos/BulletDemoEntries.h +++ b/Demos3/AllBullet2Demos/BulletDemoEntries.h @@ -15,7 +15,7 @@ #include "../bullet2/ChainDemo/ChainDemo.h" #include "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h" #include "../../Demos/ConstraintDemo/ConstraintPhysicsSetup.h" -#include "../ImportURDFDemo/ImportUrdfSetup.h" +#include "../ImportURDFDemo/ImportURDFSetup.h" static BulletDemoInterface* MyCcdPhysicsDemoCreateFunc(SimpleOpenGL3App* app) From 070802f4ded66e585c5d38b563b6393ffc5e2f39 Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Thu, 31 Jul 2014 18:19:59 -0700 Subject: [PATCH 113/116] fix premake build --- Demos3/AllBullet2Demos/premake4.lua | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Demos3/AllBullet2Demos/premake4.lua b/Demos3/AllBullet2Demos/premake4.lua index 93a648b63..91ad53dd4 100644 --- a/Demos3/AllBullet2Demos/premake4.lua +++ b/Demos3/AllBullet2Demos/premake4.lua @@ -29,6 +29,27 @@ "../../Demos/CcdPhysicsDemo/CcdPhysicsSetup.h", "../../Demos/ConstraintDemo/ConstraintPhysicsSetup.cpp", "../../Demos/ConstraintDemo/ConstraintPhysicsSetup.h", + "../ImportURDFDemo/ImportURDFSetup.cpp", + "../../btgui/urdf/urdfdom/urdf_parser/src/pose.cpp", + "../../btgui/urdf/urdfdom/urdf_parser/src/model.cpp", + "../../btgui/urdf/urdfdom/urdf_parser/src/link.cpp", + "../../btgui/urdf/urdfdom/urdf_parser/src/joint.cpp", + "../../btgui/urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h", + "../../btgui/urdf/urdfdom_headers/urdf_exception/include/urdf_exception/exception.h", + "../../btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/pose.h", + "../../btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/model.h", + "../../btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/link.h", + "../../btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/joint.h", + "../../btgui/tinyxml/tinystr.cpp", + "../../btgui/tinyxml/tinyxml.cpp", + "../../btgui/tinyxml/tinyxmlerror.cpp", + "../../btgui/tinyxml/tinyxmlparser.cpp", + "../../btgui/urdf/boost_replacement/lexical_cast.h", + "../../btgui/urdf/boost_replacement/shared_ptr.h", + "../../btgui/urdf/boost_replacement/printf_console.cpp", + "../../btgui/urdf/boost_replacement/printf_console.h", + "../../btgui/urdf/boost_replacement/string_split.cpp", + "../../btgui/urdf/boost_replacement/string_split.h", "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.cpp", "../bullet2/FeatherstoneMultiBodyDemo/BulletMultiBodyDemos.h", "../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.cpp", From 86f793a6ae63355f9824331930fbfeaf24bb7cfc Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Fri, 1 Aug 2014 13:01:31 -0700 Subject: [PATCH 114/116] start of URDF parsing (extremely preliminary) --- Demos3/AllBullet2Demos/main.cpp | 8 +- Demos3/ImportURDFDemo/ImportURDFSetup.cpp | 188 ++++++++++++++++-- btgui/OpenGLWindow/GLInstancingRenderer.cpp | 4 + btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 1 + btgui/OpenGLWindow/SimpleOpenGL3App.h | 2 +- .../urdf_model/include/urdf_model/color.h | 3 +- 6 files changed, 188 insertions(+), 18 deletions(-) diff --git a/Demos3/AllBullet2Demos/main.cpp b/Demos3/AllBullet2Demos/main.cpp index 230ceaf63..8432752df 100644 --- a/Demos3/AllBullet2Demos/main.cpp +++ b/Demos3/AllBullet2Demos/main.cpp @@ -330,9 +330,11 @@ int main(int argc, char* argv[]) GLint err = glGetError(); assert(err==GL_NO_ERROR); app->m_instancingRenderer->init(); - app->m_instancingRenderer->updateCamera(); - - app->drawGrid(); + DrawGridData dg; +// dg.upAxis = 2; + + app->m_instancingRenderer->updateCamera(dg.upAxis); + app->drawGrid(dg); static int frameCount = 0; frameCount++; diff --git a/Demos3/ImportURDFDemo/ImportURDFSetup.cpp b/Demos3/ImportURDFDemo/ImportURDFSetup.cpp index e20b8d5f6..393bec06e 100644 --- a/Demos3/ImportURDFDemo/ImportURDFSetup.cpp +++ b/Demos3/ImportURDFDemo/ImportURDFSetup.cpp @@ -45,7 +45,7 @@ void printTree(my_shared_ptr link,int level = 0) #define MSTRINGIFY(A) #A -const char* urdf_char = MSTRINGIFY( +const char* urdf_char2 = MSTRINGIFY( @@ -68,7 +68,7 @@ const char* urdf_char = MSTRINGIFY( ); -const char* urdf_char2 = MSTRINGIFY( +const char* urdf_char1 = MSTRINGIFY( @@ -81,8 +81,174 @@ const char* urdf_char2 = MSTRINGIFY( ); -int main2(int argc, char** argv) +const char* urdf_char3 = MSTRINGIFY( + + + + + + + + + + + + + + + + + + + + + + + ); + +const char* urdf_char = MSTRINGIFY( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + + +#include "BulletCollision/CollisionShapes/btCylinderShape.h" + +void URDFvisual2BulletCollisionShape(my_shared_ptr link, GraphicsPhysicsBridge& gfxBridge) { + btCollisionShape* shape = 0; + + { + printf("converting link %s",link->name.c_str()); + + for (int v=0;vvisual_array.size();v++) + { + const Visual* visual = link->visual_array[v].get(); + + + switch (visual->geometry->type) + { + // , BOX, CYLINDER, MESH: + case Geometry::CYLINDER: + { + printf("processing a cylinder\n"); + urdf::Cylinder* cyl = (urdf::Cylinder*)visual->geometry.get(); + btVector3 halfExtents(cyl->radius,cyl->radius,cyl->length); + btCylinderShapeZ* cylZShape = new btCylinderShapeZ(halfExtents); + shape = cylZShape; + break; + } + case Geometry::BOX: + { + printf("processing a box\n"); + urdf::Box* box = (urdf::Box*)visual->geometry.get(); + btVector3 halfExtents(box->dim.x,box->dim.y,box->dim.z); + btBoxShape* boxShape = new btBoxShape(halfExtents); + shape = boxShape; + break; + } + case Geometry::SPHERE: + { + break; + } + case Geometry::MESH: + { + break; + } + default: + { + printf("Error: unknown visual geometry type\n"); + } + } + + if (shape) + { + gfxBridge.createCollisionShapeGraphicsObject(shape); + + btVector3 color(0,0,1); + if (visual->material.get()) + { + color.setValue(visual->material->color.r,visual->material->color.g,visual->material->color.b);//,visual->material->color.a); + } + // btScalar mass, btMotionState* motionState, btCollisionShape* collisionShape, const btVector3& localInertia=btVector3(0,0,0)): + btScalar mass = 0.f; + btVector3 localInertia(0,0,0); + if (mass) + { + shape->calculateLocalInertia(mass,localInertia); + } + btRigidBody::btRigidBodyConstructionInfo rbci(mass,0,shape,localInertia); + btRigidBody* body = new btRigidBody(rbci); + gfxBridge.createRigidBodyGraphicsObject(body,color); + } + } + } + + for (std::vector >::const_iterator child = link->child_links.begin(); child != link->child_links.end(); child++) + { + if (*child) + { + URDFvisual2BulletCollisionShape(*child,gfxBridge); + + } + else + { + std::cout << "root link: " << link->name << " has a null child!" << *child << std::endl; + } + } + + + + +} +void ImportUrdfDemo::initPhysics(GraphicsPhysicsBridge& gfxBridge) +{ + int argc=0; + char* filename="somefile.urdf"; std::string xml_string; @@ -95,7 +261,7 @@ int main2(int argc, char** argv) { - std::fstream xml_file(argv[1], std::fstream::in); + std::fstream xml_file(filename, std::fstream::in); while ( xml_file.good() ) { std::string line; @@ -120,14 +286,12 @@ int main2(int argc, char** argv) std::cout << "root Link: " << root_link->name << " has " << root_link->child_links.size() << " child(ren)" << std::endl; - // print entire tree printTree(root_link); - return 0; -} - - -void ImportUrdfDemo::initPhysics(GraphicsPhysicsBridge& gfxBridge) -{ - main2(0,0); + + { + URDFvisual2BulletCollisionShape(root_link, gfxBridge); + } + + } \ No newline at end of file diff --git a/btgui/OpenGLWindow/GLInstancingRenderer.cpp b/btgui/OpenGLWindow/GLInstancingRenderer.cpp index 23a142f78..f64c65232 100644 --- a/btgui/OpenGLWindow/GLInstancingRenderer.cpp +++ b/btgui/OpenGLWindow/GLInstancingRenderer.cpp @@ -1311,6 +1311,10 @@ void writeTextureToPng(int textureWidth, int textureHeight, const char* fileName void GLInstancingRenderer::renderScene() { + //avoid some Intel driver on a Macbook Pro to lock-up + //todo: figure out what is going on on that machine + + glFlush(); if (useShadowMap) { diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index b3a739194..80799a12f 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -319,6 +319,7 @@ int SimpleOpenGL3App::registerGraphicsSphereShape(float radius, bool usePointSpr return graphicsShapeIndex; } + void SimpleOpenGL3App::drawGrid(DrawGridData data) { int gridSize = data.gridSize; diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.h b/btgui/OpenGLWindow/SimpleOpenGL3App.h index eb4be1f6d..adce19245 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.h +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.h @@ -41,7 +41,7 @@ struct SimpleOpenGL3App void dumpNextFrameToPng(const char* pngFilename); void dumpFramesToVideo(const char* mp4Filename); - + void drawGrid(DrawGridData data=DrawGridData()); void swapBuffer(); void drawText( const char* txt, int posX, int posY); diff --git a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/color.h b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/color.h index ffb70c922..9c15dd77b 100644 --- a/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/color.h +++ b/btgui/urdf/urdfdom_headers/urdf_model/include/urdf_model/color.h @@ -65,7 +65,7 @@ public: this->clear(); std::vector pieces; std::vector rgba; -#if 0 + boost::split( pieces, vector_str, boost::is_any_of(" ")); for (unsigned int i = 0; i < pieces.size(); ++i) { @@ -86,7 +86,6 @@ public: { return false; } -#endif this->r = rgba[0]; this->g = rgba[1]; this->b = rgba[2]; From 3c9ee805046ef26fd971eb5fd62b762080da43c0 Mon Sep 17 00:00:00 2001 From: = <=> Date: Fri, 1 Aug 2014 14:25:56 -0700 Subject: [PATCH 115/116] fix compile error --- Demos3/ImportURDFDemo/ImportURDFSetup.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Demos3/ImportURDFDemo/ImportURDFSetup.cpp b/Demos3/ImportURDFDemo/ImportURDFSetup.cpp index 393bec06e..3db2ed3f0 100644 --- a/Demos3/ImportURDFDemo/ImportURDFSetup.cpp +++ b/Demos3/ImportURDFDemo/ImportURDFSetup.cpp @@ -274,7 +274,7 @@ void ImportUrdfDemo::initPhysics(GraphicsPhysicsBridge& gfxBridge) my_shared_ptr robot = parseURDF(xml_string); if (!robot){ std::cerr << "ERROR: Model Parsing the xml failed" << std::endl; - return -1; + return ; } std::cout << "robot name is: " << robot->getName() << std::endl; @@ -282,7 +282,7 @@ void ImportUrdfDemo::initPhysics(GraphicsPhysicsBridge& gfxBridge) std::cout << "---------- Successfully Parsed XML ---------------" << std::endl; // get root link my_shared_ptr root_link=robot->getRoot(); - if (!root_link) return -1; + if (!root_link) return ; std::cout << "root Link: " << root_link->name << " has " << root_link->child_links.size() << " child(ren)" << std::endl; @@ -294,4 +294,4 @@ void ImportUrdfDemo::initPhysics(GraphicsPhysicsBridge& gfxBridge) } -} \ No newline at end of file +} From 35fa146f1306413249f61df49435f857e6a2aefe Mon Sep 17 00:00:00 2001 From: = <=> Date: Fri, 1 Aug 2014 14:41:22 -0700 Subject: [PATCH 116/116] fix build --- btgui/urdf/premake4.lua | 6 +----- btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/btgui/urdf/premake4.lua b/btgui/urdf/premake4.lua index 65abdb218..526c9114a 100644 --- a/btgui/urdf/premake4.lua +++ b/btgui/urdf/premake4.lua @@ -14,11 +14,7 @@ includedirs { ".", - "boost_replacement", - "../tinyxml", - "urdfdom/urdf_parser/include", - "urdfdom_headers/urdf_exception/include", - "urdfdom_headers/urdf_model/include", + "..", } diff --git a/btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp b/btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp index 530d64286..67e9eb165 100644 --- a/btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp +++ b/btgui/urdf/urdfdom/urdf_parser/src/check_urdf.cpp @@ -34,7 +34,7 @@ /* Author: Wim Meeussen */ -#include "urdf_parser/urdf_parser.h" +#include "urdf/urdfdom/urdf_parser/include/urdf_parser/urdf_parser.h" #include #include